rnd-20040820-1-src
[rocksndiamonds.git] / src / libgame / image.c
index 977111f442092dfd43895a9d0677ad6b265b3adc..8ddcc6879fea3fff5a9a2688218579e5e93ee2b7 100644 (file)
@@ -136,8 +136,73 @@ static Pixmap Image_to_Mask(Image *image, Display *display, Window window)
     dst_ptr += bytes_per_row;  /* continue with leftmost byte of next row */
   }
 
-  mask_pixmap = XCreateBitmapFromData(display, window, (char *)mask_data,
-                                     image->width, image->height);
+  if ((mask_pixmap = XCreateBitmapFromData(display, window, (char *)mask_data,
+                                          image->width, image->height))
+      == None)
+    Error(ERR_EXIT, "Image_to_Mask(): XCreateBitmapFromData() failed");
+
+  free(mask_data);
+
+  return mask_pixmap;
+}
+
+Pixmap Pixmap_to_Mask(Pixmap src_pixmap, int src_width, int src_height)
+{
+  XImage *src_ximage;
+  byte *src_ptr, *dst_ptr, *dst_ptr2;
+  int bits_per_pixel;
+  int bytes_per_pixel;
+  unsigned int bytes_per_row;
+  unsigned int x, y, i;
+  byte bitmask;
+  byte *mask_data;
+  Pixmap mask_pixmap;
+
+  /* copy source pixmap to temporary image */
+  if ((src_ximage = XGetImage(display, src_pixmap, 0, 0, src_width, src_height,
+                             AllPlanes, ZPixmap)) == NULL)
+    Error(ERR_EXIT, "Pixmap_to_Mask(): XGetImage() failed");
+
+  bits_per_pixel = src_ximage->bits_per_pixel;
+  bytes_per_pixel = (bits_per_pixel + 7) / 8;
+
+  bytes_per_row = (src_width + 7) / 8;
+  mask_data = checked_calloc(bytes_per_row * src_height);
+
+  src_ptr = (byte *)src_ximage->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
+   */
+
+  for (y = 0; y < src_height; y++)
+  {
+    bitmask = 0x01;            /* start with leftmost bit in the byte     */
+    dst_ptr2 = dst_ptr;                /* start with leftmost byte in the row     */
+
+    for (x = 0; x < src_width; x++)
+    {
+      for (i = 0; i < bytes_per_pixel; i++)
+       if (*src_ptr++)         /* source pixel solid? (pixel index != 0)  */
+         *dst_ptr2 |= bitmask; /* then write a bit into the image mask    */
+
+      if ((bitmask <<= 1) == 0)        /* bit at rightmost byte position reached? */
+      {
+       bitmask = 0x01;         /* start again with leftmost bit position  */
+       dst_ptr2++;             /* continue with next byte in image mask   */
+      }
+    }
+
+    dst_ptr += bytes_per_row;  /* continue with leftmost byte of next row */
+  }
+
+  if ((mask_pixmap = XCreateBitmapFromData(display, window->drawable,
+                                          (char *)mask_data,
+                                          src_width, src_height)) == None)
+    Error(ERR_EXIT, "Pixmap_to_Mask(): XCreateBitmapFromData() failed");
+
   free(mask_data);
 
   return mask_pixmap;
@@ -569,8 +634,10 @@ XImageInfo *Image_to_Pixmap(Display *display, int screen, Visual *visual,
   -----------------------------------------------------------------------------
   ZoomPixmap
 
-  Important note: The scaling code currently only supports scaling down the
-  image by a power of 2 -- scaling up is currently not supported at all!
+  Important note: The scaling code currently only supports scaling of the image
+  up or down by a power of 2 -- other scaling factors currently not supported!
+  Also not supported is scaling of pixmap masks (with depth 1); to scale them,
+  better use Pixmap_to_Mask() for now.
   -----------------------------------------------------------------------------
 */
 
@@ -582,24 +649,39 @@ void ZoomPixmap(Display *display, GC gc, Pixmap src_pixmap, Pixmap dst_pixmap,
   byte *src_ptr, *dst_ptr;
   int bits_per_pixel;
   int bytes_per_pixel;
-  int x, y, i;
-  int zoom_factor = src_width / dst_width;     /* currently very limited! */
+  int x, y, xx, yy, i;
   int row_skip, col_skip;
+  int zoom_factor;
+  boolean scale_down = (src_width > dst_width);
 
-  /* adjust source image size to integer multiple of destination image size */
-  src_width  = dst_width  * zoom_factor;
-  src_height = dst_height * zoom_factor;
+  if (scale_down)
+  {
+    zoom_factor = src_width / dst_width;
+
+    /* adjust source image size to integer multiple of destination size */
+    src_width  = dst_width  * zoom_factor;
+    src_height = dst_height * zoom_factor;
+  }
+  else
+  {
+    zoom_factor = dst_width / src_width;
+
+    /* no adjustment needed when scaling up (some pixels may be left blank) */
+  }
 
   /* copy source pixmap to temporary image */
-  src_ximage = XGetImage(display, src_pixmap, 0, 0, src_width, src_height,
-                        AllPlanes, ZPixmap);
+  if ((src_ximage = XGetImage(display, src_pixmap, 0, 0, src_width, src_height,
+                             AllPlanes, ZPixmap)) == NULL)
+    Error(ERR_EXIT, "ZoomPixmap(): XGetImage() failed");
 
   bits_per_pixel = src_ximage->bits_per_pixel;
   bytes_per_pixel = (bits_per_pixel + 7) / 8;
 
-  dst_ximage = XCreateImage(display, visual, src_ximage->depth, ZPixmap,
-                           0, NULL, dst_width, dst_height,
-                           8, dst_width * bytes_per_pixel);
+  if ((dst_ximage = XCreateImage(display, visual, src_ximage->depth, ZPixmap,
+                                0, NULL, dst_width, dst_height,
+                                8, dst_width * bytes_per_pixel)) == NULL)
+    Error(ERR_EXIT, "ZoomPixmap(): XCreateImage() failed");
+
   dst_ximage->data =
     checked_malloc(dst_width * dst_height * bytes_per_pixel);
   dst_ximage->byte_order = src_ximage->byte_order;
@@ -607,14 +689,40 @@ void ZoomPixmap(Display *display, GC gc, Pixmap src_pixmap, Pixmap dst_pixmap,
   src_ptr = (byte *)src_ximage->data;
   dst_ptr = (byte *)dst_ximage->data;
 
-  col_skip = (zoom_factor - 1) * bytes_per_pixel;
-  row_skip = col_skip * src_width;
+  if (scale_down)
+  {
+    col_skip = (zoom_factor - 1) * bytes_per_pixel;
+    row_skip = col_skip * src_width;
+
+    /* scale image down by scaling factor 'zoom_factor' */
+    for (y = 0; y < src_height; y += zoom_factor, src_ptr += row_skip)
+      for (x = 0; x < src_width; x += zoom_factor, src_ptr += col_skip)
+       for (i = 0; i < bytes_per_pixel; i++)
+         *dst_ptr++ = *src_ptr++;
+  }
+  else
+  {
+    row_skip = src_width * bytes_per_pixel;
 
-  /* scale image down by scaling factor 'zoom_factor' */
-  for (y = 0; y < src_height; y += zoom_factor, src_ptr += row_skip)
-    for (x = 0; x < src_width; x += zoom_factor, src_ptr += col_skip)
-      for (i = 0; i < bytes_per_pixel; i++)
-       *dst_ptr++ = *src_ptr++;
+    /* scale image up by scaling factor 'zoom_factor' */
+    for (y = 0; y < src_height; y++)
+    {
+      for (yy = 0; yy < zoom_factor; yy++)
+      {
+       if (yy > 0)
+         src_ptr -= row_skip;
+
+       for (x = 0; x < src_width; x++)
+       {
+         for (xx = 0; xx < zoom_factor; xx++)
+           for (i = 0; i < bytes_per_pixel; i++)
+             *dst_ptr++ = *(src_ptr + i);
+
+         src_ptr += i;
+       }
+      }
+    }
+  }
 
   /* copy scaled image to destination pixmap */
   XPutImage(display, dst_pixmap, gc, dst_ximage, 0, 0, 0, 0,