rnd-20041124-1-src
[rocksndiamonds.git] / src / libgame / image.c
index 42c3384a0cd6c8f518b97138750a370de561134c..1475fe1e45ce4592daa77197704e9d005f5ac1c5 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;
@@ -571,6 +636,8 @@ XImageInfo *Image_to_Pixmap(Display *display, int screen, Visual *visual,
 
   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.
   -----------------------------------------------------------------------------
 */
 
@@ -583,13 +650,9 @@ void ZoomPixmap(Display *display, GC gc, Pixmap src_pixmap, Pixmap dst_pixmap,
   int bits_per_pixel;
   int bytes_per_pixel;
   int x, y, xx, yy, i;
-#if 1
-  boolean scale_down = (src_width > dst_width);
-  int zoom_factor;
-#else
-  int zoom_factor = src_width / dst_width;     /* currently very limited! */
-#endif
   int row_skip, col_skip;
+  int zoom_factor;
+  boolean scale_down = (src_width > dst_width);
 
   if (scale_down)
   {
@@ -607,15 +670,18 @@ void ZoomPixmap(Display *display, GC gc, Pixmap src_pixmap, Pixmap dst_pixmap,
   }
 
   /* 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;
@@ -754,7 +820,12 @@ struct ImageInfo
   int num_references;
 
   Bitmap *bitmap;
-  boolean contains_small_images;
+
+  int original_width;                  /* original image file width */
+  int original_height;                 /* original image file height */
+
+  boolean contains_small_images;       /* set after adding small images */
+  boolean scaled_up;                   /* set after scaling up */
 };
 typedef struct ImageInfo ImageInfo;
 
@@ -780,7 +851,11 @@ static void *Load_PCX(char *filename)
 
   img_info->source_filename = getStringCopy(filename);
 
+  img_info->original_width  = img_info->bitmap->width;
+  img_info->original_height = img_info->bitmap->height;
+
   img_info->contains_small_images = FALSE;
+  img_info->scaled_up = FALSE;
 
   return img_info;
 }
@@ -807,7 +882,7 @@ int getImageListSize()
          image_info->num_dynamic_file_list_entries);
 }
 
-struct FileInfo *getImageListEntry(int pos)
+struct FileInfo *getImageListEntryFromImageID(int pos)
 {
   int num_list_entries = image_info->num_file_list_entries;
   int list_pos = (pos < num_list_entries ? pos : pos - num_list_entries);
@@ -829,33 +904,30 @@ static ImageInfo *getImageInfoEntryFromImageID(int pos)
 
 Bitmap *getBitmapFromImageID(int pos)
 {
-#if 0
-  int num_list_entries = image_info->num_file_list_entries;
-  int list_pos = (pos < num_list_entries ? pos : pos - num_list_entries);
-  ImageInfo **img_info =
-    (ImageInfo **)(pos < num_list_entries ? image_info->artwork_list :
-                  image_info->dynamic_artwork_list);
-
-  return (img_info[list_pos] != NULL ? img_info[list_pos]->bitmap : NULL);
-#else
   ImageInfo *img_info = getImageInfoEntryFromImageID(pos);
 
   return (img_info != NULL ? img_info->bitmap : NULL);
-#endif
 }
 
-char *getTokenFromImageID(int graphic)
+int getOriginalImageWidthFromImageID(int pos)
 {
-#if 0
-  /* !!! this does not work for dynamic artwork (crash!) !!! */
-  struct FileInfo *file_list = (struct FileInfo *)image_info->file_list;
+  ImageInfo *img_info = getImageInfoEntryFromImageID(pos);
+
+  return (img_info != NULL ? img_info->original_width : 0);
+}
+
+int getOriginalImageHeightFromImageID(int pos)
+{
+  ImageInfo *img_info = getImageInfoEntryFromImageID(pos);
 
-  return file_list[graphic].token;
-#else
-  struct FileInfo *file_list = getImageListEntry(graphic);
+  return (img_info != NULL ? img_info->original_height : 0);
+}
+
+char *getTokenFromImageID(int graphic)
+{
+  struct FileInfo *file_list = getImageListEntryFromImageID(graphic);
 
   return (file_list != NULL ? file_list->token : NULL);
-#endif
 }
 
 int getImageIDFromToken(char *token)
@@ -971,16 +1043,23 @@ void ReloadCustomImages()
   ReloadCustomArtworkList(image_info);
 }
 
-void CreateImageWithSmallImages(int pos)
+void CreateImageWithSmallImages(int pos, int zoom_factor)
 {
   ImageInfo *img_info = getImageInfoEntryFromImageID(pos);
 
   if (img_info == NULL || img_info->contains_small_images)
     return;
 
-  CreateBitmapWithSmallBitmaps(img_info->bitmap);
+  CreateBitmapWithSmallBitmaps(img_info->bitmap, zoom_factor);
 
   img_info->contains_small_images = TRUE;
+  img_info->scaled_up = TRUE;
+
+#if 0
+  if (zoom_factor)
+    printf("CreateImageWithSmallImages: '%s' zoomed by factor %d\n",
+          img_info->source_filename, zoom_factor);
+#endif
 
 #if 0
   printf("CreateImageWithSmallImages: '%s' done\n", img_info->source_filename);