Skip to content

Commit

Permalink
Display: Don't move the center of the viewport when zooming in when t…
Browse files Browse the repository at this point in the history
…he map is narrower/shorter than the viewport

In the test scenario, toggling between 50%/100% zoom on 1920x1080 will
now correctly switch between "Show the entire map" (50%) and "Show just
the center of the map" (100%).

Fixes #1951

(cherry picked from commit f9fc82d)
  • Loading branch information
jostephd committed Oct 15, 2019
1 parent 104bfed commit 4025eb5
Show file tree
Hide file tree
Showing 3 changed files with 24 additions and 2 deletions.
15 changes: 15 additions & 0 deletions src/display.cpp
Expand Up @@ -2033,13 +2033,28 @@ bool display::set_zoom(unsigned int amount, const bool validate_value_and_set_in
zoom_index_ = std::distance(zoom_levels.begin(), iter);
}

const SDL_Rect& outside_area = map_outside_area();
const SDL_Rect& area = map_area();

//Turn the zoom factor to a double in order to avoid rounding errors.
double zoom_factor = static_cast<double>(new_zoom) / static_cast<double>(zoom_);

// INVARIANT: xpos_ + area.w == xend where xend is as in bounds_check_position()
//
// xpos_: Position of the leftmost visible map pixel of the viewport, in pixels.
// Affected by the current zoom: this->zoom_ pixels to the hex.
//
// xpos_ + area.w/2: Position of the center of the viewport, in pixels.
//
// (xpos_ + area.w/2) * new_zoom/zoom_: Position of the center of the
// viewport, as it would be under new_zoom.
//
// (xpos_ + area.w/2) * new_zoom/zoom_ - area.w/2: Position of the
// leftmost visible map pixel, as it would be under new_zoom.
xpos_ = round_double(((xpos_ + area.w / 2) * zoom_factor) - (area.w / 2));
ypos_ = round_double(((ypos_ + area.h / 2) * zoom_factor) - (area.h / 2));
xpos_ -= (outside_area.w - area.w) / 2;
ypos_ -= (outside_area.h - area.h) / 2;

zoom_ = new_zoom;
bounds_check_position(xpos_, ypos_);
Expand Down
7 changes: 7 additions & 0 deletions src/display.hpp
Expand Up @@ -732,11 +732,18 @@ class display : public video2::draw_layering
CVideo& screen_;
size_t currentTeam_;
bool dont_show_all_; //const team *viewpoint_;
/// Position of the top-left corner of the viewport, in pixels.
///
/// Dependent on zoom_.. For example, ypos_==72 only means we're one
/// hex below the top of the map when zoom_ == 72 (the default value).
int xpos_, ypos_;
bool view_locked_;
theme theme_;
/// The current zoom, in pixels (on screen) per 72 pixels (in the
/// graphic assets), i.e., 72 means 100%.
static unsigned int zoom_;
int zoom_index_;
/// The previous value of zoom_.
static unsigned int last_zoom_;
const std::unique_ptr<fake_unit_manager> fake_unit_man_;
const std::unique_ptr<terrain_builder> builder_;
Expand Down
4 changes: 2 additions & 2 deletions src/map/map.hpp
Expand Up @@ -86,10 +86,10 @@ class gamemap
/** Overlays another map onto this one at the given position. */
void overlay(const gamemap& m, const config& rules, map_location loc);

/** Effective map width. */
/** Effective map width, in hexes. */
int w() const { return w_; }

/** Effective map height. */
/** Effective map height, in hexes. */
int h() const { return h_; }

/** Size of the map border. */
Expand Down

0 comments on commit 4025eb5

Please sign in to comment.