Complete.Org: Mailing Lists: Archives: freeciv-dev: February 2005:
[Freeciv-Dev] (PR#12085) RFC: better iteration in gui_rect_iterate
Home

[Freeciv-Dev] (PR#12085) RFC: better iteration in gui_rect_iterate

[Top] [All Lists]

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index] [Thread Index]
Subject: [Freeciv-Dev] (PR#12085) RFC: better iteration in gui_rect_iterate
From: "Jason Short" <jdorje@xxxxxxxxxxxxxxxxxxxxx>
Date: Fri, 4 Feb 2005 00:49:33 -0800
Reply-to: bugs@xxxxxxxxxxx

<URL: http://bugs.freeciv.org/Ticket/Display.html?id=12085 >

Here's a new version of the patch.  It fixes an off-by-one error in the
calculation of iso corner tiles.

-jason

? blend.png
? fog
? fog.c
? terrain1.png
? data/isotrident/fog.png
? data/isotrident/foo
? data/isotrident/grid-ew.png
? data/isotrident/grid-ns.png
? data/isotrident/old.png
Index: client/mapview_common.c
===================================================================
RCS file: /home/freeciv/CVS/freeciv/client/mapview_common.c,v
retrieving revision 1.172
diff -u -r1.172 mapview_common.c
--- client/mapview_common.c     2 Feb 2005 02:43:29 -0000       1.172
+++ client/mapview_common.c     4 Feb 2005 08:49:01 -0000
@@ -873,21 +873,37 @@
 }
 
 /**************************************************************************
+  Draw one layer of a tile, edge, corner, unit, and/or city onto the
+  canvas at the given position.
+**************************************************************************/
+static void put_one_element(struct canvas *pcanvas, enum mapview_layer layer,
+                           struct tile *ptile,
+                           const struct tile_edge *pedge,
+                           const struct tile_corner *pcorner,
+                           const struct unit *punit, struct city *pcity,
+                           int canvas_x, int canvas_y, bool citymode)
+{
+  struct drawn_sprite tile_sprs[80];
+  int count = fill_sprite_array(tile_sprs, layer, ptile, pedge, pcorner,
+                               punit, pcity, citymode);
+  bool fog = (ptile && tile_get_known(ptile) == TILE_KNOWN_FOGGED 
+             && draw_fog_of_war && fogstyle == 0);
+
+  /*** Draw terrain and specials ***/
+  put_drawn_sprites(pcanvas, canvas_x, canvas_y, count, tile_sprs, fog);
+}
+
+/**************************************************************************
   Draw the given unit onto the canvas store at the given location.  The
   area of drawing is UNIT_TILE_HEIGHT x UNIT_TILE_WIDTH.
 **************************************************************************/
 void put_unit(const struct unit *punit,
              struct canvas *pcanvas, int canvas_x, int canvas_y)
 {
-  struct drawn_sprite drawn_sprites[40];
-
   canvas_y += (UNIT_TILE_HEIGHT - NORMAL_TILE_HEIGHT);
   mapview_layer_iterate(layer) {
-    int count = fill_sprite_array(drawn_sprites, layer,
-                                 NULL, punit, NULL, FALSE);
-
-    put_drawn_sprites(pcanvas, canvas_x, canvas_y,
-                     count, drawn_sprites, FALSE);
+    put_one_element(pcanvas, layer, NULL, NULL, NULL,
+                   punit, NULL, canvas_x, canvas_y, FALSE);
   } mapview_layer_iterate_end;
 }
 
@@ -898,15 +914,11 @@
 void put_city(struct city *pcity,
              struct canvas *pcanvas, int canvas_x, int canvas_y)
 {
-  struct drawn_sprite drawn_sprites[40];
-
   canvas_y += (UNIT_TILE_HEIGHT - NORMAL_TILE_HEIGHT);
   mapview_layer_iterate(layer) {
-    int count = fill_sprite_array(drawn_sprites, layer,
-                                 NULL, NULL, pcity, FALSE);
-
-    put_drawn_sprites(pcanvas, canvas_x, canvas_y,
-                     count, drawn_sprites, FALSE);
+    put_one_element(pcanvas, layer,
+                   NULL, NULL, NULL, NULL, pcity,
+                   canvas_x, canvas_y, FALSE);
   } mapview_layer_iterate_end;
 }
 
@@ -918,16 +930,11 @@
 void put_terrain(struct tile *ptile,
                 struct canvas *pcanvas, int canvas_x, int canvas_y)
 {
-  struct drawn_sprite drawn_sprites[40];
-
   /* Use full tile height, even for terrains. */
   canvas_y += (UNIT_TILE_HEIGHT - NORMAL_TILE_HEIGHT);
   mapview_layer_iterate(layer) {
-    int count = fill_sprite_array(drawn_sprites, layer,
-                                 ptile, NULL, NULL, FALSE);
-
-    put_drawn_sprites(pcanvas, canvas_x, canvas_y,
-                     count, drawn_sprites, FALSE);
+    put_one_element(pcanvas, layer, ptile, NULL, NULL, NULL, NULL,
+                   canvas_x, canvas_y, FALSE);
   } mapview_layer_iterate_end;
 }
 
@@ -1439,15 +1446,11 @@
                  struct tile *ptile,
                  int canvas_x, int canvas_y, bool citymode)
 {
-  struct drawn_sprite tile_sprs[80];
-  int count = fill_sprite_array(tile_sprs, layer, ptile,
-                               get_drawable_unit(ptile, citymode),
-                               ptile->city, citymode);
-  bool fog = (tile_get_known(ptile) == TILE_KNOWN_FOGGED && draw_fog_of_war
-             && fogstyle == 0);
-
-  /*** Draw terrain and specials ***/
-  put_drawn_sprites(pcanvas, canvas_x, canvas_y, count, tile_sprs, fog);
+  if (tile_get_known(ptile) != TILE_UNKNOWN) {
+    put_one_element(pcanvas, layer, ptile, NULL, NULL,
+                   get_drawable_unit(ptile, citymode),
+                   ptile->city, canvas_x, canvas_y, citymode);
+  }
 }
 
 /**************************************************************************
@@ -1509,12 +1512,17 @@
   mapview_layer_iterate(layer) {
     gui_rect_iterate(gui_x0, gui_y0, width,
                     height + (is_isometric ? (NORMAL_TILE_HEIGHT / 2) : 0),
-                    ptile) {
-      int cx, cy;
-
-      if (tile_get_known(ptile) != TILE_UNKNOWN
-         && tile_to_canvas_pos(&cx, &cy, ptile)) {
+                    ptile, pedge, pcorner, cx, cy) {
+      if (ptile) {
        put_one_tile(mapview_canvas.store, layer, ptile, cx, cy, FALSE);
+      } else if (pedge) {
+       put_one_element(mapview_canvas.store, layer, NULL, pedge, NULL,
+                       NULL, NULL, cx, cy, FALSE);
+      } else if (pcorner) {
+       put_one_element(mapview_canvas.store, layer, NULL, NULL, pcorner,
+                       NULL, NULL, cx, cy, FALSE);
+      } else {
+       /* This can happen, for instance for unreal tiles. */
       }
     } gui_rect_iterate_end;
   } mapview_layer_iterate_end;
