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

Reply via email to