Complete.Org: Mailing Lists: Archives: freeciv-dev: November 2004:
[Freeciv-Dev] (PR#10865) mapview layers
Home

[Freeciv-Dev] (PR#10865) mapview layers

[Top] [All Lists]

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index] [Thread Index]
To: undisclosed-recipients: ;
Subject: [Freeciv-Dev] (PR#10865) mapview layers
From: "Jason Short" <jdorje@xxxxxxxxxxxxxxxxxxxxx>
Date: Wed, 3 Nov 2004 20:51:28 -0800
Reply-to: rt@xxxxxxxxxxx

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

The attached patch provides a preliminary mapview layered drawing system.

The advantages of layered drawing are great.  In the short term it will 
fix some drawing bugs.  For instance terrain will inconsistently cover 
up roads.  In civ3gfx tileset roads will disappear into the side of a 
mountain and reappear out from underneath the other side.  In isotrident 
forests will cover some rails but not others.  Flat terrains may cover 
gridlines (there are some ugly hacks to avoid this).  And in isotrident 
with is_mountainous set mountains may sometimes disappear behind 
grassland that is "in front" of them.

In the long term it may allow generalization of UNIT_TILE_WIDTH and 
UNIT_TILE_HEIGHT.

This patch follows a simple system for doing this.  A lot of lines are 
touched because indentation is changed.  Apply the patch and look at it 
with "cvs diff -b" to skip these.

However the patch is unworkable in its current form because it makes 
drawing (update_map_canvas) take twice as long.  I'm not really sure why 
this is.  Although a loop is introduced I'd expected the extra overhead 
would be small.

jason

Index: client/citydlg_common.c
===================================================================
RCS file: /home/freeciv/CVS/freeciv/client/citydlg_common.c,v
retrieving revision 1.50
diff -u -r1.50 citydlg_common.c
--- client/citydlg_common.c     16 Oct 2004 00:00:10 -0000      1.50
+++ client/citydlg_common.c     4 Nov 2004 04:23:12 -0000
@@ -173,14 +173,16 @@
                       get_citydlg_canvas_width(),
                       get_citydlg_canvas_height());
 
-  citydlg_known_iterate(pcity, city_x, city_y,
-                       ptile, canvas_x, canvas_y) {
-    if (is_isometric) {
-      put_one_tile_iso(pcanvas, ptile, canvas_x, canvas_y, TRUE);
-    } else {
-      put_one_tile(pcanvas, ptile, canvas_x, canvas_y, TRUE);
-    }
-  } citydlg_known_iterate_end;
+  mapview_layer_iterate(layer) {
+    citydlg_known_iterate(pcity, city_x, city_y,
+                         ptile, canvas_x, canvas_y) {
+      if (is_isometric) {
+       put_one_tile_iso(pcanvas, layer, ptile, canvas_x, canvas_y, TRUE);
+      } else {
+       put_one_tile(pcanvas, layer, ptile, canvas_x, canvas_y, TRUE);
+      }
+    } citydlg_known_iterate_end;
+  } mapview_layer_iterate_end;
 
   /* We have to put the output afterwards or it will be covered
    * in iso-view. */
Index: client/mapview_common.c
===================================================================
RCS file: /home/freeciv/CVS/freeciv/client/mapview_common.c,v
retrieving revision 1.159
diff -u -r1.159 mapview_common.c
--- client/mapview_common.c     24 Oct 2004 23:48:43 -0000      1.159
+++ client/mapview_common.c     4 Nov 2004 04:23:13 -0000
@@ -520,7 +520,7 @@
     } while (mytime < timing_sec);
 
     mytime = read_timer_seconds(anim_timer);
-    freelog(LOG_DEBUG, "Got %d frames in %f seconds: %f FPS.",
+    freelog(LOG_NORMAL, "Got %d frames in %f seconds: %f FPS.",
            frames, mytime, (double)frames / mytime);
   } else {
     base_set_mapview_origin(gui_x0, gui_y0);
@@ -871,11 +871,15 @@
              struct canvas *pcanvas, int canvas_x, int canvas_y)
 {
   struct drawn_sprite drawn_sprites[40];
-  int count = fill_sprite_array(drawn_sprites, NULL, punit, NULL, FALSE);
 
   canvas_y += (UNIT_TILE_HEIGHT - NORMAL_TILE_HEIGHT);
-  put_drawn_sprites(pcanvas, canvas_x, canvas_y,
-                   count, drawn_sprites, FALSE);
+  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);
+  } mapview_layer_iterate_end;
 }
 
 /**************************************************************************
@@ -886,11 +890,15 @@
              struct canvas *pcanvas, int canvas_x, int canvas_y)
 {
   struct drawn_sprite drawn_sprites[40];
-  int count = fill_sprite_array(drawn_sprites, NULL, NULL, pcity, FALSE);
 
   canvas_y += (UNIT_TILE_HEIGHT - NORMAL_TILE_HEIGHT);
-  put_drawn_sprites(pcanvas, canvas_x, canvas_y,
-                   count, drawn_sprites, FALSE);
+  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);
+  } mapview_layer_iterate_end;
 }
 
 /**************************************************************************
@@ -902,12 +910,16 @@
                 struct canvas *pcanvas, int canvas_x, int canvas_y)
 {
   struct drawn_sprite drawn_sprites[40];
-  int count = fill_sprite_array(drawn_sprites, ptile, NULL, NULL, FALSE);
 
   /* Use full tile height, even for terrains. */
   canvas_y += (UNIT_TILE_HEIGHT - NORMAL_TILE_HEIGHT);