@@ -1527,7 +1535,10 @@
    * from adjacent tiles (if they're close enough). */
   gui_rect_iterate(gui_x0 - GOTO_WIDTH, gui_y0 - GOTO_WIDTH,
                   width + 2 * GOTO_WIDTH, height + 2 * GOTO_WIDTH,
-                  ptile) {
+                  ptile, pedge, pcorner, cx, cy) {
+    if (!ptile) {
+      continue;
+    }
     adjc_dir_iterate(ptile, adjc_tile, dir) {
       if (is_drawn_line(ptile, dir)) {
        draw_segment(ptile, dir);
@@ -1536,17 +1547,17 @@
   } gui_rect_iterate_end;
 
   /* Draw citymap overlays on top. */
-  gui_rect_iterate(gui_x0, gui_y0, width, height, ptile) {
-    if (tile_get_known(ptile) != TILE_UNKNOWN) {
+  gui_rect_iterate(gui_x0, gui_y0, width, height,
+                  ptile, pedge, pcorner, canvas_x2, canvas_y2) {
+    if (ptile && tile_get_known(ptile) != TILE_UNKNOWN) {
       struct unit *punit;
       struct city *pcity;
-      int city_x, city_y, canvas_x2, canvas_y2;
+      int city_x, city_y;
 
       pcity = find_city_or_settler_near_tile(ptile, &punit);
       if (pcity
          && city_colors[pcity->client.color] != COLOR_STD_LAST
-         && map_to_city_map(&city_x, &city_y, pcity, ptile)
-         && tile_to_canvas_pos(&canvas_x2, &canvas_y2, ptile)) {
+         && map_to_city_map(&city_x, &city_y, pcity, ptile)) {
        enum city_tile_type worker = get_worker_city(pcity, city_x, city_y);
 
        put_city_worker(mapview_canvas.store,
@@ -1557,8 +1568,7 @@
                               mapview_canvas.store, canvas_x2, canvas_y2);
        }
       } else if (punit
-                && city_colors[punit->client.color] != COLOR_STD_LAST
-                && tile_to_canvas_pos(&canvas_x2, &canvas_y2, ptile)) {
+                && city_colors[punit->client.color] != COLOR_STD_LAST) {
        /* Draw citymap overlay for settlers. */
        put_city_worker(mapview_canvas.store,
                        city_colors[punit->client.color], C_TILE_EMPTY,
@@ -1656,14 +1666,11 @@
   gui_rect_iterate(mapview_canvas.gui_x0 + canvas_x - dx / 2,
                   mapview_canvas.gui_y0 + canvas_y - dy,
                   width + dx, height + dy - NORMAL_TILE_HEIGHT,
-                  ptile) {
-    int canvas_x, canvas_y;
-    struct city *pcity = ptile->city;
-
-    if (pcity) {
+                  ptile, pedge, pcorner, canvas_x, canvas_y) {
+    if (ptile && ptile->city) {
       int width = 0, height = 0;
+      struct city *pcity = ptile->city;
 
-      (void) tile_to_canvas_pos(&canvas_x, &canvas_y, ptile);
       show_city_desc(mapview_canvas.store, canvas_x, canvas_y,
                     pcity, &width, &height);
 
Index: client/mapview_common.h
===================================================================
RCS file: /home/freeciv/CVS/freeciv/client/mapview_common.h,v
retrieving revision 1.85
diff -u -r1.85 mapview_common.h
--- client/mapview_common.h     25 Dec 2004 20:38:14 -0000      1.85
+++ client/mapview_common.h     4 Feb 2005 08:49:02 -0000
@@ -85,9 +85,10 @@
  * iso-view iteration is at
  * http://rt.freeciv.org/Ticket/Attachment/51374/37363/isogrid.png.
  */
-#define gui_rect_iterate(gui_x0, gui_y0, width, height, ptile)             \
+#define gui_rect_iterate(GRI_gui_x0, GRI_gui_y0, width, height,                
    \
+                        ptile, pedge, pcorner, canvas_x, canvas_y)         \
 {                                                                          \
-  int _gui_x0 = (gui_x0), _gui_y0 = (gui_y0);                              \
+  int _gui_x0 = (GRI_gui_x0), _gui_y0 = (GRI_gui_y0);                      \
   int _width = (width), _height = (height);                                \
                                                                            \
   if (_width < 0) {                                                        \
@@ -99,38 +100,105 @@
     _height = -_height;                                                        
    \
   }                                                                        \
   if (_width > 0 && _height > 0) {                                         \
-    int W = (is_isometric ? (NORMAL_TILE_WIDTH / 2) : NORMAL_TILE_WIDTH);   \
-    int H = (is_isometric ? (NORMAL_TILE_HEIGHT / 2) : NORMAL_TILE_HEIGHT); \
-    int GRI_x0 = DIVIDE(_gui_x0, W), GRI_y0 = DIVIDE(_gui_y0, H);          \
-    int GRI_x1 = DIVIDE(_gui_x0 + _width + W - 1, W);                      \
-    int GRI_y1 = DIVIDE(_gui_y0 + _height + H - 1, H);                     \
-    int GRI_itr, GRI_x_itr, GRI_y_itr, _map_x, _map_y;                     \
-    int count;                                                             \
-    struct tile *ptile;                                                        
    \
+    const int _ratio = (is_isometric ? 2 : 1);                             \
+    const int _W = NORMAL_TILE_WIDTH / (_ratio * 2);                       \
+    const int _H = NORMAL_TILE_HEIGHT / (_ratio * 2);                      \
+    const int GRI_x0 = DIVIDE(_gui_x0, _W) - 1;                                
    \
+    const int GRI_y0 = DIVIDE(_gui_y0, _H) - 1;                                
    \
+    const int GRI_x1 = DIVIDE(_gui_x0 + _width + _W - 1, _W) + _ratio;     \
+    const int GRI_y1 = DIVIDE(_gui_y0 + _height + _H - 1, _H) + _ratio;        
    \
+    const int _count = (GRI_x1 - GRI_x0) * (GRI_y1 - GRI_y0);              \
+    int GRI_itr, GRI_x_itr, GRI_y_itr, GRI_sum, GRI_diff;                  \
+                                                                           \
+    for (GRI_itr = 0; GRI_itr < _count; GRI_itr++) {                       \
+      struct tile *ptile = NULL;                                           \
+      struct tile_edge *pedge = NULL;                                      \
+      struct tile_corner *pcorner = NULL;                                  \
+      struct tile_edge GRI_edge;                                           \
+      struct tile_corner GRI_corner;                                       \
+      int canvas_x, canvas_y;                                              \
                                                                            \
-    if (is_isometric) {                                                        
    \
-      /* Tiles to the left/above overlap with us. */                       \
-      GRI_x0--;                                                                
    \
-      GRI_y0--;                                                                
    \
-    }                                                                      \
-    count = (GRI_x1 - GRI_x0) * (GRI_y1 - GRI_y0);                         \
-    for (GRI_itr = 0; GRI_itr < count; GRI_itr++) {                        \
       GRI_x_itr = GRI_x0 + (GRI_itr % (GRI_x1 - GRI_x0));                  \
       GRI_y_itr = GRI_y0 + (GRI_itr / (GRI_x1 - GRI_x0));                  \
+      GRI_sum = GRI_x_itr + GRI_y_itr;                                     \
+      GRI_diff = GRI_y_itr - GRI_x_itr;                                        
    \
       if (is_isometric) {                                                  \
        if ((GRI_x_itr + GRI_y_itr) % 2 != 0) {                             \
          continue;                                                         \
        }                                                                   \
-       _map_x = (GRI_x_itr + GRI_y_itr) / 2;                               \
-       _map_y = (GRI_y_itr - GRI_x_itr) / 2;                               \
+       if (GRI_x_itr % 2 == 0 && GRI_y_itr % 2 == 0) {                     \
+         if ((GRI_x_itr + GRI_y_itr) % 4 == 0) {                           \
+           /* Tile */                                                      \
+           ptile = map_pos_to_tile(GRI_sum / 4 - 1, GRI_diff / 4);         \
+         } else {                                                          \
+           /* Corner */                                                    \
+           pcorner = &GRI_corner;                                          \
+           pcorner->tile[0] = map_pos_to_tile((GRI_sum - 6) / 4,           \
+                                              (GRI_diff - 2) / 4);         \
+           pcorner->tile[1] = map_pos_to_tile((GRI_sum - 2) / 4,           \
+                                              (GRI_diff - 2) / 4);         \
+           pcorner->tile[2] = map_pos_to_tile((GRI_sum - 2) / 4,           \
+                                              (GRI_diff + 2) / 4);         \
+           pcorner->tile[3] = map_pos_to_tile((GRI_sum - 6) / 4,           \
+                                              (GRI_diff + 2) / 4);         \
+         }                                                                 \
+       } else {                                                            \
+         /* Edge. */                                                       \
+         pedge = &GRI_edge;                                                \
+         if (GRI_sum % 4 == 0) {                                           \
+           pedge->type = EDGE_NS;                                          \
+           pedge->tile[0] = map_pos_to_tile((GRI_sum - 4) / 4, /* N */     \
+                                            (GRI_diff - 2) / 4);           \
+           pedge->tile[1] = map_pos_to_tile((GRI_sum - 4) / 4, /* S */     \
+                                            (GRI_diff + 2) / 4);           \
+         } else {                                                          \
+           pedge->type = EDGE_EW;                                          \
+           pedge->tile[0] = map_pos_to_tile((GRI_sum - 6) / 4,             \
+                                            GRI_diff / 4); /* E */         \
+           pedge->tile[1] = map_pos_to_tile((GRI_sum - 2) / 4,             \
+                                            GRI_diff / 4); /* W */         \
+         }                                                                 \
+       }                                                                   \
       } else {                                                             \
-       _map_x = GRI_x_itr;                                                 \
-       _map_y = GRI_y_itr;                                                 \
+       if (GRI_sum % 2 == 0) {                                             \
+         if (GRI_x_itr % 2 == 0) {                                         \
+           /* Corner. */                                                   \
+           pcorner = &GRI_corner;                                          \
+           pcorner->tile[0] = map_pos_to_tile(GRI_x_itr / 2 - 1,           \
+                                              GRI_y_itr / 2 - 1); /* NW */ \
+           pcorner->tile[1] = map_pos_to_tile(GRI_x_itr / 2,               \
+                                              GRI_y_itr / 2 - 1); /* NE */ \
+           pcorner->tile[2] = map_pos_to_tile(GRI_x_itr / 2,               \
+                                              GRI_y_itr / 2); /* SE */     \
+           pcorner->tile[3] = map_pos_to_tile(GRI_x_itr / 2 - 1,           \
+                                              GRI_y_itr / 2); /* SW */     \
+         } else {                                                          \
+           /* Tile. */                                                     \
+           ptile = map_pos_to_tile((GRI_x_itr - 1) / 2,                    \
+                                   (GRI_y_itr - 1) / 2);                   \
+         }                                                                 \
+       } else {                                                            \
+         /* Edge. */                                                       \
+         pedge = &GRI_edge;                                                \
+         if (GRI_y_itr % 2 == 0) {                                         \
+           pedge->type = EDGE_EW;                                          \
+           pedge->tile[0] = map_pos_to_tile(GRI_x_itr / 2 - 1,             \
+                                            (GRI_y_itr - 1) / 2);          \
+           pedge->tile[1] = map_pos_to_tile(GRI_x_itr / 2,                 \
+                                            (GRI_y_itr - 1) / 2);          \
+         } else {                                                          \
+           pedge->type = EDGE_NS;                                          \
+           pedge->tile[0] = map_pos_to_tile((GRI_x_itr - 1) / 2,           \
+                                            GRI_y_itr / 2 - 1);            \
+           pedge->tile[1] = map_pos_to_tile((GRI_x_itr - 1) / 2,           \
+                                            GRI_y_itr / 2);                \
+         }                                                                 \
+       }                                                                   \
       }                                                                        
    \
-      ptile = map_pos_to_tile(_map_x, _map_y);                             \
-      if (!ptile) {                                                        \
-       continue;                                                           \
-      }
+      canvas_x                                                             \
+       = GRI_x_itr * _W - NORMAL_TILE_WIDTH / 2 - mapview_canvas.gui_x0;   \
+      canvas_y                                                             \
+       = GRI_y_itr * _H - NORMAL_TILE_HEIGHT / 2 - mapview_canvas.gui_y0;
 
 #define gui_rect_iterate_end                                               \
     }                                                                      \
Index: client/tilespec.c
===================================================================
RCS file: /home/freeciv/CVS/freeciv/client/tilespec.c,v
retrieving revision 1.227
diff -u -r1.227 tilespec.c
--- client/tilespec.c   3 Feb 2005 19:28:40 -0000       1.227
+++ client/tilespec.c   4 Feb 2005 08:49:02 -0000
@@ -2674,7 +2674,8 @@
   is done differently.
 ****************************************************************************/
 int fill_sprite_array(struct drawn_sprite *sprs, enum mapview_layer layer,
-                     struct tile *ptile,
+                     struct tile *ptile, const struct tile_edge *pedge,
+                     const struct tile_corner *pcorner,
                      const struct unit *punit, struct city *pcity,
                      bool citymode)
 {
Index: client/tilespec.h
===================================================================
RCS file: /home/freeciv/CVS/freeciv/client/tilespec.h,v
retrieving revision 1.97
diff -u -r1.97 tilespec.h
--- client/tilespec.h   22 Jan 2005 19:45:39 -0000      1.97
+++ client/tilespec.h   4 Feb 2005 08:49:02 -0000
@@ -26,6 +26,21 @@
 
 struct Sprite;                 /* opaque; gui-dep */
 
+/* An edge is the border between two tiles.  This structure represents one
+ * edge.  The tiles are in unspecified order for the moment. */
+struct tile_edge {
+  enum {
+    EDGE_NS, EDGE_EW
+  } type;
+  struct tile *tile[2];
+};
+
+/* A corner is the endpoint of several edges.  At each corner 4 tiles will
+ * meet (3 in hex view).  Tiles are in clockwise order NESW. */
+struct tile_corner {
+  struct tile *tile[4];
+};
+
 struct drawn_sprite {
   enum {
     DRAWN_SPRITE,      /* Draw a sprite. */
@@ -114,7 +129,8 @@
 /* Gfx support */
 
 int fill_sprite_array(struct drawn_sprite *sprs, enum mapview_layer layer,
-                     struct tile *ptile,
+                     struct tile *ptile, const struct tile_edge *pedge,
+                     const struct tile_corner *pcorner,
                      const struct unit *punit, struct city *pcity,
                      bool citymode);
 

[Prev in Thread] Current Thread [Next in Thread]