Complete.Org: Mailing Lists: Archives: freeciv-dev: July 2004:
[Freeciv-Dev] (PR#9379) hex tilesets and rivers
Home

[Freeciv-Dev] (PR#9379) hex tilesets and rivers

[Top] [All Lists]

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index] [Thread Index]
To: undisclosed-recipients: ;
Subject: [Freeciv-Dev] (PR#9379) hex tilesets and rivers
From: "Jason Dorje Short" <jdorje@xxxxxxxxxxx>
Date: Tue, 13 Jul 2004 20:12:47 -0700
Reply-to: rt@xxxxxxxxxxx

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

One of the biggest problems with playing in hex (with the hex-topology 
patch and the isophex tileset) is that the rivers aren't drawn 
correctly.  Rivers connect along diagonal lines, but the tileset cannot 
draw this.

This patch is a fix for that problem, and also a step toward a more 
general design for doing "matching" sprites.

First of all it uses tileset directional lists (see PR#9338).  A list of 
valid directions and a list of cardinal directions is assembled, 
although only the cardinal directions are used.

The cardinal direction lists is used for drawing river (spec_river) 
graphics.  The algorithm is pretty simple, surely less error-prone than 
the one in place now.  And it works for hex.

This is step toward a new design, so it deserves some scrutiny.  However 
I think this design is much better and should replace all users of 
INDEX_CW/cw_str and INDEX_NSEW/nsew_str.

Also attached is a rivers.spec and rivers.png to be used with isophex. 
Add this to the isophex tileset and the new algorithm will be used. 
This is just something I scrapped together for testing.  With hex there 
are 2^6 = 64 needed river sprites, so there is some work to be done to 
get good graphics.  Of course each set of 4 of them can just be 
duplicated to get the same bad behavior we have now.

jason

Index: client/tilespec.c
===================================================================
RCS file: /home/freeciv/CVS/freeciv/client/tilespec.c,v
retrieving revision 1.183
diff -u -r1.183 tilespec.c
--- client/tilespec.c   13 Jul 2004 18:16:53 -0000      1.183
+++ client/tilespec.c   14 Jul 2004 02:48:15 -0000
@@ -88,6 +88,9 @@
 #define NUM_CORNER_DIRS 4
 #define TILES_PER_CORNER 4
 
+static int num_valid_tileset_dirs, num_cardinal_tileset_dirs;
+static enum direction8 valid_tileset_dirs[8], cardinal_tileset_dirs[8];
+
 static struct {
   enum match_style match_style;
   int count;
@@ -197,6 +200,64 @@
                                            bool required, const char *what,
                                            const char *name);
 
+/**************************************************************************
+  Return the tileset name of the direction.  This is similar to
+  dir_get_name but you shouldn't change this or all tilesets will break.
+**************************************************************************/
+static const char *dir_get_tileset_name(enum direction8 dir)
+{
+  switch (dir) {
+  case DIR8_NORTH:
+    return "n";
+  case DIR8_NORTHEAST:
+    return "ne";
+  case DIR8_EAST:
+    return "e";
+  case DIR8_SOUTHEAST:
+    return "se";
+  case DIR8_SOUTH:
+    return "s";
+  case DIR8_SOUTHWEST:
+    return "sw";
+  case DIR8_WEST:
+    return "w";
+  case DIR8_NORTHWEST:
+    return "nw";
+  }
+  assert(0);
+  return "";
+}
+
+/****************************************************************************
+  Return TRUE iff the dir is valid in this tileset.
+****************************************************************************/
+static bool is_valid_tileset_dir(enum direction8 dir)
+{
+  if (hex_width > 0) {
+    return dir != DIR8_NORTHEAST && dir != DIR8_SOUTHWEST;
+  } else if (hex_height > 0) {
+    return dir != DIR8_NORTHWEST && dir != DIR8_SOUTHEAST;
+  } else {
+    return TRUE;
+  }
+}
+
+/****************************************************************************
+  Return TRUE iff the dir is cardinal in this tileset.
+
+  "Cardinal", in this sense, means that a tile will share a border with
+  another tile in the direction rather than sharing just a single vertex.
+****************************************************************************/
+static bool is_cardinal_tileset_dir(enum direction8 dir)
+{
+  if (hex_width > 0 || hex_height > 0) {
+    return is_valid_tileset_dir(dir);
+  } else {
+    return (dir == DIR8_NORTH || dir == DIR8_EAST
+           || dir == DIR8_SOUTH || dir == DIR8_WEST);
+  }
+}
+
 /**********************************************************************
   Returns a static list of tilesets available on the system by
   searching all data directories for files matching TILESPEC_SUFFIX.
@@ -687,6 +748,7 @@
   char **spec_filenames, **terrains;
   char *file_capstr;
   bool duplicates_ok, is_hex;
+  enum direction8 dir;
 
   fname = tilespec_fullname(tileset_name);
   freelog(LOG_VERBOSE, "tilespec file is %s", fname);
@@ -738,6 +800,24 @@
     return tilespec_read_toplevel(NULL);
   }
 
+  /* Create arrays of valid and cardinal tileset dirs.  These depend
+   * entirely on the tileset, not the topology.  They are also in clockwise
+   * rotational ordering. */
+  num_valid_tileset_dirs = num_cardinal_tileset_dirs = 0;
+  dir = DIR8_NORTH;
+  do {
+    if (is_valid_tileset_dir(dir)) {
+      valid_tileset_dirs[num_valid_tileset_dirs] = dir;
+      num_valid_tileset_dirs++;
+    }
+    if (is_cardinal_tileset_dir(dir)) {
+      cardinal_tileset_dirs[num_cardinal_tileset_dirs] = dir;
+      num_cardinal_tileset_dirs++;
+    }
+
+    dir = dir_cw(dir);
+  } while (dir != DIR8_NORTH);
+
   NORMAL_TILE_WIDTH = secfile_lookup_int(file, "tilespec.normal_tile_width");
   NORMAL_TILE_HEIGHT = secfile_lookup_int(file, "tilespec.normal_tile_height");
   if (is_isometric) {
@@ -1006,6 +1086,27 @@
 }
 
 /****************************************************************************
+  Return a directional string for the cardinal directions.  Normally the
+  binary value 1000 will be converted into "n1e0s0w0".  This is in a
+  clockwise ordering.
+****************************************************************************/
+static const char *cardinal_str(int idx)
+{
+  static char c[64];
+  int i;
+
+  c[0] = '\0';
+  for (i = 0; i < num_cardinal_tileset_dirs; i++) {
+    int value = (idx >> i) & 1;
+
+    snprintf(c + strlen(c), sizeof(c) - strlen(c), "%s%d",
+            dir_get_tileset_name(cardinal_tileset_dirs[i]), value);
+  }
+
+  return c;
+}
+
+/****************************************************************************
   Do the same thing as nsew_str, except including all the cardinal and 
   diagonal directions.
   The returned string is a pointer to static memory.
@@ -1314,8 +1415,8 @@
   SET_SPRITE(tx.airbase,    "tx.airbase");
   SET_SPRITE(tx.fog,        "tx.fog");
 
-  for(i=0; i<NUM_DIRECTION_NSEW; i++) {
-    my_snprintf(buffer, sizeof(buffer), "tx.s_river_%s", nsew_str(i));
+  for (i = 0; i < NUM_DIRECTION_CARDINAL; i++) {
+    my_snprintf(buffer, sizeof(buffer), "tx.s_river_%s", cardinal_str(i));
     SET_SPRITE(tx.spec_river[i], buffer);
   }
 
@@ -2543,19 +2644,18 @@
                                         pcity);
 
     if (draw_terrain && contains_special(tspecial, S_RIVER)) {
+      int i;
+
       /* Draw rivers on top of irrigation. */
-      tileno = INDEX_NSEW((contains_special(tspecial_near[DIR8_NORTH],
-                                           S_RIVER)
-                          || is_ocean(ttype_near[DIR8_NORTH])),
-                         (contains_special(tspecial_near[DIR8_SOUTH],
-                                           S_RIVER)
-                          || is_ocean(ttype_near[DIR8_SOUTH])),
-                         (contains_special(tspecial_near[DIR8_EAST],
-                                           S_RIVER)
-                          || is_ocean(ttype_near[DIR8_EAST])),
-                         (contains_special(tspecial_near[DIR8_WEST],
-                                           S_RIVER)
-                          || is_ocean(ttype_near[DIR8_WEST])));
+      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;
+       }
+      }
       ADD_SPRITE_SIMPLE(sprites.tx.spec_river[tileno]);
     }
   
