rocksndiamonds-1.2.0
[rocksndiamonds.git] / src / image.c
index d75de85516a59de7dd74c26286c30d30fb9a192c..09a75fcee078a7eb6628042246a6acd67ecef6be 100644 (file)
-
-/* image.c */
+/***********************************************************
+*  Rocks'n'Diamonds -- McDuffin Strikes Back!              *
+*----------------------------------------------------------*
+*  (c) 1995-98 Artsoft Entertainment                       *
+*              Holger Schemel                              *
+*              Oststrasse 11a                              *
+*              33604 Bielefeld                             *
+*              phone: ++49 +521 290471                     *
+*              email: aeglos@valinor.owl.de                *
+*----------------------------------------------------------*
+*  image.c                                                 *
+***********************************************************/
 
 #include "image.h"
+#include "pcx.h"
 #include "misc.h"
 
-/* extra colors to try allocating in private color maps to minimise flashing */
-#define NOFLASH_COLORS 256
-
-Image *monochrome(Image *cimage)
-{
-  Image         *image;
-  unsigned char *sp, *dp, *dp2; /* data pointers */
-  unsigned int   spl;           /* source pixel length in bytes */
-  unsigned int   dll;           /* destination line length in bytes */
-  Pixel          color;         /* pixel color */
-  unsigned int   x, y;          /* random counters */
-  int bitmap_pixel;
-
-  if (BITMAPP(cimage))
-    return(NULL);
-
-  image = newBitImage(cimage->width, cimage->height);
-
-  spl = cimage->pixlen;
-  dll = (image->width / 8) + (image->width % 8 ? 1 : 0);
-
-  sp = cimage->data;
-  dp = image->data;
-
-  for (y= 0; y < cimage->height; y++)
-  {
-    for (x= 0; x < cimage->width; x++)
-    {
-      dp2 = dp + (x / 8);      /* dp + x/8 */
-      color= memToVal(sp, spl);
-
-      if (cimage->rgb.red[color] > 0x0000 ||
-         cimage->rgb.green[color] > 0x0000 ||
-         cimage->rgb.blue[color] > 0x0000)
-       bitmap_pixel = 0x00;
-      else
-       bitmap_pixel = 0x80;
-
-      *dp2 |= bitmap_pixel >> ( x % 8);
-      sp += spl;
-    }
-
-    dp += dll; /* next row */
-  }
+/* exclude all except newImage() and freeImage() */
+#ifndef MSDOS
 
-  return(image);
-}
+/* extra colors to try allocating in private color maps to minimize flashing */
+#define NOFLASH_COLORS 256
 
