[Freeciv-Dev] (PR#7534) generalization of coasts
[Top] [All Lists]
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index] [Thread Index]
<URL: http://rt.freeciv.org/Ticket/Display.html?id=7534 >
This patch generalizes the algorithm used in iso-view to draw ocean and
coasts.
This algorithm is slick. Consider a rectangular tile (in iso-view the
tile is tilted; this makes no difference). We divide it into four cells:
_______________
| | |
| A | B |
| | |
|-------------|
| | |
| D | C |
|______|______|
Now each of these cells borders 3 adjacent tiles (including the
diagonal). Consider each cell individually, and do a simple boolean
match against those three adjacent tiles: 8 possible choices. So for
each cell we choose one of 8 different sprites to draw.
Currently this is done with lots of is_ocean() checks. Of course we
potentially want different types of ocean, so these checks probably
aren't so good. Under this patch instead of special-casing ocean all
over the place this information is put into the ruleset. A new variable
is added to each terrain type: cell_type. If this is "single" or unset,
the traditional single-cell-drawing method is used. If it's "rect",
then the 4-rectangle drawing method is used.
Support is included for iso and non-iso view. However non-iso view is
untested since no tilesets use this option. However, using this option
(and some future options) I think a much better non-iso tileset could be
created! For anyone interested in this I refer you to the section on
terrain sprites in doc/README.graphics. Note that the data format may
change as the algorithm is made more flexible.
In future this option may be extended in two ways:
- In addition to rectangular cells, we may be able to draw using
triangular cells. This is simpler than the rectangular cell method but
may also give good results.
- Currently the match is a boolean one. In future we may do a full
match. That means instead of 2^3 sprites per cell we'd need n^3 sprites
per cell! But the results are much better.
jason
Index: client/tilespec.c
===================================================================
RCS file: /home/freeciv/CVS/freeciv/client/tilespec.c,v
retrieving revision 1.145
diff -u -r1.145 tilespec.c
--- client/tilespec.c 2004/02/25 18:14:26 1.145
+++ client/tilespec.c 2004/02/26 01:50:47
@@ -689,6 +689,7 @@
for (i = 0; i < num_terrains; i++) {
struct terrain_drawing_data *terr = fc_malloc(sizeof(*terr));
+ char *cell_type;
memset(terr, 0, sizeof(*terr));
terr->name = mystrdup(terrains[i] + strlen("terrain_"));
@@ -698,6 +699,17 @@
terrains[i]);
terr->match_type = secfile_lookup_int(file, "%s.match_type",
terrains[i]);
+ cell_type = secfile_lookup_str_default(file, "single", "%s.cell_type",
+ terrains[i]);
+ if (strcasecmp(cell_type, "single") == 0) {
+ terr->cell_type = CELL_SINGLE;
+ } else if (strcasecmp(cell_type, "rect") == 0) {
+ terr->cell_type = CELL_RECT;
+ } else {
+ freelog(LOG_ERROR, "Unknown cell type %s for %s.",
+ cell_type, terrains[i]);
+ terr->cell_type = CELL_SINGLE;
+ }
terr->mine_tag = secfile_lookup_str_default(file, NULL, "%s.mine_sprite",
terrains[i]);
if (terr->mine_tag) {
@@ -1030,15 +1042,7 @@
SET_SPRITE_ALT(tx.farmland[i], buffer, "tx.farmland");
}
- if (is_isometric) {
- for (i=0; i<4; i++) {
- for (j=0; j<8; j++) {
- char *dir2 = "udlr";
- my_snprintf(buffer, sizeof(buffer), "tx.coast_cape_%c%d", dir2[i], j);
- SET_SPRITE(tx.coast_cape_iso[j][i], buffer);
- }
- }
- } else {
+ if (!is_isometric) {
for(i=1; i<NUM_DIRECTION_NSEW; i++) {
my_snprintf(buffer, sizeof(buffer), "tx.darkness_%s", nsew_str(i));
SET_SPRITE(tx.darkness[i], buffer);
@@ -1178,31 +1182,45 @@
/* Currently ocean terrains have special handling. Although a match type
* may be specified it is ignored. This is a hack. */
- if (is_isometric && is_ocean(terrain)) {
+ if (draw->match_type == 0 || draw->is_layered) {
+ /* Load single sprite for this terrain. */
my_snprintf(buffer1, sizeof(buffer1), "t.%s1", draw->name);
draw->base = lookup_sprite_tag_alt(buffer1, "", TRUE, "tile_type",
tt->terrain_name);
- } else {
- if (draw->match_type == 0 || draw->is_layered) {
- /* Load single sprite for this terrain. */
- my_snprintf(buffer1, sizeof(buffer1), "t.%s1", draw->name);
- draw->base = lookup_sprite_tag_alt(buffer1, "", TRUE, "tile_type",
- tt->terrain_name);
- }
+ }
- if (draw->match_type != 0) {
+ if (draw->match_type != 0) {
+ int j;
+
+ switch (draw->cell_type) {
+ case CELL_SINGLE:
/* Load 16 cardinally-matched sprites. */
for (i = 0; i < NUM_DIRECTION_NSEW; i++) {
my_snprintf(buffer1, sizeof(buffer1),
"t.%s_%s", draw->name, nsew_str(i));
draw->blend[i] = lookup_sprite_tag_alt(buffer1, "", TRUE,
- "tile_type", tt->terrain_name);
+ "tile_type",
+ tt->terrain_name);
}
-
- if (!draw->base) {
- draw->base = draw->blend[0];
+ break;
+ case CELL_RECT:
+ for (i = 0; i < 4; i++) {
+ for (j = 0; j < 8; j++) {
+ char *dir2 = "udlr";
+
+ my_snprintf(buffer1, sizeof(buffer1), "t.%s_cell_%c%d",
+ draw->name, dir2[i], j);
+ draw->cells[j][i] = lookup_sprite_tag_alt(buffer1, "", TRUE,
+ "tile_type",
+ tt->terrain_name);
+ }
}
+ break;
}
+
+ if (!draw->base) {
+ draw->base = draw->blend[0];
+ }
}
for (i=0; i<2; i++) {
@@ -1887,62 +1905,73 @@
ADD_SPRITE_SIMPLE(sprite);
return 1;
}
-
- if (is_isometric && is_ocean(ttype)) {
- /* painted via coasts. */
- const enum direction8 dirs[4] = {
- DIR8_NORTHWEST, /* up */
- DIR8_SOUTHEAST, /* down */
- DIR8_SOUTHWEST, /* left */
- DIR8_NORTHEAST /* right */
- };
- const int offsets[4][2] = {
- {NORMAL_TILE_WIDTH / 4, 0},
- {NORMAL_TILE_WIDTH / 4, NORMAL_TILE_HEIGHT / 2},
- {0, NORMAL_TILE_HEIGHT / 4},
- {NORMAL_TILE_WIDTH / 2, NORMAL_TILE_HEIGHT / 4},
- };
- int i;
-
- *dither_count = 4;
-
- /* put coasts */
- for (i = 0; i < 4; i++) {
- int array_index = ((!is_ocean(ttype_near[dir_ccw(dirs[i])]) ? 1 : 0)
- + (!is_ocean(ttype_near[dirs[i]]) ? 2 : 0)
- + (!is_ocean(ttype_near[dir_cw(dirs[i])])
- ? 4 : 0));
- ADD_SPRITE(sprites.tx.coast_cape_iso[array_index][i],
- offsets[i][0], offsets[i][1]);
- }
- } else {
+ if (sprites.terrain[ttype]->match_type == 0
+ || sprites.terrain[ttype]->is_layered) {
+ ADD_SPRITE_SIMPLE(sprites.terrain[ttype]->base);
*dither_count = 1;
+ }
- if (sprites.terrain[ttype]->match_type == 0
- || sprites.terrain[ttype]->is_layered) {
- ADD_SPRITE_SIMPLE(sprites.terrain[ttype]->base);
- }
+ if (sprites.terrain[ttype]->match_type != 0) {
+ int match_type = sprites.terrain[ttype]->match_type;
- if (sprites.terrain[ttype]->match_type != 0) {
- int match_type = sprites.terrain[ttype]->match_type;
-#define MATCH(dir) (sprites.terrain[ttype_near[(dir)]]->match_type)
- int tileno = INDEX_NSEW(MATCH(DIR8_NORTH) == match_type,
- MATCH(DIR8_SOUTH) == match_type,
- MATCH(DIR8_EAST) == match_type,
- MATCH(DIR8_WEST) == match_type);
-#undef MATCH
+#define MATCH(dir) ((sprites.terrain[ttype_near[(dir)]]->match_type) \
+ == match_type)
+ if (sprites.terrain[ttype]->cell_type == CELL_SINGLE) {
+ int tileno;
+
+ tileno = INDEX_NSEW(MATCH(DIR8_NORTH), MATCH(DIR8_SOUTH),
+ MATCH(DIR8_EAST), MATCH(DIR8_WEST));
ADD_SPRITE_SIMPLE(sprites.terrain[ttype]->blend[tileno]);
- }
+ if (!sprites.terrain[ttype]->is_layered) {
+ *dither_count = 1;
+ }
+ } else if (sprites.terrain[ttype]->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). */
+ const int W = NORMAL_TILE_WIDTH, H = NORMAL_TILE_HEIGHT;
+ const enum direction8 dirs[4] = {
+ DIR8_NORTHWEST, DIR8_SOUTHEAST, DIR8_SOUTHWEST, DIR8_NORTHEAST
+ };
+ const int iso_offsets[4][2] = {
+ {W / 4, 0},
+ {W / 4, H / 2},
+ {0, H / 4},
+ {W / 2, H / 4},
+ };
+ const int noniso_offsets[4][2] = {
+ {0, 0}, {W / 2, H / 2}, {0, H / 2}, {W / 2, 0}
+ };
+ int i;
+
+ /* put coasts */
+ for (i = 0; i < 4; i++) {
+ int array_index = ((!MATCH(dir_ccw(dirs[i])) ? 1 : 0)
+ + (!MATCH(dirs[i]) ? 2 : 0)
+ + (!MATCH(dir_cw(dirs[i])) ? 4 : 0));
+ int x = (is_isometric ? iso_offsets[i][0] : noniso_offsets[i][0]);
+ int y = (is_isometric ? iso_offsets[i][1] : noniso_offsets[i][1]);
+
+ ADD_SPRITE(sprites.terrain[ttype]->cells[array_index][i], x, y);
+ }
- /* Short-cut past dithering if all adjacent tiles are the same. */
- if (ttype_near[DIR8_NORTH] == ttype
- && ttype_near[DIR8_SOUTH] == ttype
- && ttype_near[DIR8_EAST] == ttype
- && ttype_near[DIR8_WEST] == ttype) {
- *dither_count = 0;
+ /* Short-cut past dithering if all adjacent tiles are the same. */
+ if (!sprites.terrain[ttype]->is_layered) {
+ if (ttype_near[DIR8_NORTH] == ttype
+ && ttype_near[DIR8_SOUTH] == ttype
+ && ttype_near[DIR8_EAST] == ttype
+ && ttype_near[DIR8_WEST] == ttype) {
+ *dither_count = 0;
+ } else {
+ *dither_count = 4;
+ }
+ }
}
+#undef MATCH
}
/* Extra "capes" added on in non-iso view. */
Index: client/tilespec.h
===================================================================
RCS file: /home/freeciv/CVS/freeciv/client/tilespec.h,v
retrieving revision 1.54
diff -u -r1.54 tilespec.h
--- client/tilespec.h 2004/02/24 05:20:24 1.54
+++ client/tilespec.h 2004/02/26 01:50:47
@@ -95,6 +95,10 @@
DIR4_NORTH = 0, DIR4_SOUTH, DIR4_EAST, DIR4_WEST
};
+enum cell_type {
+ CELL_SINGLE, CELL_RECT
+};
+
struct terrain_drawing_data {
char *name;
char *mine_tag;
@@ -102,9 +106,11 @@
bool is_blended;
bool is_layered;
int match_type;
+ enum cell_type cell_type;
struct Sprite *base;
struct Sprite *blend[NUM_DIRECTION_NSEW];
+ struct Sprite *cells[8][4]; /* 4 = up down left right */
struct Sprite *special[2];
struct Sprite *mine;
};
@@ -211,7 +217,6 @@
*spec_river[NUM_DIRECTION_NSEW],
*darkness[NUM_DIRECTION_NSEW], /* first unused */
*river_outlet[4], /* indexed by enum direction4 */
- *coast_cape_iso[8][4], /* 4 = up down left right */
/* for non-isometric */
*coast_cape[NUM_DIRECTION_NSEW]; /* first unused */
} tx; /* terrain extra */
Index: data/isotrident.tilespec
===================================================================
RCS file: /home/freeciv/CVS/freeciv/data/isotrident.tilespec,v
retrieving revision 1.10
diff -u -r1.10 isotrident.tilespec
--- data/isotrident.tilespec 2004/02/20 15:57:18 1.10
+++ data/isotrident.tilespec 2004/02/26 01:50:48
@@ -100,7 +100,8 @@
[terrain_ocean]
is_blended = 0
is_layered = 0
-match_type = 5
+match_type = 6
+cell_type = "rect"
[terrain_plains]
is_blended = 1
Index: data/isotrident/terrain2.spec
===================================================================
RCS file: /home/freeciv/CVS/freeciv/data/isotrident/terrain2.spec,v
retrieving revision 1.2
diff -u -r1.2 terrain2.spec
--- data/isotrident/terrain2.spec 2004/02/17 04:53:00 1.2
+++ data/isotrident/terrain2.spec 2004/02/26 01:50:48
@@ -137,39 +137,39 @@
is_pixel_border = 1
tiles = { "row", "column","tag"
- 0, 0, "tx.coast_cape_u0"
- 0, 2, "tx.coast_cape_u1"
- 0, 4, "tx.coast_cape_u2"
- 0, 6, "tx.coast_cape_u3"
- 0, 8, "tx.coast_cape_u4"
- 0, 10, "tx.coast_cape_u5"
- 0, 12, "tx.coast_cape_u6"
- 0, 14, "tx.coast_cape_u7"
+ 0, 0, "t.ocean_cell_u0"
+ 0, 2, "t.ocean_cell_u1"
+ 0, 4, "t.ocean_cell_u2"
+ 0, 6, "t.ocean_cell_u3"
+ 0, 8, "t.ocean_cell_u4"
+ 0, 10, "t.ocean_cell_u5"
+ 0, 12, "t.ocean_cell_u6"
+ 0, 14, "t.ocean_cell_u7"
- 1, 0, "tx.coast_cape_d0"
- 1, 2, "tx.coast_cape_d1"
- 1, 4, "tx.coast_cape_d2"
- 1, 6, "tx.coast_cape_d3"
- 1, 8, "tx.coast_cape_d4"
- 1, 10, "tx.coast_cape_d5"
- 1, 12, "tx.coast_cape_d6"
- 1, 14, "tx.coast_cape_d7"
+ 1, 0, "t.ocean_cell_d0"
+ 1, 2, "t.ocean_cell_d1"
+ 1, 4, "t.ocean_cell_d2"
+ 1, 6, "t.ocean_cell_d3"
+ 1, 8, "t.ocean_cell_d4"
+ 1, 10, "t.ocean_cell_d5"
+ 1, 12, "t.ocean_cell_d6"
+ 1, 14, "t.ocean_cell_d7"
- 2, 0, "tx.coast_cape_l0"
- 2, 2, "tx.coast_cape_l1"
- 2, 4, "tx.coast_cape_l2"
- 2, 6, "tx.coast_cape_l3"
- 2, 8, "tx.coast_cape_l4"
- 2, 10, "tx.coast_cape_l5"
- 2, 12, "tx.coast_cape_l6"
- 2, 14, "tx.coast_cape_l7"
+ 2, 0, "t.ocean_cell_l0"
+ 2, 2, "t.ocean_cell_l1"
+ 2, 4, "t.ocean_cell_l2"
+ 2, 6, "t.ocean_cell_l3"
+ 2, 8, "t.ocean_cell_l4"
+ 2, 10, "t.ocean_cell_l5"
+ 2, 12, "t.ocean_cell_l6"
+ 2, 14, "t.ocean_cell_l7"
- 2, 1, "tx.coast_cape_r0"
- 2, 3, "tx.coast_cape_r1"
- 2, 5, "tx.coast_cape_r2"
- 2, 7, "tx.coast_cape_r3"
- 2, 9, "tx.coast_cape_r4"
- 2, 11, "tx.coast_cape_r5"
- 2, 13, "tx.coast_cape_r6"
- 2, 15, "tx.coast_cape_r7"
+ 2, 1, "t.ocean_cell_r0"
+ 2, 3, "t.ocean_cell_r1"
+ 2, 5, "t.ocean_cell_r2"
+ 2, 7, "t.ocean_cell_r3"
+ 2, 9, "t.ocean_cell_r4"
+ 2, 11, "t.ocean_cell_r5"
+ 2, 13, "t.ocean_cell_r6"
+ 2, 15, "t.ocean_cell_r7"
}
Index: doc/README.graphics
===================================================================
RCS file: /home/freeciv/CVS/freeciv/doc/README.graphics,v
retrieving revision 1.8
diff -u -r1.8 README.graphics
--- doc/README.graphics 2004/02/17 04:53:00 1.8
+++ doc/README.graphics 2004/02/26 01:50:48
@@ -133,6 +133,15 @@
sprite will be chosen that matches all cardinally
adjacent tiles whose terrain has the same
match_type.
+ cell_type : With traditional tilesets each tile is drawn using
+ one sprite. Which sprite to use may be specified
+ using a match_type, and there may be multiple layers
+ (each having one sprite). This method corresponds
+ to cell_type "single". A more sophisticated drawing
+ method breaks the tile up into 4 rectangles. Each
+ rectangular cell is adjacent to 3 different tiles.
+ Each adjacency is matched, giving 8 different sprites
+ for each of the 4 cells.
Sprites
-------
@@ -149,7 +158,15 @@
(e.g., "t.hills_n0s0e1w0". Each direcional value
<V> is either 0 or 1. Note that the directions are
in map coordinates, so n (north) in iso-view is
- northeast on the mapview.
+ northeast on the mapview. (Note this only applies
+ for cell_type "single".)
+ cell sprites : For matched terrains that have cell_type "rect",
+ 32 different sprites are needed. Each sprite is
+ a rectangle corresponding to one cell, and there are
+ 8 different sprites per cell. Each sprite has
+ a name like "t.ocean_cell_u5" where "ocean" is the
+ terrain, "u" means up (north on the map) and
+ 5 indicates which of the adjacent tiles are matched.
Examples:
[Prev in Thread] |
Current Thread |
[Next in Thread] |
- [Freeciv-Dev] (PR#7534) generalization of coasts,
Jason Short <=
|
|