rnd-20021123-1-src
[rocksndiamonds.git] / src / libgame / image.c
1 /***********************************************************
2 * Artsoft Retro-Game Library                               *
3 *----------------------------------------------------------*
4 * (c) 1994-2002 Artsoft Entertainment                      *
5 *               Holger Schemel                             *
6 *               Detmolder Strasse 189                      *
7 *               33604 Bielefeld                            *
8 *               Germany                                    *
9 *               e-mail: info@artsoft.org                   *
10 *----------------------------------------------------------*
11 * image.c                                                  *
12 ***********************************************************/
13
14 #include "image.h"
15 #include "pcx.h"
16 #include "misc.h"
17
18
19 /* ========================================================================= */
20 /* PLATFORM SPECIFIC IMAGE FUNCTIONS                                         */
21 /* ========================================================================= */
22
23 #if defined(TARGET_X11)
24
25 /* for MS-DOS/Allegro, exclude all except newImage() and freeImage() */
26
27 Image *newImage(unsigned int width, unsigned int height, unsigned int depth)
28 {
29   Image *image;
30   unsigned int bytes_per_pixel = (depth + 7) / 8;
31   int i;
32
33 #if 0
34   if (depth > 8)
35     Error(ERR_EXIT, "images with more than 256 colors are not supported");
36
37   depth = 8;
38 #endif
39
40   image = checked_calloc(sizeof(Image));
41   image->data = checked_calloc(width * height * bytes_per_pixel);
42   image->width = width;
43   image->height = height;
44   image->depth = depth;
45   image->bytes_per_pixel = bytes_per_pixel;
46   image->bytes_per_row = width * bytes_per_pixel;
47
48   image->rgb.used = 0;
49   for (i=0; i<MAX_COLORS; i++)
50     image->rgb.color_used[i] = FALSE;
51
52   image->type = (depth < 8 ? IMAGETYPE_BITMAP :
53                  depth > 8 ? IMAGETYPE_TRUECOLOR : IMAGETYPE_RGB);
54
55   return image;
56 }
57
58 void freeImage(Image *image)
59 {
60   free(image->data);
61   free(image);
62 }
63
64 #if defined(PLATFORM_UNIX)
65
66 /* extra colors to try allocating in private color maps to minimize flashing */
67 #define NOFLASH_COLORS 256
68
69 /* architecture independent value <-> memory conversions;
70    note: the internal format is big endian */
71
72 #define memory_to_value(ptr, len) (                                         \
73 (len) == 1 ? (unsigned long)(                 *( (byte *)(ptr))         ) : \
74 (len) == 2 ? (unsigned long)(((unsigned long)(*( (byte *)(ptr))   ))<< 8)   \
75                           + (                 *(((byte *)(ptr))+1)      ) : \
76 (len) == 3 ? (unsigned long)(((unsigned long)(*( (byte *)(ptr))   ))<<16)   \
77                           + (((unsigned long)(*(((byte *)(ptr))+1)))<< 8)   \
78                           + (                 *(((byte *)(ptr))+2)      ) : \
79              (unsigned long)(((unsigned long)(*( (byte *)(ptr))   ))<<24)   \
80                           + (((unsigned long)(*(((byte *)(ptr))+1)))<<16)   \
81                           + (((unsigned long)(*(((byte *)(ptr))+2)))<< 8)   \
82                           + (                 *(((byte *)(ptr))+3)      ) )
83
84
85 #define value_to_memory(value, ptr, len) (                              \
86 (len) == 1 ? (*( (byte *)(ptr)   ) = ( value     ) ) :                  \
87 (len) == 2 ? (*( (byte *)(ptr)   ) = (((unsigned long)(value))>> 8),    \
88               *(((byte *)(ptr))+1) = ( value     ) ) :                  \
89 (len) == 3 ? (*( (byte *)(ptr)   ) = (((unsigned long)(value))>>16),    \
90               *(((byte *)(ptr))+1) = (((unsigned long)(value))>> 8),    \
91               *(((byte *)(ptr))+2) = ( value     ) ) :                  \
92              (*( (byte *)(ptr)   ) = (((unsigned long)(value))>>24),    \
93               *(((byte *)(ptr))+1) = (((unsigned long)(value))>>16),    \
94               *(((byte *)(ptr))+2) = (((unsigned long)(value))>> 8),    \
95               *(((byte *)(ptr))+3) = ( value     ) ))
96
97 static Pixmap Image_to_Mask(Image *image, Display *display, Window window)
98 {
99   byte *src_ptr, *dst_ptr, *dst_ptr2;
100   unsigned int bytes_per_row;
101   unsigned int x, y, i;
102   byte bitmask;
103   byte *mask_data;
104   Pixmap mask_pixmap;
105
106   bytes_per_row = (image->width + 7) / 8;
107   mask_data = checked_calloc(bytes_per_row * image->height);
108
109   src_ptr = image->data;
110   dst_ptr = mask_data;
111
112   /* create bitmap data which can be used by 'XCreateBitmapFromData()'
113    * directly to create a pixmap of depth 1 for use as a clip mask for
114    * the corresponding image pixmap
115    */
116
117   for (y=0; y<image->height; y++)
118   {
119     bitmask = 0x01;             /* start with leftmost bit in the byte     */
120     dst_ptr2 = dst_ptr;         /* start with leftmost byte in the row     */
121
122     for (x=0; x<image->width; x++)
123     {
124       for (i=0; i<image->bytes_per_pixel; i++)
125         if (*src_ptr++)         /* source pixel solid? (pixel index != 0)  */
126           *dst_ptr2 |= bitmask; /* then write a bit into the image mask    */
127
128       if ((bitmask <<= 1) == 0) /* bit at rightmost byte position reached? */
129       {
130         bitmask = 0x01;         /* start again with leftmost bit position  */
131         dst_ptr2++;             /* continue with next byte in image mask   */
132       }
133     }
134
135     dst_ptr += bytes_per_row;   /* continue with leftmost byte of next row */
136   }
137
138   mask_pixmap = XCreateBitmapFromData(display, window, (char *)mask_data,
139                                       image->width, image->height);
140   free(mask_data);
141
142   return mask_pixmap;
143 }
144
145 static int bitsPerPixelAtDepth(Display *display, int screen, int depth)
146 {
147   XPixmapFormatValues *pixmap_format;
148   int i, num_pixmap_formats, bits_per_pixel = -1;
149
150   /* get Pixmap formats supported by the X server */
151   pixmap_format = XListPixmapFormats(display, &num_pixmap_formats);
152
153   /* find format that matches the given depth */
154   for (i=0; i<num_pixmap_formats; i++)
155     if (pixmap_format[i].depth == depth)
156       bits_per_pixel = pixmap_format[i].bits_per_pixel;
157
158   XFree(pixmap_format);
159
160   if (bits_per_pixel == -1)
161     Error(ERR_EXIT, "cannot find pixmap format for depth %d", depth);
162
163   return bits_per_pixel;
164 }
165
166 XImageInfo *Image_to_Pixmap(Display *display, int screen, Visual *visual,
167                             Window window, GC gc, int depth, Image *image)
168 {
169   static XColor xcolor_private[NOFLASH_COLORS];
170   static int colorcell_used[NOFLASH_COLORS];
171   static Colormap global_cmap = 0;
172   static Pixel *global_cmap_index;
173   static int num_cmap_entries, free_cmap_entries;
174   static boolean private_cmap = FALSE;
175   Pixel *redvalue, *greenvalue, *bluevalue;
176   unsigned int display_bytes_per_pixel, display_bits_per_pixel;
177   unsigned int a, c = 0, x, y;
178   XColor xcolor;
179   XImage *ximage;
180   XImageInfo *ximageinfo;
181   byte *src_ptr, *dst_ptr;
182   char *error = "Image_to_Pixmap(): %s";
183
184   if (image->type == IMAGETYPE_TRUECOLOR && depth == 8)
185   {
186     SetError(error, "cannot handle true-color images on 8-bit display");
187     return NULL;
188   }
189
190   if (!global_cmap)
191   {
192     if (visual == DefaultVisual(display, screen))
193       global_cmap = DefaultColormap(display, screen);
194     else
195     {
196       global_cmap = XCreateColormap(display, RootWindow(display, screen),
197                                     visual, AllocNone);
198       private_cmap = TRUE;
199     }
200   }
201
202   xcolor.flags = DoRed | DoGreen | DoBlue;
203   redvalue = greenvalue = bluevalue = NULL;
204   ximageinfo = checked_malloc(sizeof(XImageInfo));
205   ximageinfo->display = display;
206   ximageinfo->depth = depth;
207
208   switch (visual->class)
209   {
210     case TrueColor:
211     case DirectColor:
212     {
213       Pixel pixval;
214       unsigned int redcolors, greencolors, bluecolors;
215       unsigned int redstep, greenstep, bluestep;
216       unsigned int redbottom, greenbottom, bluebottom;
217       unsigned int redtop, greentop, bluetop;
218
219       redvalue = (Pixel *)checked_malloc(sizeof(Pixel) * 256);
220       greenvalue = (Pixel *)checked_malloc(sizeof(Pixel) * 256);
221       bluevalue = (Pixel *)checked_malloc(sizeof(Pixel) * 256);
222
223       ximageinfo->cmap = global_cmap;
224
225       retry_direct: /* tag we hit if a DirectColor allocation fails on
226                      * default colormap */
227
228       /* calculate number of distinct colors in each band */
229
230       redcolors = greencolors = bluecolors = 1;
231       for (pixval=1; pixval; pixval <<= 1)
232       {
233         if (pixval & visual->red_mask)
234           redcolors <<= 1;
235         if (pixval & visual->green_mask)
236           greencolors <<= 1;
237         if (pixval & visual->blue_mask)
238           bluecolors <<= 1;
239       }
240       
241       /* consistency check */
242       if (redcolors > visual->map_entries ||
243           greencolors > visual->map_entries ||
244           bluecolors > visual->map_entries)
245         Error(ERR_WARN, "inconsistency in color information");
246
247       redstep = 256 / redcolors;
248       greenstep = 256 / greencolors;
249       bluestep = 256 / bluecolors;
250       redbottom = greenbottom = bluebottom = 0;
251       redtop = greentop = bluetop = 0;
252
253       for (a=0; a<visual->map_entries; a++)
254       {
255         if (redbottom < 256)
256           redtop = redbottom + redstep;
257         if (greenbottom < 256)
258           greentop = greenbottom + greenstep;
259         if (bluebottom < 256)
260           bluetop = bluebottom + bluestep;
261
262         xcolor.red = (redtop - 1) << 8;
263         xcolor.green = (greentop - 1) << 8;
264         xcolor.blue = (bluetop - 1) << 8;
265         if (!XAllocColor(display, ximageinfo->cmap, &xcolor))
266         {
267           /* if an allocation fails for a DirectColor default visual then
268              we should create a private colormap and try again. */
269
270           if ((visual->class == DirectColor) &&
271               (visual == DefaultVisual(display, screen)))
272           {
273             global_cmap = XCopyColormapAndFree(display, global_cmap);
274             ximageinfo->cmap = global_cmap;
275             private_cmap = TRUE;
276
277             goto retry_direct;
278           }
279
280           /* something completely unexpected happened */
281
282           fprintf(stderr, "Image_to_Pixmap: XAllocColor failed on a TrueColor/Directcolor visual\n");
283
284           free(redvalue);
285           free(greenvalue);
286           free(bluevalue);
287           free(ximageinfo);
288
289           return NULL;
290         }
291
292         /* fill in pixel values for each band at this intensity */
293
294         while ((redbottom < 256) && (redbottom < redtop))
295           redvalue[redbottom++] = xcolor.pixel & visual->red_mask;
296         while ((greenbottom < 256) && (greenbottom < greentop))
297           greenvalue[greenbottom++] = xcolor.pixel & visual->green_mask;
298         while ((bluebottom < 256) && (bluebottom < bluetop))
299           bluevalue[bluebottom++] = xcolor.pixel & visual->blue_mask;
300       }
301
302       break;
303     }
304
305     case PseudoColor:
306
307       ximageinfo->cmap = global_cmap;
308
309       for (a=0; a<MAX_COLORS; a++)
310       {
311         XColor xcolor2;
312         unsigned short mask;
313         int color_found;
314         int i;
315
316         if (!image->rgb.color_used[a])
317           continue;
318
319         xcolor.red = *(image->rgb.red + a);
320         xcolor.green = *(image->rgb.green + a);
321         xcolor.blue = *(image->rgb.blue + a);
322   
323         /* look if this color already exists in our colormap */
324         if (!XAllocColor(display, ximageinfo->cmap, &xcolor))
325         {
326           if (!private_cmap)
327           {
328             if (options.verbose)
329               Error(ERR_RETURN, "switching to private colormap");
330
331             /* we just filled up the default colormap -- get a private one
332                which contains all already allocated colors */
333
334             global_cmap = XCopyColormapAndFree(display, global_cmap);
335             ximageinfo->cmap = global_cmap;
336             private_cmap = TRUE;
337
338             /* allocate the rest of the color cells read/write */
339             global_cmap_index =
340               (Pixel *)checked_malloc(sizeof(Pixel) * NOFLASH_COLORS);
341             for (i=0; i<NOFLASH_COLORS; i++)
342               if (!XAllocColorCells(display, global_cmap, FALSE, NULL, 0,
343                                     global_cmap_index + i, 1))
344                 break;
345             num_cmap_entries = free_cmap_entries = i;
346
347             /*
348             printf("We've got %d free colormap entries.\n", free_cmap_entries);
349             */
350
351             /* to minimize colormap flashing, copy default colors and try
352                to keep them as near as possible to the old values */
353
354             for(i=0; i<num_cmap_entries; i++)
355             {
356               xcolor2.pixel = *(global_cmap_index + i);
357               XQueryColor(display, DefaultColormap(display, screen), &xcolor2);
358               XStoreColor(display, global_cmap, &xcolor2);
359               xcolor_private[xcolor2.pixel] = xcolor2;
360               colorcell_used[xcolor2.pixel] = FALSE;
361             }
362
363             /* now we have the default colormap private: all colors we
364                successfully allocated so far are read-only, which is okay,
365                because we don't want to change them anymore -- if we need
366                an existing color again, we get it by XAllocColor; all other
367                colors are read/write and we can set them by XStoreColor,
368                but we will try to overwrite those color cells with our new
369                color which are as close as possible to our new color */
370           }
371
372           /* look for an existing default color close the one we want */
373
374           mask = 0xf000;
375           color_found = FALSE;
376
377           while (!color_found)
378           {
379             for (i=num_cmap_entries-1; i>=0; i--)
380             {
381               xcolor2.pixel = *(global_cmap_index + i);
382               xcolor2 = xcolor_private[xcolor2.pixel];
383
384               if (colorcell_used[xcolor2.pixel])
385                 continue;
386
387               if ((xcolor.red & mask) == (xcolor2.red & mask) &&
388                   (xcolor.green & mask) == (xcolor2.green & mask) &&
389                   (xcolor.blue & mask) == (xcolor2.blue & mask))
390               {
391                 /*
392                 printf("replacing color cell %ld with a close color\n",
393                        xcolor2.pixel);
394                        */
395                 color_found = TRUE;
396                 break;
397               }
398             }
399
400             if (mask == 0x0000)
401               break;
402
403             mask = (mask << 1) & 0xffff;
404           }
405
406           if (!color_found)             /* no more free color cells */
407           {
408             SetError(error, "cannot allocate enough color cells");
409             return NULL;
410           }
411
412           xcolor.pixel = xcolor2.pixel;
413           xcolor_private[xcolor.pixel] = xcolor;
414           colorcell_used[xcolor.pixel] = TRUE;
415           XStoreColor(display, ximageinfo->cmap, &xcolor);
416           free_cmap_entries--;
417         }
418
419         *(ximageinfo->index + a) = xcolor.pixel;
420       }
421
422       /*
423       printf("still %d free colormap entries\n", free_cmap_entries);
424       */
425
426       ximageinfo->no = a;       /* number of pixels allocated for this image */
427       break;
428   
429     default:
430       Error(ERR_RETURN,"DirectColor, TrueColor or PseudoColor display needed");
431       SetError(error, "display class not supported");
432
433       return NULL;
434   }
435
436 #if DEBUG_TIMING
437   debug_print_timestamp(2, "   ALLOCATING IMAGE COLORS:   ");
438 #endif
439
440   /* create XImage from internal image structure and convert it to Pixmap */
441
442   display_bits_per_pixel = bitsPerPixelAtDepth(display, screen, depth);
443   display_bytes_per_pixel = (display_bits_per_pixel + 7) / 8;
444
445   ximage = XCreateImage(display, visual, depth, ZPixmap, 0,
446                         NULL, image->width, image->height,
447                         8, image->width * display_bytes_per_pixel);
448   ximage->data =
449     checked_malloc(image->width * image->height * display_bytes_per_pixel);
450   ximage->byte_order = MSBFirst;
451
452   src_ptr = image->data;
453   dst_ptr = (byte *)ximage->data;
454
455   switch (visual->class)
456   {
457     case DirectColor:
458     case TrueColor:
459     {
460       Pixel pixval;
461
462       switch (image->type)
463       {
464         case IMAGETYPE_RGB:
465         {
466           for (y=0; y<image->height; y++)               /* general case */
467           {
468             for (x=0; x<image->width; x++)
469             {
470               pixval = *src_ptr++;
471               pixval =
472                 redvalue[image->rgb.red[pixval] >> 8] |
473                 greenvalue[image->rgb.green[pixval] >> 8] |
474                 bluevalue[image->rgb.blue[pixval] >> 8];
475               value_to_memory(pixval, dst_ptr, display_bytes_per_pixel);
476               dst_ptr += display_bytes_per_pixel;
477             }
478           }
479
480           break;
481         }
482
483         case IMAGETYPE_TRUECOLOR:
484         {
485           for (y=0; y<image->height; y++)               /* general case */
486           {
487             for (x=0; x<image->width; x++)
488             {
489               pixval = memory_to_value(src_ptr, image->bytes_per_pixel);
490               pixval =
491                 redvalue[TRUECOLOR_RED(pixval)] |
492                 greenvalue[TRUECOLOR_GREEN(pixval)] |
493                 bluevalue[TRUECOLOR_BLUE(pixval)];
494               value_to_memory(pixval, dst_ptr, display_bytes_per_pixel);
495               src_ptr += image->bytes_per_pixel;
496               dst_ptr += display_bytes_per_pixel;
497             }
498           }
499
500           break;
501         }
502
503         default:
504           Error(ERR_RETURN, "RGB or TrueColor image needed");
505           SetError(error, "image type not supported");
506
507           return NULL;
508       }
509
510       break;
511     }
512
513     case PseudoColor:
514     {
515       if (display_bytes_per_pixel == 1)         /* special case */
516       {
517         for (y=0; y<image->height; y++)
518           for (x=0; x<image->width; x++)
519             *dst_ptr++ = ximageinfo->index[c + *src_ptr++];
520       }
521       else                                      /* general case */
522       {
523         for (y=0; y<image->height; y++)
524         {
525           for (x=0; x<image->width; x++)
526           {
527             value_to_memory(ximageinfo->index[c + *src_ptr++],
528                             dst_ptr, display_bytes_per_pixel);
529             dst_ptr += display_bytes_per_pixel;
530           }
531         }
532       }
533
534       break;
535     }
536
537     default:
538       Error(ERR_RETURN,"DirectColor, TrueColor or PseudoColor display needed");
539       SetError(error, "display class not supported");
540
541       return NULL;
542   }
543
544   if (redvalue)
545   {
546     free((byte *)redvalue);
547     free((byte *)greenvalue);
548     free((byte *)bluevalue);
549   }
550
551 #if DEBUG_TIMING
552   debug_print_timestamp(2, "   CONVERTING IMAGE TO XIMAGE:");
553 #endif
554
555   ximageinfo->pixmap = XCreatePixmap(display, window,
556                                      ximage->width, ximage->height,
557                                      ximageinfo->depth);
558
559   XPutImage(ximageinfo->display, ximageinfo->pixmap, gc,
560             ximage, 0, 0, 0, 0, ximage->width, ximage->height);
561
562   XDestroyImage(ximage);
563
564   return ximageinfo;
565 }
566
567 void freeXImage(Image *image, XImageInfo *ximageinfo)
568 {
569   if (ximageinfo->index != NULL && ximageinfo->no > 0)
570     XFreeColors(ximageinfo->display, ximageinfo->cmap, ximageinfo->index,
571                 ximageinfo->no, 0);
572   /* this       ^^^^^^^^^^^^^^ is wrong, because the used color cells
573    * are somewhere between 0 and MAX_COLORS; there are indeed 'ximageinfo->no'
574    * used color cells, but they are not at array position 0 - 'ximageinfo->no'
575    */
576
577   free(ximageinfo);
578 }
579
580 int Read_PCX_to_Pixmap(Display *display, Window window, GC gc, char *filename,
581                        Pixmap *pixmap, Pixmap *pixmap_mask)
582 {
583   Image *image;
584   XImageInfo *ximageinfo;
585   int screen;
586   Visual *visual;
587   int depth;
588
589 #if DEBUG_TIMING
590   debug_print_timestamp(2, NULL);       /* initialize timestamp function */
591 #endif
592
593   /* read the graphic file in PCX format to image structure */
594   if ((image = Read_PCX_to_Image(filename)) == NULL)
595     return errno_pcx;
596
597 #if DEBUG_TIMING
598   printf("%s:\n", filename);
599   debug_print_timestamp(2, "   READING PCX FILE TO IMAGE: ");
600 #endif
601
602   screen = DefaultScreen(display);
603   visual = DefaultVisual(display, screen);
604   depth = DefaultDepth(display, screen);
605
606   /* convert image structure to X11 Pixmap */
607   if (!(ximageinfo = Image_to_Pixmap(display, screen, visual,
608                                      window, gc, depth, image)))
609   {
610     freeImage(image);
611
612     return PCX_OtherError;
613   }
614
615   /* if a private colormap has been created, install it */
616   if (ximageinfo->cmap != DefaultColormap(display, screen))
617     XSetWindowColormap(display, window, ximageinfo->cmap);
618
619 #if DEBUG_TIMING
620   debug_print_timestamp(2, "   CONVERTING IMAGE TO PIXMAP:");
621 #endif
622
623   /* create clip mask for the image */
624   ximageinfo->pixmap_mask = Image_to_Mask(image, display, window);
625
626 #if DEBUG_TIMING
627   debug_print_timestamp(2, "   CONVERTING IMAGE TO MASK:  ");
628 #endif
629
630   *pixmap = ximageinfo->pixmap;
631   *pixmap_mask = ximageinfo->pixmap_mask;
632
633   /* free generic image and ximageinfo after native Pixmap has been created */
634   free(ximageinfo);
635   freeImage(image);
636
637   return PCX_Success;
638 }
639
640 #endif  /* PLATFORM_UNIX */
641 #endif  /* TARGET_X11 */
642
643
644 /* ========================================================================= */
645 /* PLATFORM INDEPENDANT IMAGE FUNCTIONS                                      */
646 /* ========================================================================= */
647
648 struct ImageInfo
649 {
650   char *source_filename;
651   int num_references;
652
653   Bitmap *bitmap;
654 };
655 typedef struct ImageInfo ImageInfo;
656
657 static struct ArtworkListInfo *image_info = NULL;
658
659 static void *Load_PCX(char *filename)
660 {
661   ImageInfo *img_info;
662
663 #if 0
664   printf("loading PCX file '%s'\n", filename);
665 #endif
666
667   img_info = checked_calloc(sizeof(ImageInfo));
668
669   if ((img_info->bitmap = LoadImage(filename)) == NULL)
670   {
671     Error(ERR_WARN, "cannot read image file '%s': LoadImage() failed: %s",
672           filename, GetError());
673     free(img_info);
674     return NULL;
675   }
676
677   img_info->source_filename = getStringCopy(filename);
678
679   return img_info;
680 }
681
682 static void FreeImage(void *ptr)
683 {
684   ImageInfo *image = (ImageInfo *)ptr;
685
686   if (image == NULL)
687     return;
688
689   if (image->bitmap)
690     FreeBitmap(image->bitmap);
691
692   if (image->source_filename)
693     free(image->source_filename);
694
695   free(image);
696 }
697
698 struct FileInfo *getCurrentImageList()
699 {
700   return image_info->file_list;
701 }
702
703 Bitmap *getBitmapFromImageID(int graphic)
704 {
705   ImageInfo **img_info = (ImageInfo **)image_info->artwork_list;
706
707   return img_info[graphic]->bitmap;
708 }
709
710 void InitImageList(struct ConfigInfo *config_list,
711                    struct ConfigInfo *config_suffix_list,
712                    int num_file_list_entries)
713 {
714   int i;
715
716   image_info = checked_calloc(sizeof(struct ArtworkListInfo));
717
718   image_info->type = ARTWORK_TYPE_GRAPHICS;
719
720   image_info->num_file_list_entries = num_file_list_entries;
721   image_info->num_suffix_list_entries = 0;
722   for (i=0; config_suffix_list[i].token != NULL; i++)
723     image_info->num_suffix_list_entries++;
724
725   image_info->file_list =
726     getFileListFromConfigList(config_list, config_suffix_list,
727                               num_file_list_entries);
728   image_info->suffix_list = config_suffix_list;
729
730   image_info->artwork_list =
731     checked_calloc(num_file_list_entries * sizeof(ImageInfo *));
732
733   image_info->content_list = NULL;
734
735   image_info->load_artwork = Load_PCX;
736   image_info->free_artwork = FreeImage;
737 }
738
739 void ReloadCustomImages()
740 {
741 #if 0
742   printf("DEBUG: reloading images '%s' ...\n", artwork.gfx_current_identifier);
743 #endif
744
745   ReloadCustomArtworkList(image_info);
746 }
747
748 void FreeAllImages()
749 {
750   FreeCustomArtworkList(image_info);
751 }