Complete.Org: Mailing Lists: Archives: freeciv-dev: February 2003:
[Freeciv-Dev] (PR#3457) New sprite loading
Home

[Freeciv-Dev] (PR#3457) New sprite loading

[Top] [All Lists]

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index] [Thread Index]
To: undisclosed-recipients:;
Subject: [Freeciv-Dev] (PR#3457) New sprite loading
From: "Raimar Falke" <rf13@xxxxxxxxxxxxxxxxx>
Date: Mon, 17 Feb 2003 11:58:54 -0800
Reply-to: rt@xxxxxxxxxxxxxx


I wrote a nice explanation of the patch but than I hit 'q' in the mail
reader. ARGL. So here is the very short version:

Problems:
 - special case for not permanently loaded/used graphics needed
 - gui-sdl need sprites which other guis doesn't want to load

Solution has three functions load_sprite, unload_sprite and
finish_loading. See code for usage.

        Raimar

-- 
 email: rf13@xxxxxxxxxxxxxxxxx
  Two OS engineers facing a petri net chart:
        "dead lock in four moves!"

diff -Nurd -X clean/diff_ignore clean/client/gui-gtk-2.0/graphics.c 
tileset/client/gui-gtk-2.0/graphics.c
--- clean/client/gui-gtk-2.0/graphics.c Mon Feb 17 19:32:12 2003
+++ tileset/client/gui-gtk-2.0/graphics.c       Mon Feb 17 20:49:44 2003
@@ -114,8 +114,8 @@
   face_gc = gdk_gc_new(root_window);
 
   /* Main graphic */
-  intro_gfx_sprite = load_gfxfile(main_intro_filename);
-  tot=intro_gfx_sprite->width;
+  intro_gfx_sprite = load_sprite("special.intro");
+  tot = intro_gfx_sprite->width;
 
   pango_layout_set_text(layout, freeciv_motto(), -1);
   pango_layout_get_pixel_extents(layout, &rect, NULL);
@@ -128,9 +128,11 @@
   gdk_gc_destroy (face_gc);
 
   /* Minimap graphic */
-  radar_gfx_sprite = load_gfxfile(minimap_intro_filename);
+  radar_gfx_sprite = load_sprite("special.radar");
   tot=radar_gfx_sprite->width;
 
+  finish_loading();
+
   my_snprintf(s, sizeof(s), "%d.%d.%d%s",
              MAJOR_VERSION, MINOR_VERSION,
              PATCH_VERSION, VERSION_LABEL);
@@ -329,12 +331,16 @@
 /***************************************************************************
    Deletes a sprite.  These things can use a lot of memory.
 ***************************************************************************/
-void free_sprite(SPRITE *s)
+void free_sprite(SPRITE * s)
 {
-  if (s->pixmap)
+  if (s->pixmap) {
     g_object_unref(s->pixmap);
-  if (s->mask)
+    s->pixmap = NULL;
+  }
+  if (s->mask) {
     g_object_unref(s->mask);
+    s->mask = NULL;
+  }
   free(s);
   return;
 }
@@ -379,14 +385,11 @@
 ***************************************************************************/
 void free_intro_radar_sprites(void)
 {
-  if (intro_gfx_sprite) {
-    free_sprite(intro_gfx_sprite);
-    intro_gfx_sprite=NULL;
-  }
-  if (radar_gfx_sprite) {
-    free_sprite(radar_gfx_sprite);
-    radar_gfx_sprite=NULL;
-  }
+  unload_sprite("special.intro");
+  intro_gfx_sprite = NULL;
+
+  unload_sprite("special.radar");
+  radar_gfx_sprite = NULL;
 }
 
 /***************************************************************************
diff -Nurd -X clean/diff_ignore clean/client/tilespec.c 
tileset/client/tilespec.c
--- clean/client/tilespec.c     Mon Feb 17 19:32:12 2003
+++ tileset/client/tilespec.c   Mon Feb 17 20:36:21 2003
@@ -53,9 +53,6 @@
 
 #define TILESPEC_SUFFIX ".tilespec"
 
-char *main_intro_filename;
-char *minimap_intro_filename;
-
 struct named_sprites sprites;
 char current_tile_set_name[512];
 
@@ -79,15 +76,52 @@
 static bool is_mountainous = FALSE;
 static int roadstyle;
 
-static int num_spec_files = 0;
-static char **spec_filenames;  /* full pathnames */
+struct specfile;
+
+#define SPECLIST_TAG specfile
+#define SPECLIST_TYPE struct specfile
+#include "speclist.h"
+
+#define SPECLIST_TAG specfile
+#define SPECLIST_TYPE struct specfile
+#include "speclist_c.h"
+
+#define specfile_list_iterate(list, pitem) \
+    TYPED_LIST_ITERATE(struct specfile, list, pitem)
+#define specfile_list_iterate_end  LIST_ITERATE_END
+
+struct small_sprite;
+#define SPECLIST_TAG small_sprite
+#define SPECLIST_TYPE struct small_sprite
+#include "speclist.h"
+
+#define SPECLIST_TAG small_sprite
+#define SPECLIST_TYPE struct small_sprite
+#include "speclist_c.h"
+
+#define small_sprite_list_iterate(list, pitem) \
+    TYPED_LIST_ITERATE(struct small_sprite, list, pitem)
+#define small_sprite_list_iterate_end  LIST_ITERATE_END
+
+static struct specfile_list specfiles;
+
+struct specfile {
+  struct Sprite *big_sprite;
+  char *file_name;
+  struct small_sprite_list small_sprites;
+};
+
+struct small_sprite {
+  int ref_count;
+  int x, y, width, height;
+  struct specfile *sf;
+  struct Sprite *sprite;
+};
 
-static struct hash_table *sprite_hash = NULL;
 /*
-   This hash table sprite_hash maps tilespec tags to tile Sprite pointers.
-   This is kept permanently after setup, for doing lookups on ruleset
-   information (including on reconnections etc).
-*/
+ * This hash table maps tilespec tags to struct small_sprites.
+ */
+static struct hash_table *sprite_hash = NULL;
 
 #define TILESPEC_CAPSTR "+tilespec2 duplicates_ok roadstyle"
 /*
@@ -212,35 +246,6 @@
 }
 
 /**********************************************************************
-  Returns the correct name of the gfx file (with path and extension)
-  Must be free'd when no longer used
-***********************************************************************/
-static char *tilespec_gfx_filename(const char *gfx_filename)
-{
-  const char  *gfx_current_fileext;
-  const char **gfx_fileexts = gfx_fileextensions();
-
-  while((gfx_current_fileext = *gfx_fileexts++))
-  {
-    char *full_name =
-       fc_malloc(strlen(gfx_filename) + strlen(gfx_current_fileext) + 2);
-    char *real_full_name;
-
-    sprintf(full_name,"%s.%s",gfx_filename,gfx_current_fileext);
-
-    real_full_name = datafilename(full_name);
-    free(full_name);
-    if (real_full_name) {
-      return mystrdup(real_full_name);
-    }
-  }
-
-  freelog(LOG_FATAL, _("Couldn't find a supported gfx file extension for %s"),
-         gfx_filename);
-  exit(EXIT_FAILURE);
-}
-
-/**********************************************************************
   Frees the tilespec toplevel data, in preparation for re-reading it.
 
   See tilespec_read_toplevel().
@@ -255,14 +260,6 @@
     free(city_productions_font_name);
     city_productions_font_name = NULL;
   }
-  if (main_intro_filename) {
-    free(main_intro_filename);
-    main_intro_filename = NULL;
-  }
-  if (minimap_intro_filename) {
-    free(minimap_intro_filename);
-    minimap_intro_filename = NULL;
-  }
   /* FIXME: free spec_filenames */
 }
 
@@ -374,6 +371,130 @@
 }
 
 /**********************************************************************
+  Ensure that the big sprite of the given spec file is loaded.
+***********************************************************************/
+static void ensure_big_sprite(struct specfile *sf)
+{
+  struct section_file the_file, *file = &the_file;
+  const char *gfx_filename, *gfx_current_fileext, **gfx_fileexts;
+
+  if (sf->big_sprite) {
+    return;
+  }
+
+  if (!section_file_load(file, sf->file_name)) {
+    freelog(LOG_FATAL, _("Could not open \"%s\"."), sf->file_name);
+    exit(EXIT_FAILURE);
+  }
+  check_tilespec_capabilities(file, "spec", SPEC_CAPSTR, sf->file_name);
+
+  gfx_fileexts = gfx_fileextensions();
+  gfx_filename = secfile_lookup_str(file, "file.gfx");
+
+  while (!sf->big_sprite && (gfx_current_fileext = *gfx_fileexts++)) {
+    char *real_full_name;
+    char *full_name =
+       fc_malloc(strlen(gfx_filename) + strlen(gfx_current_fileext) + 2);
+    sprintf(full_name, "%s.%s", gfx_filename, gfx_current_fileext);
+
+    if ((real_full_name = datafilename(full_name))) {
+      freelog(LOG_DEBUG, "trying to load gfx file %s", real_full_name);
+      sf->big_sprite = load_gfxfile(real_full_name);
+      if (!sf->big_sprite) {
+       freelog(LOG_VERBOSE, "loading the gfx file %s failed",
+               real_full_name);
+      }
+    }
+    free(full_name);
+  }
+
+  if (!sf->big_sprite) {
+    freelog(LOG_FATAL, _("Couldn't load gfx file for the spec file %s"),
+           sf->file_name);
+    exit(EXIT_FAILURE);
+  }
+  section_file_free(file);
+}
+
+/**********************************************************************
+***********************************************************************/
+static void scan_specfile(struct specfile *sf)
+{
+  struct section_file the_file, *file = &the_file;
+  char **gridnames;
+  int num_grids, i;
+
+  if (!section_file_load(file, sf->file_name)) {
+    freelog(LOG_FATAL, _("Could not open \"%s\"."), sf->file_name);
+    exit(EXIT_FAILURE);
+  }
+  check_tilespec_capabilities(file, "spec", SPEC_CAPSTR, sf->file_name);
+
+  (void) section_file_lookup(file, "info.artists"); /* currently unused */
+  (void)secfile_lookup_str(file, "file.gfx");
+
+  gridnames = secfile_get_secnames_prefix(file, "grid_", &num_grids);
+  if (num_grids == 0) {
+    freelog(LOG_FATAL, "spec %s has no grid_* sections", sf->file_name);
+    exit(EXIT_FAILURE);
+  }
+
+  for (i = 0; i < num_grids; i++) {
+    int j, k;
+    int x_top_left, y_top_left, dx, dy;
+    bool is_pixel_border =
+      secfile_lookup_bool_default(file, FALSE, "%s.is_pixel_border", 
gridnames[i]);
+    x_top_left = secfile_lookup_int(file, "%s.x_top_left", gridnames[i]);
+    y_top_left = secfile_lookup_int(file, "%s.y_top_left", gridnames[i]);
+    dx = secfile_lookup_int(file, "%s.dx", gridnames[i]);
+    dy = secfile_lookup_int(file, "%s.dy", gridnames[i]);
+
+    j = -1;
+    while (section_file_lookup(file, "%s.tiles%d.tag", gridnames[i], ++j)) {
+      struct small_sprite *ss = fc_malloc(sizeof(*ss));
+      int row, column;
+      int x1, y1;
+      char **tags;
+      int num_tags;
+
+      row = secfile_lookup_int(file, "%s.tiles%d.row", gridnames[i], j);
+      column = secfile_lookup_int(file, "%s.tiles%d.column", gridnames[i], j);
+      tags = secfile_lookup_str_vec(file, &num_tags, "%s.tiles%d.tag",
+                                   gridnames[i], j);
+
+      /* there must be at least 1 because of the while(): */
+      assert(num_tags > 0);
+
+      x1 = x_top_left + column * dx + (is_pixel_border ? column : 0);
+      y1 = y_top_left + row * dy + (is_pixel_border ? row : 0);
+
+      ss->ref_count = 0;
+      ss->x = x1;
+      ss->y = y1;
+      ss->width = dx;
+      ss->height = dy;
+      ss->sf = sf;
+      ss->sprite = NULL;
+
+      small_sprite_list_insert(&ss->sf->small_sprites, ss);
+
+      for (k = 0; k < num_tags; k++) {
+       if (!hash_insert(sprite_hash, mystrdup(tags[k]), ss)) {
+         die("already have a sprite for %s", tags[k]);
+       }
+      }
+      free(tags);
+      tags = NULL;
+    }
+  }
+  free(gridnames);
+  gridnames = NULL;
+
+  section_file_check_unused(file, sf->file_name);
+  section_file_free(file);
+}
+
+/**********************************************************************
   Finds and reads the toplevel tilespec file based on given name.
   Sets global variables, including tile sizes and full names for
   intro files.
@@ -383,6 +504,8 @@
   struct section_file the_file, *file = &the_file;
   char *fname, *c;
   int i;
+  int num_spec_files;
+  char **spec_filenames;
 
   fname = tilespec_fullname(tileset_name);
   freelog(LOG_VERBOSE, "tilespec file is %s", fname);
@@ -444,24 +567,26 @@
                                 "tilespec.city_productions_font");
   city_productions_font_name = mystrdup(c);
 
-  c = secfile_lookup_str(file, "tilespec.main_intro_file");
-  main_intro_filename = tilespec_gfx_filename(c);
-  freelog(LOG_DEBUG, "intro file %s", main_intro_filename);
-  
-  c = secfile_lookup_str(file, "tilespec.minimap_intro_file");
-  minimap_intro_filename = tilespec_gfx_filename(c);
-  freelog(LOG_DEBUG, "radar file %s", minimap_intro_filename);
-
   spec_filenames = secfile_lookup_str_vec(file, &num_spec_files,
                                          "tilespec.files");
   if (num_spec_files == 0) {
     freelog(LOG_FATAL, "No tile files specified in \"%s\"", fname);
     exit(EXIT_FAILURE);
   }
-  
-  for(i=0; i<num_spec_files; i++) {
-    spec_filenames[i] = mystrdup(datafilename_required(spec_filenames[i]));
+
+  sprite_hash = hash_new(hash_fval_string, hash_fcmp_string);
+  specfile_list_init(&specfiles);
+  for (i = 0; i < num_spec_files; i++) {
+    struct specfile *sf = fc_malloc(sizeof(*sf));
+
     freelog(LOG_DEBUG, "spec file %s", spec_filenames[i]);
+    
+    sf->big_sprite = NULL;
+    sf->file_name = mystrdup(datafilename_required(spec_filenames[i]));
+    small_sprite_list_init(&sf->small_sprites);
+    scan_specfile(sf);
+
+    specfile_list_insert(&specfiles, sf);
   }
 
   section_file_check_unused(file, fname);
@@ -472,105 +597,6 @@
 }
 
 /**********************************************************************
-  Load one specfile and specified xpm file; splits xpm into tiles,
-  and save sprites in sprite_hash.
-***********************************************************************/
-static void tilespec_load_one(const char *spec_filename)
-{
-  struct section_file the_file, *file = &the_file;
-  struct Sprite *big_sprite = NULL, *small_sprite;
-  const char *gfx_filename, *gfx_current_fileext, **gfx_fileexts;
-  char **gridnames, **tags;
-  int num_grids, num_tags;
-  int i, j, k;
-  int x_top_left, y_top_left, dx, dy;
-  int row, column;
-  int x1, y1;
-
-  freelog(LOG_DEBUG, "loading spec %s", spec_filename);
-  if (!section_file_load(file, spec_filename)) {
-    freelog(LOG_FATAL, _("Could not open \"%s\"."), spec_filename);
-    exit(EXIT_FAILURE);
-  }
-  check_tilespec_capabilities(file, "spec", SPEC_CAPSTR, spec_filename);
-
-  (void) section_file_lookup(file, "info.artists"); /* currently unused */
-
-  gfx_fileexts = gfx_fileextensions();
-  gfx_filename = secfile_lookup_str(file, "file.gfx");
-
-  while((!big_sprite) && (gfx_current_fileext = *gfx_fileexts++))
-  {
-    char *full_name,*real_full_name;
-    full_name = fc_malloc(strlen(gfx_filename)+strlen(gfx_current_fileext)+2);
-    sprintf(full_name,"%s.%s",gfx_filename,gfx_current_fileext);
-
-    if((real_full_name = datafilename(full_name)))
-    {
-      freelog(LOG_DEBUG, "trying to load gfx file %s", real_full_name);
-      if(!(big_sprite = load_gfxfile(real_full_name)))
-      {
-        freelog(LOG_VERBOSE, "loading the gfx file %s failed", real_full_name);
-      }
-    }
-    free(full_name);
-  }
-
-  if(!big_sprite) {
-    freelog(LOG_FATAL, _("Couldn't load gfx file for the spec file %s"),
-           spec_filename);
-    exit(EXIT_FAILURE);
-  }
-
-
-  gridnames = secfile_get_secnames_prefix(file, "grid_", &num_grids);
-  if (num_grids==0) {
-    freelog(LOG_FATAL, "spec %s has no grid_* sections", spec_filename);
-    exit(EXIT_FAILURE);
-  }
-
-  for(i=0; i<num_grids; i++) {
-    bool is_pixel_border =
-      secfile_lookup_bool_default(file, FALSE, "%s.is_pixel_border", 
gridnames[i]);
-    x_top_left = secfile_lookup_int(file, "%s.x_top_left", gridnames[i]);
-    y_top_left = secfile_lookup_int(file, "%s.y_top_left", gridnames[i]);
-    dx = secfile_lookup_int(file, "%s.dx", gridnames[i]);
-    dy = secfile_lookup_int(file, "%s.dy", gridnames[i]);
-
-    j = -1;
-    while(section_file_lookup(file, "%s.tiles%d.tag", gridnames[i], ++j)) {
-      row = secfile_lookup_int(file, "%s.tiles%d.row", gridnames[i], j);
-      column = secfile_lookup_int(file, "%s.tiles%d.column", gridnames[i], j);
-      tags = secfile_lookup_str_vec(file, &num_tags, "%s.tiles%d.tag",
-                                   gridnames[i], j);
-
-      /* there must be at least 1 because of the while(): */
-      assert(num_tags>0);
-
-      x1 = x_top_left + column * dx + (is_pixel_border ? column : 0);
-      y1 = y_top_left + row * dy + (is_pixel_border ? row : 0);
-      small_sprite = crop_sprite(big_sprite, x1, y1, dx, dy);
-
-      for(k=0; k<num_tags; k++) {
-       /* don't free old sprite, since could be multiple tags
-          pointing to it */
-       (void) hash_replace(sprite_hash, mystrdup(tags[k]), small_sprite);
-      }
-      free(tags);
-      tags = NULL;
-    }
-  }
-  free(gridnames);
-  gridnames = NULL;
-
-  free_sprite(big_sprite);
-  
-  section_file_check_unused(file, spec_filename);
-  section_file_free(file);
-  freelog(LOG_DEBUG, "finished %s", spec_filename);
-}
-
-/**********************************************************************
   Returns a text name for the citizen, as used in the tileset.
 ***********************************************************************/
 static const char *get_citizen_name(enum citizen_type citizen)
