[Freeciv-Dev] (PR#12085) RFC: better iteration in gui_rect_iterate
[Top] [All Lists]
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index] [Thread Index]
<URL: http://bugs.freeciv.org/Ticket/Display.html?id=12085 >
And here is yet another version, updated for current CVS. This one is
really ready.
-jason
? blend.png
? fog
? fog.c
? fog.png
? foo
? terrain1.png
? data/trident/fog.png
Index: client/mapview_common.c
===================================================================
RCS file: /home/freeciv/CVS/freeciv/client/mapview_common.c,v
retrieving revision 1.174
diff -u -r1.174 mapview_common.c
--- client/mapview_common.c 4 Feb 2005 19:29:00 -0000 1.174
+++ client/mapview_common.c 4 Feb 2005 20:02:19 -0000
@@ -873,21 +873,37 @@
}
/**************************************************************************
+ Draw one layer of a tile, edge, corner, unit, and/or city onto the
+ canvas at the given position.
+**************************************************************************/
+static void put_one_element(struct canvas *pcanvas, enum mapview_layer layer,
+ struct tile *ptile,
+ const struct tile_edge *pedge,
+ const struct tile_corner *pcorner,
+ const struct unit *punit, struct city *pcity,
+ int canvas_x, int canvas_y, bool citymode)
+{
+ struct drawn_sprite tile_sprs[80];
+ int count = fill_sprite_array(tile_sprs, layer, ptile, pedge, pcorner,
+ punit, pcity, citymode);
+ bool fog = (ptile && tile_get_known(ptile) == TILE_KNOWN_FOGGED
+ && draw_fog_of_war && fogstyle == 0);
+
+ /*** Draw terrain and specials ***/
+ put_drawn_sprites(pcanvas, canvas_x, canvas_y, count, tile_sprs, fog);
+}
+
+/**************************************************************************
Draw the given unit onto the canvas store at the given location. The
area of drawing is UNIT_TILE_HEIGHT x UNIT_TILE_WIDTH.
**************************************************************************/
void put_unit(const struct unit *punit,
struct canvas *pcanvas, int canvas_x, int canvas_y)
{
- struct drawn_sprite drawn_sprites[40];
-
canvas_y += (UNIT_TILE_HEIGHT - NORMAL_TILE_HEIGHT);
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);
+ put_one_element(pcanvas, layer, NULL, NULL, NULL,
+ punit, NULL, canvas_x, canvas_y, FALSE);
} mapview_layer_iterate_end;
}
@@ -898,15 +914,11 @@
void put_city(struct city *pcity,
struct canvas *pcanvas, int canvas_x, int canvas_y)
{
- struct drawn_sprite drawn_sprites[40];
-
canvas_y += (UNIT_TILE_HEIGHT - NORMAL_TILE_HEIGHT);
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);
+ put_one_element(pcanvas, layer,
+ NULL, NULL, NULL, NULL, pcity,
+ canvas_x, canvas_y, FALSE);
} mapview_layer_iterate_end;
}
@@ -918,16 +930,11 @@
void put_terrain(struct tile *ptile,
struct canvas *pcanvas, int canvas_x, int canvas_y)
{
- struct drawn_sprite drawn_sprites[40];
-
/* Use full tile height, even for terrains. */
canvas_y += (UNIT_TILE_HEIGHT - NORMAL_TILE_HEIGHT);
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);
+ put_one_element(pcanvas, layer, ptile, NULL, NULL, NULL, NULL,
+ canvas_x, canvas_y, FALSE);
} mapview_layer_iterate_end;
}
@@ -1439,15 +1446,11 @@
struct tile *ptile,
int canvas_x, int canvas_y, bool citymode)
{
- struct drawn_sprite tile_sprs[80];
- int count = fill_sprite_array(tile_sprs, layer, ptile,
- get_drawable_unit(ptile, citymode),
- ptile->city, citymode);
- bool fog = (tile_get_known(ptile) == TILE_KNOWN_FOGGED && draw_fog_of_war
- && fogstyle == FOG_AUTO);
-
- /*** Draw terrain and specials ***/
- put_drawn_sprites(pcanvas, canvas_x, canvas_y, count, tile_sprs, fog);
+ if (tile_get_known(ptile) != TILE_UNKNOWN) {
+ put_one_element(pcanvas, layer, ptile, NULL, NULL,
+ get_drawable_unit(ptile, citymode),
+ ptile->city, canvas_x, canvas_y, citymode);
+ }
}
/**************************************************************************
@@ -1509,12 +1512,17 @@
mapview_layer_iterate(layer) {
gui_rect_iterate(gui_x0, gui_y0, width,
height + (is_isometric ? (NORMAL_TILE_HEIGHT / 2) : 0),
- ptile) {
- int cx, cy;
-
- if (tile_get_known(ptile) != TILE_UNKNOWN
- && tile_to_canvas_pos(&cx, &cy, ptile)) {
+ ptile, pedge, pcorner, cx, cy) {
+ if (ptile) {
put_one_tile(mapview_canvas.store, layer, ptile, cx, cy, FALSE);
+ } else if (pedge) {
+ put_one_element(mapview_canvas.store, layer, NULL, pedge, NULL,
+ NULL, NULL, cx, cy, FALSE);
+ } else if (pcorner) {
+ put_one_element(mapview_canvas.store, layer, NULL, NULL, pcorner,
+ NULL, NULL, cx, cy, FALSE);
+ } else {
+ /* This can happen, for instance for unreal tiles. */
}
} gui_rect_iterate_end;
} mapview_layer_iterate_end;
@@ -1527,7 +1535,10 @@
* from adjacent tiles (if they're close enough). */
gui_rect_iterate(gui_x0 - GOTO_WIDTH, gui_y0 - GOTO_WIDTH,
width + 2 * GOTO_WIDTH, height + 2 * GOTO_WIDTH,
- ptile) {
+ ptile, pedge, pcorner, cx, cy) {
+ if (!ptile) {
+ continue;
+ }
adjc_dir_iterate(ptile, adjc_tile, dir) {
if (is_drawn_line(ptile, dir)) {
draw_segment(ptile, dir);
@@ -1536,17 +1547,17 @@
} gui_rect_iterate_end;
/* Draw citymap overlays on top. */
- gui_rect_iterate(gui_x0, gui_y0, width, height, ptile) {
- if (tile_get_known(ptile) != TILE_UNKNOWN) {
+ gui_rect_iterate(gui_x0, gui_y0, width, height,
+ ptile, pedge, pcorner, canvas_x2, canvas_y2) {
+ if (ptile && tile_get_known(ptile) != TILE_UNKNOWN) {
struct unit *punit;
struct city *pcity;
- int city_x, city_y, canvas_x2, canvas_y2;
+ int city_x, city_y;
pcity = find_city_or_settler_near_tile(ptile, &punit);
if (pcity
&& city_colors[pcity->client.color] != COLOR_STD_LAST
- && map_to_city_map(&city_x, &city_y, pcity, ptile)
- && tile_to_canvas_pos(&canvas_x2, &canvas_y2, ptile)) {
+ && map_to_city_map(&city_x, &city_y, pcity, ptile)) {
enum city_tile_type worker = get_worker_city(pcity, city_x, city_y);
put_city_worker(mapview_canvas.store,
@@ -1557,8 +1568,7 @@
mapview_canvas.store, canvas_x2, canvas_y2);
}
} else if (punit
- && city_colors[punit->client.color] != COLOR_STD_LAST
- && tile_to_canvas_pos(&canvas_x2, &canvas_y2, ptile)) {
+ && city_colors[punit->client.color] != COLOR_STD_LAST) {
/* Draw citymap overlay for settlers. */
put_city_worker(mapview_canvas.store,
city_colors[punit->client.color], C_TILE_EMPTY,
@@ -1656,14 +1666,11 @@
gui_rect_iterate(mapview_canvas.gui_x0 + canvas_x - dx / 2,
mapview_canvas.gui_y0 + canvas_y - dy,
width + dx, height + dy - NORMAL_TILE_HEIGHT,
- ptile) {
- int canvas_x, canvas_y;
- struct city *pcity = ptile->city;
-
- if (pcity) {
+ ptile, pedge, pcorner, canvas_x, canvas_y) {
+ if (ptile && ptile->city) {
int width = 0, height = 0;
+ struct city *pcity = ptile->city;
- (void) tile_to_canvas_pos(&canvas_x, &canvas_y, ptile);
show_city_desc(mapview_canvas.store, canvas_x, canvas_y,
pcity, &width, &height);
Index: client/mapview_common.h
===================================================================
RCS file: /home/freeciv/CVS/freeciv/client/mapview_common.h,v
retrieving revision 1.86
diff -u -r1.86 mapview_common.h
--- client/mapview_common.h 4 Feb 2005 19:29:00 -0000 1.86
+++ client/mapview_common.h 4 Feb 2005 20:02:19 -0000
@@ -85,9 +85,10 @@
* iso-view iteration is at
* http://rt.freeciv.org/Ticket/Attachment/51374/37363/isogrid.png.
*/
-#define gui_rect_iterate(gui_x0, gui_y0, width, height, ptile) \
+#define gui_rect_iterate(GRI_gui_x0, GRI_gui_y0, width, height,
\
+ ptile, pedge, pcorner, canvas_x, canvas_y) \
{ \
- int _gui_x0 = (gui_x0), _gui_y0 = (gui_y0); \
+ int _gui_x0 = (GRI_gui_x0), _gui_y0 = (GRI_gui_y0); \
int _width = (width), _height = (height); \
\
if (_width < 0) { \
@@ -99,38 +100,105 @@
_height = -_height;
\
} \
if (_width > 0 && _height > 0) { \
- 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; \
- int count; \
- struct tile *ptile;
\
+ const int _ratio = (is_isometric ? 2 : 1); \
+ const int _W = NORMAL_TILE_WIDTH / (_ratio * 2); \
+ const int _H = NORMAL_TILE_HEIGHT / (_ratio * 2); \
+ const int GRI_x0 = DIVIDE(_gui_x0, _W) - 1;
\
+ const int GRI_y0 = DIVIDE(_gui_y0, _H) - 1;
\
+ const int GRI_x1 = DIVIDE(_gui_x0 + _width + _W - 1, _W) + _ratio; \
+ const int GRI_y1 = DIVIDE(_gui_y0 + _height + _H - 1, _H) + _ratio;
\
+ const int _count = (GRI_x1 - GRI_x0) * (GRI_y1 - GRI_y0); \
+ int GRI_itr, GRI_x_itr, GRI_y_itr, GRI_sum, GRI_diff; \
+ \
+ for (GRI_itr = 0; GRI_itr < _count; GRI_itr++) { \
+ struct tile *ptile = NULL; \
+ struct tile_edge *pedge = NULL; \
+ struct tile_corner *pcorner = NULL; \
+ struct tile_edge GRI_edge; \
+ struct tile_corner GRI_corner; \
+ int canvas_x, canvas_y; \
\
- if (is_isometric) {
\
- /* Tiles to the left/above overlap with us. */ \
- GRI_x0--;
\
- GRI_y0--;
\
- } \
- count = (GRI_x1 - GRI_x0) * (GRI_y1 - GRI_y0); \
- for (GRI_itr = 0; GRI_itr < count; GRI_itr++) { \
GRI_x_itr = GRI_x0 + (GRI_itr % (GRI_x1 - GRI_x0)); \
GRI_y_itr = GRI_y0 + (GRI_itr / (GRI_x1 - GRI_x0)); \
+ GRI_sum = GRI_x_itr + GRI_y_itr; \
+ GRI_diff = GRI_y_itr - GRI_x_itr;
\
if (is_isometric) { \
if ((GRI_x_itr + GRI_y_itr) % 2 != 0) { \
continue; \
} \
- _map_x = (GRI_x_itr + GRI_y_itr) / 2; \
- _map_y = (GRI_y_itr - GRI_x_itr) / 2; \
+ if (GRI_x_itr % 2 == 0 && GRI_y_itr % 2 == 0) { \
+ if ((GRI_x_itr + GRI_y_itr) % 4 == 0) { \
+ /* Tile */ \
+ ptile = map_pos_to_tile(GRI_sum / 4 - 1, GRI_diff / 4); \
+ } else { \
+ /* Corner */ \
+ pcorner = &GRI_corner; \
+ pcorner->tile[0] = map_pos_to_tile((GRI_sum - 6) / 4, \
+ (GRI_diff - 2) / 4); \
+ pcorner->tile[1] = map_pos_to_tile((GRI_sum - 2) / 4, \
+ (GRI_diff - 2) / 4); \
+ pcorner->tile[2] = map_pos_to_tile((GRI_sum - 2) / 4, \
+ (GRI_diff + 2) / 4); \
+ pcorner->tile[3] = map_pos_to_tile((GRI_sum - 6) / 4, \
+ (GRI_diff + 2) / 4); \
+ } \
+ } else { \
+ /* Edge. */ \
+ pedge = &GRI_edge; \
+ if (GRI_sum % 4 == 0) { \
+ pedge->type = EDGE_NS; \
+ pedge->tile[0] = map_pos_to_tile((GRI_sum - 4) / 4, /* N */ \
+ (GRI_diff - 2) / 4); \
+ pedge->tile[1] = map_pos_to_tile((GRI_sum - 4) / 4, /* S */ \
+ (GRI_diff + 2) / 4); \
+ } else { \
+ pedge->type = EDGE_EW; \
+ pedge->tile[0] = map_pos_to_tile((GRI_sum - 6) / 4, \
+ GRI_diff / 4); /* E */ \
+ pedge->tile[1] = map_pos_to_tile((GRI_sum - 2) / 4, \
+ GRI_diff / 4); /* W */ \
+ } \
+ } \
} else { \
- _map_x = GRI_x_itr; \
- _map_y = GRI_y_itr; \
+ if (GRI_sum % 2 == 0) { \
+ if (GRI_x_itr % 2 == 0) { \
+ /* Corner. */ \
+ pcorner = &GRI_corner; \
+ pcorner->tile[0] = map_pos_to_tile(GRI_x_itr / 2 - 1, \
+ GRI_y_itr / 2 - 1); /* NW */ \
+ pcorner->tile[1] = map_pos_to_tile(GRI_x_itr / 2, \
+ GRI_y_itr / 2 - 1); /* NE */ \
+ pcorner->tile[2] = map_pos_to_tile(GRI_x_itr / 2, \
+ GRI_y_itr / 2); /* SE */ \
+ pcorner->tile[3] = map_pos_to_tile(GRI_x_itr / 2 - 1, \
+ GRI_y_itr / 2); /* SW */ \
+ } else { \
+ /* Tile. */ \
+ ptile = map_pos_to_tile((GRI_x_itr - 1) / 2, \
+ (GRI_y_itr - 1) / 2); \
+ } \
+ } else { \
+ /* Edge. */ \
+ pedge = &GRI_edge; \
+ if (GRI_y_itr % 2 == 0) { \
+ pedge->type = EDGE_EW; \
+ pedge->tile[0] = map_pos_to_tile(GRI_x_itr / 2 - 1, \
+ (GRI_y_itr - 1) / 2); \
+ pedge->tile[1] = map_pos_to_tile(GRI_x_itr / 2, \
+ (GRI_y_itr - 1) / 2); \
+ } else { \
+ pedge->type = EDGE_NS; \
+ pedge->tile[0] = map_pos_to_tile((GRI_x_itr - 1) / 2, \
+ GRI_y_itr / 2 - 1); \
+ pedge->tile[1] = map_pos_to_tile((GRI_x_itr - 1) / 2, \
+ GRI_y_itr / 2); \
+ } \
+ } \
}
\
- ptile = map_pos_to_tile(_map_x, _map_y); \
- if (!ptile) { \
- continue; \
- }
+ canvas_x \
+ = GRI_x_itr * _W - NORMAL_TILE_WIDTH / 2 - mapview_canvas.gui_x0; \
+ canvas_y \
+ = GRI_y_itr * _H - NORMAL_TILE_HEIGHT / 2 - mapview_canvas.gui_y0;
#define gui_rect_iterate_end \
} \
Index: client/tilespec.c
===================================================================
RCS file: /home/freeciv/CVS/freeciv/client/tilespec.c,v
retrieving revision 1.229
diff -u -r1.229 tilespec.c
--- client/tilespec.c 4 Feb 2005 19:29:00 -0000 1.229
+++ client/tilespec.c 4 Feb 2005 20:02:19 -0000
@@ -2676,6 +2676,8 @@
****************************************************************************/
int fill_sprite_array(struct drawn_sprite *sprs, enum mapview_layer layer,
const struct tile *ptile,
+ const struct tile_edge *pedge,
+ const struct tile_corner *pcorner,
const struct unit *punit, const struct city *pcity,
bool citymode)
{
Index: client/tilespec.h
===================================================================
RCS file: /home/freeciv/CVS/freeciv/client/tilespec.h,v
retrieving revision 1.99
diff -u -r1.99 tilespec.h
--- client/tilespec.h 4 Feb 2005 19:29:00 -0000 1.99
+++ client/tilespec.h 4 Feb 2005 20:02:19 -0000
@@ -26,6 +26,21 @@
struct Sprite; /* opaque; gui-dep */
+/* An edge is the border between two tiles. This structure represents one
+ * edge. The tiles are in unspecified order for the moment. */
+struct tile_edge {
+ enum {
+ EDGE_NS, EDGE_EW
+ } type;
+ struct tile *tile[2];
+};
+
+/* A corner is the endpoint of several edges. At each corner 4 tiles will
+ * meet (3 in hex view). Tiles are in clockwise order NESW. */
+struct tile_corner {
+ struct tile *tile[4];
+};
+
struct drawn_sprite {
enum {
DRAWN_SPRITE, /* Draw a sprite. */
@@ -115,6 +130,8 @@
int fill_sprite_array(struct drawn_sprite *sprs, enum mapview_layer layer,
const struct tile *ptile,
+ const struct tile_edge *pedge,
+ const struct tile_corner *pcorner,
const struct unit *punit, const struct city *pcity,
bool citymode);
|
|