-static unsigned int *buildIndex(unsigned int width,
-                               unsigned int zoom,
-                               unsigned int *rwidth)
+/* architecture independent value-to-memory conversion
+   note: the internal format is big endian */
+
+#define value_to_memory(value, ptr, length) (                          \
+(length) == 1 ? (*( (byte *)(ptr)   ) = ( value     ) ) :              \
+(length) == 2 ? (*( (byte *)(ptr)   ) = (((unsigned long)(value))>> 8),        \
+                *(((byte *)(ptr))+1) = ( value     ) ) :               \
+(length) == 3 ? (*( (byte *)(ptr)   ) = (((unsigned long)(value))>>16),        \
+                *(((byte *)(ptr))+1) = (((unsigned long)(value))>> 8), \
+                *(((byte *)(ptr))+2) = ( value     ) ) :               \
+                (*( (byte *)(ptr)   ) = (((unsigned long)(value))>>24),        \
+                *(((byte *)(ptr))+1) = (((unsigned long)(value))>>16), \
+                *(((byte *)(ptr))+2) = (((unsigned long)(value))>> 8), \
+                *(((byte *)(ptr))+3) = ( value     ) ))
+
+static Pixmap Image_to_Mask(Image *image, Display *display, Window window)
 {
-  float         fzoom;
-  unsigned int *index;
-  unsigned int  a;
+  byte *src_ptr, *dst_ptr, *dst_ptr2;
+  unsigned int bytes_per_row;
+  unsigned int x, y;
+  byte bitmask;
+  byte *mask_data;
+  Pixmap mask_pixmap;
+
+  bytes_per_row = (image->width + 7) / 8;
+  mask_data = checked_calloc(bytes_per_row * image->height);
+
+  src_ptr = image->data;
+  dst_ptr = mask_data;
+
+  /* create bitmap data which can be used by 'XCreateBitmapFromData()'
+   * directly to create a pixmap of depth 1 for use as a clip mask for
+   * the corresponding image pixmap
+   */
 
-  if (!zoom)
+  for (y=0; y<image->height; y++)
   {
-    fzoom= 100.0;
-    *rwidth= width;
-  }
-  else
-  {
-    fzoom= (float)zoom / 100.0;
-    *rwidth= (unsigned int)(fzoom * width + 0.5);
-  }
-  index= (unsigned int *)checked_malloc(sizeof(unsigned int) * *rwidth);
-  for (a= 0; a < *rwidth; a++)
-  {
-    if (zoom)
-      *(index + a)= (unsigned int)((float)a / fzoom + 0.5);
-    else
-      *(index + a)= a;
-  }
-  return(index);
-}
-
-Image *zoom(Image *oimage, unsigned int xzoom, unsigned int yzoom)
-{
-  Image        *image;
-  unsigned int *xindex, *yindex;
-  unsigned int  xwidth, ywidth;
-  unsigned int  x, y, xsrc, ysrc;
-  unsigned int  pixlen;
-  unsigned int  srclinelen;
-  unsigned int  destlinelen;
-  byte         *srcline, *srcptr;
-  byte         *destline, *destptr;
-  byte          srcmask, destmask, bit;
-  Pixel         value;
-
-  if ((!xzoom || xzoom==100) && (!yzoom || yzoom==100)) 
-    return(oimage);
-
-  if (!xzoom)
-    printf("  Zooming image Y axis by %d%%...", yzoom);
-  else if (!yzoom)
-    printf("  Zooming image X axis by %d%%...", xzoom);
-  else if (xzoom == yzoom)
-    printf("  Zooming image by %d%%...", xzoom);
-  else
-    printf("  Zooming image X axis by %d%% and Y axis by %d%%...",
-            xzoom, yzoom);
-  fflush(stdout);
-
-  xindex= buildIndex(oimage->width, xzoom, &xwidth);
-  yindex= buildIndex(oimage->height, yzoom, &ywidth);
-
-  switch (oimage->type)
-  {
-    case IBITMAP:
-      image= newBitImage(xwidth, ywidth);
-      for (x= 0; x < oimage->rgb.used; x++)
-      {
-       *(image->rgb.red + x)= *(oimage->rgb.red + x);
-       *(image->rgb.green + x)= *(oimage->rgb.green + x);
-       *(image->rgb.blue + x)= *(oimage->rgb.blue + x);
-      }
-      image->rgb.used= oimage->rgb.used;
-      destline= image->data;
-      destlinelen= (xwidth / 8) + (xwidth % 8 ? 1 : 0);
-      srcline= oimage->data;
-      srclinelen= (oimage->width / 8) + (oimage->width % 8 ? 1 : 0);
-      for (y= 0, ysrc= *(yindex + y); y < ywidth; y++)
-      {
-       while (ysrc != *(yindex + y))
-       {
-         ysrc++;
-         srcline += srclinelen;
-       }
-       srcptr= srcline;
-       destptr= destline;
-       srcmask= 0x80;
-       destmask= 0x80;
-       bit= srcmask & *srcptr;
-       for (x= 0, xsrc= *(xindex + x); x < xwidth; x++)
-       {
-         if (xsrc != *(xindex + x))
-         {
-           do
-           {
-             xsrc++;
-             if (!(srcmask >>= 1))
-             {
-               srcmask= 0x80;
-               srcptr++;
-             }
-           }
-           while (xsrc != *(xindex + x));
-
-           bit= srcmask & *srcptr;
-         }
-         if (bit)
-           *destptr |= destmask;
-         if (!(destmask >>= 1))
-         {
-           destmask= 0x80;
-           destptr++;
-         }
-       }
-       destline += destlinelen;
-      }
-      break;
-
-    case IRGB:
-      image= newRGBImage(xwidth, ywidth, oimage->depth);
-      for (x= 0; x < oimage->rgb.used; x++)
-      {
-       *(image->rgb.red + x)= *(oimage->rgb.red + x);
-       *(image->rgb.green + x)= *(oimage->rgb.green + x);
-       *(image->rgb.blue + x)= *(oimage->rgb.blue + x);
-      }
-      image->rgb.used= oimage->rgb.used;
-
-      pixlen= oimage->pixlen;
-      destptr= image->data;
-      srcline= oimage->data;
-      srclinelen= oimage->width * pixlen;
-      for (y= 0, ysrc= *(yindex + y); y < ywidth; y++)
-      {
-       while (ysrc != *(yindex + y))
-       {
-         ysrc++;
-         srcline += srclinelen;
-       }
-
-       srcptr = srcline;
-       value = memToVal(srcptr, image->pixlen);
-
-       for (x=0, xsrc= *(xindex + x); x<xwidth; x++)
-       {
-         if (xsrc != *(xindex + x))
-         {
-           do
-           {
-             xsrc++;
-             srcptr++;
-           }
-           while (xsrc != *(xindex + x));
-           value = memToVal(srcptr, 1);
-         }
-         valToMem(value, destptr, 1);
-         destptr++;
-       }
-      }
-      break;
-
-    default:
-      /* no zooming */
-      return(oimage);
-      break;
-  }
-
-  free((byte *)xindex);
-  free((byte *)yindex);
-
-  printf("done\n");
+    bitmask = 0x01;            /* start with leftmost bit in the byte     */
+    dst_ptr2 = dst_ptr;                /* start with leftmost byte in the row     */
 
-  return(image);
-}
-
-void compress(Image *image)
-{
-  unsigned char          *used, fast[32][32][32];
-  unsigned int     dmask;       /* Depth mask protection */
-  Pixel           *map;
-  unsigned int     next_index;
-  Intensity *red = image->rgb.red,
-            *green = image->rgb.green,
-            *blue = image->rgb.blue;
-  Intensity r,g,b;
-  unsigned int x, y, badcount = 0, dupcount = 0, unusedcount = 0;
-  unsigned char *pixptr, *pixend;
-
-  if (!RGBP(image) || image->rgb.compressed)
-    return;
-
-  used = (unsigned char *)checked_calloc(sizeof(unsigned char) * depthToColors(image->depth));
-  dmask = (1 << image->depth) -1;      /* Mask any illegal bits for that depth */
-  map = (Pixel *)checked_calloc(sizeof(Pixel) * depthToColors(image->depth));
-
-  /* init fast duplicate check table */
-  for(r=0;r<32;r++)
-    for(g=0;g<32;g++)
-      for(b=0;b<32;b++)
-        fast[r][g][b] = 0;
-
-  /* do pass 1 through the image to check index usage */
-
-  pixptr = image->data;
-  pixend = pixptr + (image->height * image->width);
-  for(;pixptr < pixend; pixptr++)
-    used[(*pixptr) & dmask] = 1;
-
-  /* count the bad pixels */
-  for (x = image->rgb.used; x < depthToColors(image->depth); x++)
-    if (used[x])
-      badcount++;
-
-  /* figure out duplicates and unuseds, and create the new mapping */
-  next_index = 0;
-  for (x = 0; x < image->rgb.used; x++)
-  {
-    if (!used[x])
+    for (x=0; x<image->width; x++)
     {
-      unusedcount++;
-      continue;                /* delete this index */
-    }
+      if (*src_ptr++)          /* source pixel solid? (pixel index != 0)  */
+       *dst_ptr2 |= bitmask;   /* then write a bit into the image mask    */
 
-    /* check for duplicate */
-    r = red[x];
-    g = green[x];
-    b = blue[x];
-    if (fast[r>>11][g>>11][b>>11])     /* if matches fast check */
-    {
-      /* then do a linear search */
-      for (y = x+1; y < image->rgb.used; y++)
+      if ((bitmask <<= 1) == 0)        /* bit at rightmost byte position reached? */
       {
-        if (r == red[y] && g == green[y] && b == blue[y])
-          break;
+       bitmask = 0x01;         /* start again with leftmost bit position  */
+       dst_ptr2++;             /* continue with next byte in image mask   */
       }
-      if (y < image->rgb.used) /* found match */
-      {
-       map[x] = y;
-        dupcount++;
-       continue;               /* delete this index */
-      }
-      fast[r>>11][g>>11][b>>11] = 1;
     }
-    /* will map to this index */
-    map[x] = next_index;
-    next_index++;
-  }
 
-  /* change the image pixels */
-  pixptr = image->data;
-  pixend = pixptr + (image->height * image->width);
-  for(;pixptr < pixend; pixptr++)
-    *pixptr = map[(*pixptr) & dmask];
-
-  /* change the colormap */
-  for (x = 0; x < image->rgb.used; x++)
-  {
-    if (!used[x])
-      continue;
-    red[map[x]] = red[x];
-    green[map[x]] = green[x];
-    blue[map[x]] = blue[x];
+    dst_ptr += bytes_per_row;  /* continue with leftmost byte of next row */
   }
-  image->rgb.used = next_index;
-
-  /* clean up */
-  free(map);
-  free(used);
-
-#if 0
-  if (badcount)
-    printf("%d out-of-range pixels, ", badcount);
 
-  if (!unusedcount && !dupcount)
-    printf("no improvment\n");
-  else
-  {
-    if (dupcount)
-      printf("%d duplicate%s and %d unused color%s removed...",
-            dupcount, (dupcount == 1 ? "" : "s"),
-            unusedcount, (unusedcount == 1 ? "" : "s"));
-    printf("%d unique color%s\n",
-          next_index, (next_index == 1 ? "" : "s"));
-  }
-#endif
+  mask_pixmap = XCreateBitmapFromData(display, window, (char *)mask_data,
+                                     image->width, image->height);
+  free(mask_data);
 
-  image->rgb.compressed= TRUE; /* don't do it again */
+  return mask_pixmap;
 }
 
