|
|
8535a3 |
|
|
|
8535a3 |
#include <cairo.h></cairo.h>
|
|
|
8535a3 |
|
|
|
8535a3 |
#include "private.h"
|
|
|
8935bc |
#include "world.h"
|
|
|
8935bc |
#include "sprite.h"
|
|
|
8535a3 |
|
|
|
8535a3 |
|
|
|
8535a3 |
static HeliArray cache;
|
|
|
8535a3 |
|
|
|
8535a3 |
static cairo_status_t read(void *closure, unsigned char *data, unsigned int length) {
|
|
|
8535a3 |
return fread(data, length, 1, (FILE*)closure)
|
|
|
8535a3 |
? CAIRO_STATUS_SUCCESS : CAIRO_STATUS_READ_ERROR;
|
|
|
8535a3 |
}
|
|
|
8535a3 |
|
|
|
8535a3 |
static cairo_surface_t* loadFrame(const char *path) {
|
|
|
8535a3 |
if (!heliStringEndsWithLowcase(path, ".png"))
|
|
|
8535a3 |
return NULL;
|
|
|
07b70f |
FILE *f = fopen(path, "rb");
|
|
|
8535a3 |
if (f) {
|
|
|
8535a3 |
cairo_surface_t *frame = cairo_image_surface_create_from_png_stream(&read, f);
|
|
|
8535a3 |
fclose(f);
|
|
|
8535a3 |
if (!frame)
|
|
|
981405 |
fprintf(stderr, "helianthus: cannot load PNG content form file: %s\n", path);
|
|
|
8535a3 |
return frame;
|
|
|
8535a3 |
}
|
|
|
981405 |
fprintf(stderr, "helianthus: cannot open image file: %s\n", path);
|
|
|
8535a3 |
return NULL;
|
|
|
8535a3 |
}
|
|
|
8535a3 |
|
|
|
1c7488 |
static HeliAnimation* load(const char *path) {
|
|
|
1c7488 |
HeliAnimation *a = calloc(1, sizeof(*a));
|
|
|
8535a3 |
a->path = heliStringCopy(path);
|
|
|
8535a3 |
|
|
|
1015c5 |
Directory d = openDirectory(path);
|
|
|
1015c5 |
if (d) {
|
|
|
1015c5 |
int count = directoryGetCount(d);
|
|
|
1015c5 |
for(int i = 0; i < count; ++i) {
|
|
|
1015c5 |
char *p = heliStringConcat3(path, "/", directoryGet(d, i));
|
|
|
1015c5 |
cairo_surface_t *frame = loadFrame(p);
|
|
|
8535a3 |
free(p);
|
|
|
8535a3 |
if (frame) heliArrayInsert(&a->frames, -1, frame, (HeliFreeCallback)&cairo_surface_destroy);
|
|
|
8535a3 |
}
|
|
|
1015c5 |
closeDirectory(d);
|
|
|
8535a3 |
} else {
|
|
|
8535a3 |
cairo_surface_t *frame = loadFrame(path);
|
|
|
8535a3 |
if (frame) {
|
|
|
8535a3 |
heliArrayInsert(&a->frames, -1, frame, (HeliFreeCallback)&cairo_surface_destroy);
|
|
|
8535a3 |
} else {
|
|
|
981405 |
fprintf(stderr, "helianthus: cannot load animation by path: %s\n", path);
|
|
|
8535a3 |
}
|
|
|
8535a3 |
}
|
|
|
8535a3 |
|
|
|
8535a3 |
return a;
|
|
|
8535a3 |
}
|
|
|
8535a3 |
|
|
|
1c7488 |
static void unload(HeliAnimation *a) {
|
|
|
8535a3 |
assert(!a->refcount);
|
|
|
8535a3 |
free(a->path);
|
|
|
8535a3 |
heliArrayDestroy(&a->frames);
|
|
|
8535a3 |
free(a);
|
|
|
8535a3 |
}
|
|
|
8535a3 |
|
|
|
1c7488 |
HeliAnimation* heliAnimationLoad(const char *path) {
|
|
|
8535a3 |
HeliPair *item = heliStringmapGet(&cache, path);
|
|
|
8535a3 |
if (!item) item = heliStringmapAdd(&cache, path, load(path), (HeliFreeCallback)&unload);
|
|
|
1c7488 |
HeliAnimation *a = (HeliAnimation*)item->value;
|
|
|
8535a3 |
++a->refcount;
|
|
|
1c7488 |
return a;
|
|
|
8535a3 |
}
|
|
|
8535a3 |
|
|
|
1c7488 |
void heliAnimationUnref(HeliAnimation *a) {
|
|
|
1c7488 |
if (--a->refcount <= 0)
|
|
|
1c7488 |
heliStringmapRemove(&cache, a->path);
|
|
|
8935bc |
}
|
|
|
8535a3 |
|
|
|
07b70f |
void heliAnimationFinish()
|
|
|
07b70f |
{ heliArrayDestroy(&cache); }
|
|
|
07b70f |
|