X-Git-Url: https://git.artsoft.org/?p=rocksndiamonds.git;a=blobdiff_plain;f=src%2Fimage.c;h=09a75fcee078a7eb6628042246a6acd67ecef6be;hp=b0a8a1d50a57c2aeab396130d7d1aa51f7021a1f;hb=d4c11da68a7271553ca5591adfae54fd3b45011f;hpb=833cc59e0cc1802432f21ddbaa763c99e541fafe diff --git a/src/image.c b/src/image.c index b0a8a1d5..09a75fce 100644 --- a/src/image.c +++ b/src/image.c @@ -12,37 +12,53 @@ ***********************************************************/ #include "image.h" +#include "pcx.h" #include "misc.h" +/* exclude all except newImage() and freeImage() */ +#ifndef MSDOS -#ifdef DEBUG - -#define DEBUG_TIMING - -#endif - -#ifdef DEBUG_TIMING - long count1, count2; -#endif - - -/* extra colors to try allocating in private color maps to minimise flashing */ +/* extra colors to try allocating in private color maps to minimize flashing */ #define NOFLASH_COLORS 256 -static void Image_to_Mask(Image *image) +/* architecture independent value-to-memory conversion + note: the internal format is big endian */ + +#define value_to_memory(value, ptr, length) ( \ +(length) == 1 ? (*( (byte *)(ptr) ) = ( value ) ) : \ +(length) == 2 ? (*( (byte *)(ptr) ) = (((unsigned long)(value))>> 8), \ + *(((byte *)(ptr))+1) = ( value ) ) : \ +(length) == 3 ? (*( (byte *)(ptr) ) = (((unsigned long)(value))>>16), \ + *(((byte *)(ptr))+1) = (((unsigned long)(value))>> 8), \ + *(((byte *)(ptr))+2) = ( value ) ) : \ + (*( (byte *)(ptr) ) = (((unsigned long)(value))>>24), \ + *(((byte *)(ptr))+1) = (((unsigned long)(value))>>16), \ + *(((byte *)(ptr))+2) = (((unsigned long)(value))>> 8), \ + *(((byte *)(ptr))+3) = ( value ) )) + +static Pixmap Image_to_Mask(Image *image, Display *display, Window window) { - unsigned char *src_ptr, *dst_ptr, *dst_ptr2; + byte *src_ptr, *dst_ptr, *dst_ptr2; unsigned int bytes_per_row; unsigned int x, y; - unsigned char bitmask; + byte bitmask; + byte *mask_data; + Pixmap mask_pixmap; bytes_per_row = (image->width + 7) / 8; + mask_data = checked_calloc(bytes_per_row * image->height); + src_ptr = image->data; - dst_ptr = image->data_mask; + 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; yheight; y++) { - bitmask = 0x80; /* start with leftmost bit in the byte */ + bitmask = 0x01; /* start with leftmost bit in the byte */ dst_ptr2 = dst_ptr; /* start with leftmost byte in the row */ for (x=0; xwidth; x++) @@ -50,95 +66,46 @@ static void Image_to_Mask(Image *image) 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? */ + if ((bitmask <<= 1) == 0) /* bit at rightmost byte position reached? */ { - bitmask = 0x80; /* start again with leftmost bit position */ + 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 */ } -} - -static boolean XImage_to_Pixmap(Display *display, Window parent, - XImageInfo *ximageinfo) -{ - XGCValues gcv; - - ximageinfo->pixmap = - XCreatePixmap(display, parent, - ximageinfo->ximage->width, - ximageinfo->ximage->height, - ximageinfo->depth); - - ximageinfo->pixmap_mask = - XCreatePixmap(display, parent, - ximageinfo->ximage->width, - ximageinfo->ximage->height, - 1); - - /* build and cache the GC */ - - if (!ximageinfo->gc) - { - gcv.function = GXcopy; - ximageinfo->gc = - XCreateGC(ximageinfo->display, ximageinfo->pixmap, - GCFunction, &gcv); - } - - if (!ximageinfo->gc_mask) - { - gcv.function = GXcopy; - gcv.foreground = ximageinfo->foreground; - gcv.background = ximageinfo->background; - ximageinfo->gc_mask = - XCreateGC(ximageinfo->display, ximageinfo->pixmap_mask, - GCFunction | GCForeground | GCBackground, &gcv); - } - XPutImage(ximageinfo->display, ximageinfo->pixmap, ximageinfo->gc, - ximageinfo->ximage, 0, 0, 0, 0, - ximageinfo->ximage->width, ximageinfo->ximage->height); - XPutImage(ximageinfo->display, ximageinfo->pixmap_mask, ximageinfo->gc_mask, - ximageinfo->ximage_mask, 0, 0, 0, 0, - ximageinfo->ximage->width, ximageinfo->ximage->height); + mask_pixmap = XCreateBitmapFromData(display, window, (char *)mask_data, + image->width, image->height); + free(mask_data); - return (ximageinfo->pixmap != None && ximageinfo->pixmap_mask != None); + return mask_pixmap; } -/* find the best pixmap depth supported by the server for a particular - * visual and return that depth. - */ - -static unsigned int bitsPerPixelAtDepth(Display *display, int screen, - unsigned int depth) +static int bitsPerPixelAtDepth(Display *display, int screen, int depth) { - XPixmapFormatValues *xf; - int nxf, a; + XPixmapFormatValues *pixmap_format; + int i, num_pixmap_formats, bits_per_pixel = -1; - xf = XListPixmapFormats(display, &nxf); - for (a = 0; a < nxf; a++) - { - if (xf[a].depth == depth) - { - int bpp; - bpp = xf[a].bits_per_pixel; - XFree(xf); - return (unsigned int) bpp; - } - } - XFree(xf); + /* get Pixmap formats supported by the X server */ + pixmap_format = XListPixmapFormats(display, &num_pixmap_formats); + + /* find format that matches the given depth */ + for (i=0; idisplay = display; - ximageinfo->screen = screen; - ximageinfo->depth = 0; - ximageinfo->drawable = None; - ximageinfo->index = NULL; - ximageinfo->rootimage = FALSE; - ximageinfo->foreground = ximageinfo->background= 0; - ximageinfo->gc = NULL; - ximageinfo->gc_mask = NULL; - ximageinfo->ximage = NULL; - ximageinfo->ximage_mask = NULL; + ximageinfo->depth = depth; switch (visual->class) { @@ -205,8 +158,7 @@ XImageInfo *Image_to_XImage(Display *display, int screen, Visual *visual, retry_direct: /* tag we hit if a DirectColor allocation fails on * default colormap */ - /* calculate number of distinct colors in each band - */ + /* calculate number of distinct colors in each band */ redcolors = greencolors = bluecolors = 1; for (pixval=1; pixval; pixval <<= 1) @@ -219,15 +171,11 @@ XImageInfo *Image_to_XImage(Display *display, int screen, Visual *visual, bluecolors <<= 1; } - /* sanity check - */ - - if ((redcolors > visual->map_entries) || - (greencolors > visual->map_entries) || - (bluecolors > visual->map_entries)) - { - fprintf(stderr, "Warning: inconsistency in color information (this may be ugly)\n"); - } + /* consistency check */ + if (redcolors > visual->map_entries || + greencolors > visual->map_entries || + bluecolors > visual->map_entries) + Error(ERR_WARN, "inconsistency in color information"); redstep = 256 / redcolors; greenstep = 256 / greencolors; @@ -249,8 +197,7 @@ XImageInfo *Image_to_XImage(Display *display, int screen, Visual *visual, if (!XAllocColor(display, ximageinfo->cmap, &xcolor)) { /* if an allocation fails for a DirectColor default visual then - * we should create a private colormap and try again. - */ + we should create a private colormap and try again. */ if ((visual->class == DirectColor) && (visual == DefaultVisual(display, screen))) @@ -262,19 +209,17 @@ XImageInfo *Image_to_XImage(Display *display, int screen, Visual *visual, goto retry_direct; } - /* something completely unexpected happened - */ + /* something completely unexpected happened */ fprintf(stderr, "imageToXImage: XAllocColor failed on a TrueColor/Directcolor visual\n"); - free((byte *)redvalue); - free((byte *)greenvalue); - free((byte *)bluevalue); - free((byte *)ximageinfo); - return(NULL); + free(redvalue); + free(greenvalue); + free(bluevalue); + free(ximageinfo); + return NULL; } - /* fill in pixel values for each band at this intensity - */ + /* fill in pixel values for each band at this intensity */ while ((redbottom < 256) && (redbottom < redtop)) redvalue[redbottom++] = xcolor.pixel & visual->red_mask; @@ -289,12 +234,6 @@ XImageInfo *Image_to_XImage(Display *display, int screen, Visual *visual, case PseudoColor: ximageinfo->cmap = global_cmap; - ximageinfo->index = - (Pixel *)checked_malloc(sizeof(Pixel) * image->rgb.used); - -#if 0 - for (a=0; argb.used; a++) -#endif for (a=0; aximage = XCreateImage(display, visual, ddepth, ZPixmap, 0, - NULL, image->width, image->height, - 8, image->width * dpixlen); + ximage = XCreateImage(display, visual, depth, ZPixmap, 0, + NULL, image->width, image->height, + 8, image->width * bytes_per_pixel); + ximage->data = + checked_malloc(image->width * image->height * bytes_per_pixel); + ximage->byte_order = MSBFirst; - data = (byte *)checked_malloc(image->width * image->height * dpixlen); - ximageinfo->depth = ddepth; - ximageinfo->ximage->data = (char *)data; - ximageinfo->ximage->byte_order = MSBFirst; - srcptr = image->data; - destptr = data; + src_ptr = image->data; + dst_ptr = (byte *)ximage->data; switch (visual->class) { @@ -453,97 +384,50 @@ XImageInfo *Image_to_XImage(Display *display, int screen, Visual *visual, { Pixel pixval; - for (y=0; yheight; y++) + for (y=0; yheight; y++) /* general case */ { for (x=0; xwidth; x++) { - pixval = memToVal(srcptr, 1); + pixval = *src_ptr++; pixval = redvalue[image->rgb.red[pixval] >> 8] | greenvalue[image->rgb.green[pixval] >> 8] | bluevalue[image->rgb.blue[pixval] >> 8]; - valToMem(pixval, destptr, dpixlen); - srcptr += 1; - destptr += dpixlen; + value_to_memory(pixval, dst_ptr, bytes_per_pixel); + dst_ptr += bytes_per_pixel; } } break; } - default: + case PseudoColor: { - if (dpixlen == 1) /* most common */ + if (bytes_per_pixel == 1) /* (common) special case */ { for (y=0; yheight; y++) - { for (x=0; xwidth; x++) - { - *destptr = ximageinfo->index[c + *srcptr]; - srcptr++; - destptr++; - } - } + *dst_ptr++ = ximageinfo->index[c + *src_ptr++]; } - else /* less common */ + else /* general case */ { for (y=0; yheight; y++) { for (x=0; xwidth; x++) { - register unsigned long temp; - temp = memToVal(srcptr, 1); - valToMem(ximageinfo->index[c + temp], destptr, dpixlen); - srcptr += 1; - destptr += dpixlen; + value_to_memory(ximageinfo->index[c + *src_ptr++], + dst_ptr, bytes_per_pixel); + dst_ptr += bytes_per_pixel; } } } + break; } - } - - /* NOW CREATE IMAGE MASK */ - /* we copy the data to be more consistent */ - - linelen = ((image->width + 7) / 8); - data_mask = checked_malloc(linelen * image->height); - memcpy((char *)data_mask, (char *)image->data_mask, - linelen * image->height); - - gcv.function = GXcopy; - ximageinfo->ximage_mask = - XCreateImage(display, visual, 1, XYBitmap, 0, (char *)data_mask, - image->width, image->height, 8, linelen); - -#if 1 - if (visual->class == DirectColor || visual->class == TrueColor) - { - Pixel pixval; - dbits = bitsPerPixelAtDepth(display, screen, ddepth); - dpixlen = (dbits + 7) / 8; - pixval = - redvalue[65535 >> 8] | - greenvalue[65535 >> 8] | - bluevalue[65535 >> 8]; - ximageinfo->background = pixval; - pixval = - redvalue[0 >> 8] | - greenvalue[0 >> 8] | - bluevalue[0 >> 8]; - ximageinfo->foreground = pixval; - } - else /* Not Direct or True Color */ - { - ximageinfo->foreground = BlackPixel(display, screen); - ximageinfo->background = WhitePixel(display, screen); + default: + Error(ERR_RETURN, "display class not supported"); + Error(ERR_EXIT, "DirectColor, TrueColor or PseudoColor display needed"); + break; } -#else - ximageinfo->foreground = WhitePixel(display, screen); - ximageinfo->background = BlackPixel(display, screen); -#endif - - ximageinfo->ximage_mask->bitmap_bit_order = MSBFirst; - ximageinfo->ximage_mask->byte_order = MSBFirst; if (redvalue) { @@ -552,34 +436,42 @@ XImageInfo *Image_to_XImage(Display *display, int screen, Visual *visual, free((byte *)bluevalue); } +#if DEBUG_TIMING + debug_print_timestamp(2, " CONVERTING IMAGE TO XIMAGE:"); +#endif + + ximageinfo->pixmap = XCreatePixmap(display, window, + ximage->width, ximage->height, + ximageinfo->depth); + + XPutImage(ximageinfo->display, ximageinfo->pixmap, gc, + ximage, 0, 0, 0, 0, ximage->width, ximage->height); + + free(ximage->data); + ximage->data = NULL; + XDestroyImage(ximage); + return(ximageinfo); } -/* free up anything cached in the local Ximage structure. - */ - void freeXImage(Image *image, XImageInfo *ximageinfo) { - if (ximageinfo->index != NULL) /* if we allocated colors */ - { - if (ximageinfo->no > 0 && !ximageinfo->rootimage) /* don't free root colors */ - XFreeColors(ximageinfo->display, ximageinfo->cmap, ximageinfo->index, - ximageinfo->no, 0); - free(ximageinfo->index); - } - if (ximageinfo->gc) - XFreeGC(ximageinfo->display, ximageinfo->gc); - free((byte *)ximageinfo->ximage->data); - ximageinfo->ximage->data= NULL; - XDestroyImage(ximageinfo->ximage); - free((byte *)ximageinfo); - /* should we free private color map to ??? */ + if (ximageinfo->index != NULL && ximageinfo->no > 0) + XFreeColors(ximageinfo->display, ximageinfo->cmap, ximageinfo->index, + ximageinfo->no, 0); + /* this ^^^^^^^^^^^^^^ is wrong, because the used color cells + * are somewhere between 0 and MAX_COLORS; there are indeed 'ximageinfo->no' + * used color cells, but they are not at array position 0 - 'ximageinfo->no' + */ + + free(ximageinfo); } +#endif /* !MSDOS */ + Image *newImage(unsigned int width, unsigned int height, unsigned int depth) { Image *image; - unsigned int bytes_per_row; const unsigned int bytes_per_pixel = 1; int i; @@ -596,95 +488,61 @@ Image *newImage(unsigned int width, unsigned int height, unsigned int depth) for (i=0; irgb.color_used[i] = FALSE; - bytes_per_row = (width + 7) / 8; - image->data_mask = checked_calloc(bytes_per_row * height); - return image; } void freeImage(Image *image) { free(image->data); - free(image->data_mask); free(image); } -/* ------------------------------------------------------------------------- */ - +#ifndef MSDOS - -int Read_PCX_to_Pixmaps(Display *display, Window window, char *filename, - Pixmap *pixmap, Pixmap *pixmap_mask) +int Read_PCX_to_Pixmap(Display *display, Window window, GC gc, char *filename, + Pixmap *pixmap, Pixmap *pixmap_mask) { Image *image; XImageInfo *ximageinfo; - - /* - Image *image, *image_mask; - XImageInfo *ximageinfo, *ximageinfo_mask; - */ - int screen; Visual *visual; - unsigned int depth; + int depth; -#ifdef DEBUG_TIMING - count1 = Counter(); +#if DEBUG_TIMING + debug_print_timestamp(2, NULL); /* initialize timestamp function */ #endif + /* read the graphic file in PCX format to image structure */ if ((image = Read_PCX_to_Image(filename)) == NULL) return PCX_FileInvalid; -#ifdef DEBUG_TIMING - count2 = Counter(); - printf(" LOADING '%s' IN %.2f SECONDS\n", - filename, (float)(count2-count1)/1000.0); - count1 = Counter(); -#endif - - /* create image mask */ - Image_to_Mask(image); - -#ifdef DEBUG_TIMING - count2 = Counter(); - printf(" CONVERTING IMAGE TO MASK IN %.2f SECONDS\n", - (float)(count2-count1)/1000.0); - count1 = Counter(); +#if DEBUG_TIMING + printf("%s:\n", filename); + debug_print_timestamp(2, " READING PCX FILE TO IMAGE: "); #endif screen = DefaultScreen(display); visual = DefaultVisual(display, screen); depth = DefaultDepth(display, screen); - /* convert internal image structure to X11 XImage */ - if (!(ximageinfo = Image_to_XImage(display, screen, visual, depth, image))) - { - fprintf(stderr, "Cannot convert Image to XImage.\n"); - exit(1); - } - -#ifdef DEBUG_TIMING - count2 = Counter(); - printf(" CONVERTING IMAGE TO XIMAGE (BITMAP) IN %.2f SECONDS\n", - (float)(count2-count1)/1000.0); - count1 = Counter(); -#endif + /* convert image structure to X11 Pixmap */ + if (!(ximageinfo = Image_to_Pixmap(display, screen, visual, + window, gc, depth, image))) + Error(ERR_EXIT, "cannot convert Image to Pixmap"); + /* if a private colormap has been created, install it */ if (ximageinfo->cmap != DefaultColormap(display, screen)) XSetWindowColormap(display, window, ximageinfo->cmap); - /* convert XImage to Pixmap */ - if (!(XImage_to_Pixmap(display, window, ximageinfo))) - { - fprintf(stderr, "Cannot convert XImage to Pixmap.\n"); - exit(1); - } +#if DEBUG_TIMING + debug_print_timestamp(2, " CONVERTING IMAGE TO PIXMAP:"); +#endif -#ifdef DEBUG_TIMING - count2 = Counter(); - printf(" CONVERTING IMAGE TO PIXMAP IN %.2f SECONDS\n", - (float)(count2-count1)/1000.0); - count1 = Counter(); + /* create clip mask for the image */ + ximageinfo->pixmap_mask = Image_to_Mask(image, display, window); + +#if DEBUG_TIMING + debug_print_timestamp(2, " CONVERTING IMAGE TO MASK: "); #endif *pixmap = ximageinfo->pixmap; @@ -692,3 +550,5 @@ int Read_PCX_to_Pixmaps(Display *display, Window window, char *filename, return(PCX_Success); } + +#endif /* !MSDOS */