]> git.lizzy.rs Git - dragonblocks_alpha.git/blobdiff - src/client/texture.c
refactoring
[dragonblocks_alpha.git] / src / client / texture.c
index 1036a91218f133e457f56d63116118fd6551a43a..9f4f7ec74c9ce4e0fdb691de4c19c3c8d738d053 100644 (file)
@@ -1,57 +1,83 @@
 #define STB_IMAGE_IMPLEMENTATION
 #include <stb/stb_image.h>
 #include <stdbool.h>
-#include <dragonstd/list.h>
+#include <dragonstd/tree.h>
 #include "client/client_config.h"
 #include "client/texture.h"
-#include "util.h"
 
-static List textures;
+static Tree textures;
 
-__attribute((constructor(101))) static void textures_init()
+typedef struct {
+       char *path;
+       Texture texture;
+} TextureLookup;
+
+static int cmp_texture(TextureLookup *texture, char *path)
 {
-       textures = list_create(&list_compare_string);
+       return strcmp(texture->path, path);
 }
 
-static void list_delete_texture(unused void *key, void *value, unused void *arg)
+static bool lookup_texture(char *path, Texture **texture)
 {
-       texture_delete(value);
+       TreeNode **node = tree_nfd(&textures, path, &cmp_texture);
+
+       if (*node) {
+               *texture = &((TextureLookup *) &(*node)->dat)->texture;
+               return true;
+       }
+
+       TextureLookup *lookup = malloc(sizeof *lookup);
+       lookup->path = strdup(path);
+       *texture = &lookup->texture;
+
+       tree_nmk(&textures, node, lookup);
+       return false;
 }
 
-__attribute((destructor)) static void textures_deinit()
+static void delete_texture(TextureLookup *lookup)
 {
-       list_clear_func(&textures, &list_delete_texture, NULL);
+       free(lookup->path);
+       texture_destroy(&lookup->texture);
+       free(lookup);
 }
 
-Texture *texture_create(unsigned char *data, int width, int height, GLenum format, bool mipmap)
+__attribute__((constructor(101))) static void textures_init()
 {
-       Texture *texture = malloc(sizeof(Texture));
-       texture->width = width;
-       texture->height = height;
-
-       glGenTextures(1, &texture->id);
-
-       glBindTexture(GL_TEXTURE_2D, texture->id);
+       tree_ini(&textures);
+}
 
-       glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, (mipmap && client_config.mipmap) ? GL_NEAREST_MIPMAP_NEAREST : GL_NEAREST);
-       glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
-       glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
-       glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
+__attribute__((destructor)) static void textures_deinit()
+{
+       tree_clr(&textures, &delete_texture, NULL, NULL, 0);
+}
 
-       glTexImage2D(GL_TEXTURE_2D, 0, format, texture->width, texture->height, 0, format, GL_UNSIGNED_BYTE, data);
-       glGenerateMipmap(GL_TEXTURE_2D);
+Texture *texture_load(char *path, bool mipmap)
+{
+       Texture *texture;
+       if (lookup_texture(path, &texture))
+               return texture;
+
+       unsigned char *data = stbi_load(path,
+               &texture->width, &texture->height, &texture->channels, 0);
+       if (!data) {
+               fprintf(stderr, "[error] failed to load texture %s\n", path);
+               exit(EXIT_FAILURE);
+       }
 
-       glBindTexture(GL_TEXTURE_2D, 0);
+       texture_upload(texture, data, GL_RGBA, mipmap);
+       stbi_image_free(data);
 
        return texture;
 }
 
-GLuint texture_create_cubemap(char *path)
+Texture *texture_load_cubemap(char *path)
 {
-       GLuint id;
-       glGenTextures(1, &id);
+       Texture *texture;
+       if (lookup_texture(path, &texture))
+               return texture;
 
-       glBindTexture(GL_TEXTURE_CUBE_MAP, id);
+       glGenTextures(1, &texture->txo);
+       glBindTexture(GL_TEXTURE_CUBE_MAP, texture->txo);
 
        const char *directions[6] = {
                "right",
@@ -66,14 +92,15 @@ GLuint texture_create_cubemap(char *path)
                char filename[strlen(path) + 1 + strlen(directions[i]) + 1 + 3 + 1];
                sprintf(filename, "%s/%s.png", path, directions[i]);
 
-               int width, height, channels;
-               unsigned char *data = stbi_load(filename, &width, &height, &channels, 0);
-               if (! data) {
-                       fprintf(stderr, "Failed to load texture %s\n", filename);
-                       return 0;
+               unsigned char *data = stbi_load(filename,
+                       &texture->width, &texture->height, &texture->channels, 0);
+               if (!data) {
+                       fprintf(stderr, "[error] failed to load texture %s\n", filename);
+                       exit(EXIT_FAILURE);
                }
 
-               glTexImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_X + i, 0, GL_RGBA, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, data);
+               glTexImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_X + i, 0, GL_RGBA,
+                       texture->width, texture->height, 0, GL_RGBA, GL_UNSIGNED_BYTE, data);
                stbi_image_free(data);
        }
 
@@ -83,30 +110,26 @@ GLuint texture_create_cubemap(char *path)
        glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
        glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_R, GL_CLAMP_TO_EDGE);
 
-       return id;
+       return texture;
 }
 
-void texture_delete(Texture *texture)
+void texture_upload(Texture *texture, unsigned char *data, GLenum format, bool mipmap)
 {
-       glDeleteTextures(1, &texture->id);
-       free(texture);
-}
-
-Texture *texture_load(char *path, bool mipmap)
-{
-       int width, height, channels;
-
-       unsigned char *data = stbi_load(path, &width, &height, &channels, 0);
-       if (! data) {
-               fprintf(stderr, "Failed to load texture %s\n", path);
-               return NULL;
-       }
-
-       Texture *texture = texture_create(data, width, height, GL_RGBA, mipmap);
+       glGenTextures(1, &texture->txo);
+       glBindTexture(GL_TEXTURE_2D, texture->txo);
 
-       stbi_image_free(data);
+       glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, (mipmap && client_config.mipmap)
+               ? GL_NEAREST_MIPMAP_NEAREST : GL_NEAREST);
+       glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
+       glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
+       glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
 
-       list_put(&textures, texture, NULL);
+       glTexImage2D(GL_TEXTURE_2D, 0, format,
+               texture->width, texture->height, 0, format, GL_UNSIGNED_BYTE, data);
+       glGenerateMipmap(GL_TEXTURE_2D);
+}
 
-       return texture;
+void texture_destroy(Texture *texture)
+{
+       glDeleteTextures(1, &texture->txo);
 }