Index: client/tilespec.h
===================================================================
RCS file: /home/freeciv/CVS/freeciv/client/tilespec.h,v
retrieving revision 1.75
diff -u -r1.75 tilespec.h
--- client/tilespec.h   10 Jul 2004 18:48:17 -0000      1.75
+++ client/tilespec.h   14 Jul 2004 02:48:16 -0000
@@ -81,8 +81,8 @@
 
 
 /* This the way directional indices are now encoded: */
-
 #define NUM_DIRECTION_NSEW             16
+#define NUM_DIRECTION_CARDINAL                 64
 #define NUM_DIRECTION_CW               256
 
 #define BIT_NORTH (0x01)
@@ -269,7 +269,7 @@
       *airbase,
       *fallout,
       *fog,
-      *spec_river[NUM_DIRECTION_NSEW],
+      *spec_river[NUM_DIRECTION_CARDINAL],
       *darkness[NUM_DIRECTION_NSEW],         /* first unused */
       *river_outlet[4],                /* indexed by enum direction4 */
       /* for non-isometric */
Index: data/isotrident/terrain2.spec
===================================================================
RCS file: /home/freeciv/CVS/freeciv/data/isotrident/terrain2.spec,v
retrieving revision 1.4
diff -u -r1.4 terrain2.spec
--- data/isotrident/terrain2.spec       4 May 2004 18:22:02 -0000       1.4
+++ data/isotrident/terrain2.spec       14 Jul 2004 02:48:17 -0000
@@ -25,22 +25,22 @@
 ; Rivers (as special type), and whether north, south, east, west 
 ; also has river or is ocean:
 
