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