removed some (deactivated) code for debugging output
[rocksndiamonds.git] / src / libgame / image.c
1 // ============================================================================
2 // Artsoft Retro-Game Library
3 // ----------------------------------------------------------------------------
4 // (c) 1995-2014 by Artsoft Entertainment
5 //                  Holger Schemel
6 //                  info@artsoft.org
7 //                  http://www.artsoft.org/
8 // ----------------------------------------------------------------------------
9 // image.c
10 // ============================================================================
11
12 #include "image.h"
13 #include "misc.h"
14 #include "setup.h"
15
16
17 struct ImageInfo
18 {
19   char *source_filename;
20   int num_references;
21
22   Bitmap *bitmaps[NUM_IMG_BITMAP_POINTERS];
23
24   int original_width;                   /* original image file width */
25   int original_height;                  /* original image file height */
26
27   boolean contains_small_images;        /* set after adding small images */
28   boolean scaled_up;                    /* set after scaling up */
29
30   int conf_tile_size;                   /* tile size as defined in config */
31   int game_tile_size;                   /* tile size as resized for game */
32
33   char *leveldir;                       /* level set when image was loaded */
34 };
35 typedef struct ImageInfo ImageInfo;
36
37 static struct ArtworkListInfo *image_info = NULL;
38
39 static void *Load_Image(char *filename)
40 {
41   ImageInfo *img_info = checked_calloc(sizeof(ImageInfo));
42
43   if ((img_info->bitmaps[IMG_BITMAP_STANDARD] = LoadImage(filename)) == NULL)
44   {
45     Error(ERR_WARN, "cannot load image file '%s': LoadImage() failed: %s",
46           filename, GetError());
47
48     free(img_info);
49
50     return NULL;
51   }
52
53   img_info->source_filename = getStringCopy(filename);
54
55   img_info->original_width  = img_info->bitmaps[IMG_BITMAP_STANDARD]->width;
56   img_info->original_height = img_info->bitmaps[IMG_BITMAP_STANDARD]->height;
57
58   img_info->contains_small_images = FALSE;
59   img_info->scaled_up = FALSE;
60
61   img_info->conf_tile_size = 0;         // will be set later
62   img_info->game_tile_size = 0;         // will be set later
63
64   img_info->leveldir = NULL;            // will be set later
65
66   return img_info;
67 }
68
69 static void FreeImage(void *ptr)
70 {
71   ImageInfo *image = (ImageInfo *)ptr;
72   int i;
73
74   if (image == NULL)
75     return;
76
77   for (i = 0; i < NUM_IMG_BITMAPS; i++)
78     if (image->bitmaps[i])
79       FreeBitmap(image->bitmaps[i]);
80
81   if (image->source_filename)
82     free(image->source_filename);
83
84   free(image);
85 }
86
87 int getImageListSize()
88 {
89   return (image_info->num_file_list_entries +
90           image_info->num_dynamic_file_list_entries);
91 }
92
93 struct FileInfo *getImageListEntryFromImageID(int pos)
94 {
95   int num_list_entries = image_info->num_file_list_entries;
96   int list_pos = (pos < num_list_entries ? pos : pos - num_list_entries);
97
98   return (pos < num_list_entries ? &image_info->file_list[list_pos] :
99           &image_info->dynamic_file_list[list_pos]);
100 }
101
102 static ImageInfo *getImageInfoEntryFromImageID(int pos)
103 {
104   int num_list_entries = image_info->num_file_list_entries;
105   int list_pos = (pos < num_list_entries ? pos : pos - num_list_entries);
106   ImageInfo **img_info =
107     (ImageInfo **)(pos < num_list_entries ? image_info->artwork_list :
108                    image_info->dynamic_artwork_list);
109
110   return img_info[list_pos];
111 }
112
113 Bitmap **getBitmapsFromImageID(int pos)
114 {
115   ImageInfo *img_info = getImageInfoEntryFromImageID(pos);
116
117   return (img_info != NULL ? img_info->bitmaps : NULL);
118 }
119
120 int getOriginalImageWidthFromImageID(int pos)
121 {
122   ImageInfo *img_info = getImageInfoEntryFromImageID(pos);
123
124   return (img_info != NULL ? img_info->original_width : 0);
125 }
126
127 int getOriginalImageHeightFromImageID(int pos)
128 {
129   ImageInfo *img_info = getImageInfoEntryFromImageID(pos);
130
131   return (img_info != NULL ? img_info->original_height : 0);
132 }
133
134 char *getTokenFromImageID(int graphic)
135 {
136   struct FileInfo *file_list = getImageListEntryFromImageID(graphic);
137
138   return (file_list != NULL ? file_list->token : NULL);
139 }
140
141 int getImageIDFromToken(char *token)
142 {
143   struct FileInfo *file_list = image_info->file_list;
144   int num_list_entries = image_info->num_file_list_entries;
145   int i;
146
147   for (i = 0; i < num_list_entries; i++)
148     if (strEqual(file_list[i].token, token))
149       return i;
150
151   return -1;
152 }
153
154 char *getImageConfigFilename()
155 {
156   return getCustomArtworkConfigFilename(image_info->type);
157 }
158
159 int getImageListPropertyMappingSize()
160 {
161   return image_info->num_property_mapping_entries;
162 }
163
164 struct PropertyMapping *getImageListPropertyMapping()
165 {
166   return image_info->property_mapping;
167 }
168
169 void InitImageList(struct ConfigInfo *config_list, int num_file_list_entries,
170                    struct ConfigTypeInfo *config_suffix_list,
171                    char **base_prefixes, char **ext1_suffixes,
172                    char **ext2_suffixes, char **ext3_suffixes,
173                    char **ignore_tokens)
174 {
175   int i;
176
177   image_info = checked_calloc(sizeof(struct ArtworkListInfo));
178   image_info->type = ARTWORK_TYPE_GRAPHICS;
179
180   /* ---------- initialize file list and suffix lists ---------- */
181
182   image_info->num_file_list_entries = num_file_list_entries;
183   image_info->num_dynamic_file_list_entries = 0;
184
185   image_info->file_list =
186     getFileListFromConfigList(config_list, config_suffix_list, ignore_tokens,
187                               num_file_list_entries);
188   image_info->dynamic_file_list = NULL;
189
190   image_info->num_suffix_list_entries = 0;
191   for (i = 0; config_suffix_list[i].token != NULL; i++)
192     image_info->num_suffix_list_entries++;
193
194   image_info->suffix_list = config_suffix_list;
195
196   /* ---------- initialize base prefix and suffixes lists ---------- */
197
198   image_info->num_base_prefixes = 0;
199   for (i = 0; base_prefixes[i] != NULL; i++)
200     image_info->num_base_prefixes++;
201
202   image_info->num_ext1_suffixes = 0;
203   for (i = 0; ext1_suffixes[i] != NULL; i++)
204     image_info->num_ext1_suffixes++;
205
206   image_info->num_ext2_suffixes = 0;
207   for (i = 0; ext2_suffixes[i] != NULL; i++)
208     image_info->num_ext2_suffixes++;
209
210   image_info->num_ext3_suffixes = 0;
211   for (i = 0; ext3_suffixes[i] != NULL; i++)
212     image_info->num_ext3_suffixes++;
213
214   image_info->num_ignore_tokens = 0;
215   for (i = 0; ignore_tokens[i] != NULL; i++)
216     image_info->num_ignore_tokens++;
217
218   image_info->base_prefixes = base_prefixes;
219   image_info->ext1_suffixes = ext1_suffixes;
220   image_info->ext2_suffixes = ext2_suffixes;
221   image_info->ext3_suffixes = ext3_suffixes;
222   image_info->ignore_tokens = ignore_tokens;
223
224   image_info->num_property_mapping_entries = 0;
225
226   image_info->property_mapping = NULL;
227
228   /* ---------- initialize artwork reference and content lists ---------- */
229
230   image_info->sizeof_artwork_list_entry = sizeof(ImageInfo *);
231
232   image_info->artwork_list =
233     checked_calloc(num_file_list_entries * sizeof(ImageInfo *));
234   image_info->dynamic_artwork_list = NULL;
235
236   image_info->content_list = NULL;
237
238   /* ---------- initialize artwork loading/freeing functions ---------- */
239
240   image_info->load_artwork = Load_Image;
241   image_info->free_artwork = FreeImage;
242 }
243
244 void ReloadCustomImages()
245 {
246   print_timestamp_init("ReloadCustomImages");
247
248   LoadArtworkConfig(image_info);
249   print_timestamp_time("LoadArtworkConfig");
250
251   ReloadCustomArtworkList(image_info);
252   print_timestamp_time("ReloadCustomArtworkList");
253
254   print_timestamp_done("ReloadCustomImages");
255 }
256
257 static boolean CheckIfImageContainsSmallImages(ImageInfo *img_info,
258                                                int tile_size)
259 {
260   if (!img_info->contains_small_images)
261     return FALSE;
262
263   // at this point, small images already exist for this image;
264   // now do some checks that may require re-creating small (or in-game) images
265
266   // special case 1:
267   //
268   // check if the configured tile size for an already loaded image has changed
269   // from one level set to another; this should usually not happen, but if a
270   // custom artwork set redefines classic (or default) graphics with wrong tile
271   // size (by mistake or by intention), it will be corrected to its original
272   // tile size here by forcing complete re-creation of all small images again
273   // (this does not work if different tile sizes are used in same image file)
274
275   if (!strEqual(img_info->leveldir, leveldir_current->identifier) &&
276       img_info->conf_tile_size != tile_size)
277   {
278     int bitmap_nr = GET_BITMAP_ID_FROM_TILESIZE(img_info->conf_tile_size);
279     int i;
280
281     // free all calculated, resized bitmaps, but keep last configured size
282     for (i = 0; i < NUM_IMG_BITMAPS; i++)
283     {
284       if (i == bitmap_nr)
285         continue;
286
287       if (img_info->bitmaps[i])
288       {
289         FreeBitmap(img_info->bitmaps[i]);
290
291         img_info->bitmaps[i] = NULL;
292       }
293     }
294
295     // re-create small bitmaps from last configured size as new default size
296     if (bitmap_nr != IMG_BITMAP_STANDARD)
297     {
298       img_info->bitmaps[IMG_BITMAP_STANDARD] = img_info->bitmaps[bitmap_nr];
299       img_info->bitmaps[bitmap_nr] = NULL;
300     }
301
302     img_info->contains_small_images = FALSE;
303
304     return FALSE;
305   }
306
307   // special case 2:
308   //
309   // graphic config setting "game.tile_size" has changed since last level set;
310   // this may require resizing image to new size required for in-game graphics
311
312   if (img_info->game_tile_size != gfx.game_tile_size)
313   {
314     ReCreateGameTileSizeBitmap(img_info->bitmaps);
315
316     img_info->game_tile_size = gfx.game_tile_size;
317   }
318
319   return TRUE;
320 }
321
322 void CreateImageWithSmallImages(int pos, int zoom_factor, int tile_size)
323 {
324   ImageInfo *img_info = getImageInfoEntryFromImageID(pos);
325
326   if (img_info == NULL)
327     return;
328
329   if (CheckIfImageContainsSmallImages(img_info, tile_size))
330     return;
331
332   CreateBitmapWithSmallBitmaps(img_info->bitmaps, zoom_factor, tile_size);
333
334   img_info->contains_small_images = TRUE;
335   img_info->scaled_up = TRUE;                   // scaling was also done here
336
337   img_info->conf_tile_size = tile_size;
338   img_info->game_tile_size = gfx.game_tile_size;
339
340   setString(&img_info->leveldir, leveldir_current->identifier);
341 }
342
343 void ScaleImage(int pos, int zoom_factor)
344 {
345   ImageInfo *img_info = getImageInfoEntryFromImageID(pos);
346
347   if (img_info == NULL || img_info->scaled_up)
348     return;
349
350   if (zoom_factor != 1)
351     ScaleBitmap(img_info->bitmaps, zoom_factor);
352
353   img_info->scaled_up = TRUE;
354 }
355
356 void FreeAllImages()
357 {
358   FreeCustomArtworkLists(image_info);
359 }