summaryrefslogtreecommitdiffstats
path: root/src/resources
diff options
context:
space:
mode:
Diffstat (limited to 'src/resources')
-rw-r--r--src/resources/image.c48
-rw-r--r--src/resources/image.h14
-rw-r--r--src/resources/resource.c87
-rw-r--r--src/resources/resource.h23
4 files changed, 172 insertions, 0 deletions
diff --git a/src/resources/image.c b/src/resources/image.c
new file mode 100644
index 0000000..cd2c317
--- /dev/null
+++ b/src/resources/image.c
@@ -0,0 +1,48 @@
+#include <SDL.h>
+#include <SDL_image.h>
+#include "../logging.h"
+#include "image.h"
+#include "resource.h"
+
+struct resource_table img_res;
+
+struct image *
+img_png_get(const char *path)
+{
+ SDL_RWops *rwops;
+ struct image *img;
+
+ img = (struct image *) resource_get(&img_res, path);
+ if (img != NULL) {
+ resource_use((struct resource *) img);
+ return img;
+ }
+
+ img = resource_alloc(path, sizeof(*img));
+ rwops = SDL_RWFromFile(path, "rb");
+ img->image = IMG_LoadPNG_RW(rwops);
+ if (!img->image) {
+ err(1, "Failed to load image \"%s\" (%s)",
+ path, IMG_GetError());
+ }
+
+ resource_use((struct resource *) img);
+ resource_add(&img_res, path, (struct resource *) img);
+
+ return img;
+}
+
+void
+img_png_free(struct image *image)
+{
+ SDL_Surface *data;
+
+ if (image == NULL) {
+ return;
+ }
+
+ data = image->image;
+ if (resource_free(&img_res, (struct resource *) image)) {
+ SDL_FreeSurface(data);
+ }
+}
diff --git a/src/resources/image.h b/src/resources/image.h
new file mode 100644
index 0000000..92ef040
--- /dev/null
+++ b/src/resources/image.h
@@ -0,0 +1,14 @@
+#ifndef IMAGE_H
+#define IMAGE_H
+
+#include "resource.h"
+
+struct image {
+ struct resource res;
+ SDL_Surface *image;
+};
+
+struct image *img_png_get(const char *path);
+void img_png_free(struct image *image);
+
+#endif
diff --git a/src/resources/resource.c b/src/resources/resource.c
new file mode 100644
index 0000000..ebfcf27
--- /dev/null
+++ b/src/resources/resource.c
@@ -0,0 +1,87 @@
+#include <stdlib.h>
+#include <string.h>
+#include "resource.h"
+
+#include "../logging.h"
+
+inline void *
+resource_alloc(const char *path, size_t size)
+{
+ void *new_res;
+
+ debug("Allocating resource \"%s\"...", path);
+ new_res = malloc(size);
+ if (new_res == NULL) {
+ err(1, "Failed to allocate resource \"%s\"", path);
+ return NULL;
+ }
+ memset(new_res, 0, size);
+
+ return new_res;
+}
+
+struct resource *
+resource_get(struct resource_table *resources, const char *path)
+{
+ struct resource *res;
+
+ for (res = resources->head; res != NULL; res = res->next) {
+ if (strcmp(res->path, path) == 0) {
+ debug("Found resource \"%s\"", path);
+ return res;
+ }
+ }
+
+ return NULL;
+}
+
+void
+resource_add(struct resource_table *resources, const char *path,
+ struct resource *new_res)
+{
+ new_res->path = strdup(path);
+ new_res->prev = resources->tail;
+ new_res->next = NULL;
+
+ if (resources->head == NULL) {
+ resources->head = new_res;
+ } else {
+ resources->tail->next = new_res;
+ }
+ resources->tail = new_res;
+}
+
+/* XXX: Not thread-safe. */
+void
+resource_use(struct resource *resource)
+{
+ ++resource->refs;
+}
+
+int
+resource_free(struct resource_table *resources, struct resource *resource)
+{
+ if (resource == NULL) {
+ return -1;
+ }
+
+ debug("Releasing resource with path \"%s\" and %d refs...",
+ resource->path, resource->refs);
+
+ if (--resource->refs == 0) {
+ debug("Freeing resource with path \"%s\"...", resource->path);
+ if (resource->prev == NULL) {
+ resources->head = resource->next;
+ } else {
+ resource->prev->next = resource->next;
+ }
+ if (resource->next == NULL) {
+ resources->tail = resource->prev;
+ } else {
+ resource->next->prev = resource->prev;
+ }
+ free(resource);
+ return 1;
+ }
+ return 0;
+}
diff --git a/src/resources/resource.h b/src/resources/resource.h
new file mode 100644
index 0000000..ada91fd
--- /dev/null
+++ b/src/resources/resource.h
@@ -0,0 +1,23 @@
+#ifndef RESOURCE_H
+#define RESOURCE_H
+
+struct resource_table {
+ struct resource *head;
+ struct resource *tail;
+};
+struct resource {
+ char *path;
+ int refs;
+ struct resource *prev;
+ struct resource *next;
+};
+
+extern inline void *resource_alloc(const char *path, size_t size);
+struct resource *resource_get(struct resource_table *resources,
+ const char *path);
+void resource_add(struct resource_table *resources, const char *path,
+ struct resource *new_res);
+void resource_use(struct resource *resource);
+int resource_free(struct resource_table *resources, struct resource *resource);
+
+#endif