1 /***********************************************************
2 * Artsoft Retro-Game Library *
3 *----------------------------------------------------------*
4 * (c) 1994-2006 Artsoft Entertainment *
5 * Holger Schemel *
6 * Detmolder Strasse 189 *
7 * 33604 Bielefeld *
8 * Germany *
9 * e-mail: info@artsoft.org *
10 *----------------------------------------------------------*
11 * image.c *
12 ***********************************************************/
13
14 #include "image.h"
15 #include "pcx.h"
16 #include "misc.h"
17 #include "setup.h"
18
19
20 /* ========================================================================= */
21 /* PLATFORM SPECIFIC IMAGE FUNCTIONS */
22 /* ========================================================================= */
23
24 #if defined(TARGET_X11)
25
26 /* for MS-DOS/Allegro, exclude all except newImage() and freeImage() */
27
newImage(unsigned int width,unsigned int height,unsigned int depth)28 Image *newImage(unsigned int width, unsigned int height, unsigned int depth)
29 {
30 Image *image;
31 unsigned int bytes_per_pixel = (depth + 7) / 8;
32 int i;
33
34 image = checked_calloc(sizeof(Image));
35 image->data = checked_calloc(width * height * bytes_per_pixel);
36 image->width = width;
37 image->height = height;
38 image->depth = depth;
39 image->bytes_per_pixel = bytes_per_pixel;
40 image->bytes_per_row = width * bytes_per_pixel;
41
42 image->rgb.used = 0;
43 for (i = 0; i < MAX_COLORS; i++)
44 image->rgb.color_used[i] = FALSE;
45
46 image->type = (depth < 8 ? IMAGETYPE_BITMAP :
47 depth > 8 ? IMAGETYPE_TRUECOLOR : IMAGETYPE_RGB);
48
49 return image;
50 }
51
freeImage(Image * image)52 void freeImage(Image *image)
53 {
54 free(image->data);
55 free(image);
56 }
57
58 #if defined(PLATFORM_UNIX)
59
60 /* extra colors to try allocating in private color maps to minimize flashing */
61 #define NOFLASH_COLORS 256
62
63 /* architecture independent value <-> memory conversions;
64 note: the internal format is big endian */
65
66 #define memory_to_value(ptr, len) ( \
67 (len) == 1 ? (unsigned long)( *( (byte *)(ptr)) ) : \
68 (len) == 2 ? (unsigned long)(((unsigned long)(*( (byte *)(ptr)) ))<< 8) \
69 + ( *(((byte *)(ptr))+1) ) : \
70 (len) == 3 ? (unsigned long)(((unsigned long)(*( (byte *)(ptr)) ))<<16) \
71 + (((unsigned long)(*(((byte *)(ptr))+1)))<< 8) \
72 + ( *(((byte *)(ptr))+2) ) : \
73 (unsigned long)(((unsigned long)(*( (byte *)(ptr)) ))<<24) \
74 + (((unsigned long)(*(((byte *)(ptr))+1)))<<16) \
75 + (((unsigned long)(*(((byte *)(ptr))+2)))<< 8) \
76 + ( *(((byte *)(ptr))+3) ) )
77
78
79 #define value_to_memory(value, ptr, len) ( \
80 (len) == 1 ? (*( (byte *)(ptr) ) = ( value ) ) : \
81 (len) == 2 ? (*( (byte *)(ptr) ) = (((unsigned long)(value))>> 8), \
82 *(((byte *)(ptr))+1) = ( value ) ) : \
83 (len) == 3 ? (*( (byte *)(ptr) ) = (((unsigned long)(value))>>16), \
84 *(((byte *)(ptr))+1) = (((unsigned long)(value))>> 8), \
85 *(((byte *)(ptr))+2) = ( value ) ) : \
86 (*( (byte *)(ptr) ) = (((unsigned long)(value))>>24), \
87 *(((byte *)(ptr))+1) = (((unsigned long)(value))>>16), \
88 *(((byte *)(ptr))+2) = (((unsigned long)(value))>> 8), \
89 *(((byte *)(ptr))+3) = ( value ) ))
90
Image_to_Mask(Image * image,Display * display,Window window)91 static Pixmap Image_to_Mask(Image *image, Display *display, Window window)
92 {
93 byte *src_ptr, *dst_ptr, *dst_ptr2;
94 unsigned int bytes_per_row;
95 unsigned int x, y, i;
96 byte bitmask;
97 byte *mask_data;
98 Pixmap mask_pixmap;
99
100 bytes_per_row = (image->width + 7) / 8;
101 mask_data = checked_calloc(bytes_per_row * image->height);
102
103 src_ptr = image->data;
104 dst_ptr = mask_data;
105
106 /* create bitmap data which can be used by 'XCreateBitmapFromData()'
107 * directly to create a pixmap of depth 1 for use as a clip mask for
108 * the corresponding image pixmap
109 */
110
111 for (y = 0; y < image->height; y++)
112 {
113 bitmask = 0x01; /* start with leftmost bit in the byte */
114 dst_ptr2 = dst_ptr; /* start with leftmost byte in the row */
115
116 for (x = 0; x < image->width; x++)
117 {
118 for (i = 0; i < image->bytes_per_pixel; i++)
119 if (*src_ptr++) /* source pixel solid? (pixel index != 0) */
120 *dst_ptr2 |= bitmask; /* then write a bit into the image mask */
121
122 if ((bitmask <<= 1) == 0) /* bit at rightmost byte position reached? */
123 {
124 bitmask = 0x01; /* start again with leftmost bit position */
125 dst_ptr2++; /* continue with next byte in image mask */
126 }
127 }
128
129 dst_ptr += bytes_per_row; /* continue with leftmost byte of next row */
130 }
131
132 if ((mask_pixmap = XCreateBitmapFromData(display, window, (char *)mask_data,
133 image->width, image->height))
134 == None)
135 Error(ERR_EXIT, "Image_to_Mask(): XCreateBitmapFromData() failed");
136
137 free(mask_data);
138
139 return mask_pixmap;
140 }
141
Pixmap_to_Mask(Pixmap src_pixmap,int src_width,int src_height)142 Pixmap Pixmap_to_Mask(Pixmap src_pixmap, int src_width, int src_height)
143 {
144 XImage *src_ximage;
145 byte *src_ptr, *dst_ptr, *dst_ptr2;
146 int bits_per_pixel;
147 int bytes_per_pixel;
148 unsigned int bytes_per_row;
149 unsigned int x, y, i;
150 byte bitmask;
151 byte *mask_data;
152 Pixmap mask_pixmap;
153
154 /* copy source pixmap to temporary image */
155 if ((src_ximage = XGetImage(display, src_pixmap, 0, 0, src_width, src_height,
156 AllPlanes, ZPixmap)) == NULL)
157 Error(ERR_EXIT, "Pixmap_to_Mask(): XGetImage() failed");
158
159 bits_per_pixel = src_ximage->bits_per_pixel;
160 bytes_per_pixel = (bits_per_pixel + 7) / 8;
161
162 bytes_per_row = (src_width + 7) / 8;
163 mask_data = checked_calloc(bytes_per_row * src_height);
164
165 src_ptr = (byte *)src_ximage->data;
166 dst_ptr = mask_data;
167
168 /* create bitmap data which can be used by 'XCreateBitmapFromData()'
169 * directly to create a pixmap of depth 1 for use as a clip mask for
170 * the corresponding image pixmap
171 */
172
173 for (y = 0; y < src_height; y++)
174 {
175 bitmask = 0x01; /* start with leftmost bit in the byte */
176 dst_ptr2 = dst_ptr; /* start with leftmost byte in the row */
177
178 for (x = 0; x < src_width; x++)
179 {
180 for (i = 0; i < bytes_per_pixel; i++)
181 if (*src_ptr++) /* source pixel solid? (pixel index != 0) */
182 *dst_ptr2 |= bitmask; /* then write a bit into the image mask */
183
184 if ((bitmask <<= 1) == 0) /* bit at rightmost byte position reached? */
185 {
186 bitmask = 0x01; /* start again with leftmost bit position */
187 dst_ptr2++; /* continue with next byte in image mask */
188 }
189 }
190
191 dst_ptr += bytes_per_row; /* continue with leftmost byte of next row */
192 }
193
194 if ((mask_pixmap = XCreateBitmapFromData(display, window->drawable,
195 (char *)mask_data,
196 src_width, src_height)) == None)
197 Error(ERR_EXIT, "Pixmap_to_Mask(): XCreateBitmapFromData() failed");
198
199 free(mask_data);
200
201 return mask_pixmap;
202 }
203
bitsPerPixelAtDepth(Display * display,int screen,int depth)204 static int bitsPerPixelAtDepth(Display *display, int screen, int depth)
205 {
206 XPixmapFormatValues *pixmap_format;
207 int i, num_pixmap_formats, bits_per_pixel = -1;
208
209 /* get Pixmap formats supported by the X server */
210 pixmap_format = XListPixmapFormats(display, &num_pixmap_formats);
211
212 /* find format that matches the given depth */
213 for (i = 0; i < num_pixmap_formats; i++)
214 if (pixmap_format[i].depth == depth)
215 bits_per_pixel = pixmap_format[i].bits_per_pixel;
216
217 XFree(pixmap_format);
218
219 if (bits_per_pixel == -1)
220 Error(ERR_EXIT, "cannot find pixmap format for depth %d", depth);
221
222 return bits_per_pixel;
223 }
224
Image_to_Pixmap(Display * display,int screen,Visual * visual,Window window,GC gc,int depth,Image * image)225 XImageInfo *Image_to_Pixmap(Display *display, int screen, Visual *visual,
226 Window window, GC gc, int depth, Image *image)
227 {
228 static XColor xcolor_private[NOFLASH_COLORS];
229 static int colorcell_used[NOFLASH_COLORS];
230 static Colormap global_cmap = 0;
231 static Pixel *global_cmap_index;
232 static int num_cmap_entries, free_cmap_entries;
233 static boolean private_cmap = FALSE;
234 Pixel *redvalue, *greenvalue, *bluevalue;
235 unsigned int display_bytes_per_pixel, display_bits_per_pixel;
236 unsigned int a, c = 0, x, y;
237 XColor xcolor;
238 XImage *ximage;
239 XImageInfo *ximageinfo;
240 byte *src_ptr, *dst_ptr;
241 char *error = "Image_to_Pixmap(): %s";
242
243 if (image->type == IMAGETYPE_TRUECOLOR && depth == 8)
244 {
245 SetError(error, "cannot handle true-color images on 8-bit display");
246 return NULL;
247 }
248
249 if (!global_cmap)
250 {
251 if (visual == DefaultVisual(display, screen))
252 global_cmap = DefaultColormap(display, screen);
253 else
254 {
255 global_cmap = XCreateColormap(display, RootWindow(display, screen),
256 visual, AllocNone);
257 private_cmap = TRUE;
258 }
259 }
260
261 xcolor.flags = DoRed | DoGreen | DoBlue;
262 redvalue = greenvalue = bluevalue = NULL;
263 ximageinfo = checked_malloc(sizeof(XImageInfo));
264 ximageinfo->display = display;
265 ximageinfo->depth = depth;
266
267 switch (visual->class)
268 {
269 case TrueColor:
270 case DirectColor:
271 {
272 Pixel pixval;
273 unsigned int redcolors, greencolors, bluecolors;
274 unsigned int redstep, greenstep, bluestep;
275 unsigned int redbottom, greenbottom, bluebottom;
276 unsigned int redtop, greentop, bluetop;
277
278 redvalue = (Pixel *)checked_malloc(sizeof(Pixel) * 256);
279 greenvalue = (Pixel *)checked_malloc(sizeof(Pixel) * 256);
280 bluevalue = (Pixel *)checked_malloc(sizeof(Pixel) * 256);
281
282 ximageinfo->cmap = global_cmap;
283
284 retry_direct: /* tag we hit if a DirectColor allocation fails on
285 * default colormap */
286
287 /* calculate number of distinct colors in each band */
288
289 redcolors = greencolors = bluecolors = 1;
290 for (pixval = 1; pixval; pixval <<= 1)
291 {
292 if (pixval & visual->red_mask)
293 redcolors <<= 1;
294 if (pixval & visual->green_mask)
295 greencolors <<= 1;
296 if (pixval & visual->blue_mask)
297 bluecolors <<= 1;
298 }
299
300 /* consistency check */
301 if (redcolors > visual->map_entries ||
302 greencolors > visual->map_entries ||
303 bluecolors > visual->map_entries)
304 Error(ERR_WARN, "inconsistency in color information");
305
306 redstep = 256 / redcolors;
307 greenstep = 256 / greencolors;
308 bluestep = 256 / bluecolors;
309 redbottom = greenbottom = bluebottom = 0;
310 redtop = greentop = bluetop = 0;
311
312 for (a = 0; a < visual->map_entries; a++)
313 {
314 if (redbottom < 256)
315 redtop = redbottom + redstep;
316 if (greenbottom < 256)
317 greentop = greenbottom + greenstep;
318 if (bluebottom < 256)
319 bluetop = bluebottom + bluestep;
320
321 xcolor.red = (redtop - 1) << 8;
322 xcolor.green = (greentop - 1) << 8;
323 xcolor.blue = (bluetop - 1) << 8;
324 if (!XAllocColor(display, ximageinfo->cmap, &xcolor))
325 {
326 /* if an allocation fails for a DirectColor default visual then
327 we should create a private colormap and try again. */
328
329 if ((visual->class == DirectColor) &&
330 (visual == DefaultVisual(display, screen)))
331 {
332 global_cmap = XCopyColormapAndFree(display, global_cmap);
333 ximageinfo->cmap = global_cmap;
334 private_cmap = TRUE;
335
336 goto retry_direct;
337 }
338
339 /* something completely unexpected happened */
340
341 fprintf(stderr, "Image_to_Pixmap: XAllocColor failed on a TrueColor/Directcolor visual\n");
342
343 free(redvalue);
344 free(greenvalue);
345 free(bluevalue);
346 free(ximageinfo);
347
348 return NULL;
349 }
350
351 /* fill in pixel values for each band at this intensity */
352
353 while ((redbottom < 256) && (redbottom < redtop))
354 redvalue[redbottom++] = xcolor.pixel & visual->red_mask;
355 while ((greenbottom < 256) && (greenbottom < greentop))
356 greenvalue[greenbottom++] = xcolor.pixel & visual->green_mask;
357 while ((bluebottom < 256) && (bluebottom < bluetop))
358 bluevalue[bluebottom++] = xcolor.pixel & visual->blue_mask;
359 }
360
361 break;
362 }
363
364 case PseudoColor:
365
366 ximageinfo->cmap = global_cmap;
367
368 for (a = 0; a < MAX_COLORS; a++)
369 {
370 XColor xcolor2;
371 unsigned short mask;
372 int color_found;
373 int i;
374
375 if (!image->rgb.color_used[a])
376 continue;
377
378 xcolor.red = *(image->rgb.red + a);
379 xcolor.green = *(image->rgb.green + a);
380 xcolor.blue = *(image->rgb.blue + a);
381
382 /* look if this color already exists in our colormap */
383 if (!XAllocColor(display, ximageinfo->cmap, &xcolor))
384 {
385 if (!private_cmap)
386 {
387 if (options.verbose)
388 Error(ERR_INFO, "switching to private colormap");
389
390 /* we just filled up the default colormap -- get a private one
391 which contains all already allocated colors */
392
393 global_cmap = XCopyColormapAndFree(display, global_cmap);
394 ximageinfo->cmap = global_cmap;
395 private_cmap = TRUE;
396
397 /* allocate the rest of the color cells read/write */
398 global_cmap_index =
399 (Pixel *)checked_malloc(sizeof(Pixel) * NOFLASH_COLORS);
400 for (i = 0; i < NOFLASH_COLORS; i++)
401 if (!XAllocColorCells(display, global_cmap, FALSE, NULL, 0,
402 global_cmap_index + i, 1))
403 break;
404 num_cmap_entries = free_cmap_entries = i;
405
406 /*
407 printf("We've got %d free colormap entries.\n", free_cmap_entries);
408 */
409
410 /* to minimize colormap flashing, copy default colors and try
411 to keep them as near as possible to the old values */
412
413 for (i = 0; i < num_cmap_entries; i++)
414 {
415 xcolor2.pixel = *(global_cmap_index + i);
416 XQueryColor(display, DefaultColormap(display, screen), &xcolor2);
417 XStoreColor(display, global_cmap, &xcolor2);
418 xcolor_private[xcolor2.pixel] = xcolor2;
419 colorcell_used[xcolor2.pixel] = FALSE;
420 }
421
422 /* now we have the default colormap private: all colors we
423 successfully allocated so far are read-only, which is okay,
424 because we don't want to change them anymore -- if we need
425 an existing color again, we get it by XAllocColor; all other
426 colors are read/write and we can set them by XStoreColor,
427 but we will try to overwrite those color cells with our new
428 color which are as close as possible to our new color */
429 }
430
431 /* look for an existing default color close the one we want */
432
433 mask = 0xf000;
434 color_found = FALSE;
435
436 while (!color_found)
437 {
438 for (i = num_cmap_entries - 1; i >= 0; i--)
439 {
440 xcolor2.pixel = *(global_cmap_index + i);
441 xcolor2 = xcolor_private[xcolor2.pixel];
442
443 if (colorcell_used[xcolor2.pixel])
444 continue;
445
446 if ((xcolor.red & mask) == (xcolor2.red & mask) &&
447 (xcolor.green & mask) == (xcolor2.green & mask) &&
448 (xcolor.blue & mask) == (xcolor2.blue & mask))
449 {
450 /*
451 printf("replacing color cell %ld with a close color\n",
452 xcolor2.pixel);
453 */
454 color_found = TRUE;
455 break;
456 }
457 }
458
459 if (mask == 0x0000)
460 break;
461
462 mask = (mask << 1) & 0xffff;
463 }
464
465 if (!color_found) /* no more free color cells */
466 {
467 SetError(error, "cannot allocate enough color cells");
468 return NULL;
469 }
470
471 xcolor.pixel = xcolor2.pixel;
472 xcolor_private[xcolor.pixel] = xcolor;
473 colorcell_used[xcolor.pixel] = TRUE;
474 XStoreColor(display, ximageinfo->cmap, &xcolor);
475 free_cmap_entries--;
476 }
477
478 *(ximageinfo->index + a) = xcolor.pixel;
479 }
480
481 /*
482 printf("still %d free colormap entries\n", free_cmap_entries);
483 */
484
485 ximageinfo->no = a; /* number of pixels allocated for this image */
486 break;
487
488 default:
489 Error(ERR_INFO,"DirectColor, TrueColor or PseudoColor display needed");
490 SetError(error, "display class not supported");
491
492 return NULL;
493 }
494
495 #if DEBUG_TIMING
496 debug_print_timestamp(2, " ALLOCATING IMAGE COLORS: ");
497 #endif
498
499 /* create XImage from internal image structure and convert it to Pixmap */
500
501 display_bits_per_pixel = bitsPerPixelAtDepth(display, screen, depth);
502 display_bytes_per_pixel = (display_bits_per_pixel + 7) / 8;
503
504 ximage = XCreateImage(display, visual, depth, ZPixmap,
505 0, NULL, image->width, image->height,
506 8, image->width * display_bytes_per_pixel);
507 ximage->data =
508 checked_malloc(image->width * image->height * display_bytes_per_pixel);
509 ximage->byte_order = MSBFirst;
510
511 src_ptr = image->data;
512 dst_ptr = (byte *)ximage->data;
513
514 switch (visual->class)
515 {
516 case DirectColor:
517 case TrueColor:
518 {
519 Pixel pixval;
520
521 switch (image->type)
522 {
523 case IMAGETYPE_RGB:
524 {
525 for (y = 0; y < image->height; y++) /* general case */
526 {
527 for (x = 0; x < image->width; x++)
528 {
529 pixval = *src_ptr++;
530 pixval =
531 redvalue[image->rgb.red[pixval] >> 8] |
532 greenvalue[image->rgb.green[pixval] >> 8] |
533 bluevalue[image->rgb.blue[pixval] >> 8];
534 value_to_memory(pixval, dst_ptr, display_bytes_per_pixel);
535 dst_ptr += display_bytes_per_pixel;
536 }
537 }
538
539 break;
540 }
541
542 case IMAGETYPE_TRUECOLOR:
543 {
544 for (y = 0; y < image->height; y++) /* general case */
545 {
546 for (x = 0; x < image->width; x++)
547 {
548 pixval = memory_to_value(src_ptr, image->bytes_per_pixel);
549 pixval =
550 redvalue[TRUECOLOR_RED(pixval)] |
551 greenvalue[TRUECOLOR_GREEN(pixval)] |
552 bluevalue[TRUECOLOR_BLUE(pixval)];
553 value_to_memory(pixval, dst_ptr, display_bytes_per_pixel);
554 src_ptr += image->bytes_per_pixel;
555 dst_ptr += display_bytes_per_pixel;
556 }
557 }
558
559 break;
560 }
561
562 default:
563 Error(ERR_INFO, "RGB or TrueColor image needed");
564 SetError(error, "image type not supported");
565
566 return NULL;
567 }
568
569 break;
570 }
571
572 case PseudoColor:
573 {
574 if (display_bytes_per_pixel == 1) /* special case */
575 {
576 for (y = 0; y < image->height; y++)
577 for (x = 0; x < image->width; x++)
578 *dst_ptr++ = ximageinfo->index[c + *src_ptr++];
579 }
580 else /* general case */
581 {
582 for (y = 0; y < image->height; y++)
583 {
584 for (x = 0; x < image->width; x++)
585 {
586 value_to_memory(ximageinfo->index[c + *src_ptr++],
587 dst_ptr, display_bytes_per_pixel);
588 dst_ptr += display_bytes_per_pixel;
589 }
590 }
591 }
592
593 break;
594 }
595
596 default:
597 Error(ERR_INFO,"DirectColor, TrueColor or PseudoColor display needed");
598 SetError(error, "display class not supported");
599
600 return NULL;
601 }
602
603 if (redvalue)
604 {
605 free((byte *)redvalue);
606 free((byte *)greenvalue);
607 free((byte *)bluevalue);
608 }
609
610 #if DEBUG_TIMING
611 debug_print_timestamp(2, " CONVERTING IMAGE TO XIMAGE:");
612 #endif
613
614 ximageinfo->pixmap = XCreatePixmap(display, window,
615 ximage->width, ximage->height,
616 ximageinfo->depth);
617
618 XPutImage(ximageinfo->display, ximageinfo->pixmap, gc,
619 ximage, 0, 0, 0, 0, ximage->width, ximage->height);
620
621 X11DestroyImage(ximage);
622
623 return ximageinfo;
624 }
625
626 /*
627 -----------------------------------------------------------------------------
628 ZoomPixmap
629
630 Important note: The scaling code currently only supports scaling of the image
631 up or down by a power of 2 -- other scaling factors currently not supported!
632 Also not supported is scaling of pixmap masks (with depth 1); to scale them,
633 better use Pixmap_to_Mask() for now.
634 -----------------------------------------------------------------------------
635 */
636
ZoomPixmap(Display * display,GC gc,Pixmap src_pixmap,Pixmap dst_pixmap,int src_width,int src_height,int dst_width,int dst_height)637 void ZoomPixmap(Display *display, GC gc, Pixmap src_pixmap, Pixmap dst_pixmap,
638 int src_width, int src_height,
639 int dst_width, int dst_height)
640 {
641 XImage *src_ximage, *dst_ximage;
642 byte *src_ptr, *dst_ptr;
643 int bits_per_pixel;
644 int bytes_per_pixel;
645 int x, y, xx, yy, i;
646 int row_skip, col_skip;
647 int zoom_factor;
648 boolean scale_down = (src_width > dst_width);
649
650 if (scale_down)
651 {
652 #if 1
653 zoom_factor = MIN(src_width / dst_width, src_height / dst_height);
654 #else
655 zoom_factor = src_width / dst_width;
656 #endif
657
658 /* adjust source image size to integer multiple of destination size */
659 src_width = dst_width * zoom_factor;
660 src_height = dst_height * zoom_factor;
661 }
662 else
663 {
664 #if 1
665 zoom_factor = MIN(dst_width / src_width, dst_height / src_height);
666 #else
667 zoom_factor = dst_width / src_width;
668 #endif
669
670 /* no adjustment needed when scaling up (some pixels may be left blank) */
671 }
672
673 /* copy source pixmap to temporary image */
674 if ((src_ximage = XGetImage(display, src_pixmap, 0, 0, src_width, src_height,
675 AllPlanes, ZPixmap)) == NULL)
676 Error(ERR_EXIT, "ZoomPixmap(): XGetImage() failed");
677
678 bits_per_pixel = src_ximage->bits_per_pixel;
679 bytes_per_pixel = (bits_per_pixel + 7) / 8;
680
681 if ((dst_ximage = XCreateImage(display, visual, src_ximage->depth, ZPixmap,
682 0, NULL, dst_width, dst_height,
683 8, dst_width * bytes_per_pixel)) == NULL)
684 Error(ERR_EXIT, "ZoomPixmap(): XCreateImage() failed");
685
686 dst_ximage->data =
687 checked_malloc(dst_width * dst_height * bytes_per_pixel);
688 dst_ximage->byte_order = src_ximage->byte_order;
689
690 src_ptr = (byte *)src_ximage->data;
691 dst_ptr = (byte *)dst_ximage->data;
692
693 if (scale_down)
694 {
695 col_skip = (zoom_factor - 1) * bytes_per_pixel;
696 row_skip = col_skip * src_width;
697
698 /* scale image down by scaling factor 'zoom_factor' */
699 for (y = 0; y < src_height; y += zoom_factor, src_ptr += row_skip)
700 for (x = 0; x < src_width; x += zoom_factor, src_ptr += col_skip)
701 for (i = 0; i < bytes_per_pixel; i++)
702 *dst_ptr++ = *src_ptr++;
703 }
704 else
705 {
706 row_skip = src_width * bytes_per_pixel;
707
708 /* scale image up by scaling factor 'zoom_factor' */
709 for (y = 0; y < src_height; y++)
710 {
711 for (yy = 0; yy < zoom_factor; yy++)
712 {
713 if (yy > 0)
714 src_ptr -= row_skip;
715
716 for (x = 0; x < src_width; x++)
717 {
718 for (xx = 0; xx < zoom_factor; xx++)
719 for (i = 0; i < bytes_per_pixel; i++)
720 *dst_ptr++ = *(src_ptr + i);
721
722 src_ptr += bytes_per_pixel;
723 }
724 }
725 }
726 }
727
728 /* copy scaled image to destination pixmap */
729 XPutImage(display, dst_pixmap, gc, dst_ximage, 0, 0, 0, 0,
730 dst_width, dst_height);
731
732 /* free temporary images */
733 X11DestroyImage(src_ximage);
734 X11DestroyImage(dst_ximage);
735 }
736
freeXImage(Image * image,XImageInfo * ximageinfo)737 void freeXImage(Image *image, XImageInfo *ximageinfo)
738 {
739 if (ximageinfo->index != NULL && ximageinfo->no > 0)
740 XFreeColors(ximageinfo->display, ximageinfo->cmap, ximageinfo->index,
741 ximageinfo->no, 0);
742 /* this ^^^^^^^^^^^^^^ is wrong, because the used color cells
743 * are somewhere between 0 and MAX_COLORS; there are indeed 'ximageinfo->no'
744 * used color cells, but they are not at array position 0 - 'ximageinfo->no'
745 */
746
747 free(ximageinfo);
748 }
749
Read_PCX_to_Pixmap(Display * display,Window window,GC gc,char * filename,Pixmap * pixmap,Pixmap * pixmap_mask)750 int Read_PCX_to_Pixmap(Display *display, Window window, GC gc, char *filename,
751 Pixmap *pixmap, Pixmap *pixmap_mask)
752 {
753 Image *image;
754 XImageInfo *ximageinfo;
755 int screen;
756 Visual *visual;
757 int depth;
758
759 #if DEBUG_TIMING
760 debug_print_timestamp(2, NULL); /* initialize timestamp function */
761 #endif
762
763 /* read the graphic file in PCX format to image structure */
764 if ((image = Read_PCX_to_Image(filename)) == NULL)
765 return errno_pcx;
766
767 #if DEBUG_TIMING
768 printf("%s:\n", filename);
769 debug_print_timestamp(2, " READING PCX FILE TO IMAGE: ");
770 #endif
771
772 screen = DefaultScreen(display);
773 visual = DefaultVisual(display, screen);
774 depth = DefaultDepth(display, screen);
775
776 /* convert image structure to X11 Pixmap */
777 if (!(ximageinfo = Image_to_Pixmap(display, screen, visual,
778 window, gc, depth, image)))
779 {
780 freeImage(image);
781
782 return PCX_OtherError;
783 }
784
785 /* if a private colormap has been created, install it */
786 if (ximageinfo->cmap != DefaultColormap(display, screen))
787 XSetWindowColormap(display, window, ximageinfo->cmap);
788
789 #if DEBUG_TIMING
790 debug_print_timestamp(2, " CONVERTING IMAGE TO PIXMAP:");
791 #endif
792
793 /* create clip mask for the image */
794 ximageinfo->pixmap_mask = Image_to_Mask(image, display, window);
795
796 #if DEBUG_TIMING
797 debug_print_timestamp(2, " CONVERTING IMAGE TO MASK: ");
798 #endif
799
800 *pixmap = ximageinfo->pixmap;
801 *pixmap_mask = ximageinfo->pixmap_mask;
802
803 /* free generic image and ximageinfo after native Pixmap has been created */
804 free(ximageinfo);
805 freeImage(image);
806
807 return PCX_Success;
808 }
809
810 #endif /* PLATFORM_UNIX */
811 #endif /* TARGET_X11 */
812
813
814 /* ========================================================================= */
815 /* PLATFORM INDEPENDENT IMAGE FUNCTIONS */
816 /* ========================================================================= */
817
818 struct ImageInfo
819 {
820 char *source_filename;
821 int num_references;
822
823 Bitmap *bitmap;
824
825 int original_width; /* original image file width */
826 int original_height; /* original image file height */
827
828 boolean contains_small_images; /* set after adding small images */
829 boolean scaled_up; /* set after scaling up */
830 };
831 typedef struct ImageInfo ImageInfo;
832
833 static struct ArtworkListInfo *image_info = NULL;
834
Load_PCX(char * filename)835 static void *Load_PCX(char *filename)
836 {
837 ImageInfo *img_info;
838
839 #if 0
840 printf("::: loading PCX file '%s'\n", filename);
841 #endif
842
843 img_info = checked_calloc(sizeof(ImageInfo));
844
845 if ((img_info->bitmap = LoadImage(filename)) == NULL)
846 {
847 Error(ERR_WARN, "cannot load image file '%s': LoadImage() failed: %s",
848 filename, GetError());
849 free(img_info);
850 return NULL;
851 }
852
853 img_info->source_filename = getStringCopy(filename);
854
855 img_info->original_width = img_info->bitmap->width;
856 img_info->original_height = img_info->bitmap->height;
857
858 img_info->contains_small_images = FALSE;
859 img_info->scaled_up = FALSE;
860
861 return img_info;
862 }
863
FreeImage(void * ptr)864 static void FreeImage(void *ptr)
865 {
866 ImageInfo *image = (ImageInfo *)ptr;
867
868 if (image == NULL)
869 return;
870
871 if (image->bitmap)
872 FreeBitmap(image->bitmap);
873
874 if (image->source_filename)
875 free(image->source_filename);
876
877 free(image);
878 }
879
getImageListSize()880 int getImageListSize()
881 {
882 return (image_info->num_file_list_entries +
883 image_info->num_dynamic_file_list_entries);
884 }
885
getImageListEntryFromImageID(int pos)886 struct FileInfo *getImageListEntryFromImageID(int pos)
887 {
888 int num_list_entries = image_info->num_file_list_entries;
889 int list_pos = (pos < num_list_entries ? pos : pos - num_list_entries);
890
891 return (pos < num_list_entries ? &image_info->file_list[list_pos] :
892 &image_info->dynamic_file_list[list_pos]);
893 }
894
getImageInfoEntryFromImageID(int pos)895 static ImageInfo *getImageInfoEntryFromImageID(int pos)
896 {
897 int num_list_entries = image_info->num_file_list_entries;
898 int list_pos = (pos < num_list_entries ? pos : pos - num_list_entries);
899 ImageInfo **img_info =
900 (ImageInfo **)(pos < num_list_entries ? image_info->artwork_list :
901 image_info->dynamic_artwork_list);
902
903 return img_info[list_pos];
904 }
905
getBitmapFromImageID(int pos)906 Bitmap *getBitmapFromImageID(int pos)
907 {
908 ImageInfo *img_info = getImageInfoEntryFromImageID(pos);
909
910 return (img_info != NULL ? img_info->bitmap : NULL);
911 }
912
getOriginalImageWidthFromImageID(int pos)913 int getOriginalImageWidthFromImageID(int pos)
914 {
915 ImageInfo *img_info = getImageInfoEntryFromImageID(pos);
916
917 return (img_info != NULL ? img_info->original_width : 0);
918 }
919
getOriginalImageHeightFromImageID(int pos)920 int getOriginalImageHeightFromImageID(int pos)
921 {
922 ImageInfo *img_info = getImageInfoEntryFromImageID(pos);
923
924 return (img_info != NULL ? img_info->original_height : 0);
925 }
926
getTokenFromImageID(int graphic)927 char *getTokenFromImageID(int graphic)
928 {
929 struct FileInfo *file_list = getImageListEntryFromImageID(graphic);
930
931 return (file_list != NULL ? file_list->token : NULL);
932 }
933
getImageIDFromToken(char * token)934 int getImageIDFromToken(char *token)
935 {
936 struct FileInfo *file_list = image_info->file_list;
937 int num_list_entries = image_info->num_file_list_entries;
938 int i;
939
940 for (i = 0; i < num_list_entries; i++)
941 if (strEqual(file_list[i].token, token))
942 return i;
943
944 return -1;
945 }
946
getImageConfigFilename()947 char *getImageConfigFilename()
948 {
949 return getCustomArtworkConfigFilename(image_info->type);
950 }
951
getImageListPropertyMappingSize()952 int getImageListPropertyMappingSize()
953 {
954 return image_info->num_property_mapping_entries;
955 }
956
getImageListPropertyMapping()957 struct PropertyMapping *getImageListPropertyMapping()
958 {
959 return image_info->property_mapping;
960 }
961
InitImageList(struct ConfigInfo * config_list,int num_file_list_entries,struct ConfigTypeInfo * config_suffix_list,char ** base_prefixes,char ** ext1_suffixes,char ** ext2_suffixes,char ** ext3_suffixes,char ** ignore_tokens)962 void InitImageList(struct ConfigInfo *config_list, int num_file_list_entries,
963 struct ConfigTypeInfo *config_suffix_list,
964 char **base_prefixes, char **ext1_suffixes,
965 char **ext2_suffixes, char **ext3_suffixes,
966 char **ignore_tokens)
967 {
968 int i;
969
970 image_info = checked_calloc(sizeof(struct ArtworkListInfo));
971 image_info->type = ARTWORK_TYPE_GRAPHICS;
972
973 /* ---------- initialize file list and suffix lists ---------- */
974
975 image_info->num_file_list_entries = num_file_list_entries;
976 image_info->num_dynamic_file_list_entries = 0;
977
978 image_info->file_list =
979 getFileListFromConfigList(config_list, config_suffix_list, ignore_tokens,
980 num_file_list_entries);
981 image_info->dynamic_file_list = NULL;
982
983 image_info->num_suffix_list_entries = 0;
984 for (i = 0; config_suffix_list[i].token != NULL; i++)
985 image_info->num_suffix_list_entries++;
986
987 image_info->suffix_list = config_suffix_list;
988
989 /* ---------- initialize base prefix and suffixes lists ---------- */
990
991 image_info->num_base_prefixes = 0;
992 for (i = 0; base_prefixes[i] != NULL; i++)
993 image_info->num_base_prefixes++;
994
995 image_info->num_ext1_suffixes = 0;
996 for (i = 0; ext1_suffixes[i] != NULL; i++)
997 image_info->num_ext1_suffixes++;
998
999 image_info->num_ext2_suffixes = 0;
1000 for (i = 0; ext2_suffixes[i] != NULL; i++)
1001 image_info->num_ext2_suffixes++;
1002
1003 image_info->num_ext3_suffixes = 0;
1004 for (i = 0; ext3_suffixes[i] != NULL; i++)
1005 image_info->num_ext3_suffixes++;
1006
1007 image_info->num_ignore_tokens = 0;
1008 for (i = 0; ignore_tokens[i] != NULL; i++)
1009 image_info->num_ignore_tokens++;
1010
1011 image_info->base_prefixes = base_prefixes;
1012 image_info->ext1_suffixes = ext1_suffixes;
1013 image_info->ext2_suffixes = ext2_suffixes;
1014 image_info->ext3_suffixes = ext3_suffixes;
1015 image_info->ignore_tokens = ignore_tokens;
1016
1017 image_info->num_property_mapping_entries = 0;
1018
1019 image_info->property_mapping = NULL;
1020
1021 /* ---------- initialize artwork reference and content lists ---------- */
1022
1023 image_info->sizeof_artwork_list_entry = sizeof(ImageInfo *);
1024
1025 image_info->artwork_list =
1026 checked_calloc(num_file_list_entries * sizeof(ImageInfo *));
1027 image_info->dynamic_artwork_list = NULL;
1028
1029 image_info->content_list = NULL;
1030
1031 /* ---------- initialize artwork loading/freeing functions ---------- */
1032
1033 image_info->load_artwork = Load_PCX;
1034 image_info->free_artwork = FreeImage;
1035 }
1036
ReloadCustomImages()1037 void ReloadCustomImages()
1038 {
1039 #if 0
1040 printf("::: reloading images '%s' ...\n", artwork.gfx_current_identifier);
1041 #endif
1042
1043 LoadArtworkConfig(image_info);
1044 ReloadCustomArtworkList(image_info);
1045 }
1046
CreateImageWithSmallImages(int pos,int zoom_factor)1047 void CreateImageWithSmallImages(int pos, int zoom_factor)
1048 {
1049 ImageInfo *img_info = getImageInfoEntryFromImageID(pos);
1050
1051 if (img_info == NULL || img_info->contains_small_images)
1052 return;
1053
1054 CreateBitmapWithSmallBitmaps(img_info->bitmap, zoom_factor);
1055
1056 img_info->contains_small_images = TRUE;
1057 img_info->scaled_up = TRUE;
1058 }
1059
ScaleImage(int pos,int zoom_factor)1060 void ScaleImage(int pos, int zoom_factor)
1061 {
1062 ImageInfo *img_info = getImageInfoEntryFromImageID(pos);
1063
1064 if (img_info == NULL || img_info->scaled_up)
1065 return;
1066
1067 if (zoom_factor != 1)
1068 ScaleBitmap(img_info->bitmap, zoom_factor);
1069
1070 img_info->scaled_up = TRUE;
1071 }
1072
FreeAllImages()1073 void FreeAllImages()
1074 {
1075 FreeCustomArtworkLists(image_info);
1076 }
1077