aboutsummaryrefslogtreecommitdiff
path: root/src/core/texture.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/core/texture.c')
-rw-r--r--src/core/texture.c228
1 files changed, 228 insertions, 0 deletions
diff --git a/src/core/texture.c b/src/core/texture.c
new file mode 100644
index 0000000..372f9e6
--- /dev/null
+++ b/src/core/texture.c
@@ -0,0 +1,228 @@
1#include "texture.h"
2
3#include <gfx_assert.h>
4
5#include <error.h>
6#include <math/defs.h>
7
8#include <stdbool.h>
9
10bool gfx_init_texture(Texture* texture, const TextureDesc* desc) {
11 assert(texture);
12 assert(desc);
13
14 glGenTextures(1, &texture->id);
15 if (!texture->id) {
16 log_error("glGenTextures() failed");
17 return false;
18 }
19 texture->target = to_GL_dimension(desc->dimension);
20 glBindTexture(texture->target, texture->id);
21
22 // glTexStorageXD
23 const int levels =
24 desc->mipmaps
25 ? max(max(log2(desc->width), log2(desc->height)), log2(desc->depth)) +
26 1
27 : 1;
28 const GLenum internal_format = to_GL_internal_format(desc->format);
29 switch (texture->target) {
30 case GL_TEXTURE_2D:
31 case GL_TEXTURE_CUBE_MAP:
32 glTexStorage2D(
33 texture->target, levels, internal_format, desc->width, desc->height);
34 break;
35 default:
36 FAIL("Unhandled texture dimension");
37 gfx_del_texture(texture);
38 return false;
39 }
40 ASSERT_GL;
41
42 texture->format = to_GL_format(desc->format);
43 texture->type = to_GL_type(desc->format);
44 texture->width = desc->width;
45 texture->height = desc->height;
46 gfx_update_texture(texture, &desc->data);
47
48 // gfx_update_texture() unbinds the texture at the end, so re-bind it here.
49 glBindTexture(texture->target, texture->id);
50
51 // Mipmaps.
52 if (desc->mipmaps) {
53 glGenerateMipmap(texture->target);
54 ASSERT_GL;
55 }
56
57 // Texture filtering.
58 const bool linear = desc->filtering == LinearFiltering;
59 GLenum min = desc->mipmaps ? (linear ? GL_LINEAR_MIPMAP_LINEAR
60 : GL_NEAREST_MIPMAP_NEAREST)
61 : (linear ? GL_LINEAR : GL_NEAREST);
62 GLenum mag = linear ? GL_LINEAR : GL_NEAREST;
63 glTexParameteri(texture->target, GL_TEXTURE_MIN_FILTER, min);
64 glTexParameteri(texture->target, GL_TEXTURE_MAG_FILTER, mag);
65 ASSERT_GL;
66
67 // Texture wrapping.
68 GLenum wrap = GL_INVALID_ENUM;
69 switch (desc->wrap) {
70 case Repeat:
71 wrap = GL_REPEAT;
72 break;
73 case ClampToEdge:
74 wrap = GL_CLAMP_TO_EDGE;
75 break;
76 }
77 glTexParameteri(texture->target, GL_TEXTURE_WRAP_R, wrap);
78 glTexParameteri(texture->target, GL_TEXTURE_WRAP_S, wrap);
79 glTexParameteri(texture->target, GL_TEXTURE_WRAP_T, wrap);
80 ASSERT_GL;
81
82 glBindTexture(texture->target, 0);
83 return true;
84}
85
86void gfx_del_texture(Texture* texture) {
87 assert(texture);
88
89 if (texture->id) {
90 glDeleteTextures(1, &texture->id);
91 texture->id = 0;
92 }
93}
94
95void gfx_update_texture(Texture* texture, const TextureDataDesc* desc) {
96 assert(texture);
97 assert(desc);
98
99 glBindTexture(texture->target, texture->id);
100
101 // glTexSubImageXD
102 switch (texture->target) {
103 case GL_TEXTURE_2D:
104 if (desc->pixels) {
105 glTexSubImage2D(
106 GL_TEXTURE_2D, /*level=*/0, /*xoffset=*/0,
107 /*yoffset=*/0, texture->width, texture->height, texture->format,
108 texture->type, desc->pixels);
109 }
110 break;
111 case GL_TEXTURE_CUBE_MAP:
112 for (int i = 0; i < 6; ++i) {
113 const void* pixels = *(&desc->cubemap.pixels_pos_x + i);
114 if (pixels) {
115 glTexSubImage2D(
116 GL_TEXTURE_CUBE_MAP_POSITIVE_X + i, /*level=*/0, /*xoffset=*/0,
117 /*yoffset=*/0, texture->width, texture->height, texture->format,
118 texture->type, pixels);
119 }
120 }
121 break;
122 default:
123 FAIL("Unhandled texture dimension");
124 break;
125 }
126 ASSERT_GL;
127
128 glBindTexture(texture->target, 0);
129}
130
131GLenum to_GL_dimension(TextureDimension dim) {
132 switch (dim) {
133 case Texture2D:
134 return GL_TEXTURE_2D;
135 case TextureCubeMap:
136 return GL_TEXTURE_CUBE_MAP;
137 default:
138 FAIL("Unhandled TextureDimension");
139 return GL_INVALID_ENUM;
140 }
141}
142
143GLenum to_GL_internal_format(TextureFormat format) {
144 switch (format) {
145 case TextureDepth:
146 return GL_DEPTH_COMPONENT;
147 case TextureR8:
148 return GL_R8;
149 case TextureRG16:
150 return GL_RG16;
151 case TextureRG16F:
152 return GL_RG16F;
153 case TextureRGB8:
154 return GL_RGB8;
155 case TextureR11G11B10F:
156 return GL_R11F_G11F_B10F;
157 case TextureRGBA8:
158 return GL_RGBA8;
159 case TextureSRGB8:
160 return GL_SRGB8;
161 case TextureSRGBA8:
162 return GL_SRGB8_ALPHA8;
163 default:
164 FAIL("Unhandled TextureFormat");
165 return GL_INVALID_ENUM;
166 }
167}
168
169GLenum to_GL_format(TextureFormat format) {
170 switch (format) {
171 case TextureDepth:
172 return GL_DEPTH_COMPONENT;
173 case TextureR8:
174 return GL_RED;
175 case TextureRG16:
176 case TextureRG16F:
177 return GL_RG;
178 case TextureRGB8:
179 case TextureR11G11B10F:
180 case TextureSRGB8:
181 return GL_RGB;
182 case TextureRGBA8:
183 case TextureSRGBA8:
184 return GL_RGBA;
185 default:
186 FAIL("Unhandled TextureFormat");
187 return GL_INVALID_ENUM;
188 }
189}
190
191GLenum to_GL_type(TextureFormat format) {
192 switch (format) {
193 case TextureDepth:
194 case TextureRG16F:
195 case TextureR11G11B10F:
196 return GL_FLOAT;
197 case TextureR8:
198 case TextureRG16:
199 case TextureRGB8:
200 case TextureRGBA8:
201 case TextureSRGB8:
202 case TextureSRGBA8:
203 return GL_UNSIGNED_BYTE;
204 default:
205 FAIL("Unhandled TextureFormat");
206 return GL_INVALID_ENUM;
207 }
208}
209
210GLenum to_GL_cubemap_face(CubemapFace face) {
211 switch (face) {
212 case CubemapFacePosX:
213 return GL_TEXTURE_CUBE_MAP_POSITIVE_X;
214 case CubemapFaceNegX:
215 return GL_TEXTURE_CUBE_MAP_NEGATIVE_X;
216 case CubemapFacePosY:
217 return GL_TEXTURE_CUBE_MAP_POSITIVE_Y;
218 case CubemapFaceNegY:
219 return GL_TEXTURE_CUBE_MAP_NEGATIVE_Y;
220 case CubemapFacePosZ:
221 return GL_TEXTURE_CUBE_MAP_POSITIVE_Z;
222 case CubemapFaceNegZ:
223 return GL_TEXTURE_CUBE_MAP_NEGATIVE_Z;
224 default:
225 FAIL("Unhandled CubemapFace");
226 return GL_INVALID_ENUM;
227 }
228}