X-Git-Url: https://git.artsoft.org/?p=rocksndiamonds.git;a=blobdiff_plain;f=src%2Flibgame%2Fimage.c;h=50dce1d713b0df9c49b12be304610cf013adecdb;hp=42c3384a0cd6c8f518b97138750a370de561134c;hb=a8816d6e5319f9ec26a45346b08250f61e95c011;hpb=391f8c019bdd5591015f8f310d97cf077de93fa2 diff --git a/src/libgame/image.c b/src/libgame/image.c index 42c3384a..50dce1d7 100644 --- a/src/libgame/image.c +++ b/src/libgame/image.c @@ -1,7 +1,7 @@ /*********************************************************** * Artsoft Retro-Game Library * *----------------------------------------------------------* -* (c) 1994-2002 Artsoft Entertainment * +* (c) 1994-2006 Artsoft Entertainment * * Holger Schemel * * Detmolder Strasse 189 * * 33604 Bielefeld * @@ -31,13 +31,6 @@ Image *newImage(unsigned int width, unsigned int height, unsigned int depth) unsigned int bytes_per_pixel = (depth + 7) / 8; int i; -#if 0 - if (depth > 8) - Error(ERR_EXIT, "images with more than 256 colors are not supported"); - - depth = 8; -#endif - image = checked_calloc(sizeof(Image)); image->data = checked_calloc(width * height * bytes_per_pixel); image->width = width; @@ -71,28 +64,28 @@ void freeImage(Image *image) note: the internal format is big endian */ #define memory_to_value(ptr, len) ( \ -(len) == 1 ? (unsigned long)( *( (byte *)(ptr)) ) : \ -(len) == 2 ? (unsigned long)(((unsigned long)(*( (byte *)(ptr)) ))<< 8) \ - + ( *(((byte *)(ptr))+1) ) : \ -(len) == 3 ? (unsigned long)(((unsigned long)(*( (byte *)(ptr)) ))<<16) \ - + (((unsigned long)(*(((byte *)(ptr))+1)))<< 8) \ - + ( *(((byte *)(ptr))+2) ) : \ - (unsigned long)(((unsigned long)(*( (byte *)(ptr)) ))<<24) \ - + (((unsigned long)(*(((byte *)(ptr))+1)))<<16) \ - + (((unsigned long)(*(((byte *)(ptr))+2)))<< 8) \ - + ( *(((byte *)(ptr))+3) ) ) +(len) == 1 ? (unsigned int)( *( (byte *)(ptr)) ) : \ +(len) == 2 ? (unsigned int)(((unsigned int)(*( (byte *)(ptr)) ))<< 8) \ + + ( *(((byte *)(ptr))+1) ) : \ +(len) == 3 ? (unsigned int)(((unsigned int)(*( (byte *)(ptr)) ))<<16) \ + + (((unsigned int)(*(((byte *)(ptr))+1)))<< 8) \ + + ( *(((byte *)(ptr))+2) ) : \ + (unsigned int)(((unsigned int)(*( (byte *)(ptr)) ))<<24) \ + + (((unsigned int)(*(((byte *)(ptr))+1)))<<16) \ + + (((unsigned int)(*(((byte *)(ptr))+2)))<< 8) \ + + ( *(((byte *)(ptr))+3) ) ) #define value_to_memory(value, ptr, len) ( \ (len) == 1 ? (*( (byte *)(ptr) ) = ( value ) ) : \ -(len) == 2 ? (*( (byte *)(ptr) ) = (((unsigned long)(value))>> 8), \ +(len) == 2 ? (*( (byte *)(ptr) ) = (((unsigned int)(value))>> 8), \ *(((byte *)(ptr))+1) = ( value ) ) : \ -(len) == 3 ? (*( (byte *)(ptr) ) = (((unsigned long)(value))>>16), \ - *(((byte *)(ptr))+1) = (((unsigned long)(value))>> 8), \ +(len) == 3 ? (*( (byte *)(ptr) ) = (((unsigned int)(value))>>16), \ + *(((byte *)(ptr))+1) = (((unsigned int)(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) ) = (((unsigned int)(value))>>24), \ + *(((byte *)(ptr))+1) = (((unsigned int)(value))>>16), \ + *(((byte *)(ptr))+2) = (((unsigned int)(value))>> 8), \ *(((byte *)(ptr))+3) = ( value ) )) static Pixmap Image_to_Mask(Image *image, Display *display, Window window) @@ -136,8 +129,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; @@ -327,7 +385,7 @@ XImageInfo *Image_to_Pixmap(Display *display, int screen, Visual *visual, if (!private_cmap) { if (options.verbose) - Error(ERR_RETURN, "switching to private colormap"); + Error(ERR_INFO, "switching to private colormap"); /* we just filled up the default colormap -- get a private one which contains all already allocated colors */ @@ -428,7 +486,7 @@ XImageInfo *Image_to_Pixmap(Display *display, int screen, Visual *visual, break; default: - Error(ERR_RETURN,"DirectColor, TrueColor or PseudoColor display needed"); + Error(ERR_INFO,"DirectColor, TrueColor or PseudoColor display needed"); SetError(error, "display class not supported"); return NULL; @@ -502,7 +560,7 @@ XImageInfo *Image_to_Pixmap(Display *display, int screen, Visual *visual, } default: - Error(ERR_RETURN, "RGB or TrueColor image needed"); + Error(ERR_INFO, "RGB or TrueColor image needed"); SetError(error, "image type not supported"); return NULL; @@ -536,7 +594,7 @@ XImageInfo *Image_to_Pixmap(Display *display, int screen, Visual *visual, } default: - Error(ERR_RETURN,"DirectColor, TrueColor or PseudoColor display needed"); + Error(ERR_INFO,"DirectColor, TrueColor or PseudoColor display needed"); SetError(error, "display class not supported"); return NULL; @@ -571,6 +629,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,17 +643,17 @@ 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) { +#if 1 + zoom_factor = MIN(src_width / dst_width, src_height / dst_height); +#else zoom_factor = src_width / dst_width; +#endif /* adjust source image size to integer multiple of destination size */ src_width = dst_width * zoom_factor; @@ -601,21 +661,28 @@ void ZoomPixmap(Display *display, GC gc, Pixmap src_pixmap, Pixmap dst_pixmap, } else { +#if 1 + zoom_factor = MIN(dst_width / src_width, dst_height / src_height); +#else zoom_factor = dst_width / src_width; +#endif /* no adjustment needed when scaling up (some pixels may be left blank) */ } /* 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; @@ -652,7 +719,7 @@ void ZoomPixmap(Display *display, GC gc, Pixmap src_pixmap, Pixmap dst_pixmap, for (i = 0; i < bytes_per_pixel; i++) *dst_ptr++ = *(src_ptr + i); - src_ptr += i; + src_ptr += bytes_per_pixel; } } } @@ -754,18 +821,27 @@ 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; static struct ArtworkListInfo *image_info = NULL; +#if 1 +static void *Load_Image(char *filename) +#else static void *Load_PCX(char *filename) +#endif { ImageInfo *img_info; #if 0 - printf("loading PCX file '%s'\n", filename); + printf("::: loading PCX file '%s'\n", filename); #endif img_info = checked_calloc(sizeof(ImageInfo)); @@ -780,7 +856,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 +887,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 +909,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 file_list[graphic].token; -#else - struct FileInfo *file_list = getImageListEntry(graphic); + return (img_info != NULL ? img_info->original_width : 0); +} + +int getOriginalImageHeightFromImageID(int pos) +{ + ImageInfo *img_info = getImageInfoEntryFromImageID(pos); + + 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) @@ -865,7 +942,7 @@ int getImageIDFromToken(char *token) int i; for (i = 0; i < num_list_entries; i++) - if (strcmp(file_list[i].token, token) == 0) + if (strEqual(file_list[i].token, token)) return i; return -1; @@ -957,34 +1034,55 @@ void InitImageList(struct ConfigInfo *config_list, int num_file_list_entries, /* ---------- initialize artwork loading/freeing functions ---------- */ +#if 1 + image_info->load_artwork = Load_Image; +#else image_info->load_artwork = Load_PCX; +#endif image_info->free_artwork = FreeImage; } void ReloadCustomImages() { #if 0 - printf("DEBUG: reloading images '%s' ...\n", artwork.gfx_current_identifier); + printf("::: reloading images '%s' ...\n", artwork.gfx_current_identifier); #endif + print_timestamp_init("ReloadCustomImages"); + LoadArtworkConfig(image_info); + print_timestamp_time("LoadArtworkConfig"); + ReloadCustomArtworkList(image_info); + print_timestamp_time("ReloadCustomArtworkList"); + + print_timestamp_done("ReloadCustomImages"); } -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 - printf("CreateImageWithSmallImages: '%s' done\n", img_info->source_filename); -#endif +void ScaleImage(int pos, int zoom_factor) +{ + ImageInfo *img_info = getImageInfoEntryFromImageID(pos); + + if (img_info == NULL || img_info->scaled_up) + return; + + if (zoom_factor != 1) + ScaleBitmap(img_info->bitmap, zoom_factor); + + img_info->scaled_up = TRUE; } void FreeAllImages()