diff --git a/src/object/background.cpp b/src/object/background.cpp index 1808274671d..7008e00cb4d 100644 --- a/src/object/background.cpp +++ b/src/object/background.cpp @@ -316,8 +316,7 @@ void Background::draw_image(DrawingContext& context, const Vector& pos_) { const Sizef level(d_gameobject_manager->get_width(), d_gameobject_manager->get_height()); - const Sizef screen(context.get_width(), - context.get_height()); + const Sizef screen = context.get_viewport().get_size(); const Sizef parallax_image_size((1.0f - m_parallax_speed.x) * screen.width + level.width * m_parallax_speed.x, (1.0f - m_parallax_speed.y) * screen.height + level.height * m_parallax_speed.y); @@ -334,7 +333,6 @@ Background::draw_image(DrawingContext& context, const Vector& pos_) const int end_y = static_cast(ceilf((cliprect.get_bottom() - (pos_.y + img_h/2.0f)) / img_h)) + 1; Canvas& canvas = context.get_canvas(m_target); - context.set_flip(context.get_flip() ^ m_flip); if (m_fill) { @@ -407,7 +405,6 @@ Background::draw_image(DrawingContext& context, const Vector& pos_) break; } } - context.set_flip(context.get_flip() ^ m_flip); } void @@ -418,19 +415,27 @@ Background::draw(DrawingContext& context) if (!m_image) return; + + context.push_transform(); + if (!context.perspective_scale(m_parallax_speed.x, m_parallax_speed.y)) { + //The background is placed behind the camera. + context.pop_transform(); + return; + } + context.set_flip(context.get_flip() ^ m_flip); - Sizef level_size(d_gameobject_manager->get_width(), + const Sizef level_size(d_gameobject_manager->get_width(), d_gameobject_manager->get_height()); - Sizef screen(context.get_width(), - context.get_height()); - Sizef translation_range = level_size - screen; - Vector center_offset(context.get_translation().x - translation_range.width / 2.0f, - context.get_translation().y - translation_range.height / 2.0f); - - Vector pos(level_size.width / 2, - level_size.height / 2); + const Sizef screen = context.get_viewport().get_size(); + const Sizef translation_range = level_size - screen; + const Vector center_offset(context.get_translation().x - translation_range.width / 2.0f, + context.get_translation().y - translation_range.height / 2.0f); + + const Vector pos(level_size.width / 2, + level_size.height / 2); draw_image(context, pos + m_scroll_offset + Vector(center_offset.x * (1.0f - m_parallax_speed.x), center_offset.y * (1.0f - m_parallax_speed.y))); + context.pop_transform(); } namespace { diff --git a/src/object/tilemap.cpp b/src/object/tilemap.cpp index 422474fc05e..1c457abc4f0 100644 --- a/src/object/tilemap.cpp +++ b/src/object/tilemap.cpp @@ -442,6 +442,15 @@ TileMap::draw(DrawingContext& context) context.push_transform(); + const bool normal_speed = m_editor_active && Editor::is_active(); + const float speed_x = normal_speed ? 1.0f : m_speed_x; + const float speed_y = normal_speed ? 1.0f : m_speed_y; + if (!context.perspective_scale(speed_x, speed_y)) { + //The tilemap is placed behind the camera. + context.pop_transform(); + return; + } + if (m_flip != NO_FLIP) context.set_flip(m_flip); if (m_editor_active) { @@ -454,9 +463,7 @@ TileMap::draw(DrawingContext& context) const float trans_x = context.get_translation().x; const float trans_y = context.get_translation().y; - const bool normal_speed = m_editor_active && Editor::is_active(); - context.set_translation(Vector(trans_x * (normal_speed ? 1.0f : m_speed_x), - trans_y * (normal_speed ? 1.0f : m_speed_y))); + context.set_translation(Vector(trans_x * speed_x, trans_y * speed_y)); Rectf draw_rect = context.get_cliprect(); Rect t_draw_rect = get_tiles_overlapping(draw_rect); diff --git a/src/video/drawing_context.cpp b/src/video/drawing_context.cpp index c33a6d6570f..66bbd62b9fc 100644 --- a/src/video/drawing_context.cpp +++ b/src/video/drawing_context.cpp @@ -133,4 +133,27 @@ DrawingContext::get_size() const return Vector(get_width(), get_height()) * transform().scale; } +bool +DrawingContext::perspective_scale(float speed_x, float speed_y) +{ + DrawingTransform& tfm = transform(); + if (tfm.scale == 1 || speed_x < 0 || speed_y < 0) { + //Trivial or unreal situation: Do not apply perspective. + return true; + } + const float speed = sqrt(speed_x * speed_y); + if (speed == 0) { + //Special case: The object appears to be infinitely far. + tfm.scale = 1.0; + return true; + } + const float t = tfm.scale * (1 / speed - 1) + 1; + if (t <= 0) { + //The object will appear behind the camera, therefore we shall not see it. + return false; + } + tfm.scale /= speed * t; + return true; +} + /* EOF */ diff --git a/src/video/drawing_context.hpp b/src/video/drawing_context.hpp index ad250db5756..737e7b8d16d 100644 --- a/src/video/drawing_context.hpp +++ b/src/video/drawing_context.hpp @@ -77,6 +77,9 @@ class DrawingContext final float get_scale() const { return transform().scale; } void scale(float scale) { transform().scale *= scale; } + + /** Recalculates the scaling factor for parallax layers.*/ + bool perspective_scale(float speed_x, float speed_y); /** Apply that flip in the next draws (flips are listed on surface.h). */ void set_flip(Flip flip);