Author: bklaas
Date: Fri Feb 12 10:58:23 2010
New Revision: 8498

URL: http://svn.slimdevices.com/jive?rev=8498&view=rev
Log:
Fixed Bug: 15617
Description: Alan's patch to C code to optimize skin switching utilizing LRU 
cache for images
I've tested this on desktop all day and the speed of skin switching is greatly 
improved. No regressions detected in testing.

Modified:
    7.5/trunk/squeezeplay/src/squeezeplay/src/ui/jive.h
    7.5/trunk/squeezeplay/src/squeezeplay/src/ui/jive_surface.c
    7.5/trunk/squeezeplay/src/squeezeplay/src/ui/jive_tile.c

Modified: 7.5/trunk/squeezeplay/src/squeezeplay/src/ui/jive.h
URL: 
http://svn.slimdevices.com/jive/7.5/trunk/squeezeplay/src/squeezeplay/src/ui/jive.h?rev=8498&r1=8497&r2=8498&view=diff
==============================================================================
--- 7.5/trunk/squeezeplay/src/squeezeplay/src/ui/jive.h (original)
+++ 7.5/trunk/squeezeplay/src/squeezeplay/src/ui/jive.h Fri Feb 12 10:58:23 2010
@@ -214,13 +214,6 @@
        bool hidden;
 };
 
-struct jive_surface {
-       Uint32 refcount;
-       
-       SDL_Surface *sdl;
-       Sint16 offset_x, offset_y;      
-};
-
 struct jive_scroll_event {
        int rel;
 };
@@ -414,6 +407,7 @@
 void jive_tile_free(JiveTile *tile);
 void jive_tile_blit(JiveTile *tile, JiveSurface *dst, Uint16 dx, Uint16 dy, 
Uint16 dw, Uint16 dh);
 void jive_tile_blit_centered(JiveTile *tile, JiveSurface *dst, Uint16 dx, 
Uint16 dy, Uint16 dw, Uint16 dh);
+SDL_Surface *jive_tile_get_image_surface(JiveTile *tile);
 
 
 /* Font functions */

Modified: 7.5/trunk/squeezeplay/src/squeezeplay/src/ui/jive_surface.c
URL: 
http://svn.slimdevices.com/jive/7.5/trunk/squeezeplay/src/squeezeplay/src/ui/jive_surface.c?rev=8498&r1=8497&r2=8498&view=diff
==============================================================================
--- 7.5/trunk/squeezeplay/src/squeezeplay/src/ui/jive_surface.c (original)
+++ 7.5/trunk/squeezeplay/src/squeezeplay/src/ui/jive_surface.c Fri Feb 12 
10:58:23 2010
@@ -7,11 +7,25 @@
 #include "common.h"
 #include "jive.h"
 
+struct jive_surface {
+       Uint32 refcount;
+
+       bool is_tile; /* so we can tell if this is supposed to be a Tile or a 
Surface: they get mixed up */
+       SDL_Surface *sdl;
+       Sint16 offset_x, offset_y;
+};
+
 
 #ifdef SCREEN_ROTATION_ENABLED
 static SDL_Surface *real_sdl = NULL;
 #endif
 
+static SDL_Surface * _resolve_SDL_surface(JiveSurface *srf) {
+       if (srf->is_tile)
+               return jive_tile_get_image_surface((JiveTile *)srf);
+       else
+               return srf->sdl;
+}
 
 JiveSurface *jive_surface_set_video_mode(Uint16 w, Uint16 h, Uint16 bpp, bool 
fullscreen) {
        JiveSurface *srf;
@@ -164,6 +178,9 @@
 static JiveSurface *jive_surface_display_format(JiveSurface *srf) {
        SDL_Surface *sdl;
 
+       if (srf->is_tile)
+               LOG_ERROR(log_ui_draw, "jive_surface_display_format called with 
JiveTile");
+
        if (srf->sdl == NULL || SDL_GetVideoSurface() == NULL) {
                return srf;
        }
@@ -182,33 +199,9 @@
 
 
 JiveSurface *jive_surface_load_image(const char *path) {
-       char *fullpath;
-       JiveSurface *srf;
-       SDL_Surface *sdl;
-
-       if (!path) {
-               return NULL;
-       }
-
-       fullpath = malloc(PATH_MAX);
-       if (!squeezeplay_find_file(path, fullpath)) {
-               LOG_ERROR(log_ui_draw, "Can't find image %s\n", path);
-               free(fullpath);
-               return NULL;
-       }
-
-       sdl = IMG_Load(fullpath);
-       if (!sdl) {
-               LOG_WARN(log_ui_draw, "Error loading surface: %s\n", 
IMG_GetError());
-       }
-
-       free(fullpath);
-
-       srf = calloc(sizeof(JiveSurface), 1);
-       srf->refcount = 1;
-       srf->sdl = sdl;
-
-       return jive_surface_display_format(srf);
+
+       /* delegate to JiveTile to get image LRU cache */
+       return (JiveSurface*)jive_tile_load_image(path);
 }
 
 
@@ -225,12 +218,14 @@
 
 
 int jive_surface_set_wm_icon(JiveSurface *srf) {
-       SDL_WM_SetIcon(srf->sdl, NULL);
+       SDL_WM_SetIcon(_resolve_SDL_surface(srf), NULL);
        return 1;
 }
 
 
 int jive_surface_save_bmp(JiveSurface *srf, const char *file) {
+       if (srf->is_tile)
+               LOG_ERROR(log_ui, "jive_surface_*() called for JiveTile");
        if (!srf->sdl) {
                LOG_ERROR(log_ui, "Underlying sdl surface already freed, 
possibly with release()");
                return 0;
@@ -278,8 +273,8 @@
 
 
 int jive_surface_cmp(JiveSurface *a, JiveSurface *b, Uint32 key) {
-       SDL_Surface *sa = a->sdl;
-       SDL_Surface *sb = b->sdl;
+       SDL_Surface *sa = _resolve_SDL_surface(a);
+       SDL_Surface *sb = _resolve_SDL_surface(b);
        Uint32 pa, pb;
        int x, y;
        int count=0, equal=0;
@@ -344,6 +339,8 @@
 
 void jive_surface_set_clip(JiveSurface *srf, SDL_Rect *r) {
        SDL_Rect tmp;
+       if (srf->is_tile)
+               LOG_ERROR(log_ui, "jive_surface_*() called for JiveTile");
        if (!srf->sdl) {
                LOG_ERROR(log_ui, "Underlying sdl surface already freed, 
possibly with release()");
                return;
@@ -378,6 +375,8 @@
 
 void jive_surface_set_clip_arg(JiveSurface *srf, Uint16 x, Uint16 y, Uint16 w, 
Uint16 h) {
        SDL_Rect tmp;
+       if (srf->is_tile)
+               LOG_ERROR(log_ui, "jive_surface_*() called for JiveTile");
        if (!srf->sdl) {
                LOG_ERROR(log_ui, "Underlying sdl surface already freed, 
possibly with release()");
                return;
@@ -393,6 +392,8 @@
 
 void jive_surface_get_clip_arg(JiveSurface *srf, Uint16 *x, Uint16 *y, Uint16 
*w, Uint16 *h) {
        SDL_Rect tmp;
+       if (srf->is_tile)
+               LOG_ERROR(log_ui, "jive_surface_*() called for JiveTile");
        if (!srf->sdl) {
                LOG_ERROR(log_ui, "Underlying sdl surface already freed, 
possibly with release()");
                *x = 0;
@@ -465,7 +466,7 @@
 
 /* this function must only be used for blitting tiles */
 void jive_surface_get_tile_blit(JiveSurface *srf, SDL_Surface **sdl, Sint16 
*x, Sint16 *y) {
-       *sdl = srf->sdl;
+       *sdl = _resolve_SDL_surface(srf);
        *x = srf->offset_x;
        *y = srf->offset_y;
 }
@@ -480,7 +481,7 @@
        dr.x = dx + dst->offset_x;
        dr.y = dy + dst->offset_y;
 
-       SDL_BlitSurface(src->sdl, 0, dst->sdl, &dr);
+       SDL_BlitSurface(_resolve_SDL_surface(src), 0, dst->sdl, &dr);
 
 #ifdef JIVE_PROFILE_BLIT
        t1 = jive_jiffies();
@@ -499,7 +500,7 @@
        sr.x = sx; sr.y = sy; sr.w = sw; sr.h = sh;
        dr.x = dx + dst->offset_x; dr.y = dy + dst->offset_y;
 
-       SDL_BlitSurface(src->sdl, &sr, dst->sdl, &dr);
+       SDL_BlitSurface(_resolve_SDL_surface(src), &sr, dst->sdl, &dr);
 
 #ifdef JIVE_PROFILE_BLIT
        t1 = jive_jiffies();
@@ -517,8 +518,8 @@
        dr.x = dx + dst->offset_x;
        dr.y = dy + dst->offset_y;
 
-       SDL_SetAlpha(src->sdl, SDL_SRCALPHA, alpha);
-       SDL_BlitSurface(src->sdl, 0, dst->sdl, &dr);
+       SDL_SetAlpha(_resolve_SDL_surface(src), SDL_SRCALPHA, alpha);
+       SDL_BlitSurface(_resolve_SDL_surface(src), 0, dst->sdl, &dr);
 
 #ifdef JIVE_PROFILE_BLIT
        t1 = jive_jiffies();
@@ -528,6 +529,11 @@
 
 
 void jive_surface_get_size(JiveSurface *srf, Uint16 *w, Uint16 *h) {
+       if (srf->is_tile) {
+               jive_tile_get_min_size((JiveTile*)srf, w, h);
+               return;
+       }
+
        if (!srf->sdl) {
                LOG_ERROR(log_ui, "Underlying sdl surface already freed, 
possibly with release()");
                if (w)
@@ -537,10 +543,10 @@
                return;
        }
        if (w) {
-               *w = (srf->sdl) ? srf->sdl->w : 0;
+               *w = srf->sdl->w;
        }
        if (h) {
-               *h = (srf->sdl) ? srf->sdl->h : 0;
+               *h = srf->sdl->h;
        }
 }
 
@@ -548,6 +554,9 @@
 int jive_surface_get_bytes(JiveSurface *srf) {
        SDL_PixelFormat *format;
 
+       if (srf->is_tile)
+               LOG_ERROR(log_ui, "jive_surface_get_bytes called for JiveTile");
+
        if (!srf->sdl) {
                return 0;
        }
@@ -558,6 +567,11 @@
 
 
 void jive_surface_free(JiveSurface *srf) {
+       if (srf->is_tile) {
+               jive_tile_free((JiveTile*)srf);
+               return;
+       }
+
        if (--srf->refcount > 0) {
                return;
        }
@@ -570,6 +584,9 @@
 }
 
 void jive_surface_release(JiveSurface *srf) {
+       if (srf->is_tile)
+               LOG_ERROR(log_ui, "jive_surface_release called for JiveTile");
+
        if (srf->sdl) {
                SDL_FreeSurface (srf->sdl);
                srf->sdl = NULL;
@@ -579,6 +596,8 @@
 /* SDL_gfx encapsulated functions */
 JiveSurface *jive_surface_rotozoomSurface(JiveSurface *srf, double angle, 
double zoom, int smooth){
        JiveSurface *srf2;
+       if (srf->is_tile)
+               LOG_ERROR(log_ui, "jive_surface_rotozoomSurface called for 
JiveTile");
        if (!srf->sdl) {
                LOG_ERROR(log_ui, "Underlying sdl surface already freed, 
possibly with release()");
                return NULL;
@@ -593,6 +612,8 @@
 
 JiveSurface *jive_surface_zoomSurface(JiveSurface *srf, double zoomx, double 
zoomy, int smooth) {
        JiveSurface *srf2;
+       if (srf->is_tile)
+               LOG_ERROR(log_ui, "jive_surface_zoomSurface called for 
JiveTile");
        if (!srf->sdl) {
                LOG_ERROR(log_ui, "Underlying sdl surface already freed, 
possibly with release()");
                return NULL;
@@ -607,6 +628,8 @@
 
 JiveSurface *jive_surface_shrinkSurface(JiveSurface *srf, int factorx, int 
factory) {
        JiveSurface *srf2;
+       if (srf->is_tile)
+               LOG_ERROR(log_ui, "jive_surface_shrinkSurface called for 
JiveTile");
        if (!srf->sdl) {
                LOG_ERROR(log_ui, "Underlying sdl surface already freed, 
possibly with release()");
                return NULL;
@@ -621,6 +644,8 @@
 
 
 void jive_surface_pixelColor(JiveSurface *srf, Sint16 x, Sint16 y, Uint32 
color) {
+       if (srf->is_tile)
+               LOG_ERROR(log_ui, "jive_surface_*() called for JiveTile");
        if (!srf->sdl) {
                LOG_ERROR(log_ui, "Underlying sdl surface already freed, 
possibly with release()");
                return;
@@ -632,6 +657,8 @@
 }
 
 void jive_surface_hlineColor(JiveSurface *srf, Sint16 x1, Sint16 x2, Sint16 y, 
Uint32 color) {
+       if (srf->is_tile)
+               LOG_ERROR(log_ui, "jive_surface_*() called for JiveTile");
        if (!srf->sdl) {
                LOG_ERROR(log_ui, "Underlying sdl surface already freed, 
possibly with release()");
                return;
@@ -644,6 +671,8 @@
 }
 
 void jive_surface_vlineColor(JiveSurface *srf, Sint16 x, Sint16 y1, Sint16 y2, 
Uint32 color) {
+       if (srf->is_tile)
+               LOG_ERROR(log_ui, "jive_surface_*() called for JiveTile");
        if (!srf->sdl) {
                LOG_ERROR(log_ui, "Underlying sdl surface already freed, 
possibly with release()");
                return;
@@ -656,6 +685,8 @@
 }
 
 void jive_surface_rectangleColor(JiveSurface *srf, Sint16 x1, Sint16 y1, 
Sint16 x2, Sint16 y2, Uint32 col) {
+       if (srf->is_tile)
+               LOG_ERROR(log_ui, "jive_surface_*() called for JiveTile");
        if (!srf->sdl) {
                LOG_ERROR(log_ui, "Underlying sdl surface already freed, 
possibly with release()");
                return;
@@ -669,6 +700,8 @@
 }
 
 void jive_surface_boxColor(JiveSurface *srf, Sint16 x1, Sint16 y1, Sint16 x2, 
Sint16 y2, Uint32 col) {
+       if (srf->is_tile)
+               LOG_ERROR(log_ui, "jive_surface_*() called for JiveTile");
        if (!srf->sdl) {
                LOG_ERROR(log_ui, "Underlying sdl surface already freed, 
possibly with release()");
                return;
@@ -682,6 +715,8 @@
 }
 
 void jive_surface_lineColor(JiveSurface *srf, Sint16 x1, Sint16 y1, Sint16 x2, 
Sint16 y2, Uint32 col) {
+       if (srf->is_tile)
+               LOG_ERROR(log_ui, "jive_surface_*() called for JiveTile");
        if (!srf->sdl) {
                LOG_ERROR(log_ui, "Underlying sdl surface already freed, 
possibly with release()");
                return;
@@ -695,6 +730,8 @@
 }
 
 void jive_surface_aalineColor(JiveSurface *srf, Sint16 x1, Sint16 y1, Sint16 
x2, Sint16 y2, Uint32 col) {
+       if (srf->is_tile)
+               LOG_ERROR(log_ui, "jive_surface_*() called for JiveTile");
        if (!srf->sdl) {
                LOG_ERROR(log_ui, "Underlying sdl surface already freed, 
possibly with release()");
                return;
@@ -708,6 +745,8 @@
 }
 
 void jive_surface_circleColor(JiveSurface *srf, Sint16 x, Sint16 y, Sint16 r, 
Uint32 col) {
+       if (srf->is_tile)
+               LOG_ERROR(log_ui, "jive_surface_*() called for JiveTile");
        if (!srf->sdl) {
                LOG_ERROR(log_ui, "Underlying sdl surface already freed, 
possibly with release()");
                return;
@@ -720,6 +759,8 @@
 }
 
 void jive_surface_aacircleColor(JiveSurface *srf, Sint16 x, Sint16 y, Sint16 
r, Uint32 col) {
+       if (srf->is_tile)
+               LOG_ERROR(log_ui, "jive_surface_*() called for JiveTile");
        if (!srf->sdl) {
                LOG_ERROR(log_ui, "Underlying sdl surface already freed, 
possibly with release()");
                return;
@@ -732,6 +773,8 @@
 }
 
 void jive_surface_filledCircleColor(JiveSurface *srf, Sint16 x, Sint16 y, 
Sint16 r, Uint32 col) {
+       if (srf->is_tile)
+               LOG_ERROR(log_ui, "jive_surface_*() called for JiveTile");
        if (!srf->sdl) {
                LOG_ERROR(log_ui, "Underlying sdl surface already freed, 
possibly with release()");
                return;
@@ -744,6 +787,8 @@
 }
 
 void jive_surface_ellipseColor(JiveSurface *srf, Sint16 x, Sint16 y, Sint16 
rx, Sint16 ry, Uint32 col) {
+       if (srf->is_tile)
+               LOG_ERROR(log_ui, "jive_surface_*() called for JiveTile");
        if (!srf->sdl) {
                LOG_ERROR(log_ui, "Underlying sdl surface already freed, 
possibly with release()");
                return;
@@ -757,6 +802,8 @@
 }
 
 void jive_surface_aaellipseColor(JiveSurface *srf, Sint16 x, Sint16 y, Sint16 
rx, Sint16 ry, Uint32 col) {
+       if (srf->is_tile)
+               LOG_ERROR(log_ui, "jive_surface_*() called for JiveTile");
        if (!srf->sdl) {
                LOG_ERROR(log_ui, "Underlying sdl surface already freed, 
possibly with release()");
                return;
@@ -770,6 +817,8 @@
 }
 
 void jive_surface_filledEllipseColor(JiveSurface *srf, Sint16 x, Sint16 y, 
Sint16 rx, Sint16 ry, Uint32 col) {
+       if (srf->is_tile)
+               LOG_ERROR(log_ui, "jive_surface_*() called for JiveTile");
        if (!srf->sdl) {
                LOG_ERROR(log_ui, "Underlying sdl surface already freed, 
possibly with release()");
                return;
@@ -783,6 +832,8 @@
 }
 
 void jive_surface_pieColor(JiveSurface *srf, Sint16 x, Sint16 y, Sint16 rad, 
Sint16 start, Sint16 end, Uint32 col) {
+       if (srf->is_tile)
+               LOG_ERROR(log_ui, "jive_surface_*() called for JiveTile");
        if (!srf->sdl) {
                LOG_ERROR(log_ui, "Underlying sdl surface already freed, 
possibly with release()");
                return;
@@ -797,6 +848,8 @@
 }
 
 void jive_surface_filledPieColor(JiveSurface *srf, Sint16 x, Sint16 y, Sint16 
rad, Sint16 start, Sint16 end, Uint32 col) {
+       if (srf->is_tile)
+               LOG_ERROR(log_ui, "jive_surface_*() called for JiveTile");
        if (!srf->sdl) {
                LOG_ERROR(log_ui, "Underlying sdl surface already freed, 
possibly with release()");
                return;
@@ -811,6 +864,8 @@
 }
 
 void jive_surface_trigonColor(JiveSurface *srf, Sint16 x1, Sint16 y1, Sint16 
x2, Sint16 y2, Sint16 x3, Sint16 y3, Uint32 col) {
+       if (srf->is_tile)
+               LOG_ERROR(log_ui, "jive_surface_*() called for JiveTile");
        if (!srf->sdl) {
                LOG_ERROR(log_ui, "Underlying sdl surface already freed, 
possibly with release()");
                return;
@@ -826,6 +881,8 @@
 }
 
 void jive_surface_aatrigonColor(JiveSurface *srf, Sint16 x1, Sint16 y1, Sint16 
x2, Sint16 y2, Sint16 x3, Sint16 y3, Uint32 col) {
+       if (srf->is_tile)
+               LOG_ERROR(log_ui, "jive_surface_*() called for JiveTile");
        if (!srf->sdl) {
                LOG_ERROR(log_ui, "Underlying sdl surface already freed, 
possibly with release()");
                return;
@@ -841,6 +898,8 @@
 }
 
 void jive_surface_filledTrigonColor(JiveSurface *srf, Sint16 x1, Sint16 y1, 
Sint16 x2, Sint16 y2, Sint16 x3, Sint16 y3, Uint32 col) {
+       if (srf->is_tile)
+               LOG_ERROR(log_ui, "jive_surface_*() called for JiveTile");
        if (!srf->sdl) {
                LOG_ERROR(log_ui, "Underlying sdl surface already freed, 
possibly with release()");
                return;

Modified: 7.5/trunk/squeezeplay/src/squeezeplay/src/ui/jive_tile.c
URL: 
http://svn.slimdevices.com/jive/7.5/trunk/squeezeplay/src/squeezeplay/src/ui/jive_tile.c?rev=8498&r1=8497&r2=8498&view=diff
==============================================================================
--- 7.5/trunk/squeezeplay/src/squeezeplay/src/ui/jive_tile.c (original)
+++ 7.5/trunk/squeezeplay/src/squeezeplay/src/ui/jive_tile.c Fri Feb 12 
10:58:23 2010
@@ -11,17 +11,387 @@
 
 void jive_surface_get_tile_blit(JiveSurface *srf, SDL_Surface **sdl, Sint16 
*x, Sint16 *y);
 
+struct loaded_image_surface {
+       Uint16 image;                                                           
/* index to underlying struct image */
+       SDL_Surface *srf;
+       struct loaded_image_surface *prev, *next;       /* LRU cache 
double-linked list */
+};
+
+/* locked images (no path) are not counted or kept in the LRU list */
+#define MAX_LOADED_IMAGES 75
+static struct loaded_image_surface lruHead, lruTail;
+static Uint16 nloadedImages;
+
+struct image {
+       const char * path;
+       Uint16 w;
+       Uint16 h;
+       Uint16 flags;
+#   define IMAGE_FLAG_INIT  (1<<0)                     /* Have w & h been 
evaluated yet */
+#   define IMAGE_FLAG_AMASK (1<<1)
+       Uint16 ref_count;
+#ifdef JIVE_PROFILE_IMAGE_CACHE
+       Uint16 use_count;
+       Uint16 load_count;
+#endif
+       struct loaded_image_surface * loaded;   /* reference to loaded surface 
*/
+};
+
+/* We do not use image 0 - it is just easier to let 0 mean no image */
+#define MAX_IMAGES 500
+static struct image images[MAX_IMAGES];
+static Uint16 n_images = 1;
 
 struct jive_tile {
+       /* the first two fields must match struct jive_surface */
        Uint32 refcount;
-
-       SDL_Surface *srf[9];
+       bool is_tile;
+
+       Uint16 image[9];
        Uint16 w[2];
        Uint16 h[2];
        Uint32 bg;
-       bool is_bg;
+       Uint32 alpha_flags;
+       Uint16 flags;
+#   define TILE_FLAG_INIT  (1<<0)              /* Have w & h been evaluated 
yet */
+#   define TILE_FLAG_BG    (1<<1)
+#   define TILE_FLAG_ALPHA (1<<2)              /* have alpha flags been set of 
this tile */
+#   define TILE_FLAG_LOCK  (1<<3)              /* loaded from data, cannot be 
loaded on demand */
+#   define TILE_FLAG_IMAGE (1<<4)              /* just a single image */
 };
 
+static Uint16 _new_image_with_surface (SDL_Surface *srf) {
+       Uint16 i;
+
+       if (n_images >= MAX_IMAGES) {
+               LOG_ERROR(log_ui_draw, "Maximum number of images (%d) exceeded 
for data image\n", MAX_IMAGES);
+               return 0;
+       }
+
+       i = n_images++;
+       images[i].ref_count = 1;
+       images[i].w = srf->w;
+       images[i].h = srf->h;
+
+       images[i].loaded = calloc(sizeof *images[i].loaded, 1);
+       images[i].loaded->image = i;
+       images[i].loaded->srf = srf;
+
+       images[i].flags = IMAGE_FLAG_INIT;
+
+       return i;
+}
+
+static int _new_image(const char *path) {
+       Uint16 i;
+
+       for (i = 0; i < n_images; i++) {
+               if (images[i].ref_count <= 0)
+                       break;
+               if (images[i].path && strcmp(path, images[i].path) == 0) {
+                       images[i].ref_count++;
+                       return i;
+               }
+       }
+
+       if (i >= MAX_IMAGES) {
+               LOG_ERROR(log_ui_draw, "Maximum number of images (%d) exceeded 
for %s\n", MAX_IMAGES, path);
+               return 0;
+       }
+
+       if (i == n_images)
+               n_images++;
+       images[i].path = strdup(path);
+       images[i].ref_count = 1;
+       return i;
+}
+
+static void _unload_image(Uint16 index) {
+       struct loaded_image_surface *loaded = images[index].loaded;
+
+       if (loaded->next) {
+               nloadedImages--;        /* only counted if actually in LRU list 
*/
+               loaded->prev->next = loaded->next;
+               loaded->next->prev = loaded->prev;
+       }
+
+#ifdef JIVE_PROFILE_IMAGE_CACHE
+       LOG_DEBUG(log_ui_draw, "Unloading  %3d:%s", index, images[index].path);
+#endif
+
+       SDL_FreeSurface(loaded->srf);
+       free(loaded);
+       images[index].loaded = 0;
+}
+
+static void _use_image(Uint16 index) {
+       struct loaded_image_surface *loaded = images[index].loaded;
+
+#ifdef JIVE_PROFILE_IMAGE_CACHE
+       images[index].use_count++;
+#endif
+
+       /* short-circuit if already at head */
+       if (loaded->prev == &lruHead)
+               return;
+
+       /* ignore locked images */
+       if (images[index].path == 0)
+               return;
+
+       /* init head and tail if needed */
+       if (lruHead.next == 0) {
+               lruHead.next = &lruTail;
+               lruTail.prev = &lruHead;
+       }
+
+       /* If already in the list then just move to head */
+       if (loaded->next) {
+
+               /* cut out */
+               loaded->prev->next = loaded->next;
+               loaded->next->prev = loaded->prev;
+
+               /* insert at head */
+               loaded->next = lruHead.next;
+               loaded->next->prev = loaded;
+               loaded->prev = &lruHead;
+               lruHead.next = loaded;
+       }
+
+       /* otherwise, insert at head and eject oldest if necessary */
+       else {
+               /* insert at head */
+               loaded->next = lruHead.next;
+               loaded->next->prev = loaded;
+               loaded->prev = &lruHead;
+               lruHead.next = loaded;
+
+               if (++nloadedImages > MAX_LOADED_IMAGES) {
+                       _unload_image(lruTail.prev->image);
+               }
+       }
+}
+
+static void _load_image (Uint16 index, bool hasAlphaFlags, Uint32 alphaFlags) {
+       struct image *image = &images[index];
+       SDL_Surface *tmp, *srf;
+
+       tmp = IMG_Load(image->path);
+       if (!tmp) {
+               LOG_WARN(log_ui_draw, "Error loading tile image %s: %s\n", 
image->path, IMG_GetError());
+               return;
+       }
+       if (tmp->format->Amask) {
+               srf = SDL_DisplayFormatAlpha(tmp);
+               image->flags |= IMAGE_FLAG_AMASK;
+       } else {
+               srf = SDL_DisplayFormat(tmp);
+       }
+       SDL_FreeSurface(tmp);
+
+       if (!srf)
+               return;
+
+       if (hasAlphaFlags) {
+               SDL_SetAlpha(srf, alphaFlags, 0);
+       }
+
+       image->loaded = calloc(sizeof *(image->loaded), 1);
+       image->loaded->image = index;
+       image->loaded->srf = srf;
+
+#ifdef JIVE_PROFILE_IMAGE_CACHE
+       image->load_count++;
+#endif
+
+       if (!(image->flags & IMAGE_FLAG_INIT)) {
+               image->w = srf->w;
+               image->h = srf->h;
+               image->flags |= IMAGE_FLAG_INIT;
+       }
+
+       _use_image(index);
+
+#ifdef JIVE_PROFILE_IMAGE_CACHE
+       LOG_DEBUG(log_ui_draw, "Loaded image %3d:%s", index, image->path);
+#endif
+}
+
+static void _load_tile_images (JiveTile *tile) {
+       int i, max;
+
+#ifdef JIVE_PROFILE_IMAGE_CACHE
+       int n = 0, m = 0;
+#endif
+
+       /* shortcut for images */
+       max =  (tile->flags & TILE_FLAG_IMAGE) ? 1 : 9;
+
+       /* make two passes to avoid the unload/load shuttle problem */
+       for (i = 0; i < max; i++) {
+               Uint16 image = tile->image[i];
+
+               if (!image)
+                       continue;
+
+               if (images[image].loaded)
+                       _use_image(image);
+       }
+
+       for (i = 0; i < max; i++) {
+               Uint16 image = tile->image[i];
+
+               if (!image)
+                       continue;
+
+               if (!images[image].loaded) {
+
+#ifdef JIVE_PROFILE_IMAGE_CACHE
+                       if (images[image].flags & IMAGE_FLAG_INIT)
+                               m++;
+                       n++;
+#endif
+
+                       _load_image(image, tile->flags & TILE_FLAG_ALPHA, 
tile->alpha_flags);
+               }
+       }
+
+#ifdef JIVE_PROFILE_IMAGE_CACHE
+       if (n) {
+               int loaded = 0;
+               for (i = 0; i < n_images; i++) {
+                       if (images[i].loaded)
+                               loaded++;
+               }
+               LOG_DEBUG(log_ui_draw, "Loaded %d new images, %d already 
inited; %d of %d now loaded", n, m, loaded, n_images);
+       }
+#endif
+
+}
+
+static void _init_image_sizes(struct image *image) {
+       if (image->loaded) {
+               image->w = image->loaded->srf->w;
+               image->h = image->loaded->srf->h;
+       } else {
+               SDL_Surface *tmp;
+
+#ifdef JIVE_PROFILE_IMAGE_CACHE
+                LOG_DEBUG(log_ui_draw, "Loading image just for sizes: %s", 
image->path);
+#endif
+
+               tmp = IMG_Load(image->path);
+               if (!tmp) {
+                       LOG_WARN(log_ui_draw, "Error loading tile image %s: 
%s\n", image->path, IMG_GetError());
+                       image->flags |= IMAGE_FLAG_INIT;        /* fake it - no 
point in trying repeatedly */
+                       return;
+               }
+               if (tmp->format->Amask)
+                       image->flags |= IMAGE_FLAG_AMASK;
+
+               image->w = tmp->w;
+               image->h = tmp->h;
+
+               SDL_FreeSurface(tmp);
+       }
+       image->flags |= IMAGE_FLAG_INIT;
+}
+
+static Uint16 _get_image_w(struct image *image) {
+       if (!(image->flags & IMAGE_FLAG_INIT))
+               _init_image_sizes(image);
+       return image->w;
+}
+
+static Uint16 _get_image_h(struct image *image) {
+       if (!(image->flags & IMAGE_FLAG_INIT))
+               _init_image_sizes(image);
+       return image->h;
+}
+
+static void _init_tile_sizes(JiveTile *tile) {
+       if (tile->flags & TILE_FLAG_INIT)
+               return;
+
+       /* top left */
+       if (tile->image[1]) {
+               tile->w[0] = MAX(_get_image_w(&images[tile->image[1]]), 
tile->w[0]);
+               tile->h[0] = MAX(_get_image_h(&images[tile->image[1]]), 
tile->h[0]);
+       }
+
+       /* top right */
+       if (tile->image[3]) {
+               tile->w[1] = MAX(_get_image_w(&images[tile->image[3]]), 
tile->w[1]);
+               tile->h[0] = MAX(_get_image_h(&images[tile->image[3]]), 
tile->h[0]);
+       }
+
+       /* bottom right */
+       if (tile->image[5]) {
+               tile->w[1] = MAX(_get_image_w(&images[tile->image[5]]), 
tile->w[1]);
+               tile->h[1] = MAX(_get_image_h(&images[tile->image[5]]), 
tile->h[1]);
+       }
+
+       /* bottom left */
+       if (tile->image[7]) {
+               tile->w[0] = MAX(_get_image_w(&images[tile->image[7]]), 
tile->w[0]);
+               tile->h[1] = MAX(_get_image_h(&images[tile->image[7]]), 
tile->h[1]);
+       }
+
+       /* top */
+       if (tile->image[2]) {
+               tile->h[0] = MAX(_get_image_h(&images[tile->image[2]]), 
tile->h[0]);
+       }
+
+       /* right */
+       if (tile->image[4]) {
+               tile->w[1] = MAX(_get_image_w(&images[tile->image[4]]), 
tile->w[1]);
+       }
+
+       /* bottom */
+       if (tile->image[6]) {
+               tile->h[1] = MAX(_get_image_h(&images[tile->image[6]]), 
tile->h[1]);
+       }
+
+       /* left */
+       if (tile->image[8]) {
+               tile->w[0] = MAX(_get_image_w(&images[tile->image[8]]), 
tile->w[0]);
+       }
+
+       /* special for single images */
+       if (tile->image[0] && !tile->image[1] && !tile->w[0]) {
+               tile->w[0] = _get_image_w(&images[tile->image[0]]);
+               tile->h[0] = _get_image_h(&images[tile->image[0]]);
+       }
+
+       tile->flags |= TILE_FLAG_INIT;
+}
+
+static void _get_tile_surfaces(JiveTile *tile, SDL_Surface *srf[9], bool load) 
{
+       int i;
+
+       if (load)
+               _load_tile_images(tile);
+
+       for (i = 0; i < 9; i++) {
+               if (tile->image[i] && images[tile->image[i]].loaded) {
+                       srf[i] = images[tile->image[i]].loaded->srf;
+               } else {
+                       srf[i] = 0;
+               }
+       }
+}
+
+SDL_Surface *jive_tile_get_image_surface(JiveTile *tile) {
+       if (!tile->is_tile)
+               LOG_ERROR(log_ui_draw, "jive_tile_*() called with JiveSurface");
+
+       _load_tile_images(tile);
+       if (!images[tile->image[0]].loaded)
+               return NULL;
+
+       return images[tile->image[0]].loaded->srf;
+}
 
 JiveTile *jive_tile_fill_color(Uint32 col) {
        JiveTile *tile;
@@ -29,63 +399,36 @@
        tile = calloc(sizeof(JiveTile), 1);
        tile->refcount = 1;
 
-       tile->is_bg = true;
+       tile->flags = TILE_FLAG_INIT | TILE_FLAG_BG;
        tile->bg = col;
+       tile->is_tile = true;
 
        return tile;
 }
 
 JiveTile *jive_tile_load_image(const char *path) {
+       char *paths[9];
        JiveTile *tile;
-       char *fullpath;
-       SDL_Surface *tmp;
+
+       memset(paths, 0, sizeof paths);
+       paths[0] = (char *)path;
+
+       tile = jive_tile_load_tiles(paths);
+       tile->flags |= TILE_FLAG_IMAGE;
+
+       return tile;
+}
+
+
+JiveTile *jive_tile_load_image_data(const char *data, size_t len) {
+       JiveTile *tile;
+       SDL_Surface *tmp, *srf;
+       SDL_RWops *src;
+       Uint16 image;
 
        tile = calloc(sizeof(JiveTile), 1);
        tile->refcount = 1;
-
-       fullpath = malloc(PATH_MAX);
-
-       if (!squeezeplay_find_file(path, fullpath)) {
-               LOG_ERROR(log_ui_draw, "Can't find image %s\n", path);
-               free(fullpath);
-               free(tile);
-               return NULL;
-       }
-
-       tmp = IMG_Load(fullpath);
-       if (!tmp) {
-               LOG_WARN(log_ui_draw, "Error loading tile: %s\n", 
IMG_GetError());
-               free(fullpath);
-               free(tile);
-               return NULL;
-       }
-       else {
-               if (tmp->format->Amask) {
-                       tile->srf[0] = SDL_DisplayFormatAlpha(tmp);
-               }
-               else {
-                       tile->srf[0] = SDL_DisplayFormat(tmp);
-               }
-               SDL_FreeSurface(tmp);
-       }
-
-       /* tile sizes */
-       tile->w[0] = tile->srf[0]->w;
-       tile->h[0] = tile->srf[0]->h;
-
-       free(fullpath);
-
-       return tile;
-}
-
-
-JiveTile *jive_tile_load_image_data(const char *data, size_t len) {
-       JiveTile *tile;
-       SDL_Surface *tmp;
-       SDL_RWops *src ;
-
-       tile = calloc(sizeof(JiveTile), 1);
-       tile->refcount = 1;
+       tile->is_tile = true;
 
        src = SDL_RWFromConstMem(data, (int) len);
        tmp = IMG_Load_RW(src, 1);
@@ -97,30 +440,42 @@
        }
        else {
                if (tmp->format->Amask) {
-                       tile->srf[0] = SDL_DisplayFormatAlpha(tmp);
+                       srf = SDL_DisplayFormatAlpha(tmp);
                }
                else {
-                       tile->srf[0] = SDL_DisplayFormat(tmp);
+                       srf = SDL_DisplayFormat(tmp);
                }
                SDL_FreeSurface(tmp);
        }
 
        /* tile sizes */
-       tile->w[0] = tile->srf[0]->w;
-       tile->h[0] = tile->srf[0]->h;
+       tile->w[0] = srf->w;
+       tile->h[0] = srf->h;
+
+       image = _new_image_with_surface(srf);
+       if (!image) {
+               tile->image[0] = image;
+               SDL_FreeSurface(srf);
+               free(tile);
+               LOG_WARN(log_ui_draw, "Error loading tile");
+               return NULL;
+       }
+
+       tile->image[0] = image;
+       tile->flags = TILE_FLAG_INIT | TILE_FLAG_LOCK | TILE_FLAG_IMAGE;
+;
 
        return tile;
 }
-
 
 JiveTile *jive_tile_load_tiles(char *path[9]) {
        JiveTile *tile;
        char *fullpath;
-       SDL_Surface *tmp;
        int i;
 
        tile = calloc(sizeof(JiveTile), 1);
        tile->refcount = 1;
+       tile->is_tile = true;
 
        fullpath = malloc(PATH_MAX);
 
@@ -134,71 +489,10 @@
                        continue;
                }
 
-               tmp = IMG_Load(fullpath);
-               if (!tmp) {
-                       LOG_WARN(log_ui_draw, "Error loading tile: %s\n", 
IMG_GetError());
-               }
-               else {
-                       if (tmp->format->Amask) {
-                               tile->srf[i] = SDL_DisplayFormatAlpha(tmp);
-                       }
-                       else {
-                               tile->srf[i] = SDL_DisplayFormat(tmp);
-                       }
-                       SDL_FreeSurface(tmp);
-               }
+               tile->image[i] = _new_image(fullpath);
        }
 
        free(fullpath);
-
-
-       /* tile sizes */
-       tile->w[0] = tile->w[1] = 0;
-       tile->h[0] = tile->h[1] = 0;
-
-       /* top left */
-       if (tile->srf[1]) {
-               tile->w[0] = MAX(tile->srf[1]->w, tile->w[0]);
-               tile->h[0] = MAX(tile->srf[1]->h, tile->h[0]);
-       }
-
-       /* top right */
-       if (tile->srf[3]) {
-               tile->w[1] = MAX(tile->srf[3]->w, tile->w[1]);
-               tile->h[0] = MAX(tile->srf[3]->h, tile->h[0]);
-       }
-
-       /* bottom right */
-       if (tile->srf[5]) {
-               tile->w[1] = MAX(tile->srf[5]->w, tile->w[1]);
-               tile->h[1] = MAX(tile->srf[5]->h, tile->h[1]);
-       }
-
-       /* bottom left */
-       if (tile->srf[7]) {
-               tile->w[0] = MAX(tile->srf[7]->w, tile->w[0]);
-               tile->h[1] = MAX(tile->srf[7]->h, tile->h[1]);
-       }
-
-       /* top */
-       if (tile->srf[2]) {
-               tile->h[0] = MAX(tile->srf[2]->h, tile->h[0]);
-       }
-
-       /* right */
-       if (tile->srf[4]) {
-               tile->w[1] = MAX(tile->srf[4]->w, tile->w[1]);
-       }
-
-       /* bottom */
-       if (tile->srf[6]) {
-               tile->h[1] = MAX(tile->srf[6]->h, tile->h[1]);
-       }
-
-       /* left */
-       if (tile->srf[8]) {
-               tile->w[0] = MAX(tile->srf[8]->w, tile->w[0]);
-       }
 
        return tile;
 }
@@ -228,12 +522,21 @@
 
 JiveTile *jive_tile_ref(JiveTile *tile) {
        if (tile) {
+               if (!tile->is_tile)
+                       LOG_ERROR(log_ui_draw, "jive_tile_*() called with 
JiveSurface");
+
                tile->refcount++;
        }
        return tile;
 }
 
 void jive_tile_get_min_size(JiveTile *tile, Uint16 *w, Uint16 *h) {
+
+       if (!tile->is_tile)
+               LOG_ERROR(log_ui_draw, "jive_tile_*() called with JiveSurface");
+
+       _init_tile_sizes(tile);
+
        if (w) {
                *w = tile->w[0] + tile->w[1];
        }
@@ -243,11 +546,19 @@
 }
 
 void jive_tile_set_alpha(JiveTile *tile, Uint32 flags) {
+       SDL_Surface *srf[9];
        int i;
 
+       if (!tile->is_tile)
+               LOG_ERROR(log_ui_draw, "jive_tile_*() called with JiveSurface");
+
+       tile->alpha_flags = flags;
+       tile->flags |= TILE_FLAG_ALPHA;
+
+       _get_tile_surfaces(tile, srf, false);
        for (i=0; i<9; i++) {
-               if (tile->srf[i]) {
-                       SDL_SetAlpha(tile->srf[i], flags, 0);
+               if (srf[i]) {
+                       SDL_SetAlpha(srf[i], flags, 0);
                }
        }
 }
@@ -259,11 +570,23 @@
                return;
        }
 
+       if (!tile->is_tile)
+               LOG_ERROR(log_ui_draw, "jive_tile_*() called with JiveSurface");
+
        for (i=0; i<9; i++) {
-               if (tile->srf[i]) {
-                       SDL_FreeSurface(tile->srf[i]);
-                       tile->srf[i] = NULL;
-               }
+               struct image *image;
+
+               if (!tile->image[i])
+                       continue;
+
+               image = &images[tile->image[i]];
+               if (--image->ref_count > 0)
+                       continue;
+
+               if (image->loaded) {
+                       _unload_image(tile->image[i]);
+               }
+               memset(image, 0, sizeof *image);
        }
 
        free(tile);
@@ -302,77 +625,80 @@
        }
 }
 
-
 static void _blit_tile(JiveTile *tile, JiveSurface *dst, Uint16 dx, Uint16 dy, 
Uint16 dw, Uint16 dh) {
        int ox=0, oy=0, ow=0, oh=0;
        Sint16 dst_offset_x, dst_offset_y;
        SDL_Surface *dst_srf;
-
-       if (tile->is_bg) {
+       SDL_Surface *srf[9];
+
+       if (tile->flags & TILE_FLAG_BG) {
                jive_surface_boxColor(dst, dx, dy, dx + dw - 1, dy + dh - 1, 
tile->bg);
                return;
        }
 
+       _get_tile_surfaces(tile, srf, true);
+       _init_tile_sizes(tile);
+
        jive_surface_get_tile_blit(dst, &dst_srf, &dst_offset_x, &dst_offset_y);
 
        dx += dst_offset_x;
        dy += dst_offset_y;
 
        /* top left */
-       if (tile->srf[1]) {
+       if (srf[1]) {
                ox = MIN(tile->w[0], dw);
                oy = MIN(tile->h[0], dh);
-               blit_area(tile->srf[1], dst_srf, dx, dy, ox, oy);
+               blit_area(srf[1], dst_srf, dx, dy, ox, oy);
        }
 
        /* top right */
-       if (tile->srf[3]) {
+       if (srf[3]) {
                ow = MIN(tile->w[1], dw);
                oy = MIN(tile->h[0], dh);
-               blit_area(tile->srf[3], dst_srf, dx + dw - ow, dy, ow, oy);
+               blit_area(srf[3], dst_srf, dx + dw - ow, dy, ow, oy);
        }
 
        /* bottom right */
-       if (tile->srf[5]) {
+       if (srf[5]) {
                ow = MIN(tile->w[1], dw);
                oh = MIN(tile->h[1], dh);
-               blit_area(tile->srf[5], dst_srf, dx + dw - ow, dy + dh - oh, 
ow, oh);
+               blit_area(srf[5], dst_srf, dx + dw - ow, dy + dh - oh, ow, oh);
        }
 
        /* bottom left */
-       if (tile->srf[7]) {
+       if (srf[7]) {
                ox = MIN(tile->w[0], dw);
                oh = MIN(tile->h[1], dh);
-               blit_area(tile->srf[7], dst_srf, dx, dy + dh - oh, ox, oh);
+               blit_area(srf[7], dst_srf, dx, dy + dh - oh, ox, oh);
        }
 
        /* top */
-       if (tile->srf[2]) {
+       if (srf[2]) {
                oy = MIN(tile->h[0], dh);
-               blit_area(tile->srf[2], dst_srf, dx + ox, dy, dw - ox - ow, oy);
+               blit_area(srf[2], dst_srf, dx + ox, dy, dw - ox - ow, oy);
        }
 
        /* right */
-       if (tile->srf[4]) {
+       if (srf[4]) {
                ow = MIN(tile->w[1], dw);
-               blit_area(tile->srf[4], dst_srf, dx + dw - ow, dy + oy, ow, dh 
- oy - oh);
+               blit_area(srf[4], dst_srf, dx + dw - ow, dy + oy, ow, dh - oy - 
oh);
        }
 
        /* bottom */
-       if (tile->srf[6]) {
+       if (srf[6]) {
                oh = MIN(tile->h[1], dh);
-               blit_area(tile->srf[6], dst_srf, dx + ox, dy + dh - oh, dw - ox 
- ow, oh);
+               blit_area(srf[6], dst_srf, dx + ox, dy + dh - oh, dw - ox - ow, 
oh);
        }
 
        /* left */
-       if (tile->srf[8]) {
+       if (srf[8]) {
                ox = MIN(tile->w[0], dw);
-               blit_area(tile->srf[8], dst_srf, dx, dy + oy, ox, dh - oy - oh);
+               blit_area(srf[8], dst_srf, dx, dy + oy, ox, dh - oy - oh);
        }
 
        /* center */
-       if (tile->srf[0]) {
-               blit_area(tile->srf[0], dst_srf, dx + ox, dy + oy, dw - ox - 
ow, dh - oy - oh);
+       if (srf[0]) {
+               blit_area(srf[0], dst_srf, dx + ox, dy + oy, dw - ox - ow, dh - 
oy - oh);
        }
 }
 
@@ -383,6 +709,9 @@
 #endif //JIVE_PROFILE_BLIT
        Uint16 mw, mh;
 
+       if (!tile->is_tile)
+               LOG_ERROR(log_ui_draw, "jive_tile_*() called with JiveSurface");
+
        if (!dw || !dh) {
                jive_tile_get_min_size(tile, &mw, &mh);
                if (!dw) {
@@ -408,6 +737,9 @@
 #endif //JIVE_PROFILE_BLIT
        Uint16 mw, mh;
 
+       if (!tile->is_tile)
+               LOG_ERROR(log_ui_draw, "jive_tile_*() called with JiveSurface");
+
        jive_tile_get_min_size(tile, &mw, &mh);
        if (dw < mw) {
                dw = mw;

_______________________________________________
Jive-checkins mailing list
[email protected]
http://lists.slimdevices.com/mailman/listinfo/jive-checkins

Reply via email to