1 /***********************************************************
2 * Rocks'n'Diamonds -- McDuffin Strikes Back! *
3 *----------------------------------------------------------*
4 * (c) 1995-98 Artsoft Entertainment *
8 * phone: ++49 +521 290471 *
9 * email: aeglos@valinor.owl.de *
10 *----------------------------------------------------------*
12 ***********************************************************/
29 /* extra colors to try allocating in private color maps to minimise flashing */
30 #define NOFLASH_COLORS 256
32 static void Image_to_Mask(Image *image)
34 unsigned char *src_ptr, *dst_ptr, *dst_ptr2;
35 unsigned int bytes_per_row;
37 unsigned char bitmask;
39 bytes_per_row = (image->width + 7) / 8;
40 src_ptr = image->data;
41 dst_ptr = image->data_mask;
43 for (y=0; y<image->height; y++)
45 bitmask = 0x80; /* start with leftmost bit in the byte */
46 dst_ptr2 = dst_ptr; /* start with leftmost byte in the row */
48 for (x=0; x<image->width; x++)
50 if (*src_ptr++) /* source pixel solid? (pixel index != 0) */
51 *dst_ptr2 |= bitmask; /* then write a bit into the image mask */
53 if ((bitmask >>= 1) == 0) /* bit at rightmost byte position reached? */
55 bitmask = 0x80; /* start again with leftmost bit position */
56 dst_ptr2++; /* continue with next byte in image mask */
60 dst_ptr += bytes_per_row; /* continue with leftmost byte of next row */
64 static boolean XImage_to_Pixmap(Display *display, Window parent,
65 XImageInfo *ximageinfo)
70 XCreatePixmap(display, parent,
71 ximageinfo->ximage->width,
72 ximageinfo->ximage->height,
75 ximageinfo->pixmap_mask =
76 XCreatePixmap(display, parent,
77 ximageinfo->ximage->width,
78 ximageinfo->ximage->height,
81 /* build and cache the GC */
85 gcv.function = GXcopy;
87 XCreateGC(ximageinfo->display, ximageinfo->pixmap,
91 if (!ximageinfo->gc_mask)
93 gcv.function = GXcopy;
94 gcv.foreground = ximageinfo->foreground;
95 gcv.background = ximageinfo->background;
97 XCreateGC(ximageinfo->display, ximageinfo->pixmap_mask,
98 GCFunction | GCForeground | GCBackground, &gcv);
101 XPutImage(ximageinfo->display, ximageinfo->pixmap, ximageinfo->gc,
102 ximageinfo->ximage, 0, 0, 0, 0,
103 ximageinfo->ximage->width, ximageinfo->ximage->height);
104 XPutImage(ximageinfo->display, ximageinfo->pixmap_mask, ximageinfo->gc_mask,
105 ximageinfo->ximage_mask, 0, 0, 0, 0,
106 ximageinfo->ximage->width, ximageinfo->ximage->height);
108 return (ximageinfo->pixmap != None && ximageinfo->pixmap_mask != None);
111 /* find the best pixmap depth supported by the server for a particular
112 * visual and return that depth.
115 static unsigned int bitsPerPixelAtDepth(Display *display, int screen,
118 XPixmapFormatValues *xf;
121 xf = XListPixmapFormats(display, &nxf);
122 for (a = 0; a < nxf; a++)
124 if (xf[a].depth == depth)
127 bpp = xf[a].bits_per_pixel;
129 return (unsigned int) bpp;
134 /* this should never happen; if it does, we're in trouble */
136 fprintf(stderr, "bitsPerPixelAtDepth: Can't find pixmap depth info!\n");
140 XImageInfo *Image_to_XImage(Display *display, int screen, Visual *visual,
141 unsigned int ddepth, Image *image)
143 static XColor xcolor_private[NOFLASH_COLORS];
144 static int colorcell_used[NOFLASH_COLORS];
145 static Colormap global_cmap = 0;
146 static Pixel *global_cmap_index;
147 static int num_cmap_entries, free_cmap_entries;
148 static boolean private_cmap = FALSE;
149 Pixel *redvalue, *greenvalue, *bluevalue;
150 unsigned int a, c=0, x, y, linelen, dpixlen, dbits;
153 XImageInfo *ximageinfo;
155 /* for building image */
156 byte *data, *destptr, *srcptr;
158 /* for building image mask */
163 if (visual == DefaultVisual(display, screen))
164 global_cmap = DefaultColormap(display, screen);
167 global_cmap = XCreateColormap(display, RootWindow(display, screen),
173 xcolor.flags = DoRed | DoGreen | DoBlue;
174 redvalue = greenvalue = bluevalue = NULL;
175 ximageinfo = (XImageInfo *)checked_malloc(sizeof(XImageInfo));
176 ximageinfo->display = display;
177 ximageinfo->screen = screen;
178 ximageinfo->depth = 0;
179 ximageinfo->drawable = None;
180 ximageinfo->index = NULL;
181 ximageinfo->rootimage = FALSE;
182 ximageinfo->foreground = ximageinfo->background= 0;
183 ximageinfo->gc = NULL;
184 ximageinfo->gc_mask = NULL;
185 ximageinfo->ximage = NULL;
186 ximageinfo->ximage_mask = NULL;
188 switch (visual->class)
194 unsigned int redcolors, greencolors, bluecolors;
195 unsigned int redstep, greenstep, bluestep;
196 unsigned int redbottom, greenbottom, bluebottom;
197 unsigned int redtop, greentop, bluetop;
199 redvalue = (Pixel *)checked_malloc(sizeof(Pixel) * 256);
200 greenvalue = (Pixel *)checked_malloc(sizeof(Pixel) * 256);
201 bluevalue = (Pixel *)checked_malloc(sizeof(Pixel) * 256);
203 ximageinfo->cmap = global_cmap;
205 retry_direct: /* tag we hit if a DirectColor allocation fails on
206 * default colormap */
208 /* calculate number of distinct colors in each band
211 redcolors = greencolors = bluecolors = 1;
212 for (pixval=1; pixval; pixval <<= 1)
214 if (pixval & visual->red_mask)
216 if (pixval & visual->green_mask)
218 if (pixval & visual->blue_mask)
225 if ((redcolors > visual->map_entries) ||
226 (greencolors > visual->map_entries) ||
227 (bluecolors > visual->map_entries))
229 fprintf(stderr, "Warning: inconsistency in color information (this may be ugly)\n");
232 redstep = 256 / redcolors;
233 greenstep = 256 / greencolors;
234 bluestep = 256 / bluecolors;
235 redbottom = greenbottom = bluebottom = 0;
236 redtop = greentop = bluetop = 0;
237 for (a=0; a<visual->map_entries; a++)
240 redtop = redbottom + redstep;
241 if (greenbottom < 256)
242 greentop = greenbottom + greenstep;
243 if (bluebottom < 256)
244 bluetop = bluebottom + bluestep;
246 xcolor.red = (redtop - 1) << 8;
247 xcolor.green = (greentop - 1) << 8;
248 xcolor.blue = (bluetop - 1) << 8;
249 if (!XAllocColor(display, ximageinfo->cmap, &xcolor))
251 /* if an allocation fails for a DirectColor default visual then
252 * we should create a private colormap and try again.
255 if ((visual->class == DirectColor) &&
256 (visual == DefaultVisual(display, screen)))
258 global_cmap = XCopyColormapAndFree(display, global_cmap);
259 ximageinfo->cmap = global_cmap;
265 /* something completely unexpected happened
268 fprintf(stderr, "imageToXImage: XAllocColor failed on a TrueColor/Directcolor visual\n");
269 free((byte *)redvalue);
270 free((byte *)greenvalue);
271 free((byte *)bluevalue);
272 free((byte *)ximageinfo);
276 /* fill in pixel values for each band at this intensity
279 while ((redbottom < 256) && (redbottom < redtop))
280 redvalue[redbottom++] = xcolor.pixel & visual->red_mask;
281 while ((greenbottom < 256) && (greenbottom < greentop))
282 greenvalue[greenbottom++] = xcolor.pixel & visual->green_mask;
283 while ((bluebottom < 256) && (bluebottom < bluetop))
284 bluevalue[bluebottom++] = xcolor.pixel & visual->blue_mask;
291 ximageinfo->cmap = global_cmap;
293 (Pixel *)checked_malloc(sizeof(Pixel) * image->rgb.used);
296 for (a=0; a<image->rgb.used; a++)
299 for (a=0; a<MAX_COLORS; a++)
306 if (!image->rgb.color_used[a])
309 xcolor.red = *(image->rgb.red + a);
310 xcolor.green = *(image->rgb.green + a);
311 xcolor.blue = *(image->rgb.blue + a);
313 /* look if this color already exists in our colormap */
314 if (!XAllocColor(display, ximageinfo->cmap, &xcolor))
319 Error(ERR_RETURN, "switching to private colormap");
321 /* we just filled up the default colormap -- get a private one
322 which contains all already allocated colors */
324 global_cmap = XCopyColormapAndFree(display, global_cmap);
325 ximageinfo->cmap = global_cmap;
328 /* allocate the rest of the color cells read/write */
330 (Pixel *)checked_malloc(sizeof(Pixel) * NOFLASH_COLORS);
331 for (i=0; i<NOFLASH_COLORS; i++)
332 if (!XAllocColorCells(display, global_cmap, FALSE, NULL, 0,
333 global_cmap_index + i, 1))
335 num_cmap_entries = free_cmap_entries = i;
338 printf("We've got %d free colormap entries.\n", free_cmap_entries);
341 /* to minimize colormap flashing, copy default colors and try
342 to keep them as near as possible to the old values */
344 for(i=0; i<num_cmap_entries; i++)
346 xcolor2.pixel = *(global_cmap_index + i);
347 XQueryColor(display, DefaultColormap(display, screen), &xcolor2);
348 XStoreColor(display, global_cmap, &xcolor2);
349 xcolor_private[xcolor2.pixel] = xcolor2;
350 colorcell_used[xcolor2.pixel] = FALSE;
353 /* now we have the default colormap private: all colors we
354 successfully allocated so far are read-only, which is okay,
355 because we don't want to change them anymore -- if we need
356 an existing color again, we get it by XAllocColor; all other
357 colors are read/write and we can set them by XStoreColor,
358 but we will try to overwrite those color cells with our new
359 color which are as close as possible to our new color */
362 /* look for an existing default color close the one we want */
369 for (i=num_cmap_entries-1; i>=0; i--)
371 xcolor2.pixel = *(global_cmap_index + i);
372 xcolor2 = xcolor_private[xcolor2.pixel];
374 if (colorcell_used[xcolor2.pixel])
377 if ((xcolor.red & mask) == (xcolor2.red & mask) &&
378 (xcolor.green & mask) == (xcolor2.green & mask) &&
379 (xcolor.blue & mask) == (xcolor2.blue & mask))
382 printf("replacing color cell %ld with a close color\n",
393 mask = (mask << 1) & 0xffff;
396 if (!color_found) /* no more free color cells */
398 printf("Sorry, cannot allocate enough colors!\n");
402 xcolor.pixel = xcolor2.pixel;
403 xcolor_private[xcolor.pixel] = xcolor;
404 colorcell_used[xcolor.pixel] = TRUE;
405 XStoreColor(display, ximageinfo->cmap, &xcolor);
409 *(ximageinfo->index + a) = xcolor.pixel;
413 printf("still %d free colormap entries\n", free_cmap_entries);
416 ximageinfo->no = a; /* number of pixels allocated for this image */
420 printf("Sorry, only DirectColor, TrueColor and PseudoColor supported\n");
427 printf(" CONVERTING IMAGE TO XIMAGE (COLORMAP) IN %.2f SECONDS\n",
428 (float)(count2-count1)/1000.0);
432 /* CREATE IMAGE ITSELF */
433 /* modify image data to match visual and colormap */
435 dbits = bitsPerPixelAtDepth(display, screen, ddepth);/* bits per pixel */
436 dpixlen = (dbits + 7) / 8; /* bytes per pixel */
438 ximageinfo->ximage = XCreateImage(display, visual, ddepth, ZPixmap, 0,
439 NULL, image->width, image->height,
440 8, image->width * dpixlen);
442 data = (byte *)checked_malloc(image->width * image->height * dpixlen);
443 ximageinfo->depth = ddepth;
444 ximageinfo->ximage->data = (char *)data;
445 ximageinfo->ximage->byte_order = MSBFirst;
446 srcptr = image->data;
449 switch (visual->class)
456 for (y=0; y<image->height; y++)
458 for (x=0; x<image->width; x++)
460 pixval = memToVal(srcptr, 1);
462 redvalue[image->rgb.red[pixval] >> 8] |
463 greenvalue[image->rgb.green[pixval] >> 8] |
464 bluevalue[image->rgb.blue[pixval] >> 8];
465 valToMem(pixval, destptr, dpixlen);
475 if (dpixlen == 1) /* most common */
477 for (y=0; y<image->height; y++)
479 for (x=0; x<image->width; x++)
481 *destptr = ximageinfo->index[c + *srcptr];
487 else /* less common */
489 for (y=0; y<image->height; y++)
491 for (x=0; x<image->width; x++)
493 register unsigned long temp;
494 temp = memToVal(srcptr, 1);
495 valToMem(ximageinfo->index[c + temp], destptr, dpixlen);
504 /* NOW CREATE IMAGE MASK */
505 /* we copy the data to be more consistent */
507 linelen = ((image->width + 7) / 8);
508 data_mask = checked_malloc(linelen * image->height);
510 memcpy((char *)data_mask, (char *)image->data_mask,
511 linelen * image->height);
513 gcv.function = GXcopy;
514 ximageinfo->ximage_mask =
515 XCreateImage(display, visual, 1, XYBitmap, 0, (char *)data_mask,
516 image->width, image->height, 8, linelen);
519 if (visual->class == DirectColor || visual->class == TrueColor)
522 dbits = bitsPerPixelAtDepth(display, screen, ddepth);
523 dpixlen = (dbits + 7) / 8;
525 redvalue[65535 >> 8] |
526 greenvalue[65535 >> 8] |
527 bluevalue[65535 >> 8];
528 ximageinfo->background = pixval;
533 ximageinfo->foreground = pixval;
535 else /* Not Direct or True Color */
537 ximageinfo->foreground = BlackPixel(display, screen);
538 ximageinfo->background = WhitePixel(display, screen);
541 ximageinfo->foreground = WhitePixel(display, screen);
542 ximageinfo->background = BlackPixel(display, screen);
545 ximageinfo->ximage_mask->bitmap_bit_order = MSBFirst;
546 ximageinfo->ximage_mask->byte_order = MSBFirst;
550 free((byte *)redvalue);
551 free((byte *)greenvalue);
552 free((byte *)bluevalue);
558 /* free up anything cached in the local Ximage structure.
561 void freeXImage(Image *image, XImageInfo *ximageinfo)
563 if (ximageinfo->index != NULL) /* if we allocated colors */
565 if (ximageinfo->no > 0 && !ximageinfo->rootimage) /* don't free root colors */
566 XFreeColors(ximageinfo->display, ximageinfo->cmap, ximageinfo->index,
568 free(ximageinfo->index);
571 XFreeGC(ximageinfo->display, ximageinfo->gc);
572 free((byte *)ximageinfo->ximage->data);
573 ximageinfo->ximage->data= NULL;
574 XDestroyImage(ximageinfo->ximage);
575 free((byte *)ximageinfo);
576 /* should we free private color map to ??? */
579 Image *newImage(unsigned int width, unsigned int height, unsigned int depth)
582 unsigned int bytes_per_row;
583 const unsigned int bytes_per_pixel = 1;
587 Error(ERR_EXIT, "images with more than 256 colors are not supported");
590 image = checked_malloc(sizeof(Image));
591 image->data = checked_malloc(width * height * bytes_per_pixel);
592 image->width = width;
593 image->height = height;
594 image->depth = depth;
596 for (i=0; i<MAX_COLORS; i++)
597 image->rgb.color_used[i] = FALSE;
599 bytes_per_row = (width + 7) / 8;
600 image->data_mask = checked_calloc(bytes_per_row * height);
605 void freeImage(Image *image)
608 free(image->data_mask);
612 /* ------------------------------------------------------------------------- */
616 int Read_PCX_to_Pixmaps(Display *display, Window window, char *filename,
617 Pixmap *pixmap, Pixmap *pixmap_mask)
620 XImageInfo *ximageinfo;
623 Image *image, *image_mask;
624 XImageInfo *ximageinfo, *ximageinfo_mask;
635 if ((image = Read_PCX_to_Image(filename)) == NULL)
636 return PCX_FileInvalid;
640 printf(" LOADING '%s' IN %.2f SECONDS\n",
641 filename, (float)(count2-count1)/1000.0);
645 /* create image mask */
646 Image_to_Mask(image);
650 printf(" CONVERTING IMAGE TO MASK IN %.2f SECONDS\n",
651 (float)(count2-count1)/1000.0);
655 screen = DefaultScreen(display);
656 visual = DefaultVisual(display, screen);
657 depth = DefaultDepth(display, screen);
659 /* convert internal image structure to X11 XImage */
660 if (!(ximageinfo = Image_to_XImage(display, screen, visual, depth, image)))
662 fprintf(stderr, "Cannot convert Image to XImage.\n");
668 printf(" CONVERTING IMAGE TO XIMAGE (BITMAP) IN %.2f SECONDS\n",
669 (float)(count2-count1)/1000.0);
673 if (ximageinfo->cmap != DefaultColormap(display, screen))
674 XSetWindowColormap(display, window, ximageinfo->cmap);
676 /* convert XImage to Pixmap */
677 if (!(XImage_to_Pixmap(display, window, ximageinfo)))
679 fprintf(stderr, "Cannot convert XImage to Pixmap.\n");
685 printf(" CONVERTING IMAGE TO PIXMAP IN %.2f SECONDS\n",
686 (float)(count2-count1)/1000.0);
690 *pixmap = ximageinfo->pixmap;
691 *pixmap_mask = ximageinfo->pixmap_mask;