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