-  put_drawn_sprites(pcanvas, canvas_x, canvas_y,
-                   count, drawn_sprites, FALSE);
+  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);
+  } mapview_layer_iterate_end;
 }
 
 /****************************************************************************
@@ -1305,24 +1317,17 @@
   Draw the given map tile at the given canvas position in non-isometric
   view.
 **************************************************************************/
-void put_one_tile(struct canvas *pcanvas, struct tile *ptile,
+void put_one_tile(struct canvas *pcanvas, enum mapview_layer layer,
+                 struct tile *ptile,
                  int canvas_x, int canvas_y, bool citymode)
 {
-  if (tile_get_known(ptile) != TILE_UNKNOWN) {
-    struct drawn_sprite tile_sprs[80];
-
-    int count = fill_sprite_array(tile_sprs, ptile,
-                                 get_drawable_unit(ptile, citymode),
-                                 map_get_city(ptile), citymode);
+  struct drawn_sprite tile_sprs[80];
+  int count = fill_sprite_array(tile_sprs, layer, ptile,
+                               get_drawable_unit(ptile, citymode),
+                               map_get_city(ptile), citymode);
 
-    put_drawn_sprites(pcanvas, canvas_x, canvas_y,
-                     count, tile_sprs, FALSE);
-  } else {
-    /* tile is unknown */
-    canvas_put_rectangle(pcanvas, COLOR_STD_BLACK,
-                        canvas_x, canvas_y,
-                        NORMAL_TILE_WIDTH, NORMAL_TILE_HEIGHT);
-  }
+  put_drawn_sprites(pcanvas, canvas_x, canvas_y,
+                   count, tile_sprs, FALSE);
 }
 
 /**************************************************************************
@@ -1330,14 +1335,14 @@
   The coordinates have not been normalized, and are not guaranteed to be
   real (we have to draw unreal tiles too).
 **************************************************************************/
-static void put_tile(struct tile *ptile)
+static void put_tile(struct tile *ptile, enum mapview_layer layer)
 {
   int canvas_x, canvas_y;
 
   if (tile_to_canvas_pos(&canvas_x, &canvas_y, ptile)) {
     freelog(LOG_DEBUG, "putting (%d,%d) at (%d,%d)",
            TILE_XY(ptile), canvas_x, canvas_y);
-    put_one_tile(mapview_canvas.store, ptile,
+    put_one_tile(mapview_canvas.store, layer, ptile,
                 canvas_x, canvas_y, FALSE);
   }
 }
@@ -1455,14 +1460,15 @@
 /**************************************************************************
   Draw some or all of a tile onto the canvas, in iso-view.
 **************************************************************************/
-void put_one_tile_iso(struct canvas *pcanvas, struct tile *ptile,
+void put_one_tile_iso(struct canvas *pcanvas, enum mapview_layer layer,
+                     struct tile *ptile,
                      int canvas_x, int canvas_y, bool citymode)
 {
   struct drawn_sprite tile_sprs[80];
-  int count = fill_sprite_array(tile_sprs, ptile,
+  bool fog = ptile->known == TILE_KNOWN_FOGGED && draw_fog_of_war;
+  int count = fill_sprite_array(tile_sprs, layer, ptile,
                                get_drawable_unit(ptile, citymode),
                                ptile->city, citymode);
-  bool fog = ptile->known == TILE_KNOWN_FOGGED && draw_fog_of_war;
 
   /*** Draw terrain and specials ***/
   put_drawn_sprites(pcanvas, canvas_x, canvas_y, count, tile_sprs, fog);
@@ -1473,7 +1479,7 @@
   The coordinates have not been normalized, and are not guaranteed to be
   real (we have to draw unreal tiles too).
 **************************************************************************/
-static void put_tile_iso(struct tile *ptile)
+static void put_tile_iso(struct tile *ptile, enum mapview_layer layer)
 {
   int canvas_x, canvas_y;
 
@@ -1481,7 +1487,7 @@
     freelog(LOG_DEBUG, "putting (%d,%d) at (%d,%d)",
            TILE_XY(ptile), canvas_x, canvas_y);
 
-    put_one_tile_iso(mapview_canvas.store,
+    put_one_tile_iso(mapview_canvas.store, layer,
                     ptile, canvas_x, canvas_y,
                     FALSE);
   }
@@ -1545,21 +1551,23 @@
 
   /* FIXME: we don't have to draw black (unknown) tiles since they're already
    * cleared. */
-  if (is_isometric) {
-    gui_rect_iterate(gui_x0, gui_y0, width, height + NORMAL_TILE_HEIGHT / 2,
-                    ptile) {
-      put_tile_iso(ptile);
-    } gui_rect_iterate_end;
-  } else {
-    /* not isometric */
-    gui_rect_iterate(gui_x0, gui_y0, width, height, ptile) {
-      /*
-       * We don't normalize until later because we want to draw
-       * black tiles for unreal positions.
-       */
-      put_tile(ptile);
-    } gui_rect_iterate_end;
-  }
+  mapview_layer_iterate(layer) {
+    if (is_isometric) {
+      gui_rect_iterate(gui_x0, gui_y0, width, height + NORMAL_TILE_HEIGHT / 2,
+                      ptile) {
+       put_tile_iso(ptile, layer);
+      } gui_rect_iterate_end;
+    } else {
+      /* not isometric */
+      gui_rect_iterate(gui_x0, gui_y0, width, height, ptile) {
+       /*
+        * We don't normalize until later because we want to draw
+        * black tiles for unreal positions.
+        */
+       put_tile(ptile, layer);
+      } gui_rect_iterate_end;
+    }
+  } mapview_layer_iterate_end;
 
   /* Draw the goto lines on top of the whole thing. This is done last as
    * we want it completely on top.
Index: client/mapview_common.h
===================================================================
RCS file: /home/freeciv/CVS/freeciv/client/mapview_common.h,v
retrieving revision 1.80
diff -u -r1.80 mapview_common.h
--- client/mapview_common.h     17 Oct 2004 15:47:48 -0000      1.80
+++ client/mapview_common.h     4 Nov 2004 04:23:13 -0000
@@ -170,9 +170,11 @@
 
 void put_nuke_mushroom_pixmaps(struct tile *ptile);
 
-void put_one_tile(struct canvas *pcanvas, struct tile *ptile,
+void put_one_tile(struct canvas *pcanvas, enum mapview_layer layer,
+                 struct tile *ptile,
                  int canvas_x, int canvas_y, bool citymode);
-void put_one_tile_iso(struct canvas *pcanvas, struct tile *ptile,
+void put_one_tile_iso(struct canvas *pcanvas, enum mapview_layer layer,
+                     struct tile *ptile,
                      int canvas_x, int canvas_y, bool citymode);
 void tile_draw_grid(struct canvas *pcanvas, struct tile *ptile,
                    int canvas_x, int canvas_y, bool citymode);
Index: client/tilespec.c
===================================================================
RCS file: /home/freeciv/CVS/freeciv/client/tilespec.c,v
retrieving revision 1.208
diff -u -r1.208 tilespec.c
--- client/tilespec.c   23 Oct 2004 19:10:26 -0000      1.208
+++ client/tilespec.c   4 Nov 2004 04:23:14 -0000
@@ -2431,6 +2431,7 @@
   include specials or rivers.
 ****************************************************************************/
 static int fill_terrain_sprite_array(struct drawn_sprite *sprs,
+                                    int layer,
                                     struct tile *ptile,
                                     Terrain_type_id *ttype_near)
 {
@@ -2438,7 +2439,8 @@
   struct Sprite *sprite;
   Terrain_type_id ttype = ptile->terrain;
   struct terrain_drawing_data *draw = sprites.terrain[ttype];
-  int l, i, tileno;
+  const int l = layer;
+  int i, tileno;
   struct tile *adjc_tile;
 
   if (!draw_terrain) {
@@ -2447,156 +2449,162 @@
 
   /* Skip the normal drawing process. */
   if (ptile->spec_sprite && (sprite = load_sprite(ptile->spec_sprite))) {
-    ADD_SPRITE_SIMPLE(sprite);
-    return 1;
+    if (layer == 0) {
+      ADD_SPRITE_SIMPLE(sprite);
+      return 1;
+    } else {
+      return 0;
+    }
   }
 
-  for (l = 0; l < draw->num_layers; l++) {
-    if (draw->layer[l].match_style == MATCH_NONE) {
-      int count = sprite_vector_size(&draw->layer[l].base);
+  if (l >= draw->num_layers) {
+    return 0;
+  }
 
-      /* Pseudo-random reproducable algorithm to pick a sprite. */
+  if (draw->layer[l].match_style == MATCH_NONE) {
+    int count = sprite_vector_size(&draw->layer[l].base);
+
+    /* Pseudo-random reproducable algorithm to pick a sprite. */
 #define LARGE_PRIME 10007
 #define SMALL_PRIME 1009
-      assert(count < SMALL_PRIME);
-      assert((int)(LARGE_PRIME * MAX_MAP_INDEX) > 0);
-      count = ((ptile->index
-               * LARGE_PRIME) % SMALL_PRIME) % count;
-      ADD_SPRITE(draw->layer[l].base.p[count],
-                draw->layer[l].is_tall ? DRAW_FULL : DRAW_NORMAL,
-                TRUE, draw->layer[l].offset_x, draw->layer[l].offset_y);
-    } else {
-      int match_type = draw->layer[l].match_type;
+    assert(count < SMALL_PRIME);
+    assert((int)(LARGE_PRIME * MAX_MAP_INDEX) > 0);
+    count = ((ptile->index
+             * LARGE_PRIME) % SMALL_PRIME) % count;
+    ADD_SPRITE(draw->layer[l].base.p[count],
+              draw->layer[l].is_tall ? DRAW_FULL : DRAW_NORMAL,
+              TRUE, draw->layer[l].offset_x, draw->layer[l].offset_y);
+  } else {
+    int match_type = draw->layer[l].match_type;
 
 #define MATCH(dir)                                               \
-      (sprites.terrain[ttype_near[(dir)]]->num_layers > l       \
-       ? sprites.terrain[ttype_near[(dir)]]->layer[l].match_type : -1)
+    (sprites.terrain[ttype_near[(dir)]]->num_layers > l                        
\
+     ? sprites.terrain[ttype_near[(dir)]]->layer[l].match_type : -1)
 
-      if (draw->layer[l].cell_type == CELL_SINGLE) {
-       tileno = 0;
-       assert(draw->layer[l].match_style == MATCH_BOOLEAN);
-       for (i = 0; i < num_cardinal_tileset_dirs; i++) {
-         enum direction8 dir = cardinal_tileset_dirs[i];
+    if (draw->layer[l].cell_type == CELL_SINGLE) {
+      tileno = 0;
+      assert(draw->layer[l].match_style == MATCH_BOOLEAN);
+      for (i = 0; i < num_cardinal_tileset_dirs; i++) {
+       enum direction8 dir = cardinal_tileset_dirs[i];
 
-         if (MATCH(dir) == match_type) {
-           tileno |= 1 << i;
-         }
+       if (MATCH(dir) == match_type) {
+         tileno |= 1 << i;
        }
+      }
 
-       ADD_SPRITE(draw->layer[l].match[tileno],
-                  draw->layer[l].is_tall ? DRAW_FULL : DRAW_NORMAL,
-                  TRUE, draw->layer[l].offset_x, draw->layer[l].offset_y);
-      } else if (draw->layer[l].cell_type == CELL_RECT) {
-       /* Divide the tile up into four rectangular cells.  Now each of these
-        * cells covers one corner, and each is adjacent to 3 different
-        * tiles.  For each cell we pixk a sprite based upon the adjacent
-        * terrains at each of those tiles.  Thus we have 8 different sprites
-        * for each of the 4 cells (32 sprites total).
-        *
-        * These arrays correspond to the direction4 ordering. */
-       const int W = NORMAL_TILE_WIDTH, H = NORMAL_TILE_HEIGHT;
-       const int iso_offsets[4][2] = {
-         {W / 4, 0}, {W / 4, H / 2}, {W / 2, H / 4}, {0, H / 4}
-       };
-       const int noniso_offsets[4][2] = {
-         {0, 0}, {W / 2, H / 2}, {W / 2, 0}, {0, H / 2}
-       };
-       int i;
+      ADD_SPRITE(draw->layer[l].match[tileno],
+                draw->layer[l].is_tall ? DRAW_FULL : DRAW_NORMAL,
+                TRUE, draw->layer[l].offset_x, draw->layer[l].offset_y);
+    } else if (draw->layer[l].cell_type == CELL_RECT) {
+      /* Divide the tile up into four rectangular cells.  Now each of these
+       * cells covers one corner, and each is adjacent to 3 different
+       * tiles.  For each cell we pixk a sprite based upon the adjacent
+       * terrains at each of those tiles.  Thus we have 8 different sprites
+       * for each of the 4 cells (32 sprites total).
+       *
+       * These arrays correspond to the direction4 ordering. */
+      const int W = NORMAL_TILE_WIDTH, H = NORMAL_TILE_HEIGHT;
+      const int iso_offsets[4][2] = {
+       {W / 4, 0}, {W / 4, H / 2}, {W / 2, H / 4}, {0, H / 4}
+      };
+      const int noniso_offsets[4][2] = {
+       {0, 0}, {W / 2, H / 2}, {W / 2, 0}, {0, H / 2}
+      };
+      int i;
+
+      /* put corner cells */
+      for (i = 0; i < NUM_CORNER_DIRS; i++) {
+       const int count = draw->layer[l].match_count;
+       int array_index = 0;
+       enum direction8 dir = dir_ccw(DIR4_TO_DIR8[i]);
+       int x = (is_isometric ? iso_offsets[i][0] : noniso_offsets[i][0]);
+       int y = (is_isometric ? iso_offsets[i][1] : noniso_offsets[i][1]);
+       int m[3] = {MATCH(dir_ccw(dir)), MATCH(dir), MATCH(dir_cw(dir))};
+       struct Sprite *s;
+
+       switch (draw->layer[l].match_style) {
+       case MATCH_NONE:
+         /* Impossible */
+         assert(0);
+         break;
+       case MATCH_BOOLEAN:
+         assert(count == 2);
+         array_index = array_index * count + (m[2] != match_type);
+         array_index = array_index * count + (m[1] != match_type);
+         array_index = array_index * count + (m[0] != match_type);
+         break;
+       case MATCH_FULL:
+         if (m[0] == -1 || m[1] == -1 || m[2] == -1) {
+           break;
+         }
+         array_index = array_index * count + m[2];
+         array_index = array_index * count + m[1];
+         array_index = array_index * count + m[0];
+         break;
+       }
+       array_index = array_index * NUM_CORNER_DIRS + i;
 
-       /* put corner cells */
-       for (i = 0; i < NUM_CORNER_DIRS; i++) {
-         const int count = draw->layer[l].match_count;
-         int array_index = 0;
-         enum direction8 dir = dir_ccw(DIR4_TO_DIR8[i]);
-         int x = (is_isometric ? iso_offsets[i][0] : noniso_offsets[i][0]);
-         int y = (is_isometric ? iso_offsets[i][1] : noniso_offsets[i][1]);
-         int m[3] = {MATCH(dir_ccw(dir)), MATCH(dir), MATCH(dir_cw(dir))};
-         struct Sprite *s;
-
-         switch (draw->layer[l].match_style) {
-        case MATCH_NONE:
-          /* Impossible */
-          assert(0);
-          break;
-        case MATCH_BOOLEAN:
-          assert(count == 2);
-          array_index = array_index * count + (m[2] != match_type);
-          array_index = array_index * count + (m[1] != match_type);
-          array_index = array_index * count + (m[0] != match_type);
-          break;
-        case MATCH_FULL:
-          if (m[0] == -1 || m[1] == -1 || m[2] == -1) {
-            break;
-          }
-          array_index = array_index * count + m[2];
-          array_index = array_index * count + m[1];
-          array_index = array_index * count + m[0];
-          break;
-        }
-        array_index = array_index * NUM_CORNER_DIRS + i;
-
-        s = draw->layer[l].cells[array_index];
-        if (s) {
-          ADD_SPRITE(s, DRAW_NORMAL, TRUE, x, y);
-        }
+       s = draw->layer[l].cells[array_index];
+       if (s) {
+         ADD_SPRITE(s, DRAW_NORMAL, TRUE, x, y);
        }
       }
-#undef MATCH
     }
+#undef MATCH
+  }
 
-    /* Add blending on top of the first layer. */
-    if (l == 0 && draw->is_blended) {
-      sprs += fill_blending_sprite_array(sprs, ptile, ttype_near);
-    }
+  /* Add blending on top of the first layer. */
+  if (l == 0 && draw->is_blended) {
+    sprs += fill_blending_sprite_array(sprs, ptile, ttype_near);
+  }
 
-    /* Add darkness on top of the first layer.  Note that darkness is always
-     * drawn, even in citymode, etc. */
-    if (l == 0) {
+  /* Add darkness on top of the first layer.  Note that darkness is always
+   * drawn, even in citymode, etc. */
+  if (l == 0) {
 #define UNKNOWN(dir)                                        \
-      ((adjc_tile = mapstep(ptile, (dir)))                 \
-       && tile_get_known(adjc_tile) == TILE_UNKNOWN)
+    ((adjc_tile = mapstep(ptile, (dir)))                   \
+     && tile_get_known(adjc_tile) == TILE_UNKNOWN)
 
-      switch (darkness_style) {
-      case DARKNESS_NONE:
-       break;
-      case DARKNESS_ISORECT:
-       for (i = 0; i < 4; i++) {
-         const int W = NORMAL_TILE_WIDTH, H = NORMAL_TILE_HEIGHT;
-         int offsets[4][2] = {{W / 2, 0}, {0, H / 2}, {W / 2, H / 2}, {0, 0}};
-
-         if (UNKNOWN(DIR4_TO_DIR8[i])) {
-           ADD_SPRITE(sprites.tx.darkness[i], DRAW_NORMAL, TRUE,
-                      offsets[i][0], offsets[i][1]);
-         }
+    switch (darkness_style) {
+    case DARKNESS_NONE:
+      break;
+    case DARKNESS_ISORECT:
+      for (i = 0; i < 4; i++) {
+       const int W = NORMAL_TILE_WIDTH, H = NORMAL_TILE_HEIGHT;
+       int offsets[4][2] = {{W / 2, 0}, {0, H / 2}, {W / 2, H / 2}, {0, 0}};
+
+       if (UNKNOWN(DIR4_TO_DIR8[i])) {
+         ADD_SPRITE(sprites.tx.darkness[i], DRAW_NORMAL, TRUE,
+                    offsets[i][0], offsets[i][1]);
        }
-       break;
-      case DARKNESS_CARD_SINGLE:
-       for (i = 0; i < num_cardinal_tileset_dirs; i++) {
-         if (UNKNOWN(cardinal_tileset_dirs[i])) {
-           ADD_SPRITE_SIMPLE(sprites.tx.darkness[i]);
-         }
+      }
+      break;
+    case DARKNESS_CARD_SINGLE:
+      for (i = 0; i < num_cardinal_tileset_dirs; i++) {
+       if (UNKNOWN(cardinal_tileset_dirs[i])) {
+         ADD_SPRITE_SIMPLE(sprites.tx.darkness[i]);
        }
-       break;
-      case DARKNESS_CARD_FULL:
-       /* We're looking to find the INDEX_NSEW for the directions that
-        * are unknown.  We want to mark unknown tiles so that an unreal
-        * tile will be given the same marking as our current tile - that
-        * way we won't get the "unknown" dither along the edge of the
-        * map. */
-       tileno = 0;
-       for (i = 0; i < num_cardinal_tileset_dirs; i++) {
-         if (UNKNOWN(cardinal_tileset_dirs[i])) {
-           tileno |= 1 << i;
-         }
+      }
+      break;
+    case DARKNESS_CARD_FULL:
+      /* We're looking to find the INDEX_NSEW for the directions that
+       * are unknown.  We want to mark unknown tiles so that an unreal
+       * tile will be given the same marking as our current tile - that
+       * way we won't get the "unknown" dither along the edge of the
+       * map. */
+      tileno = 0;
+      for (i = 0; i < num_cardinal_tileset_dirs; i++) {
+       if (UNKNOWN(cardinal_tileset_dirs[i])) {
+         tileno |= 1 << i;
        }
+      }
 
-       if (tileno != 0) {
-         ADD_SPRITE_SIMPLE(sprites.tx.darkness[tileno]);
-       }
-       break;
+      if (tileno != 0) {
+       ADD_SPRITE_SIMPLE(sprites.tx.darkness[tileno]);
       }
-#undef UNKNOWN
+      break;
     }
+#undef UNKNOWN
   }
 
   return sprs - saved_sprs;
@@ -2619,7 +2627,8 @@
   citymode specifies whether this is part of a citydlg.  If so some drawing
   is done differently.
 ****************************************************************************/
-int fill_sprite_array(struct drawn_sprite *sprs, struct tile *ptile,
+int fill_sprite_array(struct drawn_sprite *sprs, enum mapview_layer layer,
+                     struct tile *ptile,
                      struct unit *punit, struct city *pcity,
                      bool citymode)
 {
@@ -2629,154 +2638,199 @@
   struct unit *pfocus = get_unit_in_focus();
   struct drawn_sprite *save_sprs = sprs;
 
-  if (ptile && tile_get_known(ptile) == TILE_UNKNOWN) {
-    ADD_BG(COLOR_STD_BLACK);
-    return sprs - save_sprs;
+  if (ptile && tile_get_known(ptile) != TILE_UNKNOWN) {
+    build_tile_data(ptile,
+                   &ttype, &tspecial, ttype_near, tspecial_near);
   }
 
-  /* Set up background color. */
-  if (solid_color_behind_units) {
-    if (punit && (draw_units || (draw_focus_unit && pfocus == punit))) {
-      ADD_BG(player_color(unit_owner(punit)));
-    } else if (pcity && draw_cities) {
-      ADD_BG(player_color(city_owner(pcity)));
+  switch (layer) {
+  case LAYER_BACKGROUND:
+    if (ptile && tile_get_known(ptile) == TILE_UNKNOWN) {
+      ADD_BG(COLOR_STD_BLACK);
+      return sprs - save_sprs;
     }
-  } else if (!draw_terrain) {
-    ADD_BG(COLOR_STD_BACKGROUND);
-  }
-
-  /* Terrain and specials. */
-  if (ptile) {
-    build_tile_data(ptile,
-                   &ttype, &tspecial, ttype_near, tspecial_near);
 
-    sprs += fill_terrain_sprite_array(sprs, ptile, ttype_near);
+    /* Set up background color. */
+    if (solid_color_behind_units) {
+      if (punit && (draw_units || (draw_focus_unit && pfocus == punit))) {
+       ADD_BG(player_color(unit_owner(punit)));
+      } else if (pcity && draw_cities) {
+       ADD_BG(player_color(city_owner(pcity)));
+      }
+    } else if (!draw_terrain) {
+      ADD_BG(COLOR_STD_BACKGROUND);
+    }
+    break;
 
-    if (is_ocean(ttype) && draw_terrain) {
-      for (dir = 0; dir < 4; dir++) {
-       if (contains_special(tspecial_near[DIR4_TO_DIR8[dir]], S_RIVER)) {
-         ADD_SPRITE_SIMPLE(sprites.tx.river_outlet[dir]);
+  case LAYER_TERRAIN1:
+  case LAYER_TERRAIN2:
+    /* Terrain and specials.  These are drawn in multiple layers so that
+     * upper layers will cover layers underneath. */
+    if (ptile && tile_get_known(ptile) != TILE_UNKNOWN) {
+      assert(MAX_NUM_LAYERS == 2);
+      sprs += fill_terrain_sprite_array(sprs,
+                                       (layer == LAYER_TERRAIN1) ? 0 : 1,
+                                       ptile, ttype_near);
+    }
+    break;
+
+  case LAYER_WATER:
+    if (ptile && tile_get_known(ptile) != TILE_UNKNOWN) {
+      if (is_ocean(ttype) && draw_terrain) {
+       for (dir = 0; dir < 4; dir++) {
+         if (contains_special(tspecial_near[DIR4_TO_DIR8[dir]], S_RIVER)) {
+           ADD_SPRITE_SIMPLE(sprites.tx.river_outlet[dir]);
+         }
        }
       }
-    }
 
-    sprs += fill_irrigation_sprite_array(sprs, tspecial, tspecial_near,
-                                        pcity);
+      sprs += fill_irrigation_sprite_array(sprs, tspecial, tspecial_near,
+                                          pcity);
 
-    if (draw_terrain && contains_special(tspecial, S_RIVER)) {
-      int i;
+      if (draw_terrain && contains_special(tspecial, S_RIVER)) {
+       int i;
 
-      /* Draw rivers on top of irrigation. */
-      tileno = 0;
-      for (i = 0; i < num_cardinal_tileset_dirs; i++) {
-       enum direction8 dir = cardinal_tileset_dirs[i];
+       /* Draw rivers on top of irrigation. */
+       tileno = 0;
+       for (i = 0; i < num_cardinal_tileset_dirs; i++) {
+         enum direction8 dir = cardinal_tileset_dirs[i];
 
-       if (contains_special(tspecial_near[dir], S_RIVER)
-           || is_ocean(ttype_near[dir])) {
-         tileno |= 1 << i;
+         if (contains_special(tspecial_near[dir], S_RIVER)
+             || is_ocean(ttype_near[dir])) {
+           tileno |= 1 << i;
+         }
        }
+       ADD_SPRITE_SIMPLE(sprites.tx.spec_river[tileno]);
       }
-      ADD_SPRITE_SIMPLE(sprites.tx.spec_river[tileno]);
     }
-  
-    sprs += fill_road_rail_sprite_array(sprs,
-                                       tspecial, tspecial_near, pcity);
+    break;
 
-    if (draw_specials) {
-      if (contains_special(tspecial, S_SPECIAL_1)) {
-       ADD_SPRITE_SIMPLE(sprites.terrain[ttype]->special[0]);
-      } else if (contains_special(tspecial, S_SPECIAL_2)) {
-       ADD_SPRITE_SIMPLE(sprites.terrain[ttype]->special[1]);
+  case LAYER_ROADS:
+    if (ptile && tile_get_known(ptile) != TILE_UNKNOWN) {
+      sprs += fill_road_rail_sprite_array(sprs,
+                                         tspecial, tspecial_near, pcity);
+    }
+    break;
+
+  case LAYER_SPECIAL1:
+    if (ptile && tile_get_known(ptile) != TILE_UNKNOWN) {
+      if (draw_specials) {
+       if (contains_special(tspecial, S_SPECIAL_1)) {
+         ADD_SPRITE_SIMPLE(sprites.terrain[ttype]->special[0]);
+       } else if (contains_special(tspecial, S_SPECIAL_2)) {
+         ADD_SPRITE_SIMPLE(sprites.terrain[ttype]->special[1]);
+       }
       }
-    }
 
-    if (draw_fortress_airbase && contains_special(tspecial, S_FORTRESS)
-       && sprites.tx.fortress_back) {
-      ADD_SPRITE_SIMPLE(sprites.tx.fortress_back);
-    }
-
-    if (draw_mines && contains_special(tspecial, S_MINE)
-       && sprites.terrain[ttype]->mine) {
-      ADD_SPRITE_SIMPLE(sprites.terrain[ttype]->mine);
-    }
-    
-    if (draw_specials && contains_special(tspecial, S_HUT)) {
-      ADD_SPRITE_SIMPLE(sprites.tx.village);
-    }
-  }
+      if (draw_fortress_airbase && contains_special(tspecial, S_FORTRESS)
+         && sprites.tx.fortress_back) {
+       ADD_SPRITE_SIMPLE(sprites.tx.fortress_back);
+      }
 
-  if (ptile && is_isometric) {
-    /* Add grid.  In classic view this is done later. */
-    ADD_GRID(ptile, citymode);
-  }
+      if (draw_mines && contains_special(tspecial, S_MINE)
+         && sprites.terrain[ttype]->mine) {
+       ADD_SPRITE_SIMPLE(sprites.terrain[ttype]->mine);
+      }
 
-  /* City.  Some city sprites are drawn later. */
-  if (pcity && draw_cities) {
-    if (!solid_color_behind_units) {
-      ADD_SPRITE(get_city_nation_flag_sprite(pcity),
-                DRAW_FULL, TRUE, flag_offset_x, flag_offset_y);
-    }
-    ADD_SPRITE_FULL(get_city_sprite(pcity));
-    if (pcity->client.occupied) {
-      ADD_SPRITE_FULL(get_city_occupied_sprite(pcity));
-    }
-    if (!is_isometric && city_got_citywalls(pcity)) {
-      /* In iso-view the city wall is a part of the city sprite. */
-      ADD_SPRITE_SIMPLE(get_city_wall_sprite(pcity));
-    }
-    if (pcity->client.unhappy) {
-      ADD_SPRITE_FULL(sprites.city.disorder);
+      if (draw_specials && contains_special(tspecial, S_HUT)) {
+       ADD_SPRITE_SIMPLE(sprites.tx.village);
+      }
     }
-  }
+    break;
 
-  if (ptile) {
-    if (draw_fortress_airbase && contains_special(tspecial, S_AIRBASE)) {
-      ADD_SPRITE_FULL(sprites.tx.airbase);
+  case LAYER_GRID1:
+    if (ptile && tile_get_known(ptile) != TILE_UNKNOWN && is_isometric) {
+      /* Add grid.  In classic view this is done later. */
+      ADD_GRID(ptile, citymode);
+    }
+    break;
+
+  case LAYER_CITY1:
+    /* City.  Some city sprites are drawn later. */
+    if (pcity && draw_cities) {
+      if (!solid_color_behind_units) {
+       ADD_SPRITE(get_city_nation_flag_sprite(pcity),
+                  DRAW_FULL, TRUE, flag_offset_x, flag_offset_y);
+      }
+      ADD_SPRITE_FULL(get_city_sprite(pcity));
+      if (pcity->client.occupied) {
+       ADD_SPRITE_FULL(get_city_occupied_sprite(pcity));
+      }
+      if (!is_isometric && city_got_citywalls(pcity)) {
+       /* In iso-view the city wall is a part of the city sprite. */
+       ADD_SPRITE_SIMPLE(get_city_wall_sprite(pcity));
+      }
+      if (pcity->client.unhappy) {
+       ADD_SPRITE_FULL(sprites.city.disorder);
+      }
     }
+    break;
 
-    if (draw_pollution && contains_special(tspecial, S_POLLUTION)) {
-      ADD_SPRITE_SIMPLE(sprites.tx.pollution);
-    }
-    if (draw_pollution && contains_special(tspecial, S_FALLOUT)) {
-      ADD_SPRITE_SIMPLE(sprites.tx.fallout);
-    }
-  }
+  case LAYER_SPECIAL2:
+    if (ptile && tile_get_known(ptile) != TILE_UNKNOWN) {
+      if (draw_fortress_airbase && contains_special(tspecial, S_AIRBASE)) {
+       ADD_SPRITE_FULL(sprites.tx.airbase);
+      }
 
-  if (!is_isometric && draw_fog_of_war
-      && ptile && tile_get_known(ptile) == TILE_KNOWN_FOGGED) {
-    /* Fogging in non-iso is done this way. */
-    ADD_SPRITE_SIMPLE(sprites.tx.fog);
-  }
+      if (draw_pollution && contains_special(tspecial, S_POLLUTION)) {
+       ADD_SPRITE_SIMPLE(sprites.tx.pollution);
+      }
+      if (draw_pollution && contains_special(tspecial, S_FALLOUT)) {
+       ADD_SPRITE_SIMPLE(sprites.tx.fallout);
+      }
+    }
+    break;
 
-  /* City size.  Drawing this under fog makes it hard to read. */
-  if (pcity && draw_cities) {
-    if (pcity->size >= 10) {
-      ADD_SPRITE(sprites.city.size_tens[pcity->size / 10], DRAW_FULL,
+  case LAYER_FOG:
+    if (!is_isometric && draw_fog_of_war
+       && ptile && tile_get_known(ptile) == TILE_KNOWN_FOGGED) {
+      /* Fogging in non-iso is done this way. */
+      ADD_SPRITE_SIMPLE(sprites.tx.fog);
+    }
+    break;
+
+  case LAYER_CITY2:
+    /* City size.  Drawing this under fog makes it hard to read. */
+    if (pcity && draw_cities) {
+      if (pcity->size >= 10) {
+       ADD_SPRITE(sprites.city.size_tens[pcity->size / 10], DRAW_FULL,
+                  FALSE, 0, 0);
+      }
+      ADD_SPRITE(sprites.city.size[pcity->size % 10], DRAW_FULL,
                 FALSE, 0, 0);
     }
-    ADD_SPRITE(sprites.city.size[pcity->size % 10], DRAW_FULL,
-              FALSE, 0, 0);
-  }
-
-  if (punit && (draw_units || (punit == pfocus && draw_focus_unit))) {
-    bool stacked = ptile && (unit_list_size(&ptile->units) > 1);
-    bool backdrop = !pcity;
-
-    sprs += fill_unit_sprite_array(sprs, punit, stacked, backdrop);
-  }
+    break;
 
-  if (ptile) {
-    if (is_isometric && draw_fortress_airbase
-       && contains_special(tspecial, S_FORTRESS)) {
-      /* Draw fortress front in iso-view (non-iso view only has a fortress
-       * back). */
-      ADD_SPRITE_FULL(sprites.tx.fortress);
+  case LAYER_UNIT:
+    if (punit && (draw_units || (punit == pfocus && draw_focus_unit))) {
+      bool stacked = ptile && (unit_list_size(&ptile->units) > 1);
+      bool backdrop = !pcity;
+
+      sprs += fill_unit_sprite_array(sprs, punit, stacked, backdrop);
+    }
+    break;
+
+  case LAYER_SPECIAL3:
+    if (ptile && tile_get_known(ptile) != TILE_UNKNOWN) {
+      if (is_isometric && draw_fortress_airbase
+         && contains_special(tspecial, S_FORTRESS)) {
+       /* Draw fortress front in iso-view (non-iso view only has a fortress
+        * back). */
+       ADD_SPRITE_FULL(sprites.tx.fortress);
+      }
     }
-  }
+    break;
 
-  if (ptile && !is_isometric) {
-    /* Add grid.  In iso-view this is done earlier. */
-    ADD_GRID(ptile, citymode);
+  case LAYER_GRID2:
+    if (ptile && tile_get_known(ptile) != TILE_UNKNOWN && !is_isometric) {
+      /* Add grid.  In iso-view this is done earlier. */
+      ADD_GRID(ptile, citymode);
+    }
+    break;
+
+  case LAYER_COUNT:
+    assert(0);
+    break;
   }
 
   return sprs - save_sprs;
Index: client/tilespec.h
===================================================================
RCS file: /home/freeciv/CVS/freeciv/client/tilespec.h,v
retrieving revision 1.90
diff -u -r1.90 tilespec.h
--- client/tilespec.h   7 Oct 2004 19:15:19 -0000       1.90
+++ client/tilespec.h   4 Nov 2004 04:23:15 -0000
@@ -57,6 +57,38 @@
   } data;
 };
 
+/* Items on the mapview are drawn in layers.  Each entry below represents
+ * one layer.  The names are basically arbitrary and just correspond to
+ * groups of elements in fill_sprite_array().  Callers of fill_sprite_array
+ * must call it once for each layer. */
+enum mapview_layer {
+  LAYER_BACKGROUND,
+  LAYER_TERRAIN1,
+  LAYER_TERRAIN2,
+  LAYER_WATER,
+  LAYER_ROADS,
+  LAYER_SPECIAL1,
+  LAYER_GRID1,
+  LAYER_CITY1,
+  LAYER_SPECIAL2,
+  LAYER_FOG,
+  LAYER_CITY2,
+  LAYER_UNIT,
+  LAYER_SPECIAL3,
+  LAYER_GRID2,
+  LAYER_COUNT
+};
+
+#define mapview_layer_iterate(layer)                                       \
+{                                                                          \
+  enum mapview_layer layer;                                                \
+                                                                           \
+  for (layer = 0; layer < LAYER_COUNT; layer++) {                          \
+
+#define mapview_layer_iterate_end                                          \
+  }                                                                        \
+}
+
 const char **get_tileset_list(void);
 
 bool tilespec_read_toplevel(const char *tileset_name);
@@ -79,7 +111,8 @@
 
 /* Gfx support */
 
-int fill_sprite_array(struct drawn_sprite *sprs, struct tile *ptile,
+int fill_sprite_array(struct drawn_sprite *sprs, enum mapview_layer layer,
+                     struct tile *ptile,
                      struct unit *punit, struct city *pcity,
                      bool citymode);
 

[Prev in Thread] Current Thread [Next in Thread]
  • [Freeciv-Dev] (PR#10865) mapview layers, Jason Short <=