X-Git-Url: https://git.artsoft.org/?p=rocksndiamonds.git;a=blobdiff_plain;f=src%2Flibgame%2Fimage.c;h=699093b7b7ebb718e6a6d74144ba3c5b81caada8;hp=c4d3080805ec3f685b1494a0010b35e990869fbb;hb=0d214d4e314f6f42df24be140bb433e980319767;hpb=ee0895b12e544444db37febb1242bcc8a72d6ad8 diff --git a/src/libgame/image.c b/src/libgame/image.c index c4d30808..699093b7 100644 --- a/src/libgame/image.c +++ b/src/libgame/image.c @@ -1,766 +1,410 @@ -/*********************************************************** -* 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) +struct ImageInfo { - 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"); + char *source_filename; + int num_references; - depth = 8; -#endif + Bitmap *bitmaps[NUM_IMG_BITMAP_POINTERS]; - 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; + int original_width; /* original image file width */ + int original_height; /* original image file height */ - image->rgb.used = 0; - for (i=0; irgb.color_used[i] = FALSE; + boolean contains_small_images; /* set after adding small images */ + boolean contains_textures; /* set after adding GPU textures */ + boolean scaled_up; /* set after scaling up */ - image->type = (depth < 8 ? IMAGETYPE_BITMAP : - depth > 8 ? IMAGETYPE_TRUECOLOR : IMAGETYPE_RGB); + int conf_tile_size; /* tile size as defined in config */ + int game_tile_size; /* tile size as resized for game */ - return image; -} + char *leveldir; /* level set when image was loaded */ +}; +typedef struct ImageInfo ImageInfo; -void freeImage(Image *image) -{ - free(image->data); - free(image); -} +static struct ArtworkListInfo *image_info = NULL; -#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) +static void *Load_Image(char *filename) { - 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; + ImageInfo *img_info = checked_calloc(sizeof(ImageInfo)); - bytes_per_row = (image->width + 7) / 8; - mask_data = checked_calloc(bytes_per_row * image->height); + if ((img_info->bitmaps[IMG_BITMAP_STANDARD] = LoadImage(filename)) == NULL) + { + Error(ERR_WARN, "cannot load image file '%s': LoadImage() failed: %s", + filename, GetError()); - src_ptr = image->data; - dst_ptr = mask_data; + free(img_info); - /* 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 - */ + return NULL; + } - 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 */ + img_info->source_filename = getStringCopy(filename); - 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 */ + img_info->original_width = img_info->bitmaps[IMG_BITMAP_STANDARD]->width; + img_info->original_height = img_info->bitmaps[IMG_BITMAP_STANDARD]->height; - 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 */ - } - } + img_info->contains_small_images = FALSE; + img_info->contains_textures = FALSE; + img_info->scaled_up = FALSE; - dst_ptr += bytes_per_row; /* continue with leftmost byte of next row */ - } + img_info->conf_tile_size = 0; // will be set later + img_info->game_tile_size = 0; // will be set later - mask_pixmap = XCreateBitmapFromData(display, window, (char *)mask_data, - image->width, image->height); - free(mask_data); + img_info->leveldir = NULL; // will be set later - return mask_pixmap; + return img_info; } -static int bitsPerPixelAtDepth(Display *display, int screen, int depth) +static void FreeImage(void *ptr) { - XPixmapFormatValues *pixmap_format; - int i, num_pixmap_formats, bits_per_pixel = -1; + ImageInfo *image = (ImageInfo *)ptr; + int i; - /* get Pixmap formats supported by the X server */ - pixmap_format = XListPixmapFormats(display, &num_pixmap_formats); + if (image == NULL) + return; - /* find format that matches the given depth */ - for (i=0; ibitmaps[i]) + FreeBitmap(image->bitmaps[i]); - XFree(pixmap_format); + if (image->source_filename) + free(image->source_filename); - if (bits_per_pixel == -1) - Error(ERR_EXIT, "cannot find pixmap format for depth %d", depth); + free(image); +} - return bits_per_pixel; +int getImageListSize() +{ + return (image_info->num_file_list_entries + + image_info->num_dynamic_file_list_entries); } -XImageInfo *Image_to_Pixmap(Display *display, int screen, Visual *visual, - Window window, GC gc, int depth, Image *image) +struct FileInfo *getImageListEntryFromImageID(int pos) { - static XColor xcolor_private[NOFLASH_COLORS]; - static int colorcell_used[NOFLASH_COLORS]; - static Colormap global_cmap = 0; - static Pixel *global_cmap_index; - static int num_cmap_entries, free_cmap_entries; - static boolean private_cmap = FALSE; - Pixel *redvalue, *greenvalue, *bluevalue; - unsigned int display_bytes_per_pixel, display_bits_per_pixel; - unsigned int a, c = 0, x, y; - XColor xcolor; - XImage *ximage; - XImageInfo *ximageinfo; - byte *src_ptr, *dst_ptr; - char *error = "Image_to_Pixmap(): %s"; - - if (image->type == IMAGETYPE_TRUECOLOR && depth == 8) - { - SetError(error, "cannot handle true-color images on 8-bit display"); - return NULL; - } + int num_list_entries = image_info->num_file_list_entries; + int list_pos = (pos < num_list_entries ? pos : pos - num_list_entries); - 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; - } - } + return (pos < num_list_entries ? &image_info->file_list[list_pos] : + &image_info->dynamic_file_list[list_pos]); +} - xcolor.flags = DoRed | DoGreen | DoBlue; - redvalue = greenvalue = bluevalue = NULL; - ximageinfo = checked_malloc(sizeof(XImageInfo)); - ximageinfo->display = display; - ximageinfo->depth = depth; +static ImageInfo *getImageInfoEntryFromImageID(int pos) +{ + 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); - 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; + return img_info[list_pos]; +} - redvalue = (Pixel *)checked_malloc(sizeof(Pixel) * 256); - greenvalue = (Pixel *)checked_malloc(sizeof(Pixel) * 256); - bluevalue = (Pixel *)checked_malloc(sizeof(Pixel) * 256); +Bitmap **getBitmapsFromImageID(int pos) +{ + ImageInfo *img_info = getImageInfoEntryFromImageID(pos); - ximageinfo->cmap = global_cmap; + return (img_info != NULL ? img_info->bitmaps : NULL); +} - retry_direct: /* tag we hit if a DirectColor allocation fails on - * default colormap */ +int getOriginalImageWidthFromImageID(int pos) +{ + ImageInfo *img_info = getImageInfoEntryFromImageID(pos); - /* calculate number of distinct colors in each band */ + return (img_info != NULL ? img_info->original_width : 0); +} - 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; - } +int getOriginalImageHeightFromImageID(int pos) +{ + ImageInfo *img_info = getImageInfoEntryFromImageID(pos); - break; - } + return (img_info != NULL ? img_info->original_height : 0); +} - case PseudoColor: +char *getTokenFromImageID(int graphic) +{ + struct FileInfo *file_list = getImageListEntryFromImageID(graphic); - ximageinfo->cmap = global_cmap; + return (file_list != NULL ? file_list->token : NULL); +} - 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; - } +char *getFilenameFromImageID(int graphic) +{ + struct FileInfo *file_list = getImageListEntryFromImageID(graphic); - /* - printf("still %d free colormap entries\n", free_cmap_entries); - */ + return (file_list != NULL ? file_list->filename : NULL); +} - 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"); +int getImageIDFromToken(char *token) +{ + struct FileInfo *file_list = image_info->file_list; + int num_list_entries = image_info->num_file_list_entries; + int i; - return NULL; - } + for (i = 0; i < num_list_entries; i++) + if (strEqual(file_list[i].token, token)) + return i; -#if DEBUG_TIMING - debug_print_timestamp(2, " ALLOCATING IMAGE COLORS: "); -#endif + return -1; +} - /* create XImage from internal image structure and convert it to Pixmap */ +char *getImageConfigFilename() +{ + return getCustomArtworkConfigFilename(image_info->type); +} - display_bits_per_pixel = bitsPerPixelAtDepth(display, screen, depth); - display_bytes_per_pixel = (display_bits_per_pixel + 7) / 8; +int getImageListPropertyMappingSize() +{ + return image_info->num_property_mapping_entries; +} - 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; +struct PropertyMapping *getImageListPropertyMapping() +{ + return image_info->property_mapping; +} - src_ptr = image->data; - dst_ptr = (byte *)ximage->data; +void 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) +{ + int i; - switch (visual->class) - { - case DirectColor: - case TrueColor: - { - Pixel pixval; + image_info = checked_calloc(sizeof(struct ArtworkListInfo)); + image_info->type = ARTWORK_TYPE_GRAPHICS; - 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; - } + /* ---------- initialize file list and suffix lists ---------- */ - break; - } + image_info->num_file_list_entries = num_file_list_entries; + image_info->num_dynamic_file_list_entries = 0; - 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; - } - } - } + image_info->file_list = + getFileListFromConfigList(config_list, config_suffix_list, ignore_tokens, + num_file_list_entries); + image_info->dynamic_file_list = NULL; - break; - } + image_info->num_suffix_list_entries = 0; + for (i = 0; config_suffix_list[i].token != NULL; i++) + image_info->num_suffix_list_entries++; - default: - Error(ERR_RETURN,"DirectColor, TrueColor or PseudoColor display needed"); - SetError(error, "display class not supported"); + image_info->suffix_list = config_suffix_list; - return NULL; - } + /* ---------- initialize base prefix and suffixes lists ---------- */ - if (redvalue) - { - free((byte *)redvalue); - free((byte *)greenvalue); - free((byte *)bluevalue); - } + image_info->num_base_prefixes = 0; + for (i = 0; base_prefixes[i] != NULL; i++) + image_info->num_base_prefixes++; -#if DEBUG_TIMING - debug_print_timestamp(2, " CONVERTING IMAGE TO XIMAGE:"); -#endif + image_info->num_ext1_suffixes = 0; + for (i = 0; ext1_suffixes[i] != NULL; i++) + image_info->num_ext1_suffixes++; - ximageinfo->pixmap = XCreatePixmap(display, window, - ximage->width, ximage->height, - ximageinfo->depth); + image_info->num_ext2_suffixes = 0; + for (i = 0; ext2_suffixes[i] != NULL; i++) + image_info->num_ext2_suffixes++; - XPutImage(ximageinfo->display, ximageinfo->pixmap, gc, - ximage, 0, 0, 0, 0, ximage->width, ximage->height); + image_info->num_ext3_suffixes = 0; + for (i = 0; ext3_suffixes[i] != NULL; i++) + image_info->num_ext3_suffixes++; - XDestroyImage(ximage); + image_info->num_ignore_tokens = 0; + for (i = 0; ignore_tokens[i] != NULL; i++) + image_info->num_ignore_tokens++; - return ximageinfo; -} + 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; -void freeXImage(Image *image, XImageInfo *ximageinfo) -{ - 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); -} + image_info->num_property_mapping_entries = 0; -int Read_PCX_to_Pixmap(Display *display, Window window, GC gc, char *filename, - Pixmap *pixmap, Pixmap *pixmap_mask) -{ - 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); + image_info->property_mapping = NULL; - return PCX_OtherError; - } + /* ---------- initialize artwork reference and content lists ---------- */ + + image_info->sizeof_artwork_list_entry = sizeof(ImageInfo *); + + image_info->artwork_list = + checked_calloc(num_file_list_entries * sizeof(ImageInfo *)); + image_info->dynamic_artwork_list = NULL; - /* if a private colormap has been created, install it */ - if (ximageinfo->cmap != DefaultColormap(display, screen)) - XSetWindowColormap(display, window, ximageinfo->cmap); + image_info->content_list = NULL; -#if DEBUG_TIMING - debug_print_timestamp(2, " CONVERTING IMAGE TO PIXMAP:"); -#endif + /* ---------- initialize artwork loading/freeing functions ---------- */ - /* create clip mask for the image */ - ximageinfo->pixmap_mask = Image_to_Mask(image, display, window); + image_info->load_artwork = Load_Image; + image_info->free_artwork = FreeImage; +} -#if DEBUG_TIMING - debug_print_timestamp(2, " CONVERTING IMAGE TO MASK: "); -#endif +void ReloadCustomImages() +{ + print_timestamp_init("ReloadCustomImages"); - *pixmap = ximageinfo->pixmap; - *pixmap_mask = ximageinfo->pixmap_mask; + LoadArtworkConfig(image_info); + print_timestamp_time("LoadArtworkConfig"); - /* free generic image and ximageinfo after native Pixmap has been created */ - free(ximageinfo); - freeImage(image); + ReloadCustomArtworkList(image_info); + print_timestamp_time("ReloadCustomArtworkList"); - return PCX_Success; + print_timestamp_done("ReloadCustomImages"); } -#endif /* PLATFORM_UNIX */ -#endif /* TARGET_X11 */ +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; -/* ========================================================================= */ -/* PLATFORM INDEPENDANT IMAGE FUNCTIONS */ -/* ========================================================================= */ + if (img_info->bitmaps[i]) + { + FreeBitmap(img_info->bitmaps[i]); -struct ImageInfo -{ - char *source_filename; - int num_references; + img_info->bitmaps[i] = NULL; + } + } - Bitmap *bitmap; -}; -typedef struct ImageInfo ImageInfo; + // 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; + } -static struct ArtworkListInfo *image_info = NULL; + img_info->contains_small_images = FALSE; -static void *Load_PCX(char *filename) -{ - ImageInfo *img_info; + 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) -#if 0 - printf("loading PCX file '%s'\n", filename); -#endif + setString(&img_info->leveldir, leveldir_current->identifier); - img_info = checked_calloc(sizeof(ImageInfo)); + // 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->bitmap = LoadImage(filename)) == NULL) + if (img_info->game_tile_size != gfx.game_tile_size) { - Error(ERR_WARN, "cannot read image file '%s': LoadImage() failed: %s", - filename, GetError()); - free(img_info); - return NULL; - } + ReCreateGameTileSizeBitmap(img_info->bitmaps); - img_info->source_filename = getStringCopy(filename); + img_info->game_tile_size = gfx.game_tile_size; + } - return img_info; + return TRUE; } -static void FreeImage(void *ptr) +void CreateImageWithSmallImages(int pos, int zoom_factor, int tile_size) { - ImageInfo *image = (ImageInfo *)ptr; + ImageInfo *img_info = getImageInfoEntryFromImageID(pos); - if (image == NULL) + if (img_info == NULL) return; - if (image->bitmap) - FreeBitmap(image->bitmap); - - if (image->source_filename) - free(image->source_filename); + if (CheckIfImageContainsSmallImages(img_info, tile_size)) + return; - free(image); -} + CreateBitmapWithSmallBitmaps(img_info->bitmaps, zoom_factor, tile_size); -struct FileInfo *getCurrentImageList() -{ - return image_info->file_list; -} + img_info->contains_small_images = TRUE; + img_info->scaled_up = TRUE; // scaling was also done here -Bitmap *getBitmapFromImageID(int graphic) -{ - ImageInfo **img_info = (ImageInfo **)image_info->artwork_list; + img_info->conf_tile_size = tile_size; + img_info->game_tile_size = gfx.game_tile_size; - return (img_info[graphic] != NULL ? img_info[graphic]->bitmap : NULL); + setString(&img_info->leveldir, leveldir_current->identifier); } -char *getTokenFromImageID(int graphic) +void CreateImageTextures(int pos) { - struct FileInfo *file_list = (struct FileInfo *)image_info->file_list; + ImageInfo *img_info = getImageInfoEntryFromImageID(pos); - return file_list[graphic].token; -} + if (img_info == NULL || img_info->contains_textures) + return; -char *getImageConfigFilename() -{ - return getCustomArtworkConfigFilename(image_info->type); + CreateBitmapTextures(img_info->bitmaps); + + img_info->contains_textures = TRUE; } -void InitImageList(struct ConfigInfo *config_list, - struct ConfigInfo *config_suffix_list, - int num_file_list_entries) +void FreeImageTextures(int pos) { - int i; + ImageInfo *img_info = getImageInfoEntryFromImageID(pos); - image_info = checked_calloc(sizeof(struct ArtworkListInfo)); - - image_info->type = ARTWORK_TYPE_GRAPHICS; - - image_info->num_file_list_entries = num_file_list_entries; - image_info->num_suffix_list_entries = 0; - for (i=0; config_suffix_list[i].token != NULL; i++) - image_info->num_suffix_list_entries++; + if (img_info == NULL || !img_info->contains_textures) + return; - image_info->file_list = - getFileListFromConfigList(config_list, config_suffix_list, - num_file_list_entries); - image_info->suffix_list = config_suffix_list; - image_info->custom_setup_list = NULL; + FreeBitmapTextures(img_info->bitmaps); - image_info->artwork_list = - checked_calloc(num_file_list_entries * sizeof(ImageInfo *)); + img_info->contains_textures = FALSE; +} - image_info->content_list = NULL; +void FreeAllImageTextures() +{ + int num_images = getImageListSize(); + int i; - image_info->load_artwork = Load_PCX; - image_info->free_artwork = FreeImage; + for (i = 0; i < num_images; i++) + FreeImageTextures(i); } -void ReloadCustomImages() +void ScaleImage(int pos, int zoom_factor) { -#if 0 - printf("DEBUG: reloading images '%s' ...\n", artwork.gfx_current_identifier); -#endif + ImageInfo *img_info = getImageInfoEntryFromImageID(pos); - LoadArtworkConfig(image_info); - ReloadCustomArtworkList(image_info); + 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() { - FreeCustomArtworkList(image_info); + FreeCustomArtworkLists(image_info); }