1 #define STB_IMAGE_IMPLEMENTATION
2 #define STB_IMAGE_RESIZE_IMPLEMENTATION
3 #include <stb/stb_image.h>
4 #include <stb/stb_image_resize.h>
6 #include <dragonstd/tree.h>
7 #include "client/client_config.h"
8 #include "client/gl_debug.h"
9 #include "client/texture.h"
18 static int cmp_texture(TextureLookup *texture, char *path)
20 return strcmp(texture->path, path);
23 static bool lookup_texture(char *path, Texture **texture)
25 TreeNode **node = tree_nfd(&textures, path, &cmp_texture);
28 *texture = &((TextureLookup *) (*node)->dat)->texture;
32 TextureLookup *lookup = malloc(sizeof *lookup);
33 lookup->path = strdup(path);
34 *texture = &lookup->texture;
36 tree_nmk(&textures, node, lookup);
40 static void delete_texture(TextureLookup *lookup)
43 texture_destroy(&lookup->texture);
47 __attribute__((constructor(101))) static void textures_init()
52 __attribute__((destructor)) static void textures_deinit()
54 tree_clr(&textures, &delete_texture, NULL, NULL, 0);
57 Texture *texture_load(char *path, bool mipmap)
60 if (lookup_texture(path, &texture))
63 unsigned char *data = stbi_load(path,
64 &texture->width, &texture->height, &texture->channels, 0);
66 fprintf(stderr, "[error] failed to load texture %s\n", path);
70 texture_upload(texture, data, GL_RGBA, mipmap);
71 stbi_image_free(data);
76 static inline int least_common_multiple(int a, int b)
93 Texture *texture_load_cubemap(char *path)
96 if (lookup_texture(path, &texture))
99 glGenTextures(1, &texture->txo); GL_DEBUG
100 glBindTexture(GL_TEXTURE_CUBE_MAP, texture->txo); GL_DEBUG
102 const char *directions[6] = {
113 int width, height, channels;
116 CubemapFace faces[6];
119 for (int i = 0; i < 6; i++) {
120 char filename[strlen(path) + 1 + strlen(directions[i]) + 1 + 3 + 1];
121 sprintf(filename, "%s/%s.png", path, directions[i]);
123 if (!(faces[i].data = stbi_load(filename,
124 &faces[i].width, &faces[i].height, &faces[i].channels, 0))) {
125 fprintf(stderr, "[error] failed to load texture %s\n", filename);
129 size = least_common_multiple(size, faces[i].width);
130 size = least_common_multiple(size, faces[i].height);
133 for (int i = 0; i < 6; i++) {
134 unsigned char *data = faces[i].data;
136 bool resize = faces[i].width != size || faces[i].height != size;
138 data = malloc(size * size * faces[i].channels);
140 stbir_resize_uint8_generic(
141 faces[i].data, faces[i].width, faces[i].height, 0,
143 faces[i].channels, STBIR_ALPHA_CHANNEL_NONE, 0,
144 STBIR_EDGE_CLAMP, STBIR_FILTER_BOX, STBIR_COLORSPACE_LINEAR,
148 glTexImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_X + i, 0, GL_RGBA,
149 size, size, 0, GL_RGBA, GL_UNSIGNED_BYTE, data); GL_DEBUG
151 stbi_image_free(faces[i].data);
153 stbi_image_free(data);
156 glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MIN_FILTER, GL_NEAREST); GL_DEBUG
157 glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MAG_FILTER, GL_NEAREST); GL_DEBUG
158 glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); GL_DEBUG
159 glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); GL_DEBUG
160 glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_R, GL_CLAMP_TO_EDGE); GL_DEBUG
165 void texture_upload(Texture *texture, unsigned char *data, GLenum format, bool mipmap)
167 glGenTextures(1, &texture->txo); GL_DEBUG
168 glBindTexture(GL_TEXTURE_2D, texture->txo); GL_DEBUG
170 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, (mipmap && client_config.mipmap)
171 ? GL_NEAREST_MIPMAP_NEAREST : GL_NEAREST); GL_DEBUG
172 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); GL_DEBUG
173 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT); GL_DEBUG
174 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT); GL_DEBUG
176 glTexImage2D(GL_TEXTURE_2D, 0, format,
177 texture->width, texture->height, 0, format, GL_UNSIGNED_BYTE, data); GL_DEBUG
178 glGenerateMipmap(GL_TEXTURE_2D); GL_DEBUG
181 void texture_destroy(Texture *texture)
183 glDeleteTextures(1, &texture->txo); GL_DEBUG