d73c9a5a4afdd112d5f7d8fee937c80e306dbdf8
[rocksndiamonds.git] / src / image.c
1 /***********************************************************
2 *  Rocks'n'Diamonds -- McDuffin Strikes Back!              *
3 *----------------------------------------------------------*
4 *  (c) 1995-98 Artsoft Entertainment                       *
5 *              Holger Schemel                              *
6 *              Oststrasse 11a                              *
7 *              33604 Bielefeld                             *
8 *              phone: ++49 +521 290471                     *
9 *              email: aeglos@valinor.owl.de                *
10 *----------------------------------------------------------*
11 *  image.c                                                 *
12 ***********************************************************/
13
14 #include "image.h"
15 #include "misc.h"
16
17 /* extra colors to try allocating in private color maps to minimise flashing */
18 #define NOFLASH_COLORS 256
19
20 Image *monochrome(Image *cimage)
21 {
22   Image         *image;
23   unsigned char *sp, *dp, *dp2; /* data pointers */
24   unsigned int   spl;           /* source pixel length in bytes */
25   unsigned int   dll;           /* destination line length in bytes */
26   Pixel          color;         /* pixel color */
27   unsigned int   x, y;          /* random counters */
28   int bitmap_pixel;
29
30   if (BITMAPP(cimage))
31   {
32     printf("-->ERROR(monochrome)\n");
33
34     return(NULL);
35   }
36
37   image = newBitImage(cimage->width, cimage->height);
38
39   spl = cimage->pixlen;
40   dll = (image->width / 8) + (image->width % 8 ? 1 : 0);
41
42   sp = cimage->data;
43   dp = image->data;
44
45   for (y=0; y<cimage->height; y++)
46   {
47     for (x=0; x<cimage->width; x++)
48     {
49       dp2 = dp + (x / 8);       /* dp + x/8 */
50       color = memToVal(sp, spl);
51
52       if (cimage->rgb.red[color] > 0x0000 ||
53           cimage->rgb.green[color] > 0x0000 ||
54           cimage->rgb.blue[color] > 0x0000)
55         bitmap_pixel = 0x00;
56       else
57         bitmap_pixel = 0x80;
58
59       *dp2 |= bitmap_pixel >> (x % 8);
60       sp += spl;
61     }
62
63     dp += dll;  /* next row */
64   }
65
66   return(image);
67 }
68
69 static unsigned int *buildIndex(unsigned int width,
70                                 unsigned int zoom,
71                                 unsigned int *rwidth)
72 {
73   float         fzoom;
74   unsigned int *index;
75   unsigned int  a;
76
77   if (!zoom)
78   {
79     fzoom = 100.0;
80     *rwidth = width;
81   }
82   else
83   {
84     fzoom = (float)zoom / 100.0;
85     *rwidth = (unsigned int)(fzoom * width + 0.5);
86   }
87   index = (unsigned int *)checked_malloc(sizeof(unsigned int) * *rwidth);
88   for (a=0; a<*rwidth; a++)
89   {
90     if (zoom)
91       *(index + a) = (unsigned int)((float)a / fzoom + 0.5);
92     else
93       *(index + a) = a;
94   }
95   return(index);
96 }
97
98 Image *zoom(Image *oimage, unsigned int xzoom, unsigned int yzoom)
99 {
100   Image        *image;
101   unsigned int *xindex, *yindex;
102   unsigned int  xwidth, ywidth;
103   unsigned int  x, y, xsrc, ysrc;
104   unsigned int  pixlen;
105   unsigned int  srclinelen;
106   unsigned int  destlinelen;
107   byte         *srcline, *srcptr;
108   byte         *destline, *destptr;
109   byte          srcmask, destmask, bit;
110   Pixel         value;
111
112   if ((!xzoom || xzoom == 100) && (!yzoom || yzoom == 100)) 
113     return(oimage);
114
115   if (!xzoom)
116     printf("  Zooming image Y axis by %d%%...", yzoom);
117   else if (!yzoom)
118     printf("  Zooming image X axis by %d%%...", xzoom);
119   else if (xzoom == yzoom)
120     printf("  Zooming image by %d%%...", xzoom);
121   else
122     printf("  Zooming image X axis by %d%% and Y axis by %d%%...",
123              xzoom, yzoom);
124   fflush(stdout);
125
126   xindex = buildIndex(oimage->width, xzoom, &xwidth);
127   yindex = buildIndex(oimage->height, yzoom, &ywidth);
128
129   switch (oimage->type)
130   {
131     case IBITMAP:
132       image = newBitImage(xwidth, ywidth);
133       for (x=0; x<oimage->rgb.used; x++)
134       {
135         *(image->rgb.red + x) = *(oimage->rgb.red + x);
136         *(image->rgb.green + x) = *(oimage->rgb.green + x);
137         *(image->rgb.blue + x) = *(oimage->rgb.blue + x);
138       }
139       image->rgb.used = oimage->rgb.used;
140       destline = image->data;
141       destlinelen = (xwidth / 8) + (xwidth % 8 ? 1 : 0);
142       srcline = oimage->data;
143       srclinelen = (oimage->width / 8) + (oimage->width % 8 ? 1 : 0);
144       for (y=0, ysrc=*(yindex + y); y<ywidth; y++)
145       {
146         while (ysrc != *(yindex + y))
147         {
148           ysrc++;
149           srcline += srclinelen;
150         }
151         srcptr = srcline;
152         destptr = destline;
153         srcmask = 0x80;
154         destmask = 0x80;
155         bit = srcmask & *srcptr;
156         for (x=0, xsrc=*(xindex + x); x<xwidth; x++)
157         {
158           if (xsrc != *(xindex + x))
159           {
160             do
161             {
162               xsrc++;
163               if (!(srcmask >>= 1))
164               {
165                 srcmask = 0x80;
166                 srcptr++;
167               }
168             }
169             while (xsrc != *(xindex + x));
170
171             bit = srcmask & *srcptr;
172           }
173           if (bit)
174             *destptr |= destmask;
175           if (!(destmask >>= 1))
176           {
177             destmask = 0x80;
178             destptr++;
179           }
180         }
181         destline += destlinelen;
182       }
183       break;
184
185     case IRGB:
186       image = newRGBImage(xwidth, ywidth, oimage->depth);
187       for (x=0; x<oimage->rgb.used; x++)
188       {
189         *(image->rgb.red + x) = *(oimage->rgb.red + x);
190         *(image->rgb.green + x) = *(oimage->rgb.green + x);
191         *(image->rgb.blue + x) = *(oimage->rgb.blue + x);
192       }
193       image->rgb.used = oimage->rgb.used;
194
195       pixlen = oimage->pixlen;
196       destptr = image->data;
197       srcline = oimage->data;
198       srclinelen = oimage->width * pixlen;
199       for (y=0, ysrc=*(yindex + y); y<ywidth; y++)
200       {
201         while (ysrc != *(yindex + y))
202         {
203           ysrc++;
204           srcline += srclinelen;
205         }
206
207         srcptr = srcline;
208         value = memToVal(srcptr, image->pixlen);
209
210         for (x=0, xsrc=*(xindex + x); x<xwidth; x++)
211         {
212           if (xsrc != *(xindex + x))
213           {
214             do
215             {
216               xsrc++;
217               srcptr++;
218             }
219             while (xsrc != *(xindex + x));
220             value = memToVal(srcptr, 1);
221           }
222           valToMem(value, destptr, 1);
223           destptr++;
224         }
225       }
226       break;
227
228     default:
229       /* no zooming */
230       return(oimage);
231       break;
232   }
233
234   free((byte *)xindex);
235   free((byte *)yindex);
236
237   printf("done\n");
238
239   return(image);
240 }
241
242 void compress(Image *image)
243 {
244   unsigned char   *used, fast[32][32][32];
245   unsigned int     dmask;       /* Depth mask protection */
246   Pixel           *map;
247   unsigned int     next_index;
248   Intensity *red = image->rgb.red,
249             *green = image->rgb.green,
250             *blue = image->rgb.blue;
251   Intensity r,g,b;
252   unsigned int x, y, badcount = 0, dupcount = 0, unusedcount = 0;
253   unsigned char *pixptr, *pixend;
254
255   if (!RGBP(image) || image->rgb.compressed)
256     return;
257
258   used = (unsigned char *)checked_calloc(sizeof(unsigned char) * depthToColors(image->depth));
259   dmask = (1 << image->depth) -1;       /* Mask any illegal bits for that depth */
260   map = (Pixel *)checked_calloc(sizeof(Pixel) * depthToColors(image->depth));
261
262   /* init fast duplicate check table */
263   for(r=0;r<32;r++)
264     for(g=0;g<32;g++)
265       for(b=0;b<32;b++)
266         fast[r][g][b] = 0;
267
268   /* do pass 1 through the image to check index usage */
269
270   pixptr = image->data;
271   pixend = pixptr + (image->height * image->width);
272   for(;pixptr < pixend; pixptr++)
273     used[(*pixptr) & dmask] = 1;
274
275   /* count the bad pixels */
276   for (x = image->rgb.used; x < depthToColors(image->depth); x++)
277     if (used[x])
278       badcount++;
279
280   /* figure out duplicates and unuseds, and create the new mapping */
281   next_index = 0;
282   for (x = 0; x < image->rgb.used; x++)
283   {
284     if (!used[x])
285     {
286       unusedcount++;
287       continue;         /* delete this index */
288     }
289
290     /* check for duplicate */
291     r = red[x];
292     g = green[x];
293     b = blue[x];
294     if (fast[r>>11][g>>11][b>>11])      /* if matches fast check */
295     {
296       /* then do a linear search */
297       for (y = x+1; y < image->rgb.used; y++)
298       {
299         if (r == red[y] && g == green[y] && b == blue[y])
300           break;
301       }
302       if (y < image->rgb.used)  /* found match */
303       {
304         map[x] = y;
305         dupcount++;
306         continue;               /* delete this index */
307       }
308       fast[r>>11][g>>11][b>>11] = 1;
309     }
310     /* will map to this index */
311     map[x] = next_index;
312     next_index++;
313   }
314
315   /* change the image pixels */
316   pixptr = image->data;
317   pixend = pixptr + (image->height * image->width);
318   for(;pixptr < pixend; pixptr++)
319     *pixptr = map[(*pixptr) & dmask];
320
321   /* change the colormap */
322   for (x = 0; x < image->rgb.used; x++)
323   {
324     if (!used[x])
325       continue;
326     red[map[x]] = red[x];
327     green[map[x]] = green[x];
328     blue[map[x]] = blue[x];
329   }
330   image->rgb.used = next_index;
331
332   /* clean up */
333   free(map);
334   free(used);
335
336
337
338 #if 0
339   if (badcount)
340     printf("%d out-of-range pixels, ", badcount);
341
342   if (!unusedcount && !dupcount)
343     printf("no improvment\n");
344   else
345   {
346     if (dupcount)
347       printf("%d duplicate%s and %d unused color%s removed...",
348              dupcount, (dupcount == 1 ? "" : "s"),
349              unusedcount, (unusedcount == 1 ? "" : "s"));
350     printf("%d unique color%s\n",
351            next_index, (next_index == 1 ? "" : "s"));
352   }
353 #endif
354
355
356
357   image->rgb.compressed = TRUE; /* don't do it again */
358 }
359
360
361
362
363 Pixmap XImage_to_Pixmap(Display *display, Window parent,
364                         XImageInfo *ximageinfo)
365 {
366   Pixmap pixmap;
367
368   pixmap = XCreatePixmap(display, parent,
369                          ximageinfo->ximage->width, ximageinfo->ximage->height,
370                          ximageinfo->depth);
371
372   ximageinfo->drawable = pixmap;
373
374   XImage_to_Drawable(ximageinfo, 0, 0, 0, 0,
375                      ximageinfo->ximage->width, ximageinfo->ximage->height);
376   return(pixmap);
377 }
378
379 /* find the best pixmap depth supported by the server for a particular
380  * visual and return that depth.
381  *
382  * this is complicated by R3's lack of XListPixmapFormats so we fake it
383  * by looking at the structure ourselves.
384  */
385
386 static unsigned int bitsPerPixelAtDepth(Display *display, int screen,
387                                         unsigned int depth)
388 {
389   XPixmapFormatValues *xf;
390   int nxf, a;
391
392   xf = XListPixmapFormats(display, &nxf);
393   for (a = 0; a < nxf; a++)
394   {
395     if (xf[a].depth == depth)
396     {
397       int bpp;
398       bpp = xf[a].bits_per_pixel;
399       XFree(xf);
400       return (unsigned int) bpp;
401     }
402   }
403   XFree(xf);
404
405   /* this should never happen; if it does, we're in trouble
406    */
407
408   fprintf(stderr, "bitsPerPixelAtDepth: Can't find pixmap depth info!\n");
409   exit(1);
410 }
411
412 XImageInfo *Image_to_XImage(Display *display, int screen, Visual *visual,
413                             unsigned int ddepth, Image *image)
414 {
415   static XColor xcolor_private[NOFLASH_COLORS];
416   static int colorcell_used[NOFLASH_COLORS];
417   static Colormap global_cmap = 0;
418   static Pixel *global_cmap_index;
419   static int num_cmap_entries, free_cmap_entries;
420   static private_cmap = FALSE;
421   Pixel *redvalue, *greenvalue, *bluevalue;
422   unsigned int a, c=0, x, y, linelen, dpixlen, dbits;
423   XColor xcolor;
424   XGCValues gcv;
425   XImageInfo *ximageinfo;
426
427   if (!global_cmap)
428   {
429     if (visual == DefaultVisual(display, screen))
430       global_cmap = DefaultColormap(display, screen);
431     else
432     {
433       global_cmap = XCreateColormap(display, RootWindow(display, screen),
434                                          visual, AllocNone);
435       private_cmap = TRUE;
436     }
437   }
438
439   xcolor.flags = DoRed | DoGreen | DoBlue;
440   redvalue = greenvalue = bluevalue = NULL;
441   ximageinfo = (XImageInfo *)checked_malloc(sizeof(XImageInfo));
442   ximageinfo->display = display;
443   ximageinfo->screen = screen;
444   ximageinfo->depth = 0;
445   ximageinfo->drawable = None;
446   ximageinfo->index = NULL;
447   ximageinfo->rootimage = FALSE;
448   ximageinfo->foreground = ximageinfo->background= 0;
449   ximageinfo->gc = NULL;
450   ximageinfo->ximage = NULL;
451
452   switch (visual->class)
453   {
454     case TrueColor:
455     case DirectColor:
456     {
457       Pixel pixval;
458       unsigned int redcolors, greencolors, bluecolors;
459       unsigned int redstep, greenstep, bluestep;
460       unsigned int redbottom, greenbottom, bluebottom;
461       unsigned int redtop, greentop, bluetop;
462
463       redvalue = (Pixel *)checked_malloc(sizeof(Pixel) * 256);
464       greenvalue = (Pixel *)checked_malloc(sizeof(Pixel) * 256);
465       bluevalue = (Pixel *)checked_malloc(sizeof(Pixel) * 256);
466
467       ximageinfo->cmap = global_cmap;
468
469       retry_direct: /* tag we hit if a DirectColor allocation fails on
470                      * default colormap */
471
472       /* calculate number of distinct colors in each band
473        */
474
475       redcolors = greencolors = bluecolors = 1;
476       for (pixval=1; pixval; pixval <<= 1)
477       {
478         if (pixval & visual->red_mask)
479           redcolors <<= 1;
480         if (pixval & visual->green_mask)
481           greencolors <<= 1;
482         if (pixval & visual->blue_mask)
483           bluecolors <<= 1;
484       }
485       
486       /* sanity check
487        */
488
489       if ((redcolors > visual->map_entries) ||
490           (greencolors > visual->map_entries) ||
491           (bluecolors > visual->map_entries))
492       {
493         fprintf(stderr, "Warning: inconsistency in color information (this may be ugly)\n");
494       }
495
496       redstep = 256 / redcolors;
497       greenstep = 256 / greencolors;
498       bluestep = 256 / bluecolors;
499       redbottom = greenbottom = bluebottom = 0;
500       redtop = greentop = bluetop = 0;
501       for (a=0; a<visual->map_entries; a++)
502       {
503         if (redbottom < 256)
504           redtop = redbottom + redstep;
505         if (greenbottom < 256)
506           greentop = greenbottom + greenstep;
507         if (bluebottom < 256)
508           bluetop = bluebottom + bluestep;
509
510         xcolor.red = (redtop - 1) << 8;
511         xcolor.green = (greentop - 1) << 8;
512         xcolor.blue = (bluetop - 1) << 8;
513         if (!XAllocColor(display, ximageinfo->cmap, &xcolor))
514         {
515           /* if an allocation fails for a DirectColor default visual then
516            * we should create a private colormap and try again.
517            */
518
519           if ((visual->class == DirectColor) &&
520               (visual == DefaultVisual(display, screen)))
521           {
522             global_cmap = XCopyColormapAndFree(display, global_cmap);
523             ximageinfo->cmap = global_cmap;
524             private_cmap = TRUE;
525
526             goto retry_direct;
527           }
528
529           /* something completely unexpected happened
530            */
531
532           fprintf(stderr, "imageToXImage: XAllocColor failed on a TrueColor/Directcolor visual\n");
533           free((byte *)redvalue);
534           free((byte *)greenvalue);
535           free((byte *)bluevalue);
536           free((byte *)ximageinfo);
537           return(NULL);
538         }
539
540         /* fill in pixel values for each band at this intensity
541          */
542
543         while ((redbottom < 256) && (redbottom < redtop))
544           redvalue[redbottom++] = xcolor.pixel & visual->red_mask;
545         while ((greenbottom < 256) && (greenbottom < greentop))
546           greenvalue[greenbottom++] = xcolor.pixel & visual->green_mask;
547         while ((bluebottom < 256) && (bluebottom < bluetop))
548           bluevalue[bluebottom++] = xcolor.pixel & visual->blue_mask;
549       }
550       break;
551     }
552
553     case PseudoColor:
554
555       ximageinfo->cmap = global_cmap;
556       ximageinfo->index =
557         (Pixel *)checked_malloc(sizeof(Pixel) * image->rgb.used);
558
559       for (a=0; a<image->rgb.used; a++)
560       {
561         XColor xcolor2;
562         unsigned short mask;
563         int color_found;
564         int i;
565   
566         xcolor.red = *(image->rgb.red + a);
567         xcolor.green = *(image->rgb.green + a);
568         xcolor.blue = *(image->rgb.blue + a);
569   
570         /* look if this color already exists in our colormap */
571         if (!XAllocColor(display, ximageinfo->cmap, &xcolor))
572         {
573           if (!private_cmap)
574           {
575             /*
576             printf("switching to private colormap...\n");
577             */
578
579             /* we just filled up the default colormap -- get a private one
580                which contains all already allocated colors */
581
582             global_cmap = XCopyColormapAndFree(display, global_cmap);
583             ximageinfo->cmap = global_cmap;
584             private_cmap = TRUE;
585
586             /* allocate the rest of the color cells read/write */
587             global_cmap_index =
588               (Pixel *)checked_malloc(sizeof(Pixel) * NOFLASH_COLORS);
589             for (i=0; i<NOFLASH_COLORS; i++)
590               if (!XAllocColorCells(display, global_cmap, FALSE, NULL, 0,
591                                     global_cmap_index + i, 1))
592                 break;
593             num_cmap_entries = free_cmap_entries = i;
594
595             /*
596             printf("We've got %d free colormap entries.\n", free_cmap_entries);
597             */
598
599             /* to minimize colormap flashing, copy default colors and try
600                to keep them as near as possible to the old values */
601
602             for(i=0; i<num_cmap_entries; i++)
603             {
604               xcolor2.pixel = *(global_cmap_index + i);
605               XQueryColor(display, DefaultColormap(display, screen), &xcolor2);
606               XStoreColor(display, global_cmap, &xcolor2);
607               xcolor_private[xcolor2.pixel] = xcolor2;
608               colorcell_used[xcolor2.pixel] = FALSE;
609             }
610
611             /* now we have the default colormap private: all colors we
612                successfully allocated so far are read-only, which is okay,
613                because we don't want to change them anymore -- if we need
614                an existing color again, we get it by XAllocColor; all other
615                colors are read/write and we can set them by XStoreColor,
616                but we will try to overwrite those color cells with our new
617                color which are as close as possible to our new color */
618           }
619
620           /* look for an existing default color close the one we want */
621
622           mask = 0xf000;
623           color_found = FALSE;
624
625           while (!color_found)
626           {
627             for (i=num_cmap_entries-1; i>=0; i--)
628             {
629               xcolor2.pixel = *(global_cmap_index + i);
630               xcolor2 = xcolor_private[xcolor2.pixel];
631
632               if (colorcell_used[xcolor2.pixel])
633                 continue;
634
635               if ((xcolor.red & mask) == (xcolor2.red & mask) &&
636                   (xcolor.green & mask) == (xcolor2.green & mask) &&
637                   (xcolor.blue & mask) == (xcolor2.blue & mask))
638               {
639                 /*
640                 printf("replacing color cell %ld with a close color\n",
641                        xcolor2.pixel);
642                        */
643                 color_found = TRUE;
644                 break;
645               }
646             }
647
648             if (mask == 0x0000)
649               break;
650
651             mask = (mask << 1) & 0xffff;
652           }
653
654           if (!color_found)             /* no more free color cells */
655           {
656             printf("Sorry, cannot allocate enough colors!\n");
657             exit(0);
658           }
659
660           xcolor.pixel = xcolor2.pixel;
661           xcolor_private[xcolor.pixel] = xcolor;
662           colorcell_used[xcolor.pixel] = TRUE;
663           XStoreColor(display, ximageinfo->cmap, &xcolor);
664           free_cmap_entries--;
665         }
666
667         *(ximageinfo->index + a) = xcolor.pixel;
668       }
669
670       /*
671       printf("still %d free colormap entries\n", free_cmap_entries);
672       */
673
674       ximageinfo->no = a;       /* number of pixels allocated for this image */
675       break;
676   
677     default:
678       printf("Sorry, only DirectColor, TrueColor and PseudoColor supported\n");
679       exit(0);
680       break;
681   }
682
683   /* create an XImage and related colormap based on the image type
684    * we have.
685    */
686
687   /*
688   printf("  Building XImage...");
689   fflush(stdout);
690   */
691
692   switch (image->type)
693   {
694     case IBITMAP:
695     {
696       byte *data;
697
698       /* we copy the data to be more consistent
699        */
700
701       linelen = ((image->width + 7) / 8);
702       data= checked_malloc(linelen * image->height);
703
704       memcpy((char *)data, (char *)image->data, linelen * image->height);
705
706       gcv.function= GXcopy;
707       ximageinfo->ximage= XCreateImage(display, visual, 1, XYBitmap,
708                                        0, (char *)data, image->width,
709                                        image->height,
710                                        8, linelen);
711
712       /* use this if you want to use the bitmap as a mask */
713       ximageinfo->depth = image->depth;
714
715       if(visual->class == DirectColor || visual->class == TrueColor)
716       {
717         Pixel pixval;
718         dbits= bitsPerPixelAtDepth(display, screen, ddepth);
719         dpixlen= (dbits + 7) / 8;
720         pixval= redvalue[image->rgb.red[0] >> 8] |
721                 greenvalue[image->rgb.green[0] >> 8] |
722                 bluevalue[image->rgb.blue[0] >> 8];
723         ximageinfo->background = pixval;
724         pixval= redvalue[image->rgb.red[1] >> 8] |
725                 greenvalue[image->rgb.green[1] >> 8] |
726                 bluevalue[image->rgb.blue[1] >> 8];
727         ximageinfo->foreground = pixval;
728       }
729       else      /* Not Direct or True Color */
730       {
731         ximageinfo->foreground = BlackPixel(display, screen);
732         ximageinfo->background = WhitePixel(display, screen);
733       }
734       ximageinfo->ximage->bitmap_bit_order= MSBFirst;
735       ximageinfo->ximage->byte_order= MSBFirst;
736
737       break;
738     }
739
740     case IRGB:
741     {
742       /* modify image data to match visual and colormap
743        */
744
745       byte *data, *destptr, *srcptr;
746
747       dbits = bitsPerPixelAtDepth(display, screen, ddepth);/* bits per pixel */
748       dpixlen = (dbits + 7) / 8;                        /* bytes per pixel */
749
750       ximageinfo->ximage = XCreateImage(display, visual, ddepth, ZPixmap, 0,
751                                         NULL, image->width, image->height,
752                                         8, image->width * dpixlen);
753
754       data = (byte *)checked_malloc(image->width * image->height * dpixlen);
755       ximageinfo->depth = ddepth;
756       ximageinfo->ximage->data = (char *)data;
757       ximageinfo->ximage->byte_order = MSBFirst;
758       srcptr = image->data;
759       destptr = data;
760
761       switch (visual->class)
762       {
763         case DirectColor:
764         case TrueColor:
765         {
766           Pixel pixval;
767
768           for (y=0; y<image->height; y++)
769           {
770             for (x=0; x<image->width; x++)
771             {
772               pixval = memToVal(srcptr, 1);
773               pixval = redvalue[image->rgb.red[pixval] >> 8] |
774                 greenvalue[image->rgb.green[pixval] >> 8] |
775                 bluevalue[image->rgb.blue[pixval] >> 8];
776               valToMem(pixval, destptr, dpixlen);
777               srcptr += 1;
778               destptr += dpixlen;
779             }
780           }
781           break;
782         }
783   
784         default:
785         {  
786           if (dpixlen == 1)                     /* most common */
787           {
788             for (y=0; y<image->height; y++)
789             {
790               for (x=0; x<image->width; x++)
791               {
792                 *destptr = ximageinfo->index[c + *srcptr];
793                 srcptr++;
794                 destptr++;
795               }
796             }
797           }
798           else                                  /* less common */
799           {
800             for (y=0; y<image->height; y++)
801             {
802               for (x=0; x<image->width; x++)
803               {
804                 register unsigned long temp;
805                 temp = memToVal(srcptr, 1);
806                 valToMem(ximageinfo->index[c + temp], destptr, dpixlen);
807                 srcptr += 1;
808                 destptr += dpixlen;
809               }
810             }
811           }
812         }
813         break;
814       }
815     }
816   }
817
818   /*
819   printf("done\n");
820   */
821
822   if (redvalue)
823   {
824     free((byte *)redvalue);
825     free((byte *)greenvalue);
826     free((byte *)bluevalue);
827   }
828
829   return(ximageinfo);
830 }
831
832 /* Given an XImage and a drawable, move a rectangle from the Ximage
833  * to the drawable.
834  */
835
836 void XImage_to_Drawable(XImageInfo *ximageinfo,
837                         int src_x, int src_y, int dst_x, int dst_y,
838                         unsigned int w, unsigned int h)
839 {
840   XGCValues gcv;
841
842   /* build and cache the GC
843    */
844
845   if (!ximageinfo->gc)
846   {
847     gcv.function = GXcopy;
848     if (ximageinfo->ximage->depth == 1)
849     {
850       gcv.foreground = ximageinfo->foreground;
851       gcv.background = ximageinfo->background;
852       ximageinfo->gc = XCreateGC(ximageinfo->display, ximageinfo->drawable,
853                                  GCFunction | GCForeground | GCBackground,
854                                  &gcv);
855     }
856     else
857       ximageinfo->gc = XCreateGC(ximageinfo->display, ximageinfo->drawable,
858                                  GCFunction, &gcv);
859   }
860
861   XPutImage(ximageinfo->display, ximageinfo->drawable, ximageinfo->gc,
862             ximageinfo->ximage, src_x, src_y, dst_x, dst_y, w, h);
863 }
864
865 /* free up anything cached in the local Ximage structure.
866  */
867
868 void freeXImage(Image *image, XImageInfo *ximageinfo)
869 {
870   if (ximageinfo->index != NULL)        /* if we allocated colors */
871   {
872     if (ximageinfo->no > 0 && !ximageinfo->rootimage)   /* don't free root colors */
873       XFreeColors(ximageinfo->display, ximageinfo->cmap, ximageinfo->index,
874                   ximageinfo->no, 0);
875     free(ximageinfo->index);
876   }
877   if (ximageinfo->gc)
878     XFreeGC(ximageinfo->display, ximageinfo->gc);
879   free((byte *)ximageinfo->ximage->data);
880   ximageinfo->ximage->data= NULL;
881   XDestroyImage(ximageinfo->ximage);
882   free((byte *)ximageinfo);
883   /* should we free private color map to ??? */
884 }
885
886
887
888 /* this table is useful for quick conversions between depth and ncolors
889  */
890
891 unsigned long DepthToColorsTable[] =
892 {
893   /*  0 */ 1,
894   /*  1 */ 2,
895   /*  2 */ 4,
896   /*  3 */ 8,
897   /*  4 */ 16,
898   /*  5 */ 32,
899   /*  6 */ 64,
900   /*  7 */ 128,
901   /*  8 */ 256,
902   /*  9 */ 512,
903   /* 10 */ 1024,
904   /* 11 */ 2048,
905   /* 12 */ 4096,
906   /* 13 */ 8192,
907   /* 14 */ 16384,
908   /* 15 */ 32768,
909   /* 16 */ 65536,
910   /* 17 */ 131072,
911   /* 18 */ 262144,
912   /* 19 */ 524288,
913   /* 20 */ 1048576,
914   /* 21 */ 2097152,
915   /* 22 */ 4194304,
916   /* 23 */ 8388608,
917   /* 24 */ 16777216
918 };
919
920 void newRGBMapData(RGBMap *rgb, unsigned int size)
921 {
922   rgb->used = 0;
923   rgb->size = size;
924   rgb->compressed = FALSE;
925   rgb->red = (Intensity *)checked_malloc(sizeof(Intensity) * size);
926   rgb->green = (Intensity *)checked_malloc(sizeof(Intensity) * size);
927   rgb->blue = (Intensity *)checked_malloc(sizeof(Intensity) * size);
928 }
929
930 void freeRGBMapData(RGBMap *rgb)
931 {
932   free((byte *)rgb->red);
933   free((byte *)rgb->green);
934   free((byte *)rgb->blue);
935 }
936
937 Image *newBitImage(unsigned int width, unsigned int height)
938 {
939   Image        *image;
940   unsigned int  linelen;
941
942   image = (Image *)checked_malloc(sizeof(Image));
943   image->type = IBITMAP;
944   newRGBMapData(&(image->rgb), (unsigned int)2);
945   *(image->rgb.red)= *(image->rgb.green) = *(image->rgb.blue)= 65535;
946   *(image->rgb.red + 1)= *(image->rgb.green + 1) = *(image->rgb.blue + 1)= 0;
947   image->rgb.used = 2;
948   image->width = width;
949   image->height = height;
950   image->depth = 1;
951   linelen = ((width + 7) / 8);
952   image->data = (unsigned char *)checked_calloc(linelen * height);
953   return(image);
954 }
955
956 Image *newRGBImage(unsigned int width, unsigned int height, unsigned int depth)
957 {
958   Image        *image;
959   unsigned int  pixlen, numcolors;
960
961   if (depth == 0)       /* special case for `zero' depth image, which is */
962     depth = 1;          /* sometimes interpreted as `one color' */
963   pixlen = ((depth+7) / 8);
964   numcolors = depthToColors(depth);
965   image = (Image *)checked_malloc(sizeof(Image));
966   image->type = IRGB;
967   newRGBMapData(&(image->rgb), numcolors);
968   image->width = width;
969   image->height = height;
970   image->depth = depth;
971   image->pixlen = pixlen;
972   image->data = (unsigned char *)checked_malloc(width * height * pixlen);
973   return(image);
974 }
975
976 void freeImageData(Image *image)
977 {
978   freeRGBMapData(&(image->rgb));
979   free(image->data);
980 }
981
982 void freeImage(Image *image)
983 {
984   freeImageData(image);
985   free((byte *)image);
986 }
987
988 /* ------------------------------------------------------------------------- */
989
990
991 #ifdef DEBUG
992 /*
993 #define DEBUG_TIMING
994 */
995 #endif
996
997
998 int Read_PCX_to_Pixmaps(Display *display, Window window, char *filename,
999                         Pixmap *pixmap, Pixmap *pixmap_mask)
1000 {
1001   Image *image, *image_mask;
1002   XImageInfo *ximageinfo, *ximageinfo_mask;
1003   int screen;
1004   Visual *visual;
1005   unsigned int depth;
1006
1007 #ifdef DEBUG_TIMING
1008   long count1, count2;
1009   count1 = Counter();
1010 #endif
1011
1012   /* load GIF file */
1013   if (!(image = Read_PCX_to_Image(filename)))
1014   {
1015     printf("Loading GIF image failed -- maybe no GIF...\n");
1016     exit(1);
1017   }
1018
1019 #ifdef DEBUG_TIMING
1020   count2 = Counter();
1021   printf("   LOADING '%s' IN %.2f SECONDS\n",
1022          filename, (float)(count2-count1)/1000.0);
1023   count1 = Counter();
1024 #endif
1025
1026   if (image->depth > 8)
1027   {
1028     printf("Sorry, GIFs with more than 256 colors are not supported.\n");
1029     exit(1);
1030   }
1031
1032   /* minimize colormap */
1033   compress(image);
1034
1035 #ifdef DEBUG_TIMING
1036   count2 = Counter();
1037   printf("   COMPRESSING IMAGE COLORMAP IN %.2f SECONDS\n",
1038          (float)(count2-count1)/1000.0);
1039   count1 = Counter();
1040 #endif
1041
1042   screen = DefaultScreen(display);
1043   visual = DefaultVisual(display, screen);
1044   depth = DefaultDepth(display, screen);
1045
1046   /* convert internal image structure to X11 XImage */
1047   if (!(ximageinfo = Image_to_XImage(display, screen, visual, depth, image)))
1048   {
1049     fprintf(stderr, "Cannot convert Image to XImage.\n");
1050     exit(1);
1051   }
1052
1053 #ifdef DEBUG_TIMING
1054   count2 = Counter();
1055   printf("   CONVERTING IMAGE TO XIMAGE IN %.2f SECONDS\n",
1056          (float)(count2-count1)/1000.0);
1057   count1 = Counter();
1058 #endif
1059
1060   if (ximageinfo->cmap != DefaultColormap(display, screen))
1061     XSetWindowColormap(display, window, ximageinfo->cmap);
1062
1063   /* convert XImage to Pixmap */
1064   if ((*pixmap = XImage_to_Pixmap(display, window, ximageinfo)) == None)
1065   {
1066     fprintf(stderr, "Cannot convert XImage to Pixmap.\n");
1067     exit(1);
1068   }
1069
1070 #ifdef DEBUG_TIMING
1071   count2 = Counter();
1072   printf("   CONVERTING IMAGE TO PIXMAP IN %.2f SECONDS\n",
1073          (float)(count2-count1)/1000.0);
1074   count1 = Counter();
1075 #endif
1076
1077   /* create mono image for masking */
1078   image_mask = monochrome(image);
1079
1080 #ifdef DEBUG_TIMING
1081   count2 = Counter();
1082   printf("   CONVERTING IMAGE TO MASK IN %.2f SECONDS\n",
1083          (float)(count2-count1)/1000.0);
1084   count1 = Counter();
1085 #endif
1086
1087   /* convert internal image structure to X11 XImage */
1088   if (!(ximageinfo_mask = Image_to_XImage(display, screen, visual, depth,
1089                                         image_mask)))
1090   {
1091     fprintf(stderr, "Cannot convert Image to XImage.\n");
1092     exit(1);
1093   }
1094
1095 #ifdef DEBUG_TIMING
1096   count2 = Counter();
1097   printf("   CONVERTING MASK TO XIMAGE IN %.2f SECONDS\n",
1098          (float)(count2-count1)/1000.0);
1099   count1 = Counter();
1100 #endif
1101
1102   /* convert XImage to Pixmap */
1103   if ((*pixmap_mask = XImage_to_Pixmap(display, window, ximageinfo_mask)) == None)
1104   {
1105     fprintf(stderr, "Cannot convert XImage to Pixmap.\n");
1106     exit(1);
1107   }
1108
1109 #ifdef DEBUG_TIMING
1110   count2 = Counter();
1111   printf("   CONVERTING MASK TO PIXMAP IN %.2f SECONDS\n",
1112          (float)(count2-count1)/1000.0);
1113   count1 = Counter();
1114 #endif
1115
1116   return(GIF_Success);
1117 }