- 2,  0, "tx.s_river_n0s0e0w0"
- 2,  1, "tx.s_river_n1s0e0w0"
- 2,  2, "tx.s_river_n0s0e1w0"
- 2,  3, "tx.s_river_n1s0e1w0"
- 2,  4, "tx.s_river_n0s1e0w0"
- 2,  5, "tx.s_river_n1s1e0w0"
- 2,  6, "tx.s_river_n0s1e1w0"
- 2,  7, "tx.s_river_n1s1e1w0"
- 3,  0, "tx.s_river_n0s0e0w1"
- 3,  1, "tx.s_river_n1s0e0w1"
- 3,  2, "tx.s_river_n0s0e1w1"
- 3,  3, "tx.s_river_n1s0e1w1"
- 3,  4, "tx.s_river_n0s1e0w1"
- 3,  5, "tx.s_river_n1s1e0w1"
- 3,  6, "tx.s_river_n0s1e1w1"
- 3,  7, "tx.s_river_n1s1e1w1"
+ 2,  0, "tx.s_river_n0e0s0w0"
+ 2,  1, "tx.s_river_n1e0s0w0"
+ 2,  2, "tx.s_river_n0e1s0w0"
+ 2,  3, "tx.s_river_n1e1s0w0"
+ 2,  4, "tx.s_river_n0e0s1w0"
+ 2,  5, "tx.s_river_n1e0s1w0"
+ 2,  6, "tx.s_river_n0e1s1w0"
+ 2,  7, "tx.s_river_n1e1s1w0"
+ 3,  0, "tx.s_river_n0e0s0w1"
+ 3,  1, "tx.s_river_n1e0s0w1"
+ 3,  2, "tx.s_river_n0e1s0w1"
+ 3,  3, "tx.s_river_n1e1s0w1"
+ 3,  4, "tx.s_river_n0e0s1w1"
+ 3,  5, "tx.s_river_n1e0s1w1"
+ 3,  6, "tx.s_river_n0e1s1w1"
+ 3,  7, "tx.s_river_n1e1s1w1"
 
 ; Rivers as overlay
 
