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 ***********************************************************/
17 /* extra colors to try allocating in private color maps to minimise flashing */
18 #define NOFLASH_COLORS 256
20 static void Image_to_Mask(Image *image)
22 unsigned char *src_ptr, *dst_ptr, *dst_ptr2;
23 unsigned int bytes_per_row;
25 unsigned char bitmask;
27 bytes_per_row = (image->width + 7) / 8;
28 src_ptr = image->data;
29 dst_ptr = image->data_mask;
31 for (y=0; y<image->height; y++)
33 bitmask = 0x80; /* start with leftmost bit in the byte */
34 dst_ptr2 = dst_ptr; /* start with leftmost byte in the row */
36 for (x=0; x<image->width; x++)
38 if (*src_ptr++) /* source pixel solid? (pixel index != 0) */
39 *dst_ptr2 |= bitmask; /* then write a bit into the image mask */
41 if ((bitmask >>= 1) == 0) /* bit at rightmost byte position reached? */
43 bitmask = 0x80; /* start again with leftmost bit position */
44 dst_ptr2++; /* continue with next byte in image mask */
48 dst_ptr += bytes_per_row; /* continue with leftmost byte of next row */
52 static boolean XImage_to_Pixmap(Display *display, Window parent,
53 XImageInfo *ximageinfo)
58 XCreatePixmap(display, parent,
59 ximageinfo->ximage->width,
60 ximageinfo->ximage->height,
63 ximageinfo->pixmap_mask =
64 XCreatePixmap(display, parent,
65 ximageinfo->ximage->width,
66 ximageinfo->ximage->height,
69 /* build and cache the GC */
73 gcv.function = GXcopy;
75 XCreateGC(ximageinfo->display, ximageinfo->pixmap,
79 if (!ximageinfo->gc_mask)
81 gcv.function = GXcopy;
82 gcv.foreground = ximageinfo->foreground;
83 gcv.background = ximageinfo->background;
85 XCreateGC(ximageinfo->display, ximageinfo->pixmap_mask,
86 GCFunction | GCForeground | GCBackground, &gcv);
89 XPutImage(ximageinfo->display, ximageinfo->pixmap, ximageinfo->gc,
90 ximageinfo->ximage, 0, 0, 0, 0,
91 ximageinfo->ximage->width, ximageinfo->ximage->height);
92 XPutImage(ximageinfo->display, ximageinfo->pixmap_mask, ximageinfo->gc_mask,
93 ximageinfo->ximage_mask, 0, 0, 0, 0,
94 ximageinfo->ximage->width, ximageinfo->ximage->height);
96 return (ximageinfo->pixmap != None && ximageinfo->pixmap_mask != None);
99 /* find the best pixmap depth supported by the server for a particular
100 * visual and return that depth.
103 static unsigned int bitsPerPixelAtDepth(Display *display, int screen,
106 XPixmapFormatValues *xf;
109 xf = XListPixmapFormats(display, &nxf);
110 for (a = 0; a < nxf; a++)
112 if (xf[a].depth == depth)
115 bpp = xf[a].bits_per_pixel;
117 return (unsigned int) bpp;
122 /* this should never happen; if it does, we're in trouble */
124 fprintf(stderr, "bitsPerPixelAtDepth: Can't find pixmap depth info!\n");
128 XImageInfo *Image_to_XImage(Display *display, int screen, Visual *visual,
129 unsigned int ddepth, Image *image)
131 static XColor xcolor_private[NOFLASH_COLORS];
132 static int colorcell_used[NOFLASH_COLORS];
133 static Colormap global_cmap = 0;
134 static Pixel *global_cmap_index;
135 static int num_cmap_entries, free_cmap_entries;
136 static private_cmap = FALSE;
137 Pixel *redvalue, *greenvalue, *bluevalue;
138 unsigned int a, c=0, x, y, linelen, dpixlen, dbits;
141 XImageInfo *ximageinfo;
143 /* for building image */
144 byte *data, *destptr, *srcptr;
146 /* for building image mask */
151 if (visual == DefaultVisual(display, screen))
152 global_cmap = DefaultColormap(display, screen);
155 global_cmap = XCreateColormap(display, RootWindow(display, screen),
161 xcolor.flags = DoRed | DoGreen | DoBlue;
162 redvalue = greenvalue = bluevalue = NULL;
163 ximageinfo = (XImageInfo *)checked_malloc(sizeof(XImageInfo));
164 ximageinfo->display = display;
165 ximageinfo->screen = screen;
166 ximageinfo->depth = 0;
167 ximageinfo->drawable = None;
168 ximageinfo->index = NULL;
169 ximageinfo->rootimage = FALSE;
170 ximageinfo->foreground = ximageinfo->background= 0;
171 ximageinfo->gc = NULL;
172 ximageinfo->gc_mask = NULL;
173 ximageinfo->ximage = NULL;
174 ximageinfo->ximage_mask = NULL;
176 switch (visual->class)
182 unsigned int redcolors, greencolors, bluecolors;
183 unsigned int redstep, greenstep, bluestep;
184 unsigned int redbottom, greenbottom, bluebottom;
185 unsigned int redtop, greentop, bluetop;
187 redvalue = (Pixel *)checked_malloc(sizeof(Pixel) * 256);
188 greenvalue = (Pixel *)checked_malloc(sizeof(Pixel) * 256);
189 bluevalue = (Pixel *)checked_malloc(sizeof(Pixel) * 256);
191 ximageinfo->cmap = global_cmap;
193 retry_direct: /* tag we hit if a DirectColor allocation fails on
194 * default colormap */
196 /* calculate number of distinct colors in each band
199 redcolors = greencolors = bluecolors = 1;
200 for (pixval=1; pixval; pixval <<= 1)
202 if (pixval & visual->red_mask)
204 if (pixval & visual->green_mask)
206 if (pixval & visual->blue_mask)
213 if ((redcolors > visual->map_entries) ||
214 (greencolors > visual->map_entries) ||
215 (bluecolors > visual->map_entries))
217 fprintf(stderr, "Warning: inconsistency in color information (this may be ugly)\n");
220 redstep = 256 / redcolors;
221 greenstep = 256 / greencolors;
222 bluestep = 256 / bluecolors;
223 redbottom = greenbottom = bluebottom = 0;
224 redtop = greentop = bluetop = 0;
225 for (a=0; a<visual->map_entries; a++)
228 redtop = redbottom + redstep;
229 if (greenbottom < 256)
230 greentop = greenbottom + greenstep;
231 if (bluebottom < 256)
232 bluetop = bluebottom + bluestep;
234 xcolor.red = (redtop - 1) << 8;
235 xcolor.green = (greentop - 1) << 8;
236 xcolor.blue = (bluetop - 1) << 8;
237 if (!XAllocColor(display, ximageinfo->cmap, &xcolor))
239 /* if an allocation fails for a DirectColor default visual then
240 * we should create a private colormap and try again.
243 if ((visual->class == DirectColor) &&
244 (visual == DefaultVisual(display, screen)))
246 global_cmap = XCopyColormapAndFree(display, global_cmap);
247 ximageinfo->cmap = global_cmap;
253 /* something completely unexpected happened
256 fprintf(stderr, "imageToXImage: XAllocColor failed on a TrueColor/Directcolor visual\n");
257 free((byte *)redvalue);
258 free((byte *)greenvalue);
259 free((byte *)bluevalue);
260 free((byte *)ximageinfo);
264 /* fill in pixel values for each band at this intensity
267 while ((redbottom < 256) && (redbottom < redtop))
268 redvalue[redbottom++] = xcolor.pixel & visual->red_mask;
269 while ((greenbottom < 256) && (greenbottom < greentop))
270 greenvalue[greenbottom++] = xcolor.pixel & visual->green_mask;
271 while ((bluebottom < 256) && (bluebottom < bluetop))
272 bluevalue[bluebottom++] = xcolor.pixel & visual->blue_mask;
279 ximageinfo->cmap = global_cmap;
281 (Pixel *)checked_malloc(sizeof(Pixel) * image->rgb.used);
284 for (a=0; a<image->rgb.used; a++)
287 for (a=0; a<MAX_COLORS; a++)
294 if (!image->rgb.color_used[a])
297 xcolor.red = *(image->rgb.red + a);
298 xcolor.green = *(image->rgb.green + a);
299 xcolor.blue = *(image->rgb.blue + a);
301 /* look if this color already exists in our colormap */
302 if (!XAllocColor(display, ximageinfo->cmap, &xcolor))
307 Error(ERR_RETURN, "switching to private colormap");
309 /* we just filled up the default colormap -- get a private one
310 which contains all already allocated colors */
312 global_cmap = XCopyColormapAndFree(display, global_cmap);
313 ximageinfo->cmap = global_cmap;
316 /* allocate the rest of the color cells read/write */
318 (Pixel *)checked_malloc(sizeof(Pixel) * NOFLASH_COLORS);
319 for (i=0; i<NOFLASH_COLORS; i++)
320 if (!XAllocColorCells(display, global_cmap, FALSE, NULL, 0,
321 global_cmap_index + i, 1))
323 num_cmap_entries = free_cmap_entries = i;
326 printf("We've got %d free colormap entries.\n", free_cmap_entries);
329 /* to minimize colormap flashing, copy default colors and try
330 to keep them as near as possible to the old values */
332 for(i=0; i<num_cmap_entries; i++)
334 xcolor2.pixel = *(global_cmap_index + i);
335 XQueryColor(display, DefaultColormap(display, screen), &xcolor2);
336 XStoreColor(display, global_cmap, &xcolor2);
337 xcolor_private[xcolor2.pixel] = xcolor2;
338 colorcell_used[xcolor2.pixel] = FALSE;
341 /* now we have the default colormap private: all colors we
342 successfully allocated so far are read-only, which is okay,
343 because we don't want to change them anymore -- if we need
344 an existing color again, we get it by XAllocColor; all other
345 colors are read/write and we can set them by XStoreColor,
346 but we will try to overwrite those color cells with our new
347 color which are as close as possible to our new color */
350 /* look for an existing default color close the one we want */
357 for (i=num_cmap_entries-1; i>=0; i--)
359 xcolor2.pixel = *(global_cmap_index + i);
360 xcolor2 = xcolor_private[xcolor2.pixel];
362 if (colorcell_used[xcolor2.pixel])
365 if ((xcolor.red & mask) == (xcolor2.red & mask) &&
366 (xcolor.green & mask) == (xcolor2.green & mask) &&
367 (xcolor.blue & mask) == (xcolor2.blue & mask))
370 printf("replacing color cell %ld with a close color\n",
381 mask = (mask << 1) & 0xffff;
384 if (!color_found) /* no more free color cells */
386 printf("Sorry, cannot allocate enough colors!\n");
390 xcolor.pixel = xcolor2.pixel;
391 xcolor_private[xcolor.pixel] = xcolor;
392 colorcell_used[xcolor.pixel] = TRUE;
393 XStoreColor(display, ximageinfo->cmap, &xcolor);
397 *(ximageinfo->index + a) = xcolor.pixel;
401 printf("still %d free colormap entries\n", free_cmap_entries);
404 ximageinfo->no = a; /* number of pixels allocated for this image */
408 printf("Sorry, only DirectColor, TrueColor and PseudoColor supported\n");
413 /* CREATE IMAGE ITSELF */
414 /* modify image data to match visual and colormap */
416 dbits = bitsPerPixelAtDepth(display, screen, ddepth);/* bits per pixel */
417 dpixlen = (dbits + 7) / 8; /* bytes per pixel */
419 ximageinfo->ximage = XCreateImage(display, visual, ddepth, ZPixmap, 0,
420 NULL, image->width, image->height,
421 8, image->width * dpixlen);
423 data = (byte *)checked_malloc(image->width * image->height * dpixlen);
424 ximageinfo->depth = ddepth;
425 ximageinfo->ximage->data = (char *)data;
426 ximageinfo->ximage->byte_order = MSBFirst;
427 srcptr = image->data;
430 switch (visual->class)
437 for (y=0; y<image->height; y++)
439 for (x=0; x<image->width; x++)
441 pixval = memToVal(srcptr, 1);
443 redvalue[image->rgb.red[pixval] >> 8] |
444 greenvalue[image->rgb.green[pixval] >> 8] |
445 bluevalue[image->rgb.blue[pixval] >> 8];
446 valToMem(pixval, destptr, dpixlen);
456 if (dpixlen == 1) /* most common */
458 for (y=0; y<image->height; y++)
460 for (x=0; x<image->width; x++)
462 *destptr = ximageinfo->index[c + *srcptr];
468 else /* less common */
470 for (y=0; y<image->height; y++)
472 for (x=0; x<image->width; x++)
474 register unsigned long temp;
475 temp = memToVal(srcptr, 1);
476 valToMem(ximageinfo->index[c + temp], destptr, dpixlen);
485 /* NOW CREATE IMAGE MASK */
486 /* we copy the data to be more consistent */
488 linelen = ((image->width + 7) / 8);
489 data_mask = checked_malloc(linelen * image->height);
491 memcpy((char *)data_mask, (char *)image->data_mask,
492 linelen * image->height);
494 gcv.function = GXcopy;
495 ximageinfo->ximage_mask =
496 XCreateImage(display, visual, 1, XYBitmap, 0, (char *)data_mask,
497 image->width, image->height, 8, linelen);
500 /* use this if you want to use the bitmap as a mask */
502 ximageinfo->depth = image->depth;
505 if (visual->class == DirectColor || visual->class == TrueColor)
508 dbits = bitsPerPixelAtDepth(display, screen, ddepth);
509 dpixlen = (dbits + 7) / 8;
511 redvalue[65535 >> 8] |
512 greenvalue[65535 >> 8] |
513 bluevalue[65535 >> 8];
515 redvalue[image->rgb.red[0] >> 8] |
516 greenvalue[image->rgb.green[0] >> 8] |
517 bluevalue[image->rgb.blue[0] >> 8];
519 ximageinfo->background = pixval;
525 redvalue[image->rgb.red[1] >> 8] |
526 greenvalue[image->rgb.green[1] >> 8] |
527 bluevalue[image->rgb.blue[1] >> 8];
529 ximageinfo->foreground = pixval;
531 else /* Not Direct or True Color */
533 ximageinfo->foreground = BlackPixel(display, screen);
534 ximageinfo->background = WhitePixel(display, screen);
538 ximageinfo->foreground = BlackPixel(display, screen);
539 ximageinfo->background = WhitePixel(display, screen);
542 ximageinfo->foreground = WhitePixel(display, screen);
543 ximageinfo->background = BlackPixel(display, screen);
546 ximageinfo->ximage_mask->bitmap_bit_order = MSBFirst;
547 ximageinfo->ximage_mask->byte_order = MSBFirst;
551 free((byte *)redvalue);
552 free((byte *)greenvalue);
553 free((byte *)bluevalue);
559 /* free up anything cached in the local Ximage structure.
562 void freeXImage(Image *image, XImageInfo *ximageinfo)
564 if (ximageinfo->index != NULL) /* if we allocated colors */
566 if (ximageinfo->no > 0 && !ximageinfo->rootimage) /* don't free root colors */
567 XFreeColors(ximageinfo->display, ximageinfo->cmap, ximageinfo->index,
569 free(ximageinfo->index);
572 XFreeGC(ximageinfo->display, ximageinfo->gc);
573 free((byte *)ximageinfo->ximage->data);
574 ximageinfo->ximage->data= NULL;
575 XDestroyImage(ximageinfo->ximage);
576 free((byte *)ximageinfo);
577 /* should we free private color map to ??? */
580 Image *newImage(unsigned int width, unsigned int height, unsigned int depth)
583 unsigned int bytes_per_row;
584 const unsigned int bytes_per_pixel = 1;
588 Error(ERR_EXIT, "images with more than 256 colors are not supported");
591 image = checked_malloc(sizeof(Image));
592 image->data = checked_malloc(width * height * bytes_per_pixel);
593 image->width = width;
594 image->height = height;
595 image->depth = depth;
597 for (i=0; i<MAX_COLORS; i++)
598 image->rgb.color_used[i] = FALSE;
600 bytes_per_row = (width + 7) / 8;
601 image->data_mask = checked_calloc(bytes_per_row * height);
606 void freeImage(Image *image)
609 free(image->data_mask);
613 /* ------------------------------------------------------------------------- */
623 int Read_PCX_to_Pixmaps(Display *display, Window window, char *filename,
624 Pixmap *pixmap, Pixmap *pixmap_mask)
627 XImageInfo *ximageinfo;
630 Image *image, *image_mask;
631 XImageInfo *ximageinfo, *ximageinfo_mask;
643 if ((image = Read_PCX_to_Image(filename)) == NULL)
644 return PCX_FileInvalid;
648 printf(" LOADING '%s' IN %.2f SECONDS\n",
649 filename, (float)(count2-count1)/1000.0);
653 /* create image mask */
654 Image_to_Mask(image);
658 printf(" CONVERTING IMAGE TO MASK IN %.2f SECONDS\n",
659 (float)(count2-count1)/1000.0);
663 screen = DefaultScreen(display);
664 visual = DefaultVisual(display, screen);
665 depth = DefaultDepth(display, screen);
667 /* convert internal image structure to X11 XImage */
668 if (!(ximageinfo = Image_to_XImage(display, screen, visual, depth, image)))
670 fprintf(stderr, "Cannot convert Image to XImage.\n");
676 printf(" CONVERTING IMAGE TO XIMAGE IN %.2f SECONDS\n",
677 (float)(count2-count1)/1000.0);
681 if (ximageinfo->cmap != DefaultColormap(display, screen))
682 XSetWindowColormap(display, window, ximageinfo->cmap);
684 /* convert XImage to Pixmap */
685 if (!(XImage_to_Pixmap(display, window, ximageinfo)))
687 fprintf(stderr, "Cannot convert XImage to Pixmap.\n");
693 printf(" CONVERTING IMAGE TO PIXMAP IN %.2f SECONDS\n",
694 (float)(count2-count1)/1000.0);
698 *pixmap = ximageinfo->pixmap;
699 *pixmap_mask = ximageinfo->pixmap_mask;