@@ -613,7 +639,7 @@
      
 /* Not very safe, but convenient: */
 #define SET_SPRITE(field, tag) do { \
-       sprites.field = hash_lookup_data(sprite_hash, tag);\
+       sprites.field = load_sprite(tag);\
        if (!sprites.field) {                              \
          die("Sprite tag %s missing.", buffer);           \
        }                                                  \
@@ -621,9 +647,9 @@
 
 /* Sets sprites.field to tag or (if tag isn't available) to alt */
 #define SET_SPRITE_ALT(field, tag, alt) do {                   \
-       sprites.field = hash_lookup_data(sprite_hash, tag);     \
+       sprites.field = load_sprite(tag);     \
        if (!sprites.field) {                                   \
-           sprites.field = hash_lookup_data(sprite_hash, alt); \
+           sprites.field = load_sprite(alt); \
        }                                                       \
        if (!sprites.field) {                                   \
          die("Sprite tag %s and alternate %s are both missing.", tag, alt); \
@@ -632,7 +658,7 @@
 
 /* Sets sprites.field to tag, or NULL if not available */
 #define SET_SPRITE_OPT(field, tag) \
-  sprites.field = hash_lookup_data(sprite_hash, tag)
+  sprites.field = load_sprite(tag)
 
 /**********************************************************************
   Initialize 'sprites' structure based on hardwired tags which
@@ -668,7 +694,7 @@
   /* Load the citizen sprite graphics. */
   for (i = 0; i < NUM_TILES_CITIZEN; i++) {
     my_snprintf(buffer, sizeof(buffer), "citizen.%s", get_citizen_name(i));
-    sprites.citizen[i].sprite[0] = hash_lookup_data(sprite_hash, buffer);
+    sprites.citizen[i].sprite[0] = load_sprite(buffer);
     if (sprites.citizen[i].sprite[0]) {
       /*
        * If this form exists, use it as the only sprite.  This allows
@@ -682,7 +708,7 @@
     for (j = 0; j < NUM_TILES_CITIZEN; j++) {
       my_snprintf(buffer, sizeof(buffer), "citizen.%s_%d",
                  get_citizen_name(i), j);
-      sprites.citizen[i].sprite[j] = hash_lookup_data(sprite_hash, buffer);
+      sprites.citizen[i].sprite[j] = load_sprite(buffer);
       if (!sprites.citizen[i].sprite[j]) {
        break;
       }
@@ -766,7 +792,7 @@
   do {
     my_snprintf(buffer, sizeof(buffer), "explode.unit_%d",
                num_tiles_explode_unit++);
-  } while (hash_key_exists(sprite_hash, buffer));
+  } while (load_sprite(buffer));
   num_tiles_explode_unit--;
     
   if (num_tiles_explode_unit==0) {
@@ -907,16 +933,8 @@
 ***********************************************************************/
 void tilespec_load_tiles(void)
 {
-  int i;
-  
-  assert(num_spec_files>0);
-  sprite_hash = hash_new(hash_fval_string, hash_fcmp_string);
-
-  for(i=0; i<num_spec_files; i++) {
-    tilespec_load_one(spec_filenames[i]);
-  }
-
   tilespec_lookup_sprite_tags();
+  finish_loading();
 }
 
 /**********************************************************************
@@ -935,10 +953,10 @@
     die("attempt to lookup for %s %s before sprite_hash setup", what, name);
   }
 
-  sp = hash_lookup_data(sprite_hash, tag);
+  sp = load_sprite(tag);
   if (sp) return sp;
 
-  sp = hash_lookup_data(sprite_hash, alt);
+  sp = load_sprite(alt);
   if (sp) {
     freelog(loglevel, "Using alternate graphic %s (instead of %s) for %s %s",
            alt, tag, what, name);
@@ -2119,10 +2137,10 @@
 
   for(j=0; j<32 && city_styles[style].tiles_num < MAX_CITY_TILES; j++) {
     my_snprintf(buffer, sizeof(buffer), "%s_%d", graphics, j);
-    sp = hash_lookup_data(sprite_hash, buffer);
+    sp = load_sprite(buffer);
     if (is_isometric) {
       my_snprintf(buffer, sizeof(buffer_wall), "%s_%d_wall", graphics, j);
-      sp_wall = hash_lookup_data(sprite_hash, buffer);
+      sp_wall = load_sprite(buffer);
     }
     if (sp) {
       sprites.city.tile[style][city_styles[style].tiles_num] = sp;
@@ -2142,7 +2160,7 @@
   if (!is_isometric) {
     /* the wall tile */
     my_snprintf(buffer, sizeof(buffer), "%s_wall", graphics);
-    sp = hash_lookup_data(sprite_hash, buffer);
+    sp = load_sprite(buffer);
     if (sp) {
       sprites.city.tile[style][city_styles[style].tiles_num] = sp;
     } else {
@@ -2152,7 +2170,7 @@
 
   /* occupied tile */
   my_snprintf(buffer, sizeof(buffer), "%s_occupied", graphics);
-  sp = hash_lookup_data(sprite_hash, buffer);
+  sp = load_sprite(buffer);
   if (sp) {
     sprites.city.tile[style][city_styles[style].tiles_num+1] = sp;
   } else {
@@ -2183,12 +2201,9 @@
            "No tiles for alternate %s style, using default tiles",
             city_styles[style].graphic_alt);
 
-    sprites.city.tile[style][0] =
-      hash_lookup_data(sprite_hash, "cd.city");
-    sprites.city.tile[style][1] =
-      hash_lookup_data(sprite_hash, "cd.city_wall");
-    sprites.city.tile[style][2] =
-      hash_lookup_data(sprite_hash, "cd.occupied");
+    sprites.city.tile[style][0] = load_sprite("cd.city");
+    sprites.city.tile[style][1] = load_sprite("cd.city_wall");
+    sprites.city.tile[style][2] = load_sprite("cd.occupied");
     city_styles[style].tiles_num = 1;
     city_styles[style].tresh[0] = 0;
   }
@@ -2321,24 +2336,18 @@
     return NULL;
 }
 
-/**********************************************************************
-...
-***********************************************************************/
-static int my_cmp(const void *a1, const void *a2)
+static void unload_all_sprites(void )
 {
-  const struct Sprite **b1 = (const struct Sprite **) a1;
-  const struct Sprite **b2 = (const struct Sprite **) a2;
+  int i, entries = hash_num_entries(sprite_hash);
 
-  const struct Sprite *c1 = *b1;
-  const struct Sprite *c2 = *b2;
+  for (i = 0; i < entries; i++) {
+    const char *tag_name = hash_key_by_number(sprite_hash, i);
+    struct small_sprite *ss = hash_lookup_data(sprite_hash, tag_name);
 
-  if (c1 < c2) {
-    return -1;
-  }
-  if (c2 < c1) {
-    return 1;
+    while (ss->ref_count > 0) {
+      unload_sprite(tag_name);
+    }
   }
-  return 0;
 }
 
 /**********************************************************************
@@ -2347,33 +2356,35 @@
 void tilespec_free_tiles(void)
 {
   int i, entries = hash_num_entries(sprite_hash);
-  struct Sprite **sprites = fc_malloc(sizeof(*sprites) * entries);
-  struct Sprite *last_sprite = NULL;
 
   freelog(LOG_DEBUG, "tilespec_free_tiles");
 
+  unload_all_sprites();
+
   for (i = 0; i < entries; i++) {
     const char *key = hash_key_by_number(sprite_hash, 0);
 
-    sprites[i] = hash_delete_entry(sprite_hash, key);
+    hash_delete_entry(sprite_hash, key);
     free((void *) key);
   }
 
-  qsort(sprites, entries, sizeof(sprites[0]), my_cmp);
-
-  for (i = 0; i < entries; i++) {
-    if (sprites[i] == last_sprite) {
-      continue;
-    }
-
-    last_sprite = sprites[i];
-    free_sprite(sprites[i]);
-  }
-
-  free(sprites);
-
   hash_free(sprite_hash);
   sprite_hash = NULL;
+
+  specfile_list_iterate(specfiles, sf) {
+    small_sprite_list_iterate(sf->small_sprites, ss) {
+      small_sprite_list_unlink(&sf->small_sprites, ss);
+      assert(ss->sprite == NULL);
+      free(ss);
+    } small_sprite_list_iterate_end;
+
+    specfile_list_unlink(&specfiles, sf);
+    if (sf->big_sprite) {
+      free_sprite(sf->big_sprite);
+      sf->big_sprite = NULL;
+    }
+    free(sf);
+  } specfile_list_iterate_end;
 }
 
 /**************************************************************************
@@ -2390,3 +2401,52 @@
   citizen_index %= sprites.citizen[type].count;
   return sprites.citizen[type].sprite[citizen_index];
 }
+
+struct Sprite *load_sprite(const char *tag_name)
+{
+  struct small_sprite *ss = hash_lookup_data(sprite_hash, tag_name);
+
+  freelog(LOG_DEBUG, "load_sprite(tag='%s')", tag_name);
+  if (!ss) {
+    return NULL;
+  }
+
+  assert(ss->ref_count >= 0);
+
+  if (!ss->sprite) {
+    assert(ss->ref_count == 0);
+    ensure_big_sprite(ss->sf);
+    ss->sprite =
+       crop_sprite(ss->sf->big_sprite, ss->x, ss->y, ss->width, ss->height);
+  }
+
+  ss->ref_count++;
+  return ss->sprite;
+}
+
+void finish_loading(void)
+{
+  specfile_list_iterate(specfiles, sf) {
+    if (sf->big_sprite) {
+      free_sprite(sf->big_sprite);
+      sf->big_sprite = NULL;
+    }
+  } specfile_list_iterate_end;
+}
+
+void unload_sprite(const char *tag_name)
+{
+  struct small_sprite *ss = hash_lookup_data(sprite_hash, tag_name);
+
+  assert(ss);
+  assert(ss->ref_count >= 1);
+  assert(ss->sprite);
+
+  ss->ref_count--;
+
+  if (ss->ref_count == 0) {
+    freelog(LOG_NORMAL, "freeing sprite '%s'", tag_name);
+    free_sprite(ss->sprite);
+    ss->sprite = NULL;
+  }
+}
diff -Nurd -X clean/diff_ignore clean/client/tilespec.h 
tileset/client/tilespec.h
--- clean/client/tilespec.h     Mon Feb 17 19:32:12 2003
+++ tileset/client/tilespec.h   Sat Feb 15 22:20:29 2003
@@ -210,10 +210,6 @@
 
 extern char current_tile_set_name[512];
 
-/* full pathnames: */
-extern char *main_intro_filename;
-extern char *minimap_intro_filename;
-
 /* NOTE: The following comments are out of date and need to
  *       be revised!  -- dwp
  *
@@ -261,4 +257,8 @@
 
 extern int num_tiles_explode_unit;
 
+struct Sprite *load_sprite(const char *tag_name);
+void unload_sprite(const char *tag_name);
+void finish_loading(void);
+
 #endif  /* FC__TILESPEC_H */
diff -Nurd -X clean/diff_ignore clean/data/misc/intro.spec 
tileset/data/misc/intro.spec
--- clean/data/misc/intro.spec  Thu Jan  1 01:00:00 1970
+++ tileset/data/misc/intro.spec        Sat Feb 15 22:37:44 2003
@@ -0,0 +1,27 @@
+
+[spec]
+
+; Format and options of this spec file:
+options = "+spec2"
+
+[info]
+
+artists = ""
+
+[file]
+gfx = "misc/intro"
+
+[grid_main]
+
+; Could use separate "grids" for the smaller components, but not
+; bothering for now.
+
+x_top_left = 0
+y_top_left = 0
+dx = 510
+dy = 300
+
+tiles = { "row", "column", "tag"
+
+  0,  0, "special.intro"
+}
diff -Nurd -X clean/diff_ignore clean/data/misc/radar.spec 
tileset/data/misc/radar.spec
--- clean/data/misc/radar.spec  Thu Jan  1 01:00:00 1970
+++ tileset/data/misc/radar.spec        Sat Feb 15 22:38:00 2003
@@ -0,0 +1,27 @@
+
+[spec]
+
+; Format and options of this spec file:
+options = "+spec2"
+
+[info]
+
+artists = ""
+
+[file]
+gfx = "misc/radar"
+
+[grid_main]
+
+; Could use separate "grids" for the smaller components, but not
+; bothering for now.
+
+x_top_left = 0
+y_top_left = 0
+dx = 160
+dy = 100
+
+tiles = { "row", "column", "tag"
+
+  0,  0, "special.radar"
+}
diff -Nurd -X clean/diff_ignore clean/data/trident.tilespec 
tileset/data/trident.tilespec
--- clean/data/trident.tilespec Mon Feb 17 19:32:12 2003
+++ tileset/data/trident.tilespec       Sat Feb 15 22:41:05 2003
@@ -30,11 +30,6 @@
 ; Font to use to draw city productions:
 city_productions_font = "6x13"
 
-; These are special because they get freed and reloaded
-; as required:
-main_intro_file    = "misc/intro"
-minimap_intro_file = "misc/radar"
-
 ; Below, the graphics spec files; must be somewhere (anywhere) in 
 ; the data path. Order may be important for color allocation on 
 ; low-color systems, and if there are any duplicate tags (lattermost
@@ -50,4 +45,6 @@
 ;  "misc/techs.spec",
   "misc/treaty.spec",
   "trident/cities.spec",
-  "trident/explosions.spec"
+  "trident/explosions.spec",
+  "misc/intro.spec",
+  "misc/radar.spec"

[Prev in Thread] Current Thread [Next in Thread]
  • [Freeciv-Dev] (PR#3457) New sprite loading, Raimar Falke <=