Blame src/animation.c

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