Complete.Org: Mailing Lists: Archives: freeciv-dev: April 2004:
[Freeciv-Dev] (PR#4004) A canvas_iterate macro for mapview
Home

[Freeciv-Dev] (PR#4004) A canvas_iterate macro for mapview

[Top] [All Lists]

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index] [Thread Index]
To: undisclosed-recipients: ;
Subject: [Freeciv-Dev] (PR#4004) A canvas_iterate macro for mapview
From: "Jason Short" <jdorje@xxxxxxxxxxxxxxxxxxxxx>
Date: Wed, 21 Apr 2004 15:13:03 -0700
Reply-to: rt@xxxxxxxxxxx

<URL: http://rt.freeciv.org/Ticket/Display.html?id=4004 >

> [jdorje - Mon Apr 14 17:31:56 2003]:
> 
> I would like to write a new macro, canvas_iterate, to the mapview code. 

Here's a preliminary patch.  It has just one user; not really enough for
full debugging.

I'm convinced the algorithm is correct, although it's possible there are
off-by-one errors.

I believe in the long term this macro will be obscenely useful.

jason

? jason game.gz
Index: client/mapview_common.c
===================================================================
RCS file: /home/freeciv/CVS/freeciv/client/mapview_common.c,v
retrieving revision 1.103
diff -u -r1.103 mapview_common.c
--- client/mapview_common.c     20 Apr 2004 19:56:16 -0000      1.103
+++ client/mapview_common.c     21 Apr 2004 22:00:31 -0000
@@ -34,6 +34,60 @@
 #include "mapview_common.h"
 #include "tilespec.h"
 
+#define gui_rect_iterate(gui_x0, gui_y0, width, height, map_x, map_y, draw) \
+  {                                                                        \
+  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;                         \
+  enum draw_type draw;                                                     \
+  int count = (GRI_x1 - GRI_x0) * (GRI_y1 - GRI_y0);                       \
+  assert((width) > 0 && (height) > 0);                                     \
+  if (is_isometric) {                                                      \
+    /* Extra half-tile of UNIT_TILE_HEIGHT. */                             \
+    GRI_y1++;                                                              \
+    /* Tiles to the left/above overlap with us. */                         \
+    GRI_x0--;                                                              \
+    GRI_y0--;                                                              \
+  }                                                                        \
+  for (GRI_itr = 0; GRI_itr < count; GRI_itr++) {                          \
+    GRI_x_itr = GRI_x0 + FC_WRAP(GRI_itr, GRI_x1 - GRI_x0);                \
+    GRI_y_itr = GRI_y0 + DIVIDE(GRI_itr, GRI_x1 - GRI_x0);                 \
+    if (is_isometric) {                                                        
    \
+      if ((GRI_x_itr + GRI_y_itr) % 2 != 0) {                              \
+       continue;                                                           \
+      }                                                                        
    \
+      draw = 0;                                                                
    \
+      if (GRI_x_itr > GRI_x0) {                                                
    \
+       draw |= D_L;                                                        \
+      }                                                                        
    \
+      if (GRI_x_itr < GRI_x1 - 1) {                                        \
+       draw |= D_R;                                                        \
+      }                                                                        
    \
+      if (GRI_y_itr > GRI_y0) {                                                
    \
+       draw |= D_M;                                                        \
+      }                                                                        
    \
+      if (GRI_y_itr > GRI_y0 + 1) {                                        \
+       draw |= D_T;                                                        \
+      }                                                                        
    \
+      if (GRI_y_itr < GRI_y1 - 2) {                                        \
+       draw |= D_B;                                                        \
+      }                                                                        
    \
+      map_x = (GRI_x_itr + GRI_y_itr) / 2;                                 \
+      map_y = (GRI_y_itr - GRI_x_itr) / 2;                                 \
+    } else {                                                               \
+      draw = D_FULL;                                                       \
+      map_x = GRI_x_itr;                                                   \
+      map_y = GRI_y_itr;                                                   \
+    }
+    
+
+#define gui_rect_iterate_end                                               \
+  }                                                                        \
+}
+
 struct mapview_canvas mapview_canvas;
 struct overview overview;
 
@@ -805,28 +859,28 @@
       *end_x = W - inset;
       *start_y = inset + width;
       *end_y = H / 2 + width;
-      return (draw & D_M_R);
+      return (draw & D_M_R) == D_M_R;
     case DIR8_SOUTH:
       /* Bottom left. */
       *start_x = inset;
       *end_x = W / 2;
       *start_y = H / 2 - overlap;
       *end_y = H - inset - overlap;
-      return (draw & D_B_L) && (inset + overlap) > 0;
+      return (draw & D_B_L) == D_B_L && (inset + overlap) > 0;
     case DIR8_EAST:
       /* Bottom right. */
       *start_x = W - inset;
       *end_x = W / 2;
       *start_y = H / 2 - overlap;
       *end_y = H - inset - overlap;
-      return (draw & D_B_R) && (inset + overlap) > 0;
+      return (draw & D_B_R) == D_B_R && (inset + overlap) > 0;
     case DIR8_WEST:
       /* Top left. */
       *start_x = inset;
       *end_x = W / 2;
       *start_y = H / 2 + width;
       *end_y = inset + width;
-      return (draw & D_M_L);
+      return (draw & D_M_L) == D_M_L;
     case DIR8_NORTHEAST:
     case DIR8_SOUTHEAST:
     case DIR8_SOUTHWEST:
@@ -1197,36 +1251,36 @@
     freelog(LOG_DEBUG, "putting (%d,%d) at (%d,%d), draw %x",
            map_x, map_y, canvas_x, canvas_y, draw);
 
-    if ((draw & D_TMB_L) && (draw & D_TMB_R)) {
+    if ((draw & D_L) && (draw & D_R)) {
       width = NORMAL_TILE_WIDTH;
     } else {
       width = NORMAL_TILE_WIDTH / 2;
     }
 
-    if (draw & D_TMB_L) {
+    if (draw & D_L) {
       offset_x = 0;
     } else {
       offset_x = NORMAL_TILE_WIDTH / 2;
     }
 
     height = 0;
-    if (draw & D_M_LR) {
+    if (draw & D_M) {
       height += NORMAL_TILE_HEIGHT / 2;
     }
-    if (draw & D_B_LR) {
+    if (draw & D_B) {
       height += NORMAL_TILE_HEIGHT / 2;
     }
 
     height_unit = height;
-    if (draw & D_T_LR) {
+    if (draw & D_T) {
       height_unit += NORMAL_TILE_HEIGHT / 2;
     }
 
-    offset_y = (draw & D_M_LR) ? 0 : NORMAL_TILE_HEIGHT / 2;
+    offset_y = (draw & D_M) ? 0 : NORMAL_TILE_HEIGHT / 2;
 
-    if (draw & D_T_LR) {
+    if (draw & D_T) {
       offset_y_unit = 0;
-    } else if (draw & D_M_LR) {
+    } else if (draw & D_M) {
       offset_y_unit = NORMAL_TILE_HEIGHT / 2;
     } else {
       offset_y_unit = NORMAL_TILE_HEIGHT;
@@ -1433,7 +1487,6 @@
 void show_city_descriptions(void)
 {
   int canvas_x, canvas_y;
-  int map_x0, map_y0;
 
   if (!draw_city_names && !draw_city_productions) {
     return;
@@ -1441,43 +1494,16 @@
 
   prepare_show_city_descriptions();
 
-  canvas_to_map_pos(&map_x0, &map_y0, 0, 0);
-  if (is_isometric) {
-    int w, h;
-
-    for (h = -1; h < mapview_canvas.tile_height * 2; h++) {
-      int x_base = map_x0 + h / 2 + (h != -1 ? h % 2 : 0);
-      int y_base = map_y0 + h / 2 + (h == -1 ? -1 : 0);
-
-      for (w = 0; w <= mapview_canvas.tile_width; w++) {
-       int x = x_base + w;
-       int y = y_base - w;
-       struct city *pcity;
-
-       if (normalize_map_pos(&x, &y)
-           && (pcity = map_get_city(x, y))) {
-         map_to_canvas_pos(&canvas_x, &canvas_y, x, y);
-         show_city_desc(pcity, canvas_x, canvas_y);
-       }
-      }
-    }
-  } else {                     /* is_isometric */
-    int x1, y1;
-
-    for (x1 = 0; x1 <= mapview_canvas.tile_width; x1++) {
-      for (y1 = 0; y1 <= mapview_canvas.tile_height; y1++) {
-       int x = map_x0 + x1;
-       int y = map_y0 + y1;
-       struct city *pcity;
-
-       if (normalize_map_pos(&x, &y)
-           && (pcity = map_get_city(x, y))) {
-         map_to_canvas_pos(&canvas_x, &canvas_y, x, y);
-         show_city_desc(pcity, canvas_x, canvas_y);
-       }
-      }
+  gui_rect_iterate(mapview_canvas.gui_x0, mapview_canvas.gui_y0,
+                  mapview_canvas.width, mapview_canvas.height, x, y, draw) {
+    struct city *pcity;
+
+    if (normalize_map_pos(&x, &y)
+       && (pcity = map_get_city(x, y))) {
+      map_to_canvas_pos(&canvas_x, &canvas_y, x, y);
+      show_city_desc(pcity, canvas_x, canvas_y);
     }
-  }
+  } gui_rect_iterate_end;
 }
 
 /****************************************************************************
Index: client/mapview_common.h
===================================================================
RCS file: /home/freeciv/CVS/freeciv/client/mapview_common.h,v
retrieving revision 1.56
diff -u -r1.56 mapview_common.h
--- client/mapview_common.h     15 Apr 2004 19:36:00 -0000      1.56
+++ client/mapview_common.h     21 Apr 2004 22:00:31 -0000
@@ -61,22 +61,25 @@
 
 /* 
  * When drawing a tile (currently only in isometric mode), there are
- * six relevant parts we can draw.  Each of these is a rectangle of
- * size NORMAL_TILE_WIDTH/2 x NORMAL_TILE_HEIGHT/2.
+ * 5 relevant bits: top, middle, bottom, left, and right.  A drawing area
+ * is comprised of an OR-ing of these.  Note that if you must have a vertical
+ * (D_T, D_M, D_B) and horizontal (D_L, D_R) element to get any actual
+ * area.
  *
- *   Left    Right
+ *
+ * Left:D_L Right:D_R
  *
  * -----------------
  * |       |       |
- * | D_T_L | D_T_R |  Top, above the actual tile
+ * | D_T_L | D_T_R |  Top, above the actual tile : D_T
  * |       |       |
  * -----------------
  * |       |       |
- * | D_M_L | D_M_R |  Middle, upper half of the actual tile
+ * | D_M_L | D_M_R |  Middle, upper half of the actual tile : D_M
  * |       |       |
  * -----------------
  * |       |       |
- * | D_B_L | D_B_R |  Bottom, lower half of the actual tile
+ * | D_B_L | D_B_R |  Bottom, lower half of the actual tile : D_B
  * |       |       |
  * -----------------
  *
@@ -97,12 +100,11 @@
  * These values are used as a mask; see enum draw_type.
  */
 enum draw_part {
-  D_T_L = 1,
-  D_T_R = 2,
-  D_M_L = 4,
-  D_M_R = 8,
-  D_B_L = 16,
-  D_B_R = 32
+  D_T = 1, /* Draw top. */
+  D_M = 2, /* Draw middle. */
+  D_B = 4, /* Draw bottom. */
+  D_L = 8, /* Draw left. */
+  D_R = 16 /* Draw right. */
 };
 
 /* 
@@ -119,17 +121,23 @@
  * needed.
  */
 enum draw_type {
-  D_FULL = D_T_L | D_T_R | D_M_L | D_M_R | D_B_L | D_B_R,
-  D_B_LR = D_B_L | D_B_R,
-  D_MB_L = D_M_L | D_B_L,
-  D_MB_R = D_M_R | D_B_R,
-  D_TM_L = D_T_L | D_M_L,
-  D_TM_R = D_T_R | D_M_R,
-  D_T_LR = D_T_L | D_T_R,
-  D_TMB_L = D_T_L | D_M_L | D_B_L,
-  D_TMB_R = D_T_R | D_M_R | D_B_R,
-  D_M_LR = D_M_L | D_M_R,
-  D_MB_LR = D_M_L | D_M_R | D_B_L | D_B_R
+  D_FULL = D_T | D_M | D_B | D_L | D_R,
+  D_T_L = D_T | D_L,
+  D_T_R = D_T | D_R,
+  D_M_L = D_M | D_L,
+  D_M_R = D_M | D_R,
+  D_B_L = D_B | D_L,
+  D_B_R = D_B | D_R,
+  D_T_LR = D_T | D_L | D_R,
+  D_M_LR = D_M | D_L | D_R,
+  D_B_LR = D_B | D_L | D_R,
+  D_TM_L = D_T | D_M | D_L,
+  D_TM_R = D_T | D_M | D_R,
+  D_MB_L = D_M | D_B | D_L,
+  D_MB_R = D_M | D_B | D_R,
+  D_TMB_L = D_T | D_M | D_B | D_L,
+  D_TMB_R = D_T | D_M | D_B | D_R,
+  D_MB_LR = D_M | D_B | D_L | D_R
 };
 
 #define BORDER_WIDTH 2

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