rnd-20040612-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 #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,
447                         0, 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   X11DestroyImage(ximage);
564
565   return ximageinfo;
566 }
567
568 /*
569   -----------------------------------------------------------------------------
570   ZoomPixmap
571
572   Important note: The scaling code currently only supports scaling down the
573   image by a power of 2 -- scaling up is currently not supported at all!
574   -----------------------------------------------------------------------------
575 */
576
577 void ZoomPixmap(Display *display, GC gc, Pixmap src_pixmap, Pixmap dst_pixmap,
578                 int src_width, int src_height,
579                 int dst_width, int dst_height)
580 {
581   XImage *src_ximage, *dst_ximage;
582   byte *src_ptr, *dst_ptr;
583   int bits_per_pixel;
584   int bytes_per_pixel;
585   int x, y, i;
586   int zoom_factor = src_width / dst_width;      /* currently very limited! */
587   int row_skip, col_skip;
588
589   /* adjust source image size to integer multiple of destination image size */
590   src_width  = dst_width  * zoom_factor;
591   src_height = dst_height * zoom_factor;
592
593   /* copy source pixmap to temporary image */
594   src_ximage = XGetImage(display, src_pixmap, 0, 0, src_width, src_height,
595                          AllPlanes, ZPixmap);
596
597   bits_per_pixel = src_ximage->bits_per_pixel;
598   bytes_per_pixel = (bits_per_pixel + 7) / 8;
599
600   dst_ximage = XCreateImage(display, visual, src_ximage->depth, ZPixmap,
601                             0, NULL, dst_width, dst_height,
602                             8, dst_width * bytes_per_pixel);
603   dst_ximage->data =
604     checked_malloc(dst_width * dst_height * bytes_per_pixel);
605   dst_ximage->byte_order = src_ximage->byte_order;
606
607   src_ptr = (byte *)src_ximage->data;
608   dst_ptr = (byte *)dst_ximage->data;
609
610   col_skip = (zoom_factor - 1) * bytes_per_pixel;
611   row_skip = col_skip * src_width;
612
613   /* scale image down by scaling factor 'zoom_factor' */
614   for (y = 0; y < src_height; y += zoom_factor, src_ptr += row_skip)
615     for (x = 0; x < src_width; x += zoom_factor, src_ptr += col_skip)
616       for (i = 0; i < bytes_per_pixel; i++)
617         *dst_ptr++ = *src_ptr++;
618
619   /* copy scaled image to destination pixmap */
620   XPutImage(display, dst_pixmap, gc, dst_ximage, 0, 0, 0, 0,
621             dst_width, dst_height);
622
623   /* free temporary images */
624   X11DestroyImage(src_ximage);
625   X11DestroyImage(dst_ximage);
626 }
627
628 void freeXImage(Image *image, XImageInfo *ximageinfo)
629 {
630   if (ximageinfo->index != NULL && ximageinfo->no > 0)
631     XFreeColors(ximageinfo->display, ximageinfo->cmap, ximageinfo->index,
632                 ximageinfo->no, 0);
633   /* this       ^^^^^^^^^^^^^^ is wrong, because the used color cells
634    * are somewhere between 0 and MAX_COLORS; there are indeed 'ximageinfo->no'
635    * used color cells, but they are not at array position 0 - 'ximageinfo->no'
636    */
637
638   free(ximageinfo);
639 }
640
641 int Read_PCX_to_Pixmap(Display *display, Window window, GC gc, char *filename,
642                        Pixmap *pixmap, Pixmap *pixmap_mask)
643 {
644   Image *image;
645   XImageInfo *ximageinfo;
646   int screen;
647   Visual *visual;
648   int depth;
649
650 #if DEBUG_TIMING
651   debug_print_timestamp(2, NULL);       /* initialize timestamp function */
652 #endif
653
654   /* read the graphic file in PCX format to image structure */
655   if ((image = Read_PCX_to_Image(filename)) == NULL)
656     return errno_pcx;
657
658 #if DEBUG_TIMING
659   printf("%s:\n", filename);
660   debug_print_timestamp(2, "   READING PCX FILE TO IMAGE: ");
661 #endif
662
663   screen = DefaultScreen(display);
664   visual = DefaultVisual(display, screen);
665   depth = DefaultDepth(display, screen);
666
667   /* convert image structure to X11 Pixmap */
668   if (!(ximageinfo = Image_to_Pixmap(display, screen, visual,
669                                      window, gc, depth, image)))
670   {
671     freeImage(image);
672
673     return PCX_OtherError;
674   }
675
676   /* if a private colormap has been created, install it */
677   if (ximageinfo->cmap != DefaultColormap(display, screen))
678     XSetWindowColormap(display, window, ximageinfo->cmap);
679
680 #if DEBUG_TIMING
681   debug_print_timestamp(2, "   CONVERTING IMAGE TO PIXMAP:");
682 #endif
683
684   /* create clip mask for the image */
685   ximageinfo->pixmap_mask = Image_to_Mask(image, display, window);
686
687 #if DEBUG_TIMING
688   debug_print_timestamp(2, "   CONVERTING IMAGE TO MASK:  ");
689 #endif
690
691   *pixmap = ximageinfo->pixmap;
692   *pixmap_mask = ximageinfo->pixmap_mask;
693
694   /* free generic image and ximageinfo after native Pixmap has been created */
695   free(ximageinfo);
696   freeImage(image);
697
698   return PCX_Success;
699 }
700
701 #endif  /* PLATFORM_UNIX */
702 #endif  /* TARGET_X11 */
703
704
705 /* ========================================================================= */
706 /* PLATFORM INDEPENDENT IMAGE FUNCTIONS                                      */
707 /* ========================================================================= */
708
709 struct ImageInfo
710 {
711   char *source_filename;
712   int num_references;
713
714   Bitmap *bitmap;
715   boolean contains_small_images;
716 };
717 typedef struct ImageInfo ImageInfo;
718
719 static struct ArtworkListInfo *image_info = NULL;
720
721 static void *Load_PCX(char *filename)
722 {
723   ImageInfo *img_info;
724
725 #if 0
726   printf("loading PCX file '%s'\n", filename);
727 #endif
728
729   img_info = checked_calloc(sizeof(ImageInfo));
730
731   if ((img_info->bitmap = LoadImage(filename)) == NULL)
732   {
733     Error(ERR_WARN, "cannot load image file '%s': LoadImage() failed: %s",
734           filename, GetError());
735     free(img_info);
736     return NULL;
737   }
738
739   img_info->source_filename = getStringCopy(filename);
740
741   img_info->contains_small_images = FALSE;
742
743   return img_info;
744 }
745
746 static void FreeImage(void *ptr)
747 {
748   ImageInfo *image = (ImageInfo *)ptr;
749
750   if (image == NULL)
751     return;
752
753   if (image->bitmap)
754     FreeBitmap(image->bitmap);
755
756   if (image->source_filename)
757     free(image->source_filename);
758
759   free(image);
760 }
761
762 int getImageListSize()
763 {
764   return (image_info->num_file_list_entries +
765           image_info->num_dynamic_file_list_entries);
766 }
767
768 struct FileInfo *getImageListEntry(int pos)
769 {
770   int num_list_entries = image_info->num_file_list_entries;
771   int list_pos = (pos < num_list_entries ? pos : pos - num_list_entries);
772
773   return (pos < num_list_entries ? &image_info->file_list[list_pos] :
774           &image_info->dynamic_file_list[list_pos]);
775 }
776
777 static ImageInfo *getImageInfoEntryFromImageID(int pos)
778 {
779   int num_list_entries = image_info->num_file_list_entries;
780   int list_pos = (pos < num_list_entries ? pos : pos - num_list_entries);
781   ImageInfo **img_info =
782     (ImageInfo **)(pos < num_list_entries ? image_info->artwork_list :
783                    image_info->dynamic_artwork_list);
784
785   return img_info[list_pos];
786 }
787
788 Bitmap *getBitmapFromImageID(int pos)
789 {
790 #if 0
791   int num_list_entries = image_info->num_file_list_entries;
792   int list_pos = (pos < num_list_entries ? pos : pos - num_list_entries);
793   ImageInfo **img_info =
794     (ImageInfo **)(pos < num_list_entries ? image_info->artwork_list :
795                    image_info->dynamic_artwork_list);
796
797   return (img_info[list_pos] != NULL ? img_info[list_pos]->bitmap : NULL);
798 #else
799   ImageInfo *img_info = getImageInfoEntryFromImageID(pos);
800
801   return (img_info != NULL ? img_info->bitmap : NULL);
802 #endif
803 }
804
805 char *getTokenFromImageID(int graphic)
806 {
807 #if 0
808   /* !!! this does not work for dynamic artwork (crash!) !!! */
809   struct FileInfo *file_list = (struct FileInfo *)image_info->file_list;
810
811   return file_list[graphic].token;
812 #else
813   struct FileInfo *file_list = getImageListEntry(graphic);
814
815   return (file_list != NULL ? file_list->token : NULL);
816 #endif
817 }
818
819 int getImageIDFromToken(char *token)
820 {
821   struct FileInfo *file_list = image_info->file_list;
822   int num_list_entries = image_info->num_file_list_entries;
823   int i;
824
825   for (i = 0; i < num_list_entries; i++)
826     if (strcmp(file_list[i].token, token) == 0)
827       return i;
828
829   return -1;
830 }
831
832 char *getImageConfigFilename()
833 {
834   return getCustomArtworkConfigFilename(image_info->type);
835 }
836
837 int getImageListPropertyMappingSize()
838 {
839   return image_info->num_property_mapping_entries;
840 }
841
842 struct PropertyMapping *getImageListPropertyMapping()
843 {
844   return image_info->property_mapping;
845 }
846
847 void InitImageList(struct ConfigInfo *config_list, int num_file_list_entries,
848                    struct ConfigTypeInfo *config_suffix_list,
849                    char **base_prefixes, char **ext1_suffixes,
850                    char **ext2_suffixes, char **ext3_suffixes,
851                    char **ignore_tokens)
852 {
853   int i;
854
855   image_info = checked_calloc(sizeof(struct ArtworkListInfo));
856   image_info->type = ARTWORK_TYPE_GRAPHICS;
857
858   /* ---------- initialize file list and suffix lists ---------- */
859
860   image_info->num_file_list_entries = num_file_list_entries;
861   image_info->num_dynamic_file_list_entries = 0;
862
863   image_info->file_list =
864     getFileListFromConfigList(config_list, config_suffix_list, ignore_tokens,
865                               num_file_list_entries);
866   image_info->dynamic_file_list = NULL;
867
868   image_info->num_suffix_list_entries = 0;
869   for (i = 0; config_suffix_list[i].token != NULL; i++)
870     image_info->num_suffix_list_entries++;
871
872   image_info->suffix_list = config_suffix_list;
873
874   /* ---------- initialize base prefix and suffixes lists ---------- */
875
876   image_info->num_base_prefixes = 0;
877   for (i = 0; base_prefixes[i] != NULL; i++)
878     image_info->num_base_prefixes++;
879
880   image_info->num_ext1_suffixes = 0;
881   for (i = 0; ext1_suffixes[i] != NULL; i++)
882     image_info->num_ext1_suffixes++;
883
884   image_info->num_ext2_suffixes = 0;
885   for (i = 0; ext2_suffixes[i] != NULL; i++)
886     image_info->num_ext2_suffixes++;
887
888   image_info->num_ext3_suffixes = 0;
889   for (i = 0; ext3_suffixes[i] != NULL; i++)
890     image_info->num_ext3_suffixes++;
891
892   image_info->num_ignore_tokens = 0;
893   for (i = 0; ignore_tokens[i] != NULL; i++)
894     image_info->num_ignore_tokens++;
895
896   image_info->base_prefixes = base_prefixes;
897   image_info->ext1_suffixes = ext1_suffixes;
898   image_info->ext2_suffixes = ext2_suffixes;
899   image_info->ext3_suffixes = ext3_suffixes;
900   image_info->ignore_tokens = ignore_tokens;
901
902   image_info->num_property_mapping_entries = 0;
903
904   image_info->property_mapping = NULL;
905
906   /* ---------- initialize artwork reference and content lists ---------- */
907
908   image_info->sizeof_artwork_list_entry = sizeof(ImageInfo *);
909
910   image_info->artwork_list =
911     checked_calloc(num_file_list_entries * sizeof(ImageInfo *));
912   image_info->dynamic_artwork_list = NULL;
913
914   image_info->content_list = NULL;
915
916   /* ---------- initialize artwork loading/freeing functions ---------- */
917
918   image_info->load_artwork = Load_PCX;
919   image_info->free_artwork = FreeImage;
920 }
921
922 void ReloadCustomImages()
923 {
924 #if 0
925   printf("DEBUG: reloading images '%s' ...\n", artwork.gfx_current_identifier);
926 #endif
927
928   LoadArtworkConfig(image_info);
929   ReloadCustomArtworkList(image_info);
930 }
931
932 void CreateImageWithSmallImages(int pos)
933 {
934   ImageInfo *img_info = getImageInfoEntryFromImageID(pos);
935
936   if (img_info == NULL || img_info->contains_small_images)
937     return;
938
939   CreateBitmapWithSmallBitmaps(img_info->bitmap);
940
941   img_info->contains_small_images = TRUE;
942
943 #if 0
944   printf("CreateImageWithSmallImages: '%s' done\n", img_info->source_filename);
945 #endif
946 }
947
948 void FreeAllImages()
949 {
950   FreeCustomArtworkLists(image_info);
951 }