Author: alink
Date: Sun Jun 22 23:26:17 2008
New Revision: 27418
URL: http://svn.gna.org/viewcvs/wesnoth?rev=27418&view=rev
Log:
Optimize scrolling, haloes and out-of-hex units:
by adding a more precise rectangle to hexes conversion (at the pixel level,
instead of padding with full hexes). This often halves the invalidated hexes.
Added a new structure+iterator for simplifying this frequent operation.
Remove various now unneeded functions.
Modified:
trunk/src/display.cpp
trunk/src/display.hpp
trunk/src/game_display.cpp
trunk/src/halo.cpp
trunk/src/unit_frame.cpp
Modified: trunk/src/display.cpp
URL:
http://svn.gna.org/viewcvs/wesnoth/trunk/src/display.cpp?rev=27418&r1=27417&r2=27418&view=diff
==============================================================================
--- trunk/src/display.cpp (original)
+++ trunk/src/display.cpp Sun Jun 22 23:26:17 2008
@@ -331,47 +331,58 @@
return res;
}
-void display::get_rect_hex_bounds(SDL_Rect rect, gamemap::location &topleft,
gamemap::location &bottomright) const
-{
- // Change the coordinates of the rect send
- // to be relative to the map area, instead of the screen area.
- const SDL_Rect& map_rect = map_area();
- rect.x -= map_rect.x;
- rect.y -= map_rect.y;
- // Only move the left side.
- // The right side should remain
- // at the same coordinates, so fix that
- rect.w += map_rect.x;
- rect.h += map_rect.y;
-
- const int tile_width = hex_width();
-
- // Adjust for the border
- topleft.x = static_cast<int>(-theme_.border().size + (xpos_ + rect.x) /
tile_width);
- topleft.y = static_cast<int>(-theme_.border().size + (ypos_ + rect.y -
(is_odd(topleft.x) ? zoom_/2 : 0)) / zoom_);
-
- bottomright.x = static_cast<int>(-theme_.border().size + (xpos_ +
rect.x + rect.w) / tile_width);
- bottomright.y = static_cast<int>(-theme_.border().size + ((ypos_ +
rect.y + rect.h) - (is_odd(bottomright.x) ? zoom_/2 : 0)) / zoom_);
-
- // This routine does a rough approximation, so might be off by one.
- // To be sure enough tiles are included, the boundaries are increased
- // by one if the terrain is "on the map" due to the extra border.
- // This uses a bit larger area.
- //! @todo FIXME This routine should properly determine what to update,
- //! and not increase by one just to be sure.
- if(topleft.x >= -1) {
- topleft.x--;
- }
- if(topleft.y >= -1) {
- topleft.y--;
- }
- if(bottomright.x <= map_.w()) {
- bottomright.x++;
- }
- if(bottomright.y <= map_.h()) {
- bottomright.y++;
- }
-}
+void display::rect_of_hexes::iterator::operator++()
+{
+ if (loc_.y < rect_.bottom[loc_.x & 1])
+ loc_.y++;
+ else {
+ loc_.x++;
+ loc_.y = rect_.top[loc_.x & 1];
+ }
+}
+
+// begin is top left, and end is after bottom right
+display::rect_of_hexes::iterator display::rect_of_hexes::begin()
+{
+ return iterator(gamemap::location(left, top[left & 1]), *this);
+}
+display::rect_of_hexes::iterator display::rect_of_hexes::end()
+{
+ return iterator(gamemap::location(right+1, top[(right+1) & 1]), *this);
+}
+
+const display::rect_of_hexes display::hexes_under_rect(const SDL_Rect& r) const
+{
+ rect_of_hexes res;
+
+ SDL_Rect map_rect = map_area();
+ // translate rect coordinates from screen-based to map_area-based
+ int x = xpos_ - map_rect.x + r.x;
+ int y = ypos_ - map_rect.y + r.y;
+ // we use the "double" type to avoid important rounding error (size of
an hex!)
+ // we will also need to use std::floor to avoid bad rounding at border
(negative values)
+ double tile_width = hex_width();
+ double tile_size = hex_size();
+ double border = theme_.border().size;
+ // the "-0.25" is for the horizontal imbrication of hexes (1/4
overlaps).
+ res.left = static_cast<int>(std::floor(-border + x / tile_width -
0.25));
+ // we remove 1 pixel of the rectangle dimensions
+ // (the rounded division take one pixel more than needed)
+ res.right = static_cast<int>(std::floor(-border + (x + r.w-1) /
tile_width));
+
+ // for odd x, we must shift up one half-hex. Since x will vary along
the edge,
+ // we store here the y values for even and odd x, respectively
+ res.top[0] = static_cast<int>(std::floor(-border + y / tile_size));
+ res.top[1] = static_cast<int>(std::floor(-border + y / tile_size -
0.5));
+ res.bottom[0] = static_cast<int>(std::floor(-border + (y + r.h-1) /
tile_size));
+ res.bottom[1] = static_cast<int>(std::floor(-border + (y + r.h-1) /
tile_size - 0.5));
+
+ // TODO: in some rare cases (1/16), a corner of the big rect is on a
tile
+ // (the 72x72 rectangle containing the hex) but not on the hex itself
+ // Can maybe be optimized by using pixel_position_to_hex
+
+ return res;
+};
int display::get_location_x(const gamemap::location& loc) const
{
@@ -411,12 +422,6 @@
loc.y = map_.h() - 1;
return loc;
-}
-
-void display::get_visible_hex_bounds(gamemap::location &topleft,
gamemap::location &bottomright) const
-{
- SDL_Rect r = map_area();
- get_rect_hex_bounds(r, topleft, bottomright);
}
int display::screenshot(std::string filename, bool map_screenshot)
@@ -1051,16 +1056,13 @@
invalidate(mouseoverHex_);
}
-bool display::invalidate_locations_in_rect(SDL_Rect r)
+bool display::invalidate_locations_in_rect(const SDL_Rect& rect)
{
bool result = false;
- gamemap::location topleft, bottomright;
- get_rect_hex_bounds(r, topleft, bottomright);
- for (int x = topleft.x; x <= bottomright.x; ++x) {
- for (int y = topleft.y; y <= bottomright.y; ++y) {
- gamemap::location loc(x, y);
- result |= invalidate(loc);
- }
+ rect_of_hexes hexes = hexes_under_rect(rect);
+ rect_of_hexes::iterator i = hexes.begin(), end = hexes.end();
+ for (;i != end; ++i) {
+ result |= invalidate(*i);
}
return result;
}
@@ -1114,13 +1116,10 @@
if(invalidateAll_) {
DBG_DP << "draw() with invalidateAll\n";
- gamemap::location topleft;
- gamemap::location bottomright;
- get_visible_hex_bounds(topleft, bottomright);
- for(int x = topleft.x; x <= bottomright.x; ++x)
- for(int y = topleft.y; y <= bottomright.y; ++y)
- invalidated_.insert(gamemap::location(x,y));
+
+ // toggle invalidateAll_ first to allow regular invalidations
invalidateAll_ = false;
+ invalidate_locations_in_rect(map_area());
redrawMinimap_ = true;
}
@@ -1395,15 +1394,15 @@
if (dy != 0) {
SDL_Rect r = map_area();
- r.x = 0;
- r.y = dy < 0 ? r.h+dy : 0;
+ if(dy < 0)
+ r.y = r.y + r.h + dy;
r.h = abs(dy);
invalidate_locations_in_rect(r);
}
if (dx != 0) {
SDL_Rect r = map_area();
- r.x = dx < 0 ? r.w+dx : 0;
- r.y = 0;
+ if (dx < 0)
+ r.x = r.x + r.w + dx;
r.w = abs(dx);
invalidate_locations_in_rect(r);
}
@@ -2134,71 +2133,29 @@
reportSurfaces_[report_num].assign(NULL);
}
}
-bool display::invalidate_rectangle(const gamemap::location& first_corner,
const gamemap::location& second_corner) {
- // unused variable - const SDL_Rect& rect = map_area();
- bool result = false;
-
- const int min_x = minimum<int>(first_corner.x,second_corner.x);
- const int min_y = minimum<int>(first_corner.y,second_corner.y);
- const int max_x = maximum<int>(first_corner.x,second_corner.x);
- const int max_y = maximum<int>(first_corner.y,second_corner.y);
-
- for (int x = min_x; x <= max_x;x++) {
- for (int y = min_y; y <= max_y;y++) {
- result |= invalidate(gamemap::location(x,y));
- }
- // take a margin on Y because of "misaligned hexes"
- gamemap::location margein(x, is_odd(x) ? min_y-1 : max_y+1);
- result |= invalidate(margein);
- }
- return result;
-}
-
-bool display::invalidate_zone(const int x1,const int y1, const int x2, const
int y2) {
- const SDL_Rect& rect = map_area();
- return invalidate_rectangle(pixel_position_to_hex(x1 - rect.x+xpos_, y1
- rect.y+ypos_),pixel_position_to_hex(x2 - rect.x+xpos_, y2 - rect.y+ypos_));
-}
-
-bool display::rectangle_need_update(const gamemap::location& first_corner,
const gamemap::location& second_corner) const {
- const int min_x = minimum<int>(first_corner.x,second_corner.x);
- const int min_y = minimum<int>(first_corner.y,second_corner.y);
- const int max_x = maximum<int>(first_corner.x,second_corner.x);
- const int max_y = maximum<int>(first_corner.y,second_corner.y);
-
- for (int x = min_x; x <= max_x;x++) {
- for (int y = min_y; y <= max_y;y++) {
- // take a margin on Y because of "misaligned hexes"
- if(invalidated_.find(gamemap::location(x,y)) !=
invalidated_.end())
- return true;
- }
- // take a margin on Y because of "misaligned hexes"
- gamemap::location margein(x, is_odd(x) ? min_y-1 : max_y+1);
- if(invalidated_.find(margein) != invalidated_.end())
+
+bool display::rectangle_need_update(const SDL_Rect& rect) const
+{
+ rect_of_hexes hexes = hexes_under_rect(rect);
+ rect_of_hexes::iterator i = hexes.begin(), end = hexes.end();
+ for (;i != end; ++i) {
+ if(invalidated_.find(*i) != invalidated_.end())
return true;
}
return false;
-}
-
-bool display::zone_need_update(const int x1,const int y1, const int x2, const
int y2) const {
- const SDL_Rect& rect = map_area();
- return rectangle_need_update(pixel_position_to_hex(x1 - rect.x+xpos_,
y1 - rect.y+ypos_),pixel_position_to_hex(x2 - rect.x+xpos_, y2 - rect.y+ypos_));
}
void display::invalidate_animations() {
if (preferences::animate_map()) {
- gamemap::location topleft;
- gamemap::location bottomright;
- get_visible_hex_bounds(topleft, bottomright);
- for(int x = topleft.x; x <= bottomright.x; ++x) {
- for(int y = topleft.y; y <= bottomright.y; ++y) {
- const gamemap::location loc(x,y);
- if (!shrouded(loc)) {
- if (builder_.update_animation(loc)) {
- invalidate(loc);
- } else {
-
invalidate_animations_location(loc);
- }
+ rect_of_hexes hexes = get_visible_hexes();
+ rect_of_hexes::iterator i = hexes.begin(), end = hexes.end();
+ for (;i != end; ++i) {
+ if (!shrouded(*i)) {
+ if (builder_.update_animation(*i)) {
+ invalidate(*i);
+ } else {
+ invalidate_animations_location(*i);
}
}
}
Modified: trunk/src/display.hpp
URL:
http://svn.gna.org/viewcvs/wesnoth/trunk/src/display.hpp?rev=27418&r1=27417&r2=27418&view=diff
==============================================================================
--- trunk/src/display.hpp (original)
+++ trunk/src/display.hpp Sun Jun 22 23:26:17 2008
@@ -151,11 +151,44 @@
//! Function to invalidate the game status displayed on the sidebar.
void invalidate_game_status() { invalidateGameStatus_ = true; }
- void get_rect_hex_bounds(SDL_Rect rect, gamemap::location &topleft,
gamemap::location &bottomright) const;
-
//! Functions to get the on-screen positions of hexes.
int get_location_x(const gamemap::location& loc) const;
int get_location_y(const gamemap::location& loc) const;
+
+ /**
+ * Rectangular area of hexes, allowing to decide how the top and bottom
+ * edges handles the vertical shift for each parity of the x coordinate
+ */
+ struct rect_of_hexes{
+ int left;
+ int right;
+ int top[2]; // for even and odd values of x, respectively
+ int bottom[2];
+
+ //! very simple iterator to walk into the rect_of_hexes
+ struct iterator {
+ iterator(gamemap::location loc, rect_of_hexes& rect)
+ : loc_(loc), rect_(rect){};
+
+ //! increment y first, then when reaching bottom,
increment x
+ void operator++();
+ bool operator!=(const iterator &that) const {return
that.loc_ != loc_;};
+ const gamemap::location& operator*() const {return
loc_;};
+
+ private:
+ gamemap::location loc_;
+ rect_of_hexes& rect_;
+ };
+
+ iterator begin();
+ iterator end();
+ };
+
+ //! Return the rectangular area of hexes overlapped by r (r is in
screen coordinates)
+ const rect_of_hexes hexes_under_rect(const SDL_Rect& r) const;
+
+ //! Returns the rectangular area of visible hexes
+ const rect_of_hexes get_visible_hexes() const {return
hexes_under_rect(map_area());};
//! Returns true if location (x,y) is covered in shroud.
bool shrouded(const gamemap::location& loc) const {
@@ -170,10 +203,6 @@
//! (to more clearly show where hexes are)
void set_grid(const bool grid) { grid_ = grid; }
- //! Returns the locations of 2 hexes
- //! that bind the visible area of the map.
- void get_visible_hex_bounds(gamemap::location &topleft,
gamemap::location &bottomright) const;
-
//! Save a (map-)screenshot and return the estimated file size
int screenshot(std::string filename, bool map_screenshot = false);
@@ -191,12 +220,11 @@
// Will be overridden in the display subclass
virtual bool invalidate(const gamemap::location& loc) {return
invalidated_.insert(loc).second;};
- virtual bool invalidate_rectangle(const gamemap::location&
first_corner, const gamemap::location& second_corner) ;
- virtual bool invalidate_zone(const int x1,const int y1, const int x2,
const int y2);
- virtual bool rectangle_need_update(const gamemap::location&
first_corner, const gamemap::location& second_corner) const;
- virtual bool zone_need_update(const int x1,const int y1, const int x2,
const int y2) const;
+ bool rectangle_need_update(const SDL_Rect& rect) const;
virtual void draw_minimap_units() {};
-
+
+ bool invalidate_locations_in_rect(const SDL_Rect& rect);
+
/**
* Function to invalidate animated terrains which may have changed.
*/
@@ -623,8 +651,6 @@
//! redraw all panels associated with the map display
void draw_all_panels();
- bool invalidate_locations_in_rect(SDL_Rect r);
-
//! Strict weak ordering to sort a STL-set of hexes
//! for drawing using the z-order.
//! (1000 are just to weight the y compare to x)
Modified: trunk/src/game_display.cpp
URL:
http://svn.gna.org/viewcvs/wesnoth/trunk/src/game_display.cpp?rev=27418&r1=27417&r2=27418&view=diff
==============================================================================
--- trunk/src/game_display.cpp (original)
+++ trunk/src/game_display.cpp Sun Jun 22 23:26:17 2008
@@ -775,20 +775,17 @@
if (reach_map_.empty() != reach_map_old_.empty()) {
// Invalidate everything except the non-darkened tiles
reach_map &full = reach_map_.empty() ? reach_map_old_ :
reach_map_;
- gamemap::location topleft;
- gamemap::location bottomright;
- get_visible_hex_bounds(topleft, bottomright);
- for(int x = topleft.x; x <= bottomright.x; ++x) {
- for(int y = topleft.y; y <= bottomright.y; ++y) {
- gamemap::location loc(x, y);
- reach_map::iterator reach = full.find(loc);
- if (reach == full.end()) {
- // Location needs to be darkened or
brightened
- invalidate(loc);
- } else if (reach->second != 1) {
- // Number needs to be displayed or
cleared
- invalidate(loc);
- }
+
+ rect_of_hexes hexes = get_visible_hexes();
+ rect_of_hexes::iterator i = hexes.begin(), end = hexes.end();
+ for (;i != end; ++i) {
+ reach_map::iterator reach = full.find(*i);
+ if (reach == full.end()) {
+ // Location needs to be darkened or brightened
+ invalidate(*i);
+ } else if (reach->second != 1) {
+ // Number needs to be displayed or cleared
+ invalidate(*i);
}
}
} else if (!reach_map_.empty()) {
Modified: trunk/src/halo.cpp
URL:
http://svn.gna.org/viewcvs/wesnoth/trunk/src/halo.cpp?rev=27418&r1=27417&r2=27418&view=diff
==============================================================================
--- trunk/src/halo.cpp (original)
+++ trunk/src/halo.cpp Sun Jun 22 23:26:17 2008
@@ -171,12 +171,10 @@
// If rendered the first time, need to determine the area affected.
// If a halo changes size, it is not updated.
if(overlayed_hexes_.empty()) {
- gamemap::location topleft, bottomright;
- disp->get_rect_hex_bounds(rect, topleft, bottomright);
- for (int x = topleft.x; x <= bottomright.x; ++x) {
- for (int y = topleft.y; y <= bottomright.y; ++y) {
- overlayed_hexes_.push_back(gamemap::location(x,
y));
- }
+ display::rect_of_hexes hexes = disp->hexes_under_rect(rect);
+ display::rect_of_hexes::iterator i = hexes.begin(), end =
hexes.end();
+ for (;i != end; ++i) {
+ overlayed_hexes_.push_back(*i);
}
}
Modified: trunk/src/unit_frame.cpp
URL:
http://svn.gna.org/viewcvs/wesnoth/trunk/src/unit_frame.cpp?rev=27418&r1=27417&r2=27418&view=diff
==============================================================================
--- trunk/src/unit_frame.cpp (original)
+++ trunk/src/unit_frame.cpp Sun Jun 22 23:26:17 2008
@@ -455,14 +455,14 @@
} else {
// if we need to update ourselve because we changed,
invalidate our hexs
// and return whether or not our hexs was invalidated
- if(force || need_update()){
- bool tmp =
game_display::get_singleton()->invalidate_zone(x,y,x+image->w,y+image->h);
- return tmp;
+ if(force || need_update()){
+ const SDL_Rect r = {x,y,image->w,image->h};
+ return
game_display::get_singleton()->invalidate_locations_in_rect(r);
}
// if not, check if any of our hexes is already
invalidated, if any is, invalidate all of them
-
if(game_display::get_singleton()->zone_need_update(x,y,x+image->w,y+image->h)) {
- bool tmp =
game_display::get_singleton()->invalidate_zone(x,y,x+image->w,y+image->h);
- return tmp;
+ const SDL_Rect r = {x,y,image->w,image->h};
+
if(game_display::get_singleton()->rectangle_need_update(r)) {
+ return
game_display::get_singleton()->invalidate_locations_in_rect(r);
}
return false;
_______________________________________________
Wesnoth-commits mailing list
[email protected]
https://mail.gna.org/listinfo/wesnoth-commits