Index: client/civclient.c =================================================================== RCS file: /home/freeciv/CVS/freeciv/client/civclient.c,v retrieving revision 1.102 diff -u -r1.102 civclient.c --- client/civclient.c 2001/09/16 18:49:44 1.102 +++ client/civclient.c 2001/10/25 16:01:12 @@ -522,6 +526,7 @@ role_unit_precalcs(); boot_help_texts(); /* reboot */ update_unit_focus(); + update_whole_tile_sprite_cache(); } else if(client_state==CLIENT_PRE_GAME_STATE) { popdown_all_city_dialogs(); Index: client/control.c =================================================================== RCS file: /home/freeciv/CVS/freeciv/client/control.c,v retrieving revision 1.62 diff -u -r1.62 control.c --- client/control.c 2001/10/18 15:12:46 1.62 +++ client/control.c 2001/10/25 16:01:13 @@ -885,6 +885,7 @@ return; draw_terrain ^= 1; + update_whole_tile_sprite_cache(); update_map_canvas_visible(); } @@ -909,6 +910,7 @@ return; draw_roads_rails ^= 1; + update_whole_tile_sprite_cache(); update_map_canvas_visible(); } @@ -921,6 +923,7 @@ return; draw_irrigation ^= 1; + update_whole_tile_sprite_cache(); update_map_canvas_visible(); } @@ -933,6 +936,7 @@ return; draw_mines ^= 1; + update_whole_tile_sprite_cache(); update_map_canvas_visible(); } @@ -945,6 +949,7 @@ return; draw_fortress_airbase ^= 1; + update_whole_tile_sprite_cache(); update_map_canvas_visible(); } @@ -957,6 +962,7 @@ return; draw_specials ^= 1; + update_whole_tile_sprite_cache(); update_map_canvas_visible(); } @@ -969,6 +975,7 @@ return; draw_pollution ^= 1; + update_whole_tile_sprite_cache(); update_map_canvas_visible(); } @@ -1017,6 +1024,7 @@ return; draw_fog_of_war ^= 1; + update_whole_tile_sprite_cache(); update_map_canvas_visible(); } Index: client/packhand.c =================================================================== RCS file: /home/freeciv/CVS/freeciv/client/packhand.c,v retrieving revision 1.196 diff -u -r1.196 packhand.c --- client/packhand.c 2001/10/18 16:45:31 1.196 +++ client/packhand.c 2001/10/25 16:01:15 @@ -1003,6 +1003,7 @@ map_allocate(); climap_init_continents(); init_client_goto(); + init_tile_sprite_cache(); set_overview_dimensions(map.xsize, map.ysize); } @@ -1484,6 +1485,10 @@ /* refresh tiles */ if(get_client_state()==CLIENT_GAME_RUNNING_STATE) { int x = packet->x, y = packet->y; + + if (tile_changed || ptile->known != old_known) { + update_tile_sprite_cache_at_map_position(x, y); + } /* the tile itself */ if (tile_changed || old_known!=ptile->known) Index: client/tilespec.c =================================================================== RCS file: /home/freeciv/CVS/freeciv/client/tilespec.c,v retrieving revision 1.55 diff -u -r1.55 tilespec.c --- client/tilespec.c 2001/10/19 08:12:51 1.55 +++ client/tilespec.c 2001/10/25 16:01:16 @@ -111,6 +111,137 @@ */ static int no_backdrop = 0; +static int base_fill_tile_sprite_array(struct Sprite **sprs, int abs_x0, + int abs_y0); +static int get_darkness_sprite_index(int map_x,int map_y); + +#define TILE_SPRITE_CACHE_SIZE 1000 +/* Can currently be 21 */ +#define TILE_SPRITE_CACHE_MAX_COMPONENTS 25 +#define USE_TILE_SPRITE_CACHE 1 + +static struct { + int entries_used; + struct { + int refcount, components_used; + struct Sprite *result; + struct Sprite *components[TILE_SPRITE_CACHE_MAX_COMPONENTS]; + } entries[TILE_SPRITE_CACHE_SIZE]; +} tile_sprite_cache; + +void init_tile_sprite_cache(void) +{ + int i; + + tile_sprite_cache.entries_used = 0; + for (i = 0; i < TILE_SPRITE_CACHE_SIZE; i++) { + tile_sprite_cache.entries[i].refcount = 0; + } +} + +#if USE_TILE_SPRITE_CACHE +static struct Sprite *merge_sprite_array(struct Sprite **sprites, int count) +{ + int i; + struct Sprite *result = NULL; + + assert(count > 0); + result = clone_sprite(sprites[0]); + for (i = 1; i < count; i++) { + merge_sprites(result, sprites[i]); + } + + return result; +} + + +static void tile_sprite_cache_update(int x, int y) +{ + struct tile *ptile = map_get_tile(x, y); + int index = ptile->client.tile_sprite_cache_index; + struct Sprite *sprites[80]; + int i, sprites_used, found, unused_entry; + + ptile->client.darkness_sprite_index = get_darkness_sprite_index(x, y); + + if (index != -1) { + assert(tile_sprite_cache.entries[index].refcount>0); + tile_sprite_cache.entries[index].refcount--; + if (tile_sprite_cache.entries[index].refcount == 0) { + tile_sprite_cache.entries_used--; + free_sprite(tile_sprite_cache.entries[index].result); + } + } + + sprites_used = base_fill_tile_sprite_array(sprites, x, y); + + found = 0; + unused_entry = -1; + for (i = 0; i < TILE_SPRITE_CACHE_SIZE; i++) { + if (tile_sprite_cache.entries[i].refcount == 0 && unused_entry == -1) { + unused_entry = i; + } + if (tile_sprite_cache.entries[i].refcount > 0 + && tile_sprite_cache.entries[i].components_used == sprites_used && + memcmp(sprites, tile_sprite_cache.entries[i].components, + sizeof(struct Sprite *) * sprites_used) == 0) { + found = 1; + break; + } + } + + if (found) { + index = i; + freelog(LOG_DEBUG, + "hit for (%d,%d) entry: index=%d refcount=%d sprites=%d", x, y, + index, tile_sprite_cache.entries[index].refcount, + sprites_used); + } else { + tile_sprite_cache.entries_used++; + assert(unused_entry != -1); + index = unused_entry; + tile_sprite_cache.entries[index].refcount = 0; + tile_sprite_cache.entries[index].components_used = sprites_used; + memcpy(tile_sprite_cache.entries[index].components, sprites, + sizeof(struct Sprite *) * sprites_used); + if (sprites_used > 0) { + tile_sprite_cache.entries[index].result = + merge_sprite_array(tile_sprite_cache.entries[index].components, + sprites_used); + } + freelog(LOG_DEBUG, + "miss for (%d,%d) entry: index=%d refcount=%d sprites=%d", x, y, + index, tile_sprite_cache.entries[index].refcount, + sprites_used); + } + + tile_sprite_cache.entries[index].refcount++; + ptile->client.tile_sprite_cache_index = index; +} +#endif + +void update_tile_sprite_cache_at_map_position(int x, int y) +{ +#if USE_TILE_SPRITE_CACHE + tile_sprite_cache_update(x, y); + adjc_iterate(x, y, x1, y1) { + tile_sprite_cache_update(x1, y1); + } adjc_iterate_end; +#endif +} + +void update_whole_tile_sprite_cache(void) +{ +#if USE_TILE_SPRITE_CACHE + freelog(LOG_NORMAL,"Filling tile sprite cache..."); + whole_map_iterate(x, y) { + tile_sprite_cache_update(x,y); + } whole_map_iterate_end; + freelog(LOG_NORMAL, "...done. Cache contains %d entries", + tile_sprite_cache.entries_used); +#endif +} + /********************************************************************** Gets full filename for tilespec file, based on input name. Returned data is allocated, and freed by user as required. @@ -1305,6 +1436,24 @@ return sprs - save_sprs; } +static int get_darkness_sprite_index(int map_x,int map_y) +{ + /* + * We're looking to find the INDEX_NSEW for the directions that + * are unknown + */ + int known[4]; + memset(known, 0, sizeof(known)); + adjc_dir_iterate(map_x, map_y, x, y, dir8) { + if (!DIR_IS_CARDINAL(dir8)) + continue; + known[dir8_to_dir4(dir8)] = (tile_is_known(x, y) != TILE_UNKNOWN); + } adjc_dir_iterate_end; + + return INDEX_NSEW(!known[DIR4_NORTH], !known[DIR4_SOUTH], + !known[DIR4_EAST], !known[DIR4_WEST]); +} + /********************************************************************** Fill in the sprite array for the tile at position (abs_x0,abs_y0) @@ -1322,8 +1471,8 @@ 11) fallout 12) FoW ***********************************************************************/ -int fill_tile_sprite_array(struct Sprite **sprs, int abs_x0, int abs_y0, - int citymode, int *solid_bg, struct player **pplayer) +static int base_fill_tile_sprite_array(struct Sprite **sprs, int abs_x0, + int abs_y0) { int ttype, ttype_near[8]; int tspecial, tspecial_near[8]; @@ -1334,14 +1483,9 @@ int tileno; struct tile *ptile; struct Sprite *mysprite; - struct city *pcity; - struct unit *pfocus; - struct unit *punit; int den_y=map.ysize*.24; struct Sprite **save_sprs=sprs; - *solid_bg = 0; - *pplayer = NULL; assert(is_normal_map_pos(abs_x0, abs_y0)); ptile=map_get_tile(abs_x0, abs_y0); @@ -1350,28 +1494,6 @@ return 0; } - pcity=map_get_city(abs_x0, abs_y0); - pfocus=get_unit_in_focus(); - - if(!flags_are_transparent || solid_color_behind_units) { - /* non-transparent flags -> just draw city or unit */ - - punit = get_drawable_unit(abs_x0, abs_y0, citymode); - if (punit && (draw_units || (draw_focus_unit && pfocus == punit))) { - sprs += fill_unit_sprite_array(sprs, punit, solid_bg); - *pplayer = unit_owner(punit); - if (unit_list_size(&ptile->units) > 1) - *sprs++ = sprites.unit.stack; - return sprs - save_sprs; - } - - if (pcity && draw_cities) { - sprs+=fill_city_sprite_array(sprs, pcity, solid_bg); - *pplayer = city_owner(pcity); - return sprs - save_sprs; - } - } - ttype=map_get_terrain(abs_x0, abs_y0); for (dir = 0; dir < 8; dir++) { int x, y; @@ -1408,7 +1530,6 @@ } if (draw_terrain) *sprs++=mysprite; - else *solid_bg = 1; if(ttype==T_OCEAN && draw_terrain) { int dir8; @@ -1565,25 +1686,71 @@ if(tspecial & S_FALLOUT && draw_pollution) *sprs++ = sprites.tx.fallout; if(ptile->known==TILE_KNOWN_FOGGED && draw_fog_of_war) *sprs++ = sprites.tx.fog; - if(!citymode) { - /* - * We're looking to find the INDEX_NSEW for the directions that - * are unknown - */ - int known[4]; - memset(known, 0, sizeof(known)); - adjc_dir_iterate(abs_x0, abs_y0, x, y, dir8) { - if (!DIR_IS_CARDINAL(dir8)) - continue; - known[dir8_to_dir4(dir8)] = (tile_is_known(x, y) != TILE_UNKNOWN); - } adjc_dir_iterate_end; + return sprs - save_sprs; +} - tileno = - INDEX_NSEW(!known[DIR4_NORTH], !known[DIR4_SOUTH], - !known[DIR4_EAST], !known[DIR4_WEST]); +int fill_tile_sprite_array(struct Sprite **sprs, int abs_x0, int abs_y0, + int citymode, int *solid_bg, struct player **pplayer) +{ + int tileno; + struct tile *ptile; + struct city *pcity; + struct unit *pfocus; + struct unit *punit; + + struct Sprite **save_sprs=sprs; + *solid_bg = 0; + *pplayer = NULL; + + assert(is_normal_map_pos(abs_x0, abs_y0)); + ptile=map_get_tile(abs_x0, abs_y0); + + if (ptile->known == TILE_UNKNOWN) { + return 0; + } + + pcity=map_get_city(abs_x0, abs_y0); + pfocus=get_unit_in_focus(); + + if(!flags_are_transparent || solid_color_behind_units) { + /* non-transparent flags -> just draw city or unit */ + + punit = get_drawable_unit(abs_x0, abs_y0, citymode); + if (punit && (draw_units || (draw_focus_unit && pfocus == punit))) { + sprs += fill_unit_sprite_array(sprs, punit, solid_bg); + *pplayer = unit_owner(punit); + if (unit_list_size(&ptile->units) > 1) + *sprs++ = sprites.unit.stack; + return sprs - save_sprs; + } + + if (pcity && draw_cities) { + sprs+=fill_city_sprite_array(sprs, pcity, solid_bg); + *pplayer = city_owner(pcity); + return sprs - save_sprs; + } + } + + *solid_bg = !draw_terrain; + +#if USE_TILE_SPRITE_CACHE + assert(ptile->client.tile_sprite_cache_index != -1); + if (tile_sprite_cache.entries[ptile->client.tile_sprite_cache_index]. + components_used > 0) { + *sprs++ = + tile_sprite_cache.entries[ptile->client. + tile_sprite_cache_index].result; + } + tileno = ptile->client.darkness_sprite_index; +#else + sprs += base_fill_tile_sprite_array(sprs, abs_x0, abs_y0); + if (!citymode) { + tileno = get_darkness_sprite_index(abs_x0, abs_y0); + } +#endif - if (tileno) - *sprs++ = sprites.tx.darkness[tileno]; + if (!citymode && tileno) { + *sprs++ = sprites.tx.darkness[tileno]; } if (flags_are_transparent) { Index: client/tilespec.h =================================================================== RCS file: /home/freeciv/CVS/freeciv/client/tilespec.h,v retrieving revision 1.23 diff -u -r1.23 tilespec.h --- client/tilespec.h 2001/10/19 08:12:52 1.23 +++ client/tilespec.h 2001/10/25 16:01:16 @@ -54,6 +54,9 @@ void set_focus_unit_hidden_state(int hide); struct unit *get_drawable_unit(int x, int y, int citymode); +void init_tile_sprite_cache(void); +void update_tile_sprite_cache_at_map_position(int x,int y); +void update_whole_tile_sprite_cache(void); /* This the way directional indices are now encoded: */ Index: client/gui-gtk/graphics.c =================================================================== RCS file: /home/freeciv/CVS/freeciv/client/gui-gtk/graphics.c,v retrieving revision 1.32 diff -u -r1.32 graphics.c --- client/gui-gtk/graphics.c 2001/09/09 09:03:18 1.32 +++ client/gui-gtk/graphics.c 2001/10/25 16:01:16 @@ -18,6 +18,7 @@ #include #include #include +#include #include @@ -606,4 +607,35 @@ } gdk_image_destroy(mask_image); +} + +void merge_sprites(SPRITE * sprite, const SPRITE * const other) +{ + GdkColor pixel; + GdkGC *mask_fg_gc = gdk_gc_new(sprite->mask); + + pixel.pixel = 1; + gdk_gc_set_foreground(mask_fg_gc, &pixel); + + assert(sprite); + assert(other); + + gdk_gc_set_clip_origin(civ_gc, 0, 0); + gdk_gc_set_clip_origin(mask_fg_gc, 0, 0); + gdk_gc_set_clip_mask(civ_gc, other->mask); + gdk_gc_set_clip_mask(mask_fg_gc, other->mask); + + gdk_draw_pixmap(sprite->pixmap, civ_gc, other->pixmap, + 0, 0, 0, 0, other->width, other->height); + + gdk_draw_pixmap(sprite->mask, mask_fg_gc, other->mask, + 0, 0, 0, 0, other->width, other->height); + gdk_gc_set_clip_mask(civ_gc, NULL); + gdk_gc_set_clip_mask(mask_fg_gc, NULL); + gdk_gc_destroy(mask_fg_gc); +} + +struct Sprite *clone_sprite(struct Sprite *source) +{ + return crop_sprite(source, 0, 0, source->width, source->height); } Index: client/gui-gtk/mapview.c =================================================================== RCS file: /home/freeciv/CVS/freeciv/client/gui-gtk/mapview.c,v retrieving revision 1.105 diff -u -r1.105 mapview.c --- client/gui-gtk/mapview.c 2001/10/16 09:11:15 1.105 +++ client/gui-gtk/mapview.c 2001/10/25 16:01:18 @@ -834,6 +834,10 @@ **************************************************************************/ void center_tile_mapcanvas(int x, int y) { + if (get_client_state() != CLIENT_GAME_RUNNING_STATE) { + return; + } + if (is_isometric) { x -= map_canvas_store_twidth/2; y += map_canvas_store_twidth/2; @@ -1292,6 +1296,10 @@ freelog(LOG_DEBUG, "update_map_canvas(pos=(%d,%d), size=(%d,%d), write_to_screen=%d)", x, y, width, height, write_to_screen); + + if (get_client_state() != CLIENT_GAME_RUNNING_STATE) { + return; + } if (is_isometric) { int i; Index: client/include/graphics_g.h =================================================================== RCS file: /home/freeciv/CVS/freeciv/client/include/graphics_g.h,v retrieving revision 1.6 diff -u -r1.6 graphics_g.h --- client/include/graphics_g.h 2001/02/04 13:45:21 1.6 +++ client/include/graphics_g.h 2001/10/25 16:01:18 @@ -28,6 +28,11 @@ struct Sprite *load_gfxfile(const char *filename); struct Sprite *crop_sprite(struct Sprite *source, int x, int y, int width, int height); + +struct Sprite *clone_sprite(struct Sprite *s); void free_sprite(struct Sprite *s); + +void merge_sprites(struct Sprite *this_sprite, + const struct Sprite *const other); #endif /* FC__GRAPHICS_G_H */ Index: common/map.c =================================================================== RCS file: /home/freeciv/CVS/freeciv/common/map.c,v retrieving revision 1.97 diff -u -r1.97 map.c --- common/map.c 2001/10/15 13:42:50 1.97 +++ common/map.c 2001/10/25 16:01:20 @@ -1149,6 +1149,7 @@ unit_list_init(&ptile->units); ptile->worked = NULL; /* pointer to city working tile */ ptile->assigned = 0; /* bitvector */ + ptile->client.tile_sprite_cache_index = -1; } /*************************************************************** Index: common/map.h =================================================================== RCS file: /home/freeciv/CVS/freeciv/common/map.h,v retrieving revision 1.100 diff -u -r1.100 map.h --- common/map.h 2001/10/19 08:12:52 1.100 +++ common/map.h 2001/10/25 16:01:20 @@ -59,6 +59,9 @@ struct city *worked; /* city working tile, or NULL if none */ signed short continent; signed char move_cost[8]; /* don't know if this helps! */ + struct { + int tile_sprite_cache_index, darkness_sprite_index; + } client; };