Index: data/trident/tiles.spec
===================================================================
RCS file: /home/freeciv/CVS/freeciv/data/trident/tiles.spec,v
retrieving revision 1.17
diff -u -r1.17 tiles.spec
--- data/trident/tiles.spec     29 Jun 2004 05:39:52 -0000      1.17
+++ data/trident/tiles.spec     14 Jul 2004 02:48:17 -0000
@@ -205,22 +205,22 @@
 ; Rivers (as special type), and whether north, south, east, west 
 ; also has river or is ocean:
 
- 18,  0, "tx.s_river_n0s0e0w0"
- 18,  1, "tx.s_river_n1s0e0w0"
- 18,  2, "tx.s_river_n0s0e1w0"
- 18,  3, "tx.s_river_n1s0e1w0"
- 18,  4, "tx.s_river_n0s1e0w0"
- 18,  5, "tx.s_river_n1s1e0w0"
- 18,  6, "tx.s_river_n0s1e1w0"
- 18,  7, "tx.s_river_n1s1e1w0"
- 18,  8, "tx.s_river_n0s0e0w1"
- 18,  9, "tx.s_river_n1s0e0w1"
- 18, 10, "tx.s_river_n0s0e1w1"
- 18, 11, "tx.s_river_n1s0e1w1"
- 18, 12, "tx.s_river_n0s1e0w1"
- 18, 13, "tx.s_river_n1s1e0w1"
- 18, 14, "tx.s_river_n0s1e1w1"
- 18, 15, "tx.s_river_n1s1e1w1"
+ 18,  0, "tx.s_river_n0e0s0w0"
+ 18,  1, "tx.s_river_n1e0s0w0"
+ 18,  2, "tx.s_river_n0e1s0w0"
+ 18,  3, "tx.s_river_n1e1s0w0"
+ 18,  4, "tx.s_river_n0e0s1w0"
+ 18,  5, "tx.s_river_n1e0s1w0"
+ 18,  6, "tx.s_river_n0e1s1w0"
+ 18,  7, "tx.s_river_n1e1s1w0"
+ 18,  8, "tx.s_river_n0e0s0w1"
+ 18,  9, "tx.s_river_n1e0s0w1"
+ 18, 10, "tx.s_river_n0e1s0w1"
+ 18, 11, "tx.s_river_n1e1s0w1"
+ 18, 12, "tx.s_river_n0e0s1w1"
+ 18, 13, "tx.s_river_n1e0s1w1"
+ 18, 14, "tx.s_river_n0e1s1w1"
+ 18, 15, "tx.s_river_n1e1s1w1"
 
 ; Ocean, and whether terrain to north, south, east, west 
 ; is more ocean (else shoreline)
[spec]

; Format and options of this spec file:
options = "+spec2"

[info]

artists = "
    Tim F. Smith <yoohootim@xxxxxxxxxxx>
    Daniel Speyer <dspeyer@xxxxxxxxxxxx> (mix)
    Frederic Rodrigo <f.rodrigo@xxxxxxxxxxxxx> (mix)
    Andreas Røsdal <andrearo@xxxxxxxxxxx> (hex mode)
    Jason Short <jdorje@xxxxxxxxxxxx> (hex mixing)
"

[file]
gfx = "isophex/rivers"

[grid_main]

x_top_left = 1
y_top_left = 1
dx = 64
dy = 32
is_pixel_border = 1

