[Freeciv-Dev] (PR#8622) civ3-style base terrain graphics
[Top] [All Lists]
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index] [Thread Index]
<URL: http://rt.freeciv.org/Ticket/Display.html?id=8622 >
http://freeciv.org/~jdorje/civ3.png
http://freeciv.org/~jdorje/civ3.tar.gz (tileset)
It's late so I'll skip over all the explanations. Suffice it to say
that the attached patch includes all the drawing code changes needed to
use the civ3 algorithm for drawing base terrains. It includes at least
two separate new features plus one bugfix, includes a number of hacks,
and has no documentation yet (obviously it's not ready for CVS yet).
But it does allow some really nice graphics like the ones in the
screenshot above.
It's worth noting though that drawing code changes are not enough to use
a civ3 tileset. The civ3 tileset puts several restrictions on the
ruleset and mapgen code. Some of these include:
- No swamps.
- Only 3 terrains can ever meet at a tile vertex (a tile vertex is the
intersection of 4 tiles). So you can have
plains-grassland-desert-plains but not plains-grassland-desert-coast.
This rarely happens randomly, however (you don't see it at all in the
screenshot).
- Tundra may only border grassland and coast. This is a problem for any
arctic regions.
- Arctic may only border deep ocean, and only in limited ways. This is
a problem since freeciv has no deep ocean.
- Terrain transforming must be prohibited, since otherwise these rules
would quickly be violated.
There are probably more restrictions that just happen rarely. Or maybe
I missed some sprites and some of these actually are possible.
jason
? tests/check-output
? tests/header_guard.sh
? tests/va_list.sh
Index: client/tilespec.c
===================================================================
RCS file: /home/freeciv/CVS/freeciv/client/tilespec.c,v
retrieving revision 1.165
diff -u -r1.165 tilespec.c
--- client/tilespec.c 29 Apr 2004 15:11:32 -0000 1.165
+++ client/tilespec.c 30 Apr 2004 05:16:30 -0000
@@ -86,6 +86,15 @@
static int roadstyle;
static int flag_offset_x, flag_offset_y;
+#define NUM_CORNER_DIRS 4
+#define TILES_PER_CORNER 4
+
+static struct {
+ enum match_style match_style;
+ int count;
+ char **match_types;
+} layers[MAX_NUM_LAYERS];
+
/* Darkness style. Don't reorder this enum since tilesets depend on it. */
static enum {
/* No darkness sprites are drawn. */
@@ -737,6 +746,26 @@
minimap_intro_filename = tilespec_gfx_filename(c);
freelog(LOG_DEBUG, "radar file %s", minimap_intro_filename);
+ /* Terrain layer info. */
+ for (i = 0; i < MAX_NUM_LAYERS; i++) {
+ char *style = secfile_lookup_str_default(file, "none",
+ "layer%d.match_style", i);
+ int j;
+
+ if (mystrcasecmp(style, "full") == 0) {
+ layers[i].match_style = MATCH_FULL;
+ } else if (mystrcasecmp(style, "bool") == 0) {
+ layers[i].match_style = MATCH_BOOLEAN;
+ } else {
+ layers[i].match_style = MATCH_NONE;
+ }
+
+ layers[i].match_types = secfile_lookup_str_vec(file, &layers[i].count,
+ "layer%d.match_types", i);
+ for (j = 0; j < layers[i].count; j++) {
+ layers[i].match_types[j] = mystrdup(layers[i].match_types[j]);
+ }
+ }
/* Terrain drawing info. */
terrains = secfile_get_secnames_prefix(file, "terrain_", &num_terrains);
@@ -751,7 +780,7 @@
for (i = 0; i < num_terrains; i++) {
struct terrain_drawing_data *terr = fc_malloc(sizeof(*terr));
char *cell_type;
- int l;
+ int l, j;
memset(terr, 0, sizeof(*terr));
terr->name = mystrdup(terrains[i] + strlen("terrain_"));
@@ -759,9 +788,12 @@
terrains[i]);
terr->num_layers = secfile_lookup_int(file, "%s.num_layers",
terrains[i]);
- terr->num_layers = MAX(1, terr->num_layers);
+ terr->num_layers = CLIP(1, terr->num_layers, MAX_NUM_LAYERS);
for (l = 0; l < terr->num_layers; l++) {
+ char *match_type;
+ char *match_style;
+
terr->layer[l].is_tall
= secfile_lookup_bool_default(file, FALSE, "%s.layer%d_is_tall",
terrains[i], l);
@@ -771,9 +803,61 @@
terr->layer[l].offset_y
= secfile_lookup_int_default(file, 0, "%s.layer%d_offset_y",
terrains[i], l);
- terr->layer[l].match_type
- = secfile_lookup_int_default(file, 0, "%s.layer%d_match_type",
- terrains[i], l);
+
+ match_style = secfile_lookup_str_default(file, "none",
+ "%s.layer%d_match_style",
+ terrains[i], l);
+ if (mystrcasecmp(match_style, "full") == 0) {
+ terr->layer[l].match_style = MATCH_FULL;
+ } else if (mystrcasecmp(match_style, "bool") == 0) {
+ terr->layer[l].match_style = MATCH_BOOLEAN;
+ } else {
+ terr->layer[l].match_style = MATCH_NONE;
+ }
+
+ match_type = secfile_lookup_str_default(file, NULL,
+ "%s.layer%d_match_type",
+ terrains[i], l);
+ if (match_type) {
+ /* Set match_count */
+ switch (terr->layer[l].match_style) {
+ case MATCH_NONE:
+ terr->layer[l].match_count = 0;
+ break;
+ case MATCH_FULL:
+ terr->layer[l].match_count = layers[l].count;
+ break;
+ case MATCH_BOOLEAN:
+ terr->layer[l].match_count = 2;
+ break;
+ }
+
+ /* Determine out match_type. */
+ for (j = 0; j < layers[l].count; j++) {
+ if (mystrcasecmp(layers[l].match_types[j], match_type) == 0) {
+ break;
+ }
+ }
+ terr->layer[l].match_type = j;
+ if (j >= layers[l].count) {
+ freelog(LOG_ERROR, "Invalid match type given for %s.", terrains[i]);
+ terr->layer[l].match_type = 0;
+ terr->layer[l].match_style = MATCH_NONE;
+ }
+ } else {
+ terr->layer[l].match_style = MATCH_NONE;
+ if (layers[l].match_style != MATCH_NONE) {
+ freelog(LOG_ERROR, "Layer %d has a match_style set; all terrains"
+ " must have a match_type. %s doesn't.", l, terrains[i]);
+ }
+ }
+
+ if (terr->layer[l].match_style == MATCH_NONE
+ && layers[l].match_style == MATCH_FULL) {
+ freelog(LOG_ERROR, "Layer %d has match_type full set; all terrains"
+ " must match this. %s doesn't.", l, terrains[i]);
+ }
+
cell_type
= secfile_lookup_str_default(file, "single", "%s.layer%d_cell_type",
terrains[i], l);
@@ -1298,15 +1382,13 @@
/* Set up each layer of the drawing. */
for (l = 0; l < draw->num_layers; l++) {
- if (draw->layer[l].match_type == 0) {
+ if (draw->layer[l].match_style == MATCH_NONE) {
/* Load single sprite for this terrain. */
my_snprintf(buffer1, sizeof(buffer1), "t.%s1", draw->name);
draw->layer[l].base = lookup_sprite_tag_alt(buffer1, "", TRUE,
"tile_type",
tt->terrain_name);
} else {
- int j;
-
switch (draw->layer[l].cell_type) {
case CELL_SINGLE:
/* Load 16 cardinally-matched sprites. */
@@ -1320,15 +1402,101 @@
draw->layer[l].base = draw->layer[l].match[0];
break;
case CELL_RECT:
- for (i = 0; i < 4; i++) {
- for (j = 0; j < 8; j++) {
+ {
+ const int count = draw->layer[l].match_count;
+ int number;
+
+ /* N directions (NSEW) * 3 dimensions of matching */
+ /* FIXME: should use exp() or expi() here. */
+ number = NUM_CORNER_DIRS * count * count * count;
+ draw->layer[l].cells
+ = fc_malloc(number * sizeof(*draw->layer[l].cells));
+
+ for (i = 0; i < number; i++) {
+ int value = i / NUM_CORNER_DIRS;
+ enum direction4 dir = i % NUM_CORNER_DIRS;
char *dir2 = "udlr";
- my_snprintf(buffer1, sizeof(buffer1), "t.%s_cell_%c%d",
- draw->name, dir2[i], j);
- draw->layer[l].cells[j][i]
- = lookup_sprite_tag_alt(buffer1, "", TRUE, "tile_type",
- tt->terrain_name);
+ switch (draw->layer[l].match_style) {
+ case MATCH_NONE:
+ /* Impossible. */
+ assert(0);
+ break;
+ case MATCH_BOOLEAN:
+ my_snprintf(buffer1, sizeof(buffer1), "t.%s_cell_%c%d",
+ draw->name, dir2[dir], value);
+ draw->layer[l].cells[i]
+ = lookup_sprite_tag_alt(buffer1, "", TRUE, "tile_type",
+ tt->terrain_name);
+ break;
+ case MATCH_FULL:
+ {
+ int n = 0, s = 0, e = 0, w = 0;
+ int v1, v2, v3;
+ int this = draw->layer[l].match_type;
+ struct Sprite *sprite;
+
+ v1 = value % count;
+ value /= count;
+ v2 = value % count;
+ value /= count;
+ v3 = value % count;
+
+ assert(v1 < count && v2 < count && v3 < count);
+
+ /* Assume merged cells. This should be a separate option. */
+ switch (dir) {
+ case DIR4_NORTH:
+ s = this;
+ w = v1;
+ n = v2;
+ e = v3;
+ break;
+ case DIR4_EAST:
+ w = this;
+ n = v1;
+ e = v2;
+ s = v3;
+ break;
+ case DIR4_SOUTH:
+ n = this;
+ e = v1;
+ s = v2;
+ w = v3;
+ break;
+ case DIR4_WEST:
+ e = this;
+ s = v1;
+ w = v2;
+ n = v3;
+ break;
+ }
+ my_snprintf(buffer1, sizeof(buffer1),
+ "t.cellgroup_%s_%s_%s_%s",
+ layers[l].match_types[n],
+ layers[l].match_types[e],
+ layers[l].match_types[s],
+ layers[l].match_types[w]);
+ sprite = load_sprite(buffer1);
+
+ if (sprite) {
+ /* Crop the sprite to separate this cell. */
+ const int W = NORMAL_TILE_WIDTH, H = NORMAL_TILE_HEIGHT;
+ int x[4] = {W / 4, W / 4, 0, W / 2};
+ int y[4] = {H / 2, 0, H / 4, H / 4};
+ int xo[4] = {0, 0, -W / 2, W / 2};
+ int yo[4] = {H / 2, -H / 2, 0, 0};
+
+ sprite = crop_sprite(sprite,
+ x[dir], y[dir], W / 2, H / 2,
+ sprites.black_tile, xo[dir], yo[dir]);
+
+ }
+
+ draw->layer[l].cells[i] = sprite;
+ break;
+ }
+ }
}
}
my_snprintf(buffer1, sizeof(buffer1), "t.%s1", draw->name);
@@ -1985,14 +2153,13 @@
}
for (l = 0; l < draw->num_layers; l++) {
- if (draw->layer[l].match_type == 0) {
+ if (draw->layer[l].match_style == MATCH_NONE) {
ADD_SPRITE_SIMPLE(draw->layer[l].base);
} else {
int match_type = draw->layer[l].match_type;
#define MATCH(dir) \
- ((sprites.terrain[ttype_near[(dir)]]->layer[l].match_type) \
- == match_type)
+ (sprites.terrain[ttype_near[(dir)]]->layer[l].match_type)
if (draw->layer[l].cell_type == CELL_SINGLE) {
int tileno;
@@ -2011,26 +2178,50 @@
* 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
+ DIR8_NORTHWEST, DIR8_SOUTHEAST, DIR8_NORTHEAST, DIR8_SOUTHWEST
};
const int iso_offsets[4][2] = {
- {W / 4, 0}, {W / 4, H / 2}, {0, H / 4}, {W / 2, H / 4},
+ {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}, {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));
+ /* put corner cells */
+ for (i = 0; i < NUM_CORNER_DIRS; i++) {
+ const int count = draw->layer[l].match_count;
+ int array_index = 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]);
+ int m[3] = {MATCH(dir_ccw(dirs[i])),
+ MATCH(dirs[i]),
+ MATCH(dir_cw(dirs[i]))};
+ 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:
+ 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;
- ADD_SPRITE(draw->layer[l].cells[array_index][i],
- DRAW_NORMAL, TRUE, x, y);
+ s = draw->layer[l].cells[array_index];
+ if (s) {
+ ADD_SPRITE(s, DRAW_NORMAL, TRUE, x, y);
+ }
}
}
#undef MATCH
Index: client/tilespec.h
===================================================================
RCS file: /home/freeciv/CVS/freeciv/client/tilespec.h,v
retrieving revision 1.66
diff -u -r1.66 tilespec.h
--- client/tilespec.h 29 Apr 2004 15:11:32 -0000 1.66
+++ client/tilespec.h 30 Apr 2004 05:16:32 -0000
@@ -104,10 +104,16 @@
DIR4_NORTH = 0, DIR4_SOUTH, DIR4_EAST, DIR4_WEST
};
+enum match_style {
+ MATCH_NONE, MATCH_BOOLEAN, MATCH_FULL
+};
+
enum cell_type {
CELL_SINGLE, CELL_RECT
};
+#define MAX_NUM_LAYERS 2
+
struct terrain_drawing_data {
char *name;
char *mine_tag;
@@ -116,13 +122,16 @@
struct {
bool is_tall;
int offset_x, offset_y;
- int match_type;
+
+ enum match_style match_style;
+ int match_type, match_count;
+
enum cell_type cell_type;
struct Sprite *base;
struct Sprite *match[NUM_DIRECTION_NSEW];
- struct Sprite *cells[8][4]; /* 4 = up down left right */
- } layer[2];
+ struct Sprite **cells;
+ } layer[MAX_NUM_LAYERS];
bool is_blended;
struct Sprite *blend[4]; /* indexed by a direction4 */
Index: data/isotrident.tilespec
===================================================================
RCS file: /home/freeciv/CVS/freeciv/data/isotrident.tilespec,v
retrieving revision 1.16
diff -u -r1.16 isotrident.tilespec
--- data/isotrident.tilespec 1 Apr 2004 23:11:23 -0000 1.16
+++ data/isotrident.tilespec 30 Apr 2004 05:16:32 -0000
@@ -64,55 +64,74 @@
; Terrain info - see README.graphics
+[layer0]
+match_style = "BOOL"
+match_types = "ocean", "other"
+
+[layer1]
+match_style = "BOOL"
+match_types = "forest", "hills", "mountains"
+
[terrain_arctic]
is_blended = 1
num_layers = 1
+layer0_match_type = "other"
mine_sprite = "tx.oil_mine"
[terrain_desert]
is_blended = 1
num_layers = 1
+layer0_match_type = "other"
mine_sprite = "tx.oil_mine"
[terrain_forest]
is_blended = 1
num_layers = 2
-layer1_match_type = 1
+layer0_match_type = "other"
+layer1_match_type = "forest"
[terrain_grassland]
is_blended = 1
num_layers = 1
+layer0_match_type = "other"
[terrain_hills]
is_blended = 1
num_layers = 2
-layer1_match_type = 2
+layer0_match_type = "other"
+layer1_match_type = "hills"
mine_sprite = "tx.mine"
[terrain_jungle]
is_blended = 1
num_layers = 1
+layer0_match_type = "other"
[terrain_mountains]
is_blended = 1
num_layers = 2
-layer1_match_type = 3
+layer0_match_type = "other"
+layer1_match_type = "mountains"
mine_sprite = "tx.mine"
[terrain_ocean]
is_blended = 1
num_layers = 1
-layer0_match_type = 6
+layer0_match_style = "bool"
+layer0_match_type = "ocean"
layer0_cell_type = "rect"
[terrain_plains]
is_blended = 1
num_layers = 1
+layer0_match_type = "other"
[terrain_swamp]
is_blended = 1
num_layers = 1
+layer0_match_type = "other"
[terrain_tundra]
is_blended = 1
num_layers = 1
+layer0_match_type = "other"
[Prev in Thread] |
Current Thread |
[Next in Thread] |
- [Freeciv-Dev] (PR#8622) civ3-style base terrain graphics,
Jason Short <=
|
|