-
-
-
-Pixmap XImage_to_Pixmap(Display *disp, Window parent, XImageInfo *ximageinfo)
+static int bitsPerPixelAtDepth(Display *display, int screen, int depth)
 {
-  Pixmap pixmap;
+  XPixmapFormatValues *pixmap_format;
+  int i, num_pixmap_formats, bits_per_pixel = -1;
 
-  pixmap = XCreatePixmap(disp, parent,
-                        ximageinfo->ximage->width, ximageinfo->ximage->height,
-                        ximageinfo->depth);
+  /* get Pixmap formats supported by the X server */
+  pixmap_format = XListPixmapFormats(display, &num_pixmap_formats);
 
-  ximageinfo->drawable = pixmap;
+  /* find format that matches the given depth */
+  for (i=0; i<num_pixmap_formats; i++)
+    if (pixmap_format[i].depth == depth)
+      bits_per_pixel = pixmap_format[i].bits_per_pixel;
 
-  XImage_to_Drawable(ximageinfo, 0, 0, 0, 0,
-                    ximageinfo->ximage->width, ximageinfo->ximage->height);
-  return(pixmap);
-}
-
-/* find the best pixmap depth supported by the server for a particular
- * visual and return that depth.
- *
- * this is complicated by R3's lack of XListPixmapFormats so we fake it
- * by looking at the structure ourselves.
- */
+  XFree(pixmap_format);
 
