X-Git-Url: https://git.artsoft.org/?p=rocksndiamonds.git;a=blobdiff_plain;f=src%2Flibgame%2Fimage.c;h=699093b7b7ebb718e6a6d74144ba3c5b81caada8;hp=f72c37e81577f52f5c269ea97a5d616fbf950b90;hb=0d214d4e314f6f42df24be140bb433e980319767;hpb=ff2510f5098b545a03965c6b95296eec6885a4fb diff --git a/src/libgame/image.c b/src/libgame/image.c index f72c37e8..699093b7 100644 --- a/src/libgame/image.c +++ b/src/libgame/image.c @@ -1,740 +1,69 @@ -/*********************************************************** -* Artsoft Retro-Game Library * -*----------------------------------------------------------* -* (c) 1994-2002 Artsoft Entertainment * -* Holger Schemel * -* Detmolder Strasse 189 * -* 33604 Bielefeld * -* Germany * -* e-mail: info@artsoft.org * -*----------------------------------------------------------* -* image.c * -***********************************************************/ +// ============================================================================ +// Artsoft Retro-Game Library +// ---------------------------------------------------------------------------- +// (c) 1995-2014 by Artsoft Entertainment +// Holger Schemel +// info@artsoft.org +// http://www.artsoft.org/ +// ---------------------------------------------------------------------------- +// image.c +// ============================================================================ #include "image.h" -#include "pcx.h" #include "misc.h" #include "setup.h" -/* ========================================================================= */ -/* PLATFORM SPECIFIC IMAGE FUNCTIONS */ -/* ========================================================================= */ - -#if defined(TARGET_X11) - -/* for MS-DOS/Allegro, exclude all except newImage() and freeImage() */ - -Image *newImage(unsigned int width, unsigned int height, unsigned int depth) -{ - Image *image; - 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; - image->height = height; - image->depth = depth; - image->bytes_per_pixel = bytes_per_pixel; - image->bytes_per_row = width * bytes_per_pixel; - - image->rgb.used = 0; - for (i=0; irgb.color_used[i] = FALSE; - - image->type = (depth < 8 ? IMAGETYPE_BITMAP : - depth > 8 ? IMAGETYPE_TRUECOLOR : IMAGETYPE_RGB); - - return image; -} - -void freeImage(Image *image) -{ - free(image->data); - free(image); -} - -#if defined(PLATFORM_UNIX) - -/* extra colors to try allocating in private color maps to minimize flashing */ -#define NOFLASH_COLORS 256 - -/* architecture independent value <-> memory conversions; - 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) ) ) - - -#define value_to_memory(value, ptr, len) ( \ -(len) == 1 ? (*( (byte *)(ptr) ) = ( value ) ) : \ -(len) == 2 ? (*( (byte *)(ptr) ) = (((unsigned long)(value))>> 8), \ - *(((byte *)(ptr))+1) = ( value ) ) : \ -(len) == 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) -{ - byte *src_ptr, *dst_ptr, *dst_ptr2; - unsigned int bytes_per_row; - unsigned int x, y, i; - 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 = 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 = 0x01; /* start with leftmost bit in the byte */ - dst_ptr2 = dst_ptr; /* start with leftmost byte in the row */ - - for (x=0; xwidth; x++) - { - for (i=0; ibytes_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 */ - } - - mask_pixmap = XCreateBitmapFromData(display, window, (char *)mask_data, - image->width, image->height); - free(mask_data); - - return mask_pixmap; -} - -static int bitsPerPixelAtDepth(Display *display, int screen, int depth) -{ - XPixmapFormatValues *pixmap_format; - int i, num_pixmap_formats, bits_per_pixel = -1; - - /* 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; itype == IMAGETYPE_TRUECOLOR && depth == 8) - { - SetError(error, "cannot handle true-color images on 8-bit display"); - return NULL; - } - - if (!global_cmap) - { - if (visual == DefaultVisual(display, screen)) - global_cmap = DefaultColormap(display, screen); - else - { - global_cmap = XCreateColormap(display, RootWindow(display, screen), - visual, AllocNone); - private_cmap = TRUE; - } - } - - xcolor.flags = DoRed | DoGreen | DoBlue; - redvalue = greenvalue = bluevalue = NULL; - ximageinfo = checked_malloc(sizeof(XImageInfo)); - ximageinfo->display = display; - ximageinfo->depth = depth; - - switch (visual->class) - { - case TrueColor: - case DirectColor: - { - Pixel pixval; - unsigned int redcolors, greencolors, bluecolors; - unsigned int redstep, greenstep, bluestep; - unsigned int redbottom, greenbottom, bluebottom; - unsigned int redtop, greentop, bluetop; - - redvalue = (Pixel *)checked_malloc(sizeof(Pixel) * 256); - greenvalue = (Pixel *)checked_malloc(sizeof(Pixel) * 256); - bluevalue = (Pixel *)checked_malloc(sizeof(Pixel) * 256); - - ximageinfo->cmap = global_cmap; - - retry_direct: /* tag we hit if a DirectColor allocation fails on - * default colormap */ - - /* calculate number of distinct colors in each band */ - - redcolors = greencolors = bluecolors = 1; - for (pixval=1; pixval; pixval <<= 1) - { - if (pixval & visual->red_mask) - redcolors <<= 1; - if (pixval & visual->green_mask) - greencolors <<= 1; - if (pixval & visual->blue_mask) - bluecolors <<= 1; - } - - /* 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; - bluestep = 256 / bluecolors; - redbottom = greenbottom = bluebottom = 0; - redtop = greentop = bluetop = 0; - - for (a=0; amap_entries; a++) - { - if (redbottom < 256) - redtop = redbottom + redstep; - if (greenbottom < 256) - greentop = greenbottom + greenstep; - if (bluebottom < 256) - bluetop = bluebottom + bluestep; - - xcolor.red = (redtop - 1) << 8; - xcolor.green = (greentop - 1) << 8; - xcolor.blue = (bluetop - 1) << 8; - 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. */ - - if ((visual->class == DirectColor) && - (visual == DefaultVisual(display, screen))) - { - global_cmap = XCopyColormapAndFree(display, global_cmap); - ximageinfo->cmap = global_cmap; - private_cmap = TRUE; - - goto retry_direct; - } - - /* something completely unexpected happened */ - - fprintf(stderr, "Image_to_Pixmap: XAllocColor failed on a TrueColor/Directcolor visual\n"); - - free(redvalue); - free(greenvalue); - free(bluevalue); - free(ximageinfo); - - return NULL; - } - - /* fill in pixel values for each band at this intensity */ - - while ((redbottom < 256) && (redbottom < redtop)) - redvalue[redbottom++] = xcolor.pixel & visual->red_mask; - while ((greenbottom < 256) && (greenbottom < greentop)) - greenvalue[greenbottom++] = xcolor.pixel & visual->green_mask; - while ((bluebottom < 256) && (bluebottom < bluetop)) - bluevalue[bluebottom++] = xcolor.pixel & visual->blue_mask; - } - - break; - } - - case PseudoColor: - - ximageinfo->cmap = global_cmap; - - for (a=0; argb.color_used[a]) - continue; - - xcolor.red = *(image->rgb.red + a); - xcolor.green = *(image->rgb.green + a); - xcolor.blue = *(image->rgb.blue + a); - - /* look if this color already exists in our colormap */ - if (!XAllocColor(display, ximageinfo->cmap, &xcolor)) - { - if (!private_cmap) - { - if (options.verbose) - Error(ERR_RETURN, "switching to private colormap"); - - /* we just filled up the default colormap -- get a private one - which contains all already allocated colors */ - - global_cmap = XCopyColormapAndFree(display, global_cmap); - ximageinfo->cmap = global_cmap; - private_cmap = TRUE; - - /* allocate the rest of the color cells read/write */ - global_cmap_index = - (Pixel *)checked_malloc(sizeof(Pixel) * NOFLASH_COLORS); - for (i=0; i=0; i--) - { - xcolor2.pixel = *(global_cmap_index + i); - xcolor2 = xcolor_private[xcolor2.pixel]; - - if (colorcell_used[xcolor2.pixel]) - continue; - - if ((xcolor.red & mask) == (xcolor2.red & mask) && - (xcolor.green & mask) == (xcolor2.green & mask) && - (xcolor.blue & mask) == (xcolor2.blue & mask)) - { - /* - printf("replacing color cell %ld with a close color\n", - xcolor2.pixel); - */ - color_found = TRUE; - break; - } - } - - if (mask == 0x0000) - break; - - mask = (mask << 1) & 0xffff; - } - - if (!color_found) /* no more free color cells */ - { - SetError(error, "cannot allocate enough color cells"); - return NULL; - } - - xcolor.pixel = xcolor2.pixel; - xcolor_private[xcolor.pixel] = xcolor; - colorcell_used[xcolor.pixel] = TRUE; - XStoreColor(display, ximageinfo->cmap, &xcolor); - free_cmap_entries--; - } - - *(ximageinfo->index + a) = xcolor.pixel; - } - - /* - printf("still %d free colormap entries\n", free_cmap_entries); - */ - - ximageinfo->no = a; /* number of pixels allocated for this image */ - break; - - default: - Error(ERR_RETURN,"DirectColor, TrueColor or PseudoColor display needed"); - SetError(error, "display class not supported"); - - return NULL; - } - -#if DEBUG_TIMING - debug_print_timestamp(2, " ALLOCATING IMAGE COLORS: "); -#endif - - /* create XImage from internal image structure and convert it to Pixmap */ - - display_bits_per_pixel = bitsPerPixelAtDepth(display, screen, depth); - display_bytes_per_pixel = (display_bits_per_pixel + 7) / 8; - - ximage = XCreateImage(display, visual, depth, ZPixmap, - 0, NULL, image->width, image->height, - 8, image->width * display_bytes_per_pixel); - ximage->data = - checked_malloc(image->width * image->height * display_bytes_per_pixel); - ximage->byte_order = MSBFirst; - - src_ptr = image->data; - dst_ptr = (byte *)ximage->data; - - switch (visual->class) - { - case DirectColor: - case TrueColor: - { - Pixel pixval; - - switch (image->type) - { - case IMAGETYPE_RGB: - { - for (y=0; yheight; y++) /* general case */ - { - for (x=0; xwidth; x++) - { - pixval = *src_ptr++; - pixval = - redvalue[image->rgb.red[pixval] >> 8] | - greenvalue[image->rgb.green[pixval] >> 8] | - bluevalue[image->rgb.blue[pixval] >> 8]; - value_to_memory(pixval, dst_ptr, display_bytes_per_pixel); - dst_ptr += display_bytes_per_pixel; - } - } - - break; - } - - case IMAGETYPE_TRUECOLOR: - { - for (y=0; yheight; y++) /* general case */ - { - for (x=0; xwidth; x++) - { - pixval = memory_to_value(src_ptr, image->bytes_per_pixel); - pixval = - redvalue[TRUECOLOR_RED(pixval)] | - greenvalue[TRUECOLOR_GREEN(pixval)] | - bluevalue[TRUECOLOR_BLUE(pixval)]; - value_to_memory(pixval, dst_ptr, display_bytes_per_pixel); - src_ptr += image->bytes_per_pixel; - dst_ptr += display_bytes_per_pixel; - } - } - - break; - } - - default: - Error(ERR_RETURN, "RGB or TrueColor image needed"); - SetError(error, "image type not supported"); - - return NULL; - } - - break; - } - - case PseudoColor: - { - if (display_bytes_per_pixel == 1) /* special case */ - { - for (y=0; yheight; y++) - for (x=0; xwidth; x++) - *dst_ptr++ = ximageinfo->index[c + *src_ptr++]; - } - else /* general case */ - { - for (y=0; yheight; y++) - { - for (x=0; xwidth; x++) - { - value_to_memory(ximageinfo->index[c + *src_ptr++], - dst_ptr, display_bytes_per_pixel); - dst_ptr += display_bytes_per_pixel; - } - } - } - - break; - } - - default: - Error(ERR_RETURN,"DirectColor, TrueColor or PseudoColor display needed"); - SetError(error, "display class not supported"); - - return NULL; - } - - if (redvalue) - { - free((byte *)redvalue); - free((byte *)greenvalue); - 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); - - XDestroyImage(ximage); - - return ximageinfo; -} - -/* - ----------------------------------------------------------------------------- - ZoomPixmap - - Important note: The scaling code currently only supports scaling down the - image by a power of 2 -- scaling up is currently not supported at all! - ----------------------------------------------------------------------------- -*/ - -void ZoomPixmap(Display *display, GC gc, Pixmap src_pixmap, Pixmap dst_pixmap, - int src_width, int src_height, - int dst_width, int dst_height) -{ - XImage *src_ximage, *dst_ximage; - byte *src_ptr, *dst_ptr; - int bits_per_pixel; - int bytes_per_pixel; - int x, y, i; - int zoom_factor = src_width / dst_width; /* currently very limited! */ - int row_skip, col_skip; - - /* copy source pixmap to temporary image */ - src_ximage = XGetImage(display, src_pixmap, 0, 0, - src_width, src_height, AllPlanes, ZPixmap); - - 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); - dst_ximage->data = - checked_malloc(dst_width * dst_height * bytes_per_pixel); - dst_ximage->byte_order = src_ximage->byte_order; - - src_ptr = (byte *)src_ximage->data; - dst_ptr = (byte *)dst_ximage->data; - - col_skip = (zoom_factor - 1) * bytes_per_pixel; - row_skip = col_skip * src_width; - - /* scale image down by scaling factor 'zoom_factor' */ - for (y=0; y < src_height; y += zoom_factor, src_ptr += row_skip) - for (x=0; x < src_width; x += zoom_factor, src_ptr += col_skip) - for (i=0; iindex != 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); -} - -int Read_PCX_to_Pixmap(Display *display, Window window, GC gc, char *filename, - Pixmap *pixmap, Pixmap *pixmap_mask) +struct ImageInfo { - Image *image; - XImageInfo *ximageinfo; - int screen; - Visual *visual; - int depth; - -#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 errno_pcx; - -#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 image structure to X11 Pixmap */ - if (!(ximageinfo = Image_to_Pixmap(display, screen, visual, - window, gc, depth, image))) - { - freeImage(image); - - return PCX_OtherError; - } - - /* if a private colormap has been created, install it */ - if (ximageinfo->cmap != DefaultColormap(display, screen)) - XSetWindowColormap(display, window, ximageinfo->cmap); - -#if DEBUG_TIMING - debug_print_timestamp(2, " CONVERTING IMAGE TO PIXMAP:"); -#endif - - /* 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; - *pixmap_mask = ximageinfo->pixmap_mask; - - /* free generic image and ximageinfo after native Pixmap has been created */ - free(ximageinfo); - freeImage(image); - - return PCX_Success; -} + char *source_filename; + int num_references; -#endif /* PLATFORM_UNIX */ -#endif /* TARGET_X11 */ + Bitmap *bitmaps[NUM_IMG_BITMAP_POINTERS]; + int original_width; /* original image file width */ + int original_height; /* original image file height */ -/* ========================================================================= */ -/* PLATFORM INDEPENDANT IMAGE FUNCTIONS */ -/* ========================================================================= */ + boolean contains_small_images; /* set after adding small images */ + boolean contains_textures; /* set after adding GPU textures */ + boolean scaled_up; /* set after scaling up */ -struct ImageInfo -{ - char *source_filename; - int num_references; + int conf_tile_size; /* tile size as defined in config */ + int game_tile_size; /* tile size as resized for game */ - Bitmap *bitmap; - boolean contains_small_images; + char *leveldir; /* level set when image was loaded */ }; typedef struct ImageInfo ImageInfo; static struct ArtworkListInfo *image_info = NULL; -static void *Load_PCX(char *filename) +static void *Load_Image(char *filename) { - ImageInfo *img_info; - -#if 0 - printf("loading PCX file '%s'\n", filename); -#endif + ImageInfo *img_info = checked_calloc(sizeof(ImageInfo)); - img_info = checked_calloc(sizeof(ImageInfo)); - - if ((img_info->bitmap = LoadImage(filename)) == NULL) + if ((img_info->bitmaps[IMG_BITMAP_STANDARD] = LoadImage(filename)) == NULL) { - Error(ERR_WARN, "cannot read image file '%s': LoadImage() failed: %s", + Error(ERR_WARN, "cannot load image file '%s': LoadImage() failed: %s", filename, GetError()); + free(img_info); + return NULL; } img_info->source_filename = getStringCopy(filename); + img_info->original_width = img_info->bitmaps[IMG_BITMAP_STANDARD]->width; + img_info->original_height = img_info->bitmaps[IMG_BITMAP_STANDARD]->height; + img_info->contains_small_images = FALSE; + img_info->contains_textures = FALSE; + img_info->scaled_up = FALSE; + + img_info->conf_tile_size = 0; // will be set later + img_info->game_tile_size = 0; // will be set later + + img_info->leveldir = NULL; // will be set later return img_info; } @@ -742,12 +71,14 @@ static void *Load_PCX(char *filename) static void FreeImage(void *ptr) { ImageInfo *image = (ImageInfo *)ptr; + int i; if (image == NULL) return; - if (image->bitmap) - FreeBitmap(image->bitmap); + for (i = 0; i < NUM_IMG_BITMAPS; i++) + if (image->bitmaps[i]) + FreeBitmap(image->bitmaps[i]); if (image->source_filename) free(image->source_filename); @@ -761,7 +92,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); @@ -781,28 +112,52 @@ static ImageInfo *getImageInfoEntryFromImageID(int pos) return img_info[list_pos]; } -Bitmap *getBitmapFromImageID(int pos) +Bitmap **getBitmapsFromImageID(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); + ImageInfo *img_info = getImageInfoEntryFromImageID(pos); + + return (img_info != NULL ? img_info->bitmaps : NULL); +} + +int getOriginalImageWidthFromImageID(int pos) +{ + ImageInfo *img_info = getImageInfoEntryFromImageID(pos); - return (img_info[list_pos] != NULL ? img_info[list_pos]->bitmap : NULL); -#else + return (img_info != NULL ? img_info->original_width : 0); +} + +int getOriginalImageHeightFromImageID(int pos) +{ ImageInfo *img_info = getImageInfoEntryFromImageID(pos); - return (img_info != NULL ? img_info->bitmap : NULL); -#endif + return (img_info != NULL ? img_info->original_height : 0); } char *getTokenFromImageID(int graphic) { - struct FileInfo *file_list = (struct FileInfo *)image_info->file_list; + struct FileInfo *file_list = getImageListEntryFromImageID(graphic); - return file_list[graphic].token; + return (file_list != NULL ? file_list->token : NULL); +} + +char *getFilenameFromImageID(int graphic) +{ + struct FileInfo *file_list = getImageListEntryFromImageID(graphic); + + return (file_list != NULL ? file_list->filename : NULL); +} + +int getImageIDFromToken(char *token) +{ + struct FileInfo *file_list = image_info->file_list; + int num_list_entries = image_info->num_file_list_entries; + int i; + + for (i = 0; i < num_list_entries; i++) + if (strEqual(file_list[i].token, token)) + return i; + + return -1; } char *getImageConfigFilename() @@ -821,11 +176,10 @@ struct PropertyMapping *getImageListPropertyMapping() } void InitImageList(struct ConfigInfo *config_list, int num_file_list_entries, - struct ConfigInfo *config_suffix_list, - char **base_prefixes, - char **ext1_suffixes, - char **ext2_suffixes, - char **ext3_suffixes) + struct ConfigTypeInfo *config_suffix_list, + char **base_prefixes, char **ext1_suffixes, + char **ext2_suffixes, char **ext3_suffixes, + char **ignore_tokens) { int i; @@ -838,12 +192,12 @@ void InitImageList(struct ConfigInfo *config_list, int num_file_list_entries, image_info->num_dynamic_file_list_entries = 0; image_info->file_list = - getFileListFromConfigList(config_list, config_suffix_list, + getFileListFromConfigList(config_list, config_suffix_list, ignore_tokens, num_file_list_entries); image_info->dynamic_file_list = NULL; image_info->num_suffix_list_entries = 0; - for (i=0; config_suffix_list[i].token != NULL; i++) + for (i = 0; config_suffix_list[i].token != NULL; i++) image_info->num_suffix_list_entries++; image_info->suffix_list = config_suffix_list; @@ -851,25 +205,30 @@ void InitImageList(struct ConfigInfo *config_list, int num_file_list_entries, /* ---------- initialize base prefix and suffixes lists ---------- */ image_info->num_base_prefixes = 0; - for (i=0; base_prefixes[i] != NULL; i++) + for (i = 0; base_prefixes[i] != NULL; i++) image_info->num_base_prefixes++; image_info->num_ext1_suffixes = 0; - for (i=0; ext1_suffixes[i] != NULL; i++) + for (i = 0; ext1_suffixes[i] != NULL; i++) image_info->num_ext1_suffixes++; image_info->num_ext2_suffixes = 0; - for (i=0; ext2_suffixes[i] != NULL; i++) + for (i = 0; ext2_suffixes[i] != NULL; i++) image_info->num_ext2_suffixes++; image_info->num_ext3_suffixes = 0; - for (i=0; ext3_suffixes[i] != NULL; i++) + for (i = 0; ext3_suffixes[i] != NULL; i++) image_info->num_ext3_suffixes++; + image_info->num_ignore_tokens = 0; + for (i = 0; ignore_tokens[i] != NULL; i++) + image_info->num_ignore_tokens++; + image_info->base_prefixes = base_prefixes; image_info->ext1_suffixes = ext1_suffixes; image_info->ext2_suffixes = ext2_suffixes; image_info->ext3_suffixes = ext3_suffixes; + image_info->ignore_tokens = ignore_tokens; image_info->num_property_mapping_entries = 0; @@ -887,32 +246,162 @@ void InitImageList(struct ConfigInfo *config_list, int num_file_list_entries, /* ---------- initialize artwork loading/freeing functions ---------- */ - image_info->load_artwork = Load_PCX; + image_info->load_artwork = Load_Image; image_info->free_artwork = FreeImage; } void ReloadCustomImages() { -#if 0 - printf("DEBUG: 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) +static boolean CheckIfImageContainsSmallImages(ImageInfo *img_info, + int tile_size) +{ + if (!img_info->contains_small_images) + return FALSE; + + // at this point, small images already exist for this image; + // now do some checks that may require re-creating small (or in-game) images + + // special case 1: + // + // check if the configured tile size for an already loaded image has changed + // from one level set to another; this should usually not happen, but if a + // custom artwork set redefines classic (or default) graphics with wrong tile + // size (by mistake or by intention), it will be corrected to its original + // tile size here by forcing complete re-creation of all small images again + + if (!strEqual(img_info->leveldir, leveldir_current->identifier) && + img_info->conf_tile_size != tile_size) + { + int bitmap_nr = GET_BITMAP_ID_FROM_TILESIZE(img_info->conf_tile_size); + int i; + + // free all calculated, resized bitmaps, but keep last configured size + for (i = 0; i < NUM_IMG_BITMAPS; i++) + { + if (i == bitmap_nr) + continue; + + if (img_info->bitmaps[i]) + { + FreeBitmap(img_info->bitmaps[i]); + + img_info->bitmaps[i] = NULL; + } + } + + // re-create small bitmaps from last configured size as new default size + if (bitmap_nr != IMG_BITMAP_STANDARD) + { + img_info->bitmaps[IMG_BITMAP_STANDARD] = img_info->bitmaps[bitmap_nr]; + img_info->bitmaps[bitmap_nr] = NULL; + } + + img_info->contains_small_images = FALSE; + + return FALSE; + } + + // special case 1 (continued): + // + // if different tile sizes are used in same image file (usually by mistake, + // like forgetting option ".tile_size" for one or more graphic definitions), + // make sure to use only the first tile size that is processed for this image + // (and ignore all subsequent, potentially different tile size definitions + // for this image within the current level set by disabling the above check) + + setString(&img_info->leveldir, leveldir_current->identifier); + + // special case 2: + // + // graphic config setting "game.tile_size" has changed since last level set; + // this may require resizing image to new size required for in-game graphics + + if (img_info->game_tile_size != gfx.game_tile_size) + { + ReCreateGameTileSizeBitmap(img_info->bitmaps); + + img_info->game_tile_size = gfx.game_tile_size; + } + + return TRUE; +} + +void CreateImageWithSmallImages(int pos, int zoom_factor, int tile_size) { ImageInfo *img_info = getImageInfoEntryFromImageID(pos); - if (img_info == NULL || img_info->contains_small_images) + if (img_info == NULL) return; - printf(" creating small image for '%s'\n", img_info->source_filename); + if (CheckIfImageContainsSmallImages(img_info, tile_size)) + return; - CreateBitmapWithSmallBitmaps(img_info->bitmap); + CreateBitmapWithSmallBitmaps(img_info->bitmaps, zoom_factor, tile_size); img_info->contains_small_images = TRUE; + img_info->scaled_up = TRUE; // scaling was also done here + + img_info->conf_tile_size = tile_size; + img_info->game_tile_size = gfx.game_tile_size; + + setString(&img_info->leveldir, leveldir_current->identifier); +} + +void CreateImageTextures(int pos) +{ + ImageInfo *img_info = getImageInfoEntryFromImageID(pos); + + if (img_info == NULL || img_info->contains_textures) + return; + + CreateBitmapTextures(img_info->bitmaps); + + img_info->contains_textures = TRUE; +} + +void FreeImageTextures(int pos) +{ + ImageInfo *img_info = getImageInfoEntryFromImageID(pos); + + if (img_info == NULL || !img_info->contains_textures) + return; + + FreeBitmapTextures(img_info->bitmaps); + + img_info->contains_textures = FALSE; +} + +void FreeAllImageTextures() +{ + int num_images = getImageListSize(); + int i; + + for (i = 0; i < num_images; i++) + FreeImageTextures(i); +} + +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->bitmaps, zoom_factor); + + img_info->scaled_up = TRUE; } void FreeAllImages()