#include <glib.h>
#include <cairo.h>
#include "private.h"
static HeliArray cache;
static cairo_status_t read(void *closure, unsigned char *data, unsigned int length) {
return fread(data, length, 1, (FILE*)closure)
? CAIRO_STATUS_SUCCESS : CAIRO_STATUS_READ_ERROR;
}
static cairo_surface_t* loadFrame(const char *path) {
if (!heliStringEndsWithLowcase(path, ".png"))
return NULL;
FILE *f = fopen(path, "rb");
if (f) {
cairo_surface_t *frame = cairo_image_surface_create_from_png_stream(&read, f);
fclose(f);
if (!frame)
fprintf(stderr, "helianthus: cannot load PNG content form file: %s\n", path);
return frame;
}
fprintf(stderr, "helianthus: cannot open image file: %s\n", path);
return NULL;
}
static HeliAnimation* load(const char *path) {
HeliAnimation *a = calloc(1, sizeof(*a));
a->path = heliStringCopy(path);
GDir *dir = g_dir_open(path, 0, NULL);
if (dir) {
while(TRUE) {
const char* name = g_dir_read_name(dir);
if (!name) break;
char *p = heliStringConcat3(path, "/", name);
cairo_surface_t *frame = loadFrame(p);
free(p);
if (frame) heliArrayInsert(&a->frames, -1, frame, (HeliFreeCallback)&cairo_surface_destroy);
}
} else {
cairo_surface_t *frame = loadFrame(path);
if (frame) {
heliArrayInsert(&a->frames, -1, frame, (HeliFreeCallback)&cairo_surface_destroy);
} else {
fprintf(stderr, "helianthus: cannot load animation by path: %s\n", path);
}
}
return a;
}
static void unload(HeliAnimation *a) {
assert(!a->refcount);
free(a->path);
heliArrayDestroy(&a->frames);
free(a);
}
HeliAnimation *heliCreateAnimation(const char *path) {
HeliPair *item = heliStringmapGet(&cache, path);
if (!item) item = heliStringmapAdd(&cache, path, load(path), (HeliFreeCallback)&unload);
HeliAnimation *a = (HeliAnimation*)item->value;
++a->refcount;
return a;
}
void heliAnimationUnref(HeliAnimation *a)
{ if (--a->refcount <= 0) heliStringmapRemove(&cache, a->path); }
void heliAnimationFinish()
{ heliArrayDestroy(&cache); }