-static unsigned int bitsPerPixelAtDepth(Display *disp, int scrn,
-                                       unsigned int depth)
-{
-  XPixmapFormatValues *xf;
-  int nxf, a;
+  if (bits_per_pixel == -1)
+    Error(ERR_EXIT, "cannot find pixmap format for depth %d", depth);
 
-  xf = XListPixmapFormats(disp, &nxf);
-  for (a = 0; a < nxf; a++)
-  {
-    if (xf[a].depth == depth)
-    {
-      int bpp;
-      bpp = xf[a].bits_per_pixel;
-      XFree(xf);
-      return (unsigned int) bpp;
-    }
-  }
-  XFree(xf);
-
-  /* this should never happen; if it does, we're in trouble
-   */
-
-  fprintf(stderr, "bitsPerPixelAtDepth: Can't find pixmap depth info!\n");
-  exit(1);
+  return bits_per_pixel;
 }
 
-XImageInfo *Image_to_XImage(Display *disp, int scrn, Visual *visual,
-                           unsigned int ddepth, Image *image)
+XImageInfo *Image_to_Pixmap(Display *display, int screen, Visual *visual,
+                           Window window, GC gc, int depth, Image *image)
 {
   static XColor xcolor_private[NOFLASH_COLORS];
   static int colorcell_used[NOFLASH_COLORS];
   static Colormap global_cmap = 0;
   static Pixel *global_cmap_index;
   static int num_cmap_entries, free_cmap_entries;
-  static private_cmap = FALSE;
+  static boolean private_cmap = FALSE;
   Pixel *redvalue, *greenvalue, *bluevalue;
-  unsigned int a, c=0, x, y, linelen, dpixlen, dbits;
+  unsigned int a, c = 0, x, y, bytes_per_pixel, bits_per_pixel;
   XColor xcolor;
-  XGCValues gcv;
+  XImage *ximage;
   XImageInfo *ximageinfo;
+  byte *src_ptr, *dst_ptr;
 
   if (!global_cmap)
   {
-    if (visual == DefaultVisual(disp, scrn))
-      global_cmap = DefaultColormap(disp, scrn);
+    if (visual == DefaultVisual(display, screen))
+      global_cmap = DefaultColormap(display, screen);
     else
     {
-      global_cmap = XCreateColormap(disp, RootWindow(disp, scrn),
-                                        visual, AllocNone);
+      global_cmap = XCreateColormap(display, RootWindow(display, screen),
+                                   visual, AllocNone);
       private_cmap = TRUE;
     }
   }
 
   xcolor.flags = DoRed | DoGreen | DoBlue;
   redvalue = greenvalue = bluevalue = NULL;
-  ximageinfo = (XImageInfo *)checked_malloc(sizeof(XImageInfo));
-  ximageinfo->disp = disp;
-  ximageinfo->scrn = scrn;
-  ximageinfo->depth = 0;
-  ximageinfo->drawable = None;
-  ximageinfo->index = NULL;
-  ximageinfo->rootimage = FALSE;
-  ximageinfo->foreground = ximageinfo->background= 0;
-  ximageinfo->gc = NULL;
-  ximageinfo->ximage = NULL;
+  ximageinfo = checked_malloc(sizeof(XImageInfo));
+  ximageinfo->display = display;
+  ximageinfo->depth = depth;
 
   switch (visual->class)
   {
@@ -450,8 +158,7 @@ XImageInfo *Image_to_XImage(Display *disp, int scrn, Visual *visual,
       retry_direct: /* tag we hit if a DirectColor allocation fails on
                     * default colormap */
 
-      /* calculate number of distinct colors in each band
-       */
+      /* calculate number of distinct colors in each band */
 
       redcolors = greencolors = bluecolors = 1;
       for (pixval=1; pixval; pixval <<= 1)
@@ -464,15 +171,11 @@ XImageInfo *Image_to_XImage(Display *disp, int scrn, Visual *visual,
          bluecolors <<= 1;
       }
       
-      /* sanity check
-       */
-
-      if ((redcolors > visual->map_entries) ||
-         (greencolors > visual->map_entries) ||
-         (bluecolors > visual->map_entries))
-      {
-       fprintf(stderr, "Warning: inconsistency in color information (this may be ugly)\n");
-      }
+      /* consistency check */
+      if (redcolors > visual->map_entries ||
+         greencolors > visual->map_entries ||
+         bluecolors > visual->map_entries)
+       Error(ERR_WARN, "inconsistency in color information");
 
       redstep = 256 / redcolors;
       greenstep = 256 / greencolors;
@@ -491,35 +194,32 @@ XImageInfo *Image_to_XImage(Display *disp, int scrn, Visual *visual,
        xcolor.red = (redtop - 1) << 8;
        xcolor.green = (greentop - 1) << 8;
        xcolor.blue = (bluetop - 1) << 8;
-       if (!XAllocColor(disp, ximageinfo->cmap, &xcolor))
+       if (!XAllocColor(display, ximageinfo->cmap, &xcolor))
        {
          /* if an allocation fails for a DirectColor default visual then
-          * we should create a private colormap and try again.
-          */
+            we should create a private colormap and try again. */
 
          if ((visual->class == DirectColor) &&
-             (visual == DefaultVisual(disp, scrn)))
+             (visual == DefaultVisual(display, screen)))
          {
-           global_cmap = XCopyColormapAndFree(disp, global_cmap);
+           global_cmap = XCopyColormapAndFree(display, global_cmap);
            ximageinfo->cmap = global_cmap;
            private_cmap = TRUE;
 
            goto retry_direct;
          }
 
-         /* something completely unexpected happened
-          */
+         /* something completely unexpected happened */
 
          fprintf(stderr, "imageToXImage: XAllocColor failed on a TrueColor/Directcolor visual\n");
-          free((byte *)redvalue);
-          free((byte *)greenvalue);
-          free((byte *)bluevalue);
-          free((byte *)ximageinfo);
-         return(NULL);
+          free(redvalue);
+          free(greenvalue);
+          free(bluevalue);
+          free(ximageinfo);
+         return NULL;
        }
 
-       /* fill in pixel values for each band at this intensity
-        */
+       /* fill in pixel values for each band at this intensity */
 
        while ((redbottom < 256) && (redbottom < redtop))
          redvalue[redbottom++] = xcolor.pixel & visual->red_mask;
@@ -534,33 +234,33 @@ XImageInfo *Image_to_XImage(Display *disp, int scrn, Visual *visual,
     case PseudoColor:
 
       ximageinfo->cmap = global_cmap;
-      ximageinfo->index =
-       (Pixel *)checked_malloc(sizeof(Pixel) * image->rgb.used);
 
-      for (a=0; a<image->rgb.used; a++)
+      for (a=0; a<MAX_COLORS; a++)
       {
        XColor xcolor2;
        unsigned short mask;
        int color_found;
        int i;
-  
+
+       if (!image->rgb.color_used[a])
+         continue;
+
        xcolor.red = *(image->rgb.red + a);
        xcolor.green = *(image->rgb.green + a);
        xcolor.blue = *(image->rgb.blue + a);
   
        /* look if this color already exists in our colormap */
-       if (!XAllocColor(disp, ximageinfo->cmap, &xcolor))
+       if (!XAllocColor(display, ximageinfo->cmap, &xcolor))
        {
          if (!private_cmap)
          {
-           /*
-           printf("switching to private colormap...\n");
-           */
+           if (options.verbose)
+             Error(ERR_RETURN, "switching to private colormap");
 
            /* we just filled up the default colormap -- get a private one
               which contains all already allocated colors */
 
-           global_cmap = XCopyColormapAndFree(disp, global_cmap);
+           global_cmap = XCopyColormapAndFree(display, global_cmap);
            ximageinfo->cmap = global_cmap;
            private_cmap = TRUE;
 
@@ -568,7 +268,7 @@ XImageInfo *Image_to_XImage(Display *disp, int scrn, Visual *visual,
            global_cmap_index =
              (Pixel *)checked_malloc(sizeof(Pixel) * NOFLASH_COLORS);
            for (i=0; i<NOFLASH_COLORS; i++)
-             if (!XAllocColorCells(disp, global_cmap, FALSE, NULL, 0,
+             if (!XAllocColorCells(display, global_cmap, FALSE, NULL, 0,
                                    global_cmap_index + i, 1))
                break;
            num_cmap_entries = free_cmap_entries = i;
@@ -583,8 +283,8 @@ XImageInfo *Image_to_XImage(Display *disp, int scrn, Visual *visual,
            for(i=0; i<num_cmap_entries; i++)
            {
              xcolor2.pixel = *(global_cmap_index + i);
-             XQueryColor(disp, DefaultColormap(disp, scrn), &xcolor2);
-             XStoreColor(disp, global_cmap, &xcolor2);
+             XQueryColor(display, DefaultColormap(display, screen), &xcolor2);
+             XStoreColor(display, global_cmap, &xcolor2);
              xcolor_private[xcolor2.pixel] = xcolor2;
              colorcell_used[xcolor2.pixel] = FALSE;
            }
@@ -633,15 +333,12 @@ XImageInfo *Image_to_XImage(Display *disp, int scrn, Visual *visual,
          }
 
          if (!color_found)             /* no more free color cells */
-         {
-           printf("Sorry, cannot allocate enough colors!\n");
-           exit(0);
-         }
+           Error(ERR_EXIT, "cannot allocate enough color cells");
 
          xcolor.pixel = xcolor2.pixel;
          xcolor_private[xcolor.pixel] = xcolor;
          colorcell_used[xcolor.pixel] = TRUE;
-         XStoreColor(disp, ximageinfo->cmap, &xcolor);
+         XStoreColor(display, ximageinfo->cmap, &xcolor);
          free_cmap_entries--;
        }
 
@@ -656,148 +353,81 @@ XImageInfo *Image_to_XImage(Display *disp, int scrn, Visual *visual,
       break;
   
     default:
-      printf("Sorry, only DirectColor, TrueColor and PseudoColor supported\n");
-      exit(0);
+      Error(ERR_RETURN, "display class not supported");
+      Error(ERR_EXIT, "DirectColor, TrueColor or PseudoColor display needed");
       break;
   }
 
-  /* create an XImage and related colormap based on the image type
-   * we have.
-   */
-
-  /*
-  printf("  Building XImage...");
-  fflush(stdout);
-  */
-
-  switch (image->type)
-  {
-    case IBITMAP:
-    {
-      byte *data;
+#if DEBUG_TIMING
+  debug_print_timestamp(2, "   ALLOCATING IMAGE COLORS:   ");
+#endif
 
-      /* we copy the data to be more consistent
-       */
+  /* create XImage from internal image structure and convert it to Pixmap */
 
-      linelen = ((image->width + 7) / 8);
-      data= checked_malloc(linelen * image->height);
+  bits_per_pixel = bitsPerPixelAtDepth(display, screen, depth);
+  bytes_per_pixel = (bits_per_pixel + 7) / 8;
 
-      memcpy((char *)data, (char *)image->data, linelen * image->height);
+  ximage = XCreateImage(display, visual, depth, ZPixmap, 0,
+                       NULL, image->width, image->height,
+                       8, image->width * bytes_per_pixel);
+  ximage->data =
+    checked_malloc(image->width * image->height * bytes_per_pixel);
+  ximage->byte_order = MSBFirst;
 
-      gcv.function= GXcopy;
-      ximageinfo->ximage= XCreateImage(disp, visual, 1, XYBitmap,
-                                      0, (char *)data, image->width, image->height,
-                                      8, linelen);
+  src_ptr = image->data;
+  dst_ptr = (byte *)ximage->data;
 
-      /* use this if you want to use the bitmap as a mask */
-      ximageinfo->depth = image->depth;
+  switch (visual->class)
+  {
+    case DirectColor:
+    case TrueColor:
+    {
+      Pixel pixval;
 
-      if(visual->class == DirectColor || visual->class == TrueColor)
+      for (y=0; y<image->height; y++)          /* general case */
       {
-        Pixel pixval;
-        dbits= bitsPerPixelAtDepth(disp, scrn, ddepth);
-        dpixlen= (dbits + 7) / 8;
-        pixval= redvalue[image->rgb.red[0] >> 8] |
-                greenvalue[image->rgb.green[0] >> 8] |
-                bluevalue[image->rgb.blue[0] >> 8];
-        ximageinfo->background = pixval;
-        pixval= redvalue[image->rgb.red[1] >> 8] |
-                greenvalue[image->rgb.green[1] >> 8] |
-                bluevalue[image->rgb.blue[1] >> 8];
-        ximageinfo->foreground = pixval;
-      }
-      else     /* Not Direct or True Color */
-      {
-        ximageinfo->foreground = BlackPixel(disp,scrn);
-        ximageinfo->background = WhitePixel(disp,scrn);
+       for (x=0; x<image->width; x++)
+       {
+         pixval = *src_ptr++;
+         pixval =
+           redvalue[image->rgb.red[pixval] >> 8] |
+           greenvalue[image->rgb.green[pixval] >> 8] |
+           bluevalue[image->rgb.blue[pixval] >> 8];
+         value_to_memory(pixval, dst_ptr, bytes_per_pixel);
+         dst_ptr += bytes_per_pixel;
+       }
       }
-      ximageinfo->ximage->bitmap_bit_order= MSBFirst;
-      ximageinfo->ximage->byte_order= MSBFirst;
-
       break;
     }
 
-    case IRGB:
+    case PseudoColor:
     {
-      /* modify image data to match visual and colormap
-       */
-
-      byte *data, *destptr, *srcptr;
-
-      dbits = bitsPerPixelAtDepth(disp, scrn, ddepth); /* bits per pixel */
-      dpixlen = (dbits + 7) / 8;                       /* bytes per pixel */
-
-      ximageinfo->ximage = XCreateImage(disp, visual, ddepth, ZPixmap, 0,
-                                       NULL, image->width, image->height,
-                                       8, image->width * dpixlen);
-
-      data = (byte *)checked_malloc(image->width * image->height * dpixlen);
-      ximageinfo->depth = ddepth;
-      ximageinfo->ximage->data = (char *)data;
-      ximageinfo->ximage->byte_order = MSBFirst;
-      srcptr = image->data;
-      destptr = data;
-
-      switch (visual->class)
+      if (bytes_per_pixel == 1)                        /* (common) special case */
       {
-       case DirectColor:
-       case TrueColor:
-       {
-         Pixel pixval;
-
-         for (y=0; y<image->height; y++)
-         {
-           for (x=0; x<image->width; x++)
-           {
-             pixval = memToVal(srcptr, 1);
-             pixval = redvalue[image->rgb.red[pixval] >> 8] |
-               greenvalue[image->rgb.green[pixval] >> 8] |
-               bluevalue[image->rgb.blue[pixval] >> 8];
-             valToMem(pixval, destptr, dpixlen);
-             srcptr += 1;
-             destptr += dpixlen;
-           }
-         }
-         break;
-       }
-  
-        default:
-       {  
-         if (dpixlen == 1)                     /* most common */
-         {
-           for (y=0; y<image->height; y++)
-           {
-             for (x=0; x<image->width; x++)
-             {
-               *destptr = ximageinfo->index[c + *srcptr];
-               srcptr++;
-               destptr++;
-             }
-           }
-         }
-         else                                  /* less common */
+       for (y=0; y<image->height; y++)
+         for (x=0; x<image->width; x++)
+           *dst_ptr++ = ximageinfo->index[c + *src_ptr++];
+      }
+      else                                     /* general case */
+      {
+       for (y=0; y<image->height; y++)
+       {
+         for (x=0; x<image->width; x++)
          {
-           for (y=0; y<image->height; y++)
-           {
-             for (x=0; x<image->width; x++)
-             {
-               register unsigned long temp;
-               temp = memToVal(srcptr, 1);
-               valToMem(ximageinfo->index[c + temp], destptr, dpixlen);
-               srcptr += 1;
-               destptr += dpixlen;
-             }
-           }
+           value_to_memory(ximageinfo->index[c + *src_ptr++],
+                           dst_ptr, bytes_per_pixel);
+           dst_ptr += bytes_per_pixel;
          }
        }
-       break;
       }
+      break;
     }
-  }
 
-  /*
-  printf("done\n");
-  */
+    default:
+      Error(ERR_RETURN, "display class not supported");
+      Error(ERR_EXIT, "DirectColor, TrueColor or PseudoColor display needed");
+      break;
+  }
 
   if (redvalue)
   {
@@ -806,161 +436,119 @@ XImageInfo *Image_to_XImage(Display *disp, int scrn, Visual *visual,
     free((byte *)bluevalue);
   }
 
-  return(ximageinfo);
-}
+#if DEBUG_TIMING
+  debug_print_timestamp(2, "   CONVERTING IMAGE TO XIMAGE:");
+#endif
 
-/* Given an XImage and a drawable, move a rectangle from the Ximage
- * to the drawable.
- */
+  ximageinfo->pixmap = XCreatePixmap(display, window,
+                                    ximage->width, ximage->height,
+                                    ximageinfo->depth);
 
-void XImage_to_Drawable(XImageInfo *ximageinfo,
-                       int src_x, int src_y, int dst_x, int dst_y,
-                       unsigned int w, unsigned int h)
-{
-  XGCValues gcv;
+  XPutImage(ximageinfo->display, ximageinfo->pixmap, gc,
+           ximage, 0, 0, 0, 0, ximage->width, ximage->height);
 
-  /* build and cache the GC
-   */
+  free(ximage->data);
+  ximage->data = NULL;
+  XDestroyImage(ximage);
 
-  if (!ximageinfo->gc)
-  {
-    gcv.function = GXcopy;
-    if (ximageinfo->ximage->depth == 1)
-    {
-      gcv.foreground = ximageinfo->foreground;
-      gcv.background = ximageinfo->background;
-      ximageinfo->gc = XCreateGC(ximageinfo->disp, ximageinfo->drawable,
-                                GCFunction | GCForeground | GCBackground,
-                                &gcv);
-    }
-    else
-      ximageinfo->gc = XCreateGC(ximageinfo->disp, ximageinfo->drawable,
-                                GCFunction, &gcv);
-  }
-
-  XPutImage(ximageinfo->disp, ximageinfo->drawable, ximageinfo->gc,
-           ximageinfo->ximage, src_x, src_y, dst_x, dst_y, w, h);
+  return(ximageinfo);
 }
 
-/* free up anything cached in the local Ximage structure.
- */
-
 void freeXImage(Image *image, XImageInfo *ximageinfo)
 {
-  if (ximageinfo->index != NULL)       /* if we allocated colors */
-  {
-    if (ximageinfo->no > 0 && !ximageinfo->rootimage)  /* don't free root colors */
-      XFreeColors(ximageinfo->disp, ximageinfo->cmap, ximageinfo->index,
-                 ximageinfo->no, 0);
-    free(ximageinfo->index);
-  }
-  if (ximageinfo->gc)
-    XFreeGC(ximageinfo->disp, ximageinfo->gc);
-  free((byte *)ximageinfo->ximage->data);
-  ximageinfo->ximage->data= NULL;
-  XDestroyImage(ximageinfo->ximage);
-  free((byte *)ximageinfo);
-  /* should we free private color map to ??? */
-}
-
-
-
-/* this table is useful for quick conversions between depth and ncolors
- */
+  if (ximageinfo->index != NULL && ximageinfo->no > 0)
+    XFreeColors(ximageinfo->display, ximageinfo->cmap, ximageinfo->index,
+               ximageinfo->no, 0);
+  /* this       ^^^^^^^^^^^^^^ is wrong, because the used color cells
+   * are somewhere between 0 and MAX_COLORS; there are indeed 'ximageinfo->no'
+   * used color cells, but they are not at array position 0 - 'ximageinfo->no'
+   */
 
-unsigned long DepthToColorsTable[] =
-{
-  /*  0 */ 1,
-  /*  1 */ 2,
-  /*  2 */ 4,
-  /*  3 */ 8,
-  /*  4 */ 16,
-  /*  5 */ 32,
-  /*  6 */ 64,
-  /*  7 */ 128,
-  /*  8 */ 256,
-  /*  9 */ 512,
-  /* 10 */ 1024,
-  /* 11 */ 2048,
-  /* 12 */ 4096,
-  /* 13 */ 8192,
-  /* 14 */ 16384,
-  /* 15 */ 32768,
-  /* 16 */ 65536,
-  /* 17 */ 131072,
-  /* 18 */ 262144,
-  /* 19 */ 524288,
-  /* 20 */ 1048576,
-  /* 21 */ 2097152,
-  /* 22 */ 4194304,
-  /* 23 */ 8388608,
-  /* 24 */ 16777216
-};
-
-void newRGBMapData(RGBMap *rgb, unsigned int size)
-{
-  rgb->used = 0;
-  rgb->size = size;
-  rgb->compressed = FALSE;
-  rgb->red = (Intensity *)checked_malloc(sizeof(Intensity) * size);
-  rgb->green = (Intensity *)checked_malloc(sizeof(Intensity) * size);
-  rgb->blue = (Intensity *)checked_malloc(sizeof(Intensity) * size);
+  free(ximageinfo);
 }
 
-void freeRGBMapData(RGBMap *rgb)
-{
-  free((byte *)rgb->red);
-  free((byte *)rgb->green);
-  free((byte *)rgb->blue);
-}
+#endif /* !MSDOS */
 
-Image *newBitImage(unsigned int width, unsigned int height)
+Image *newImage(unsigned int width, unsigned int height, unsigned int depth)
 {
-  Image        *image;
-  unsigned int  linelen;
-
-  image = (Image *)checked_malloc(sizeof(Image));
-  image->type = IBITMAP;
-  newRGBMapData(&(image->rgb), (unsigned int)2);
-  *(image->rgb.red)= *(image->rgb.green) = *(image->rgb.blue)= 65535;
-  *(image->rgb.red + 1)= *(image->rgb.green + 1) = *(image->rgb.blue + 1)= 0;
-  image->rgb.used = 2;
-  image->width = width;
-  image->height = height;
-  image->depth = 1;
-  linelen = ((width + 7) / 8);
-  image->data = (unsigned char *)checked_calloc(linelen * height);
-  return(image);
-}
+  Image *image;
+  const unsigned int bytes_per_pixel = 1;
+  int i;
 
-Image *newRGBImage(unsigned int width, unsigned int height, unsigned int depth)
-{
-  Image        *image;
-  unsigned int  pixlen, numcolors;
-
-  if (depth == 0)      /* special case for `zero' depth image, which is */
-    depth = 1;         /* sometimes interpreted as `one color' */
-  pixlen = ((depth+7) / 8);
-  numcolors = depthToColors(depth);
-  image = (Image *)checked_malloc(sizeof(Image));
-  image->type = IRGB;
-  newRGBMapData(&(image->rgb), numcolors);
+  if (depth > 8)
+    Error(ERR_EXIT, "images with more than 256 colors are not supported");
+
+  depth = 8;
+  image = checked_malloc(sizeof(Image));
+  image->data = checked_malloc(width * height * bytes_per_pixel);
   image->width = width;
   image->height = height;
   image->depth = depth;
-  image->pixlen = pixlen;
-  image->data = (unsigned char *)checked_malloc(width * height * pixlen);
-  return(image);
+  image->rgb.used = 0;
+  for (i=0; i<MAX_COLORS; i++)
+    image->rgb.color_used[i] = FALSE;
+
+  return image;
 }
 
-void freeImageData(Image *image)
+void freeImage(Image *image)
 {
-  freeRGBMapData(&(image->rgb));
   free(image->data);
+  free(image);
 }
 
-void freeImage(Image *image)
+#ifndef MSDOS
+
+int Read_PCX_to_Pixmap(Display *display, Window window, GC gc, char *filename,
+                      Pixmap *pixmap, Pixmap *pixmap_mask)
 {
-  freeImageData(image);
-  free((byte *)image);
+  Image *image;
+  XImageInfo *ximageinfo;
+  int screen;
+  Visual *visual;
+  int depth;
+
+#if DEBUG_TIMING
+  debug_print_timestamp(2, NULL);      /* initialize timestamp function */
+#endif
+
+  /* read the graphic file in PCX format to image structure */
+  if ((image = Read_PCX_to_Image(filename)) == NULL)
+    return PCX_FileInvalid;
+
+#if DEBUG_TIMING
+  printf("%s:\n", filename);
+  debug_print_timestamp(2, "   READING PCX FILE TO IMAGE: ");
+#endif
+
+  screen = DefaultScreen(display);
+  visual = DefaultVisual(display, screen);
+  depth = DefaultDepth(display, screen);
+
+  /* convert image structure to X11 Pixmap */
+  if (!(ximageinfo = Image_to_Pixmap(display, screen, visual,
+                                    window, gc, depth, image)))
+    Error(ERR_EXIT, "cannot convert Image to Pixmap");
+
+  /* if a private colormap has been created, install it */
+  if (ximageinfo->cmap != DefaultColormap(display, screen))
+    XSetWindowColormap(display, window, ximageinfo->cmap);
+
+#if DEBUG_TIMING
+  debug_print_timestamp(2, "   CONVERTING IMAGE TO PIXMAP:");
+#endif
+
+  /* create clip mask for the image */
+  ximageinfo->pixmap_mask = Image_to_Mask(image, display, window);
+
+#if DEBUG_TIMING
+  debug_print_timestamp(2, "   CONVERTING IMAGE TO MASK:  ");
+#endif
+
+  *pixmap = ximageinfo->pixmap;
+  *pixmap_mask = ximageinfo->pixmap_mask;
+
+  return(PCX_Success);
 }
+
+#endif /* !MSDOS */