tiles = { "row", "column","tag"
; Rivers (as special type), and whether north, south, east, west 
; also has river or is ocean:

 2,  0, "tx.s_river_n0e0se0s0w0nw0"
 2,  1, "tx.s_river_n1e0se0s0w0nw0"
 2,  2, "tx.s_river_n0e1se0s0w0nw0"
 2,  3, "tx.s_river_n1e1se0s0w0nw0"
 2,  4, "tx.s_river_n0e0se0s1w0nw0"
 2,  5, "tx.s_river_n1e0se0s1w0nw0"
 2,  6, "tx.s_river_n0e1se0s1w0nw0"
 2,  7, "tx.s_river_n1e1se0s1w0nw0"
 3,  0, "tx.s_river_n0e0se0s0w1nw0"
 3,  1, "tx.s_river_n1e0se0s0w1nw0"
 3,  2, "tx.s_river_n0e1se0s0w1nw0"
 3,  3, "tx.s_river_n1e1se0s0w1nw0"
 3,  4, "tx.s_river_n0e0se0s1w1nw0"
 3,  5, "tx.s_river_n1e0se0s1w1nw0"
 3,  6, "tx.s_river_n0e1se0s1w1nw0"
 3,  7, "tx.s_river_n1e1se0s1w1nw0"

 4,  0, "tx.s_river_n0e0se1s0w0nw0"
 4,  1, "tx.s_river_n1e0se1s0w0nw0"
 4,  2, "tx.s_river_n0e1se1s0w0nw0"
 4,  3, "tx.s_river_n1e1se1s0w0nw0"
 4,  4, "tx.s_river_n0e0se1s1w0nw0"
 4,  5, "tx.s_river_n1e0se1s1w0nw0"
 4,  6, "tx.s_river_n0e1se1s1w0nw0"
 4,  7, "tx.s_river_n1e1se1s1w0nw0"
 5,  0, "tx.s_river_n0e0se1s0w1nw0"
 5,  1, "tx.s_river_n1e0se1s0w1nw0"
 5,  2, "tx.s_river_n0e1se1s0w1nw0"
 5,  3, "tx.s_river_n1e1se1s0w1nw0"
 5,  4, "tx.s_river_n0e0se1s1w1nw0"
 5,  5, "tx.s_river_n1e0se1s1w1nw0"
 5,  6, "tx.s_river_n0e1se1s1w1nw0"
 5,  7, "tx.s_river_n1e1se1s1w1nw0"

 6,  0, "tx.s_river_n0e0se0s0w0nw1"
 6,  1, "tx.s_river_n1e0se0s0w0nw1"
 6,  2, "tx.s_river_n0e1se0s0w0nw1"
 6,  3, "tx.s_river_n1e1se0s0w0nw1"
 6,  4, "tx.s_river_n0e0se0s1w0nw1"
 6,  5, "tx.s_river_n1e0se0s1w0nw1"
 6,  6, "tx.s_river_n0e1se0s1w0nw1"
 6,  7, "tx.s_river_n1e1se0s1w0nw1"
 7,  0, "tx.s_river_n0e0se0s0w1nw1"
 7,  1, "tx.s_river_n1e0se0s0w1nw1"
 7,  2, "tx.s_river_n0e1se0s0w1nw1"
 7,  3, "tx.s_river_n1e1se0s0w1nw1"
 7,  4, "tx.s_river_n0e0se0s1w1nw1"
 7,  5, "tx.s_river_n1e0se0s1w1nw1"
 7,  6, "tx.s_river_n0e1se0s1w1nw1"
 7,  7, "tx.s_river_n1e1se0s1w1nw1"

 8,  0, "tx.s_river_n0e0se1s0w0nw1"
 8,  1, "tx.s_river_n1e0se1s0w0nw1"
 8,  2, "tx.s_river_n0e1se1s0w0nw1"
 8,  3, "tx.s_river_n1e1se1s0w0nw1"
 8,  4, "tx.s_river_n0e0se1s1w0nw1"
 8,  5, "tx.s_river_n1e0se1s1w0nw1"
 8,  6, "tx.s_river_n0e1se1s1w0nw1"
 8,  7, "tx.s_river_n1e1se1s1w0nw1"
 9,  0, "tx.s_river_n0e0se1s0w1nw1"
 9,  1, "tx.s_river_n1e0se1s0w1nw1"
 9,  2, "tx.s_river_n0e1se1s0w1nw1"
 9,  3, "tx.s_river_n1e1se1s0w1nw1"
 9,  4, "tx.s_river_n0e0se1s1w1nw1"
 9,  5, "tx.s_river_n1e0se1s1w1nw1"
 9,  6, "tx.s_river_n0e1se1s1w1nw1"
 9,  7, "tx.s_river_n1e1se1s1w1nw1"

}

PNG image


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