+
+void RrImageDrawRGBA(RrPixel32 *target, RrTextureRGBA *rgba,
+ gint target_w, gint target_h,
+ RrRect *area)
+{
+ RrImagePic *scaled;
+
+ scaled = ResizeImage(rgba->data, rgba->width, rgba->height,
+ area->width, area->height);
+
+ if (scaled) {
+#ifdef DEBUG
+ g_warning("Scaling an RGBA! You should avoid this and just make "
+ "it the right size yourself!");
+#endif
+ DrawRGBA(target, target_w, target_h,
+ scaled->data, scaled->width, scaled->height,
+ rgba->alpha, area);
+ }
+ else
+ DrawRGBA(target, target_w, target_h,
+ rgba->data, rgba->width, rgba->height,
+ rgba->alpha, area);
+}
+
+RrImage* RrImageNew(RrImageCache *cache)
+{
+ RrImage *self;
+
+ self = g_new0(RrImage, 1);
+ self->ref = 1;
+ self->cache = cache;
+ return self;
+}
+
+void RrImageRef(RrImage *self)
+{
+ ++self->ref;
+}
+
+void RrImageUnref(RrImage *self)
+{
+ if (self && --self->ref == 0) {
+#ifdef DEBUG
+ g_print("Refcount to 0, removing ALL pictures from the cache: "
+ "Image 0x%x\n", (guint)self);
+#endif
+ while (self->n_original > 0)
+ RemovePicture(self, &self->original, 0, &self->n_original);
+ while (self->n_resized > 0)
+ RemovePicture(self, &self->resized, 0, &self->n_resized);
+ g_free(self);
+ }
+}
+
+void RrImageAddPicture(RrImage *self, RrPixel32 *data, gint w, gint h)
+{
+ gint i;
+ RrImagePic *pic;
+
+ /* make sure we don't already have this size.. */
+ for (i = 0; i < self->n_original; ++i)
+ if (self->original[i]->width == w && self->original[i]->height == h) {
+#ifdef DEBUG
+ g_print("Found duplicate ORIGINAL image: "
+ "Image 0x%x, w %d h %d\n", (guint)self, w, h);
+#endif
+ return;
+ }
+
+ /* remove any resized pictures of this same size */
+ for (i = 0; i < self->n_resized; ++i)
+ if (self->resized[i]->width == w || self->resized[i]->height == h) {
+ RemovePicture(self, &self->resized, i, &self->n_resized);
+ break;
+ }
+
+ /* add the new picture */
+ pic = g_new(RrImagePic, 1);
+ pic->width = w;
+ pic->height = h;
+ pic->data = g_memdup(data, w*h*sizeof(RrPixel32));
+ AddPicture(self, &self->original, &self->n_original, pic);
+}
+
+void RrImageRemovePicture(RrImage *self, gint w, gint h)
+{
+ gint i;
+
+ /* remove any resized pictures of this same size */
+ for (i = 0; i < self->n_original; ++i)
+ if (self->original[i]->width == w && self->original[i]->height == h) {
+ RemovePicture(self, &self->original, i, &self->n_original);
+ break;
+ }
+}
+
+void RrImageDrawImage(RrPixel32 *target, RrTextureImage *img,
+ gint target_w, gint target_h,
+ RrRect *area)
+{
+ gint i, min_diff, min_i;
+ RrImage *self;
+ RrImagePic *pic;
+
+ self = img->image;
+ pic = NULL;
+
+ /* is there an original of this size? (only w or h has to be right cuz
+ we maintain aspect ratios) */
+ for (i = 0; i < self->n_original; ++i)
+ if (self->original[i]->width == area->width ||
+ self->original[i]->height == area->height)
+ {
+ pic = self->original[i];
+ break;
+ }
+
+ /* is there a resize of this size? */
+ for (i = 0; i < self->n_resized; ++i)
+ if (self->resized[i]->width == area->width ||
+ self->resized[i]->height == area->height)
+ {
+ gint j;
+ RrImagePic *saved;
+
+ /* save the selected one */
+ saved = self->resized[i];
+
+ /* shift all the others down */
+ for (j = i; j > 0; --j)
+ self->resized[j] = self->resized[j-1];
+
+ /* and move the selected one to the top of the list */
+ self->resized[0] = saved;
+
+ pic = self->resized[0];
+ break;
+ }
+
+ if (!pic) {
+ /* find an original with a close size */
+ min_diff = -1;
+ min_i = 0;
+ for (i = 0; i < self->n_original; ++i) {
+ gint diff;
+ gint wdiff, hdiff;
+
+ /* our size difference metric.. */
+ wdiff = self->original[i]->width - area->width;
+ hdiff = self->original[i]->height - area->height;
+ diff = (wdiff * wdiff) + (hdiff * hdiff);
+
+ if (min_diff < 0 || diff < min_diff) {
+ min_diff = diff;
+ min_i = i;
+ }
+ }
+
+ /* resize the original to the given area */
+ pic = ResizeImage(self->original[min_i]->data,
+ self->original[min_i]->width,
+ self->original[min_i]->height,
+ area->width, area->height);
+
+ /* add the resized image to the image, as the first in the resized
+ list */
+ if (self->n_resized >= MAX_CACHE_RESIZED) {
+ /* remove the last one (last used one) */
+ RemovePicture(self, &self->resized, self->n_resized - 1,
+ &self->n_resized);
+ }
+ /* add it to the top of the resized list */
+ AddPicture(self, &self->resized, &self->n_resized, pic);
+ }
+
+ g_assert(pic != NULL);
+
+ DrawRGBA(target, target_w, target_h,
+ pic->data, pic->width, pic->height,
+ img->alpha, area);
+}