added support for special media buttons on Amazon Fire TV remote control
[rocksndiamonds.git] / src / libgame / image.c
index 7f8302fcc2605101fdaae9f404367b7272dbe26f..699093b7b7ebb718e6a6d74144ba3c5b81caada8 100644 (file)
@@ -1,15 +1,13 @@
-/***********************************************************
-* Artsoft Retro-Game Library                               *
-*----------------------------------------------------------*
-* (c) 1994-2006 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 "misc.h"
@@ -21,60 +19,66 @@ struct ImageInfo
   char *source_filename;
   int num_references;
 
-  Bitmap *bitmap;
+  Bitmap *bitmaps[NUM_IMG_BITMAP_POINTERS];
 
   int original_width;                  /* original image file width */
   int original_height;                 /* original image file height */
 
   boolean contains_small_images;       /* set after adding small images */
+  boolean contains_textures;           /* set after adding GPU textures */
   boolean scaled_up;                   /* set after scaling up */
+
+  int conf_tile_size;                  /* tile size as defined in config */
+  int game_tile_size;                  /* tile size as resized for game */
+
+  char *leveldir;                      /* level set when image was loaded */
 };
 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);
-#endif
-
-  img_info = checked_calloc(sizeof(ImageInfo));
+  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 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->bitmap->width;
-  img_info->original_height = img_info->bitmap->height;
+  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;
 }
 
 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);
@@ -108,11 +112,11 @@ static ImageInfo *getImageInfoEntryFromImageID(int pos)
   return img_info[list_pos];
 }
 
-Bitmap *getBitmapFromImageID(int pos)
+Bitmap **getBitmapsFromImageID(int pos)
 {
   ImageInfo *img_info = getImageInfoEntryFromImageID(pos);
 
-  return (img_info != NULL ? img_info->bitmap : NULL);
+  return (img_info != NULL ? img_info->bitmaps : NULL);
 }
 
 int getOriginalImageWidthFromImageID(int pos)
@@ -136,6 +140,13 @@ char *getTokenFromImageID(int graphic)
   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;
@@ -235,20 +246,12 @@ 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("::: reloading images '%s' ...\n", artwork.gfx_current_identifier);
-#endif
-
   print_timestamp_init("ReloadCustomImages");
 
   LoadArtworkConfig(image_info);
@@ -260,17 +263,132 @@ void ReloadCustomImages()
   print_timestamp_done("ReloadCustomImages");
 }
 
+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;
 
-  CreateBitmapWithSmallBitmaps(img_info->bitmap, zoom_factor, tile_size);
+  if (CheckIfImageContainsSmallImages(img_info, tile_size))
+    return;
+
+  CreateBitmapWithSmallBitmaps(img_info->bitmaps, zoom_factor, tile_size);
 
   img_info->contains_small_images = TRUE;
-  img_info->scaled_up = 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)
@@ -281,7 +399,7 @@ void ScaleImage(int pos, int zoom_factor)
     return;
 
   if (zoom_factor != 1)
-    ScaleBitmap(img_info->bitmap, zoom_factor);
+    ScaleBitmap(img_info->bitmaps, zoom_factor);
 
   img_info->scaled_up = TRUE;
 }