Project Alice
Loading...
Searching...
No Matches
texture.cpp
Go to the documentation of this file.
1#include "texture.hpp"
2#include "system_state.hpp"
3#include "simple_fs.hpp"
4
5#define STB_IMAGE_IMPLEMENTATION 1
6#define STBI_NO_STDIO 1
7#define STBI_NO_LINEAR 1
8#define STBI_NO_JPEG 1
9//#define STBI_NO_PNG 1
10//#define STBI_NO_BMP 1
11#define STBI_NO_PSD 1
12//#define STBI_NO_TGA 1
13#define STBI_NO_GIF 1
14#define STBI_NO_HDR 1
15#define STBI_NO_PIC 1
16#define STBI_NO_PNM 1
17#define STBI_NO_THREAD_LOCALS 1
18
19#include "stb_image.h"
20
21namespace ogl {
22
23// DDS loader taken from SOIL2
24
25#define DDSD_CAPS 0x00000001
26#define DDSD_HEIGHT 0x00000002
27#define DDSD_WIDTH 0x00000004
28#define DDSD_PITCH 0x00000008
29#define DDSD_PIXELFORMAT 0x00001000
30#define DDSD_MIPMAPCOUNT 0x00020000
31#define DDSD_LINEARSIZE 0x00080000
32#define DDSD_DEPTH 0x00800000
33
34/* DirectDraw Pixel Format */
35#define DDPF_ALPHAPIXELS 0x00000001
36#define DDPF_FOURCC 0x00000004
37#define DDPF_RGB 0x00000040
38#define DDPF_PALETTEINDEXED8 0x00000020
39
40/* The dwCaps1 member of the DDSCAPS2 structure can be
41set to one or more of the following values. */
42#define DDSCAPS_COMPLEX 0x00000008
43#define DDSCAPS_TEXTURE 0x00001000
44#define DDSCAPS_MIPMAP 0x00400000
45
46/* The dwCaps2 member of the DDSCAPS2 structure can be
47 set to one or more of the following values. */
48#define DDSCAPS2_CUBEMAP 0x00000200
49#define DDSCAPS2_CUBEMAP_POSITIVEX 0x00000400
50#define DDSCAPS2_CUBEMAP_NEGATIVEX 0x00000800
51#define DDSCAPS2_CUBEMAP_POSITIVEY 0x00001000
52#define DDSCAPS2_CUBEMAP_NEGATIVEY 0x00002000
53#define DDSCAPS2_CUBEMAP_POSITIVEZ 0x00004000
54#define DDSCAPS2_CUBEMAP_NEGATIVEZ 0x00008000
55#define DDSCAPS2_VOLUME 0x00200000
56
57#define SOIL_GL_SRGB 0x8C40
58#define SOIL_GL_SRGB_ALPHA 0x8C42
59#define SOIL_RGB_S3TC_DXT1 0x83F0
60#define SOIL_RGBA_S3TC_DXT1 0x83F1
61#define SOIL_RGBA_S3TC_DXT3 0x83F2
62#define SOIL_RGBA_S3TC_DXT5 0x83F3
63
64#define SOIL_TEXTURE_WRAP_R 0x8072
65#define SOIL_CLAMP_TO_EDGE 0x812F
66#define SOIL_REFLECTION_MAP 0x8512
67
68 typedef struct {
69 unsigned int dwMagic;
70 unsigned int dwSize;
71 unsigned int dwFlags;
72 unsigned int dwHeight;
73 unsigned int dwWidth;
74 unsigned int dwPitchOrLinearSize;
75 unsigned int dwDepth;
76 unsigned int dwMipMapCount;
77 unsigned int dwReserved1[11];
78
79 /* DDPIXELFORMAT */
80 struct {
81 unsigned int dwSize;
82 unsigned int dwFlags;
83 unsigned int dwFourCC;
84 unsigned int dwRGBBitCount;
85 unsigned int dwRBitMask;
86 unsigned int dwGBitMask;
87 unsigned int dwBBitMask;
88 unsigned int dwAlphaBitMask;
89 } sPixelFormat;
90
91 /* DDCAPS2 */
92 struct {
93 unsigned int dwCaps1;
94 unsigned int dwCaps2;
95 unsigned int dwDDSX;
96 unsigned int dwReserved;
97 } sCaps;
98 unsigned int dwReserved2;
99 } DDS_header;
100
101 GLuint SOIL_direct_load_DDS_from_memory(unsigned char const* const buffer, uint32_t buffer_length, uint32_t& width, uint32_t& height, int soil_flags) {
102 /* file reading variables */
103 uint32_t block_size = 16;
104 if(buffer_length < sizeof(DDS_header)) {
105 return 0;
106 }
107
108 /* try reading in the header */
109 DDS_header const* header = reinterpret_cast<DDS_header const*>(buffer);
110 uint32_t buffer_index = sizeof(DDS_header);
111 uint32_t palette_index = buffer_index;
112
113 /* validate the header (warning, "goto"'s ahead, shield your eyes!!) */
114 if(header->dwMagic != (('D' << 0) | ('D' << 8) | ('S' << 16) | (' ' << 24))) {
115 return 0;
116 }
117 if(header->dwSize != 124) {
118 return 0;
119 }
120 /* I need all of these */
122 if((header->dwFlags & flag) != flag) {
123 return 0;
124 }
125 /* According to the MSDN spec, the dwFlags should contain
126 DDSD_LINEARSIZE if it's compressed, or DDSD_PITCH if
127 uncompressed. Some DDS writers do not conform to the
128 spec, so I need to make my reader more tolerant */
129 if(header->sPixelFormat.dwSize != 32) {
130 return 0;
131 }
132 /* I need one of these */
133 bool is_alpha = (header->sPixelFormat.dwFlags & (DDPF_ALPHAPIXELS)) != 0;
134 bool uncompressed = (header->sPixelFormat.dwFlags & DDPF_FOURCC) == 0;
135 if((header->sPixelFormat.dwFlags & (DDPF_FOURCC | DDPF_RGB | DDPF_PALETTEINDEXED8)) == 0) {
136 return 0;
137 }
138 /* make sure it is a type we can upload */
139 if((header->sPixelFormat.dwFlags & DDPF_FOURCC) &&
140 !((header->sPixelFormat.dwFourCC == (('D' << 0) | ('X' << 8) | ('T' << 16) | ('1' << 24)))
141 || (header->sPixelFormat.dwFourCC == (('D' << 0) | ('X' << 8) | ('T' << 16) | ('3' << 24)))
142 || (header->sPixelFormat.dwFourCC == (('D' << 0) | ('X' << 8) | ('T' << 16) | ('5' << 24))))) {
143 return 0;
144 }
145 if((header->sCaps.dwCaps1 & DDSCAPS_TEXTURE) == 0) {
146 return 0;
147 }
148 if((header->sCaps.dwCaps2 & DDSCAPS2_CUBEMAP) != 0) {
149 return 0;
150 }
151 /* OK, validated the header, let's load the image data */
152 width = header->dwWidth;
153 height = header->dwHeight;
154
155 GLint s3tc_format = 0; //How we want to give it to shaders
156 GLint s3tc_format_layout = 0; //How's it laid on memory
157 GLint s3tc_type = GL_UNSIGNED_BYTE;
158 uint32_t dds_main_size = 0;
159 if(uncompressed) {
160 block_size = 3;
161 if(is_alpha) {
162 block_size = 4;
163 if(header->sPixelFormat.dwRGBBitCount == 16) {
164 //s3tc_format_layout = GL_RGBA;
165 //s3tc_type = GL_UNSIGNED_BYTE;
166 block_size = 2;
167 }
168 }
169 if((header->sPixelFormat.dwFlags & DDPF_PALETTEINDEXED8) != 0) {
170 block_size = 1;
171 // skip the palette
172 palette_index = buffer_index;
173 buffer_index += 4 * 256;
174 }
175 //pitch = (width * (header->sPixelFormat.dwRGBBitCount) + 7) / 8;
176 dds_main_size = width * height * block_size;
177 } else {
178 /* can we even handle direct uploading to OpenGL DXT compressed images? */
179 /* well, we know it is DXT1/3/5, because we checked above */
180 switch((header->sPixelFormat.dwFourCC >> 24) - '0') {
181 case 1:
182 s3tc_format = SOIL_RGBA_S3TC_DXT1;
183 block_size = 8;
184 break;
185 case 3:
186 s3tc_format = SOIL_RGBA_S3TC_DXT3;
187 block_size = 16;
188 break;
189 case 5:
190 s3tc_format = SOIL_RGBA_S3TC_DXT5;
191 block_size = 16;
192 break;
193 }
194 dds_main_size = ((width + 3) >> 2) * ((height + 3) >> 2) * block_size;
195 }
196
197 uint32_t dds_full_size = dds_main_size;
198 uint32_t mipmaps = 0;
199 if((header->sCaps.dwCaps1 & DDSCAPS_MIPMAP) != 0 && (header->dwMipMapCount > 1)) {
200 mipmaps = header->dwMipMapCount - 1;
201 for(uint32_t i = 1; i <= mipmaps; ++i) {
202 uint32_t w = std::max<uint32_t>(width >> i, 1);
203 uint32_t h = std::max<uint32_t>(height >> i, 1);
204 if(uncompressed) {
205 /* uncompressed DDS, simple MIPmap size calculation */
206 dds_full_size += w * h * block_size;
207 } else {
208 /* compressed DDS, MIPmap size calculation is block based */
209 dds_full_size += ((w + 3) / 4) * ((h + 3) / 4) * block_size;
210 }
211 }
212 }
213 /* do this for each face of the cubemap! */
214 if(buffer_index + dds_full_size <= uint32_t(buffer_length)) {
215 /* got the image data RAM, create or use an existing OpenGL texture handle */
216 GLuint texid = 0;
217 glGenTextures(1, &texid);
218 /* bind an OpenGL texture ID */
219 glBindTexture(GL_TEXTURE_2D, texid);
220 if(!texid)
221 return 0;
222 /* did I have MIPmaps? */
223 if(mipmaps > 0) {
224 /* instruct OpenGL to use the MIPmaps */
225 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
226 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_NEAREST);
227 } else {
228 /* instruct OpenGL _NOT_ to use the MIPmaps */
229 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
230 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
231 }
232 /* does the user want clamping, or wrapping? */
233 if((soil_flags & SOIL_FLAG_TEXTURE_REPEATS) != 0) {
234 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
235 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
236 glTexParameteri(GL_TEXTURE_2D, SOIL_TEXTURE_WRAP_R, GL_REPEAT);
237 } else {
238 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
239 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
240 glTexParameteri(GL_TEXTURE_2D, SOIL_TEXTURE_WRAP_R, GL_CLAMP_TO_EDGE);
241 }
242 /* upload the main chunk */
243 if(uncompressed) {
244 /* TODO: make keep_rgba return false if we can compress it to 3-components without affecting alignment */
245 bool keep_rgba = true;
246 /* and remember, DXT uncompressed uses BGR(A), so swap to (A)BGR for ALL MIPmap levels */
247 std::unique_ptr<uint8_t[]> dds_dest_data = std::unique_ptr<uint8_t[]>(new uint8_t[dds_full_size]);
248 switch(block_size) {
249 case 1:
250 {
251 if(keep_rgba) {
252 dds_dest_data = std::unique_ptr<uint8_t[]>(new uint8_t[(dds_full_size / block_size) * 4]);
253 for(uint32_t i = 0; i < dds_full_size / block_size; i++) {
254 uint8_t pidx = buffer[buffer_index + i];
255 dds_dest_data[i * 4 + 0] = buffer[palette_index + pidx * 4 + 0];
256 dds_dest_data[i * 4 + 1] = buffer[palette_index + pidx * 4 + 1];
257 dds_dest_data[i * 4 + 2] = buffer[palette_index + pidx * 4 + 2];
258 dds_dest_data[i * 4 + 3] = is_alpha ? buffer[palette_index + pidx * 4 + 3] : 0xff;
259 }
260 s3tc_format = s3tc_format_layout = GL_RGBA;
261 } else {
262 dds_dest_data = std::unique_ptr<uint8_t[]>(new uint8_t[(dds_full_size / block_size) * 3]);
263 for(uint32_t i = 0; i < dds_full_size / block_size; i++) {
264 uint8_t pidx = buffer[buffer_index + i];
265 dds_dest_data[i * 3 + 0] = buffer[palette_index + pidx * 4 + 0];
266 dds_dest_data[i * 3 + 1] = buffer[palette_index + pidx * 4 + 1];
267 dds_dest_data[i * 3 + 2] = buffer[palette_index + pidx * 4 + 2];
268 }
269 s3tc_format = s3tc_format_layout = GL_RGB;
270 }
271 break;
272 }
273 case 2:
274 {
275 uint16_t mr1 = uint16_t(header->sPixelFormat.dwRBitMask >> std::countr_zero(header->sPixelFormat.dwRBitMask));
276 float mr2 = mr1 == 0 ? 0.f : 255.f / float(mr1);
277 uint16_t mg1 = uint16_t(header->sPixelFormat.dwGBitMask >> std::countr_zero(header->sPixelFormat.dwGBitMask));
278 float mg2 = mg1 == 0 ? 0.f : 255.f / float(mg1);
279 uint16_t mb1 = uint16_t(header->sPixelFormat.dwBBitMask >> std::countr_zero(header->sPixelFormat.dwBBitMask));
280 float mb2 = mb1 == 0 ? 0.f : 255.f / float(mb1);
281 uint16_t ma1 = uint16_t(header->sPixelFormat.dwAlphaBitMask >> std::countr_zero(header->sPixelFormat.dwAlphaBitMask));
282 float ma2 = ma1 == 0 ? 0.f : 255.f / float(ma1);
283 uint16_t rmask_zeros = uint16_t(std::countr_zero(header->sPixelFormat.dwRBitMask));
284 uint16_t gmask_zeros = uint16_t(std::countr_zero(header->sPixelFormat.dwGBitMask));
285 uint16_t bmask_zeros = uint16_t(std::countr_zero(header->sPixelFormat.dwBBitMask));
286 uint16_t amask_zeros = uint16_t(std::countr_zero(header->sPixelFormat.dwAlphaBitMask));
287 if(keep_rgba) {
288 dds_dest_data = std::unique_ptr<uint8_t[]>(new uint8_t[(dds_full_size / block_size) * 4]);
289 for(uint32_t i = 0; i < dds_full_size / block_size; i++) {
290 uint16_t data = *reinterpret_cast<uint16_t const*>(buffer + buffer_index + i * block_size);
291 uint16_t r = (data & header->sPixelFormat.dwRBitMask) >> rmask_zeros;
292 uint16_t g = (data & header->sPixelFormat.dwGBitMask) >> gmask_zeros;
293 uint16_t b = (data & header->sPixelFormat.dwBBitMask) >> bmask_zeros;
294 uint16_t a = (data & header->sPixelFormat.dwAlphaBitMask) >> amask_zeros;
295 dds_dest_data[i * 4 + 0] = uint8_t(float(r) * mr2);
296 dds_dest_data[i * 4 + 1] = uint8_t(float(g) * mg2);
297 dds_dest_data[i * 4 + 2] = uint8_t(float(b) * mb2);
298 dds_dest_data[i * 4 + 3] = is_alpha ? uint8_t(float(a) * ma2) : 0xff;
299 }
300 s3tc_format = s3tc_format_layout = GL_RGBA;
301 } else {
302 dds_dest_data = std::unique_ptr<uint8_t[]>(new uint8_t[(dds_full_size / block_size) * 3]);
303 for(uint32_t i = 0; i < dds_full_size / block_size; i++) {
304 uint16_t data = *reinterpret_cast<uint16_t const*>(buffer + buffer_index + i * block_size);
305 uint16_t r = (data & header->sPixelFormat.dwRBitMask) >> rmask_zeros;
306 uint16_t g = (data & header->sPixelFormat.dwGBitMask) >> gmask_zeros;
307 uint16_t b = (data & header->sPixelFormat.dwBBitMask) >> bmask_zeros;
308 uint16_t a = (data & header->sPixelFormat.dwAlphaBitMask) >> amask_zeros;
309 dds_dest_data[i * 3 + 0] = uint8_t(float(r) * mr2);
310 dds_dest_data[i * 3 + 1] = uint8_t(float(g) * mg2);
311 dds_dest_data[i * 3 + 2] = uint8_t(float(b) * mb2);
312 }
313 s3tc_format = s3tc_format_layout = GL_RGB;
314 }
315 break;
316 }
317 case 3:
318 {
319 uint32_t rmask_zeros = uint32_t(std::countr_zero(header->sPixelFormat.dwRBitMask));
320 uint32_t gmask_zeros = uint32_t(std::countr_zero(header->sPixelFormat.dwGBitMask));
321 uint32_t bmask_zeros = uint32_t(std::countr_zero(header->sPixelFormat.dwBBitMask));
322 uint32_t amask_zeros = uint32_t(std::countr_zero(header->sPixelFormat.dwAlphaBitMask));
323 if(keep_rgba) {
324 dds_dest_data = std::unique_ptr<uint8_t[]>(new uint8_t[(dds_full_size / block_size) * 4]);
325 for(uint32_t i = 0; i < dds_full_size / block_size; i++) {
326 auto ptr = buffer + buffer_index + i * block_size;
327 uint32_t data = uint32_t((ptr[2] << 16) | (ptr[1] << 8) | ptr[0]);
328 uint32_t r = (data & header->sPixelFormat.dwRBitMask) >> rmask_zeros;
329 uint32_t g = (data & header->sPixelFormat.dwGBitMask) >> gmask_zeros;
330 uint32_t b = (data & header->sPixelFormat.dwBBitMask) >> bmask_zeros;
331 uint32_t a = (data & header->sPixelFormat.dwAlphaBitMask) >> amask_zeros;
332 dds_dest_data[i * 4 + 0] = static_cast<uint8_t>(r);
333 dds_dest_data[i * 4 + 1] = static_cast<uint8_t>(g);
334 dds_dest_data[i * 4 + 2] = static_cast<uint8_t>(b);
335 dds_dest_data[i * 4 + 3] = is_alpha ? static_cast<uint8_t>(a) : 0xff;
336 }
337 s3tc_format = s3tc_format_layout = GL_RGBA;
338 } else {
339 dds_dest_data = std::unique_ptr<uint8_t[]>(new uint8_t[(dds_full_size / block_size) * 3]);
340 for(uint32_t i = 0; i < dds_full_size / block_size; i++) {
341 auto ptr = buffer + buffer_index + i * block_size;
342 uint32_t data = uint32_t((ptr[2] << 16) | (ptr[1] << 8) | ptr[0]);
343 uint32_t r = (data & header->sPixelFormat.dwRBitMask) >> rmask_zeros;
344 uint32_t g = (data & header->sPixelFormat.dwGBitMask) >> gmask_zeros;
345 uint32_t b = (data & header->sPixelFormat.dwBBitMask) >> bmask_zeros;
346 uint32_t a = (data & header->sPixelFormat.dwAlphaBitMask) >> amask_zeros;
347 dds_dest_data[i * 3 + 0] = static_cast<uint8_t>(r);
348 dds_dest_data[i * 3 + 1] = static_cast<uint8_t>(g);
349 dds_dest_data[i * 3 + 2] = static_cast<uint8_t>(b);
350 }
351 s3tc_format = s3tc_format_layout = GL_RGB;
352 }
353 break;
354 }
355 case 4:
356 {
357 uint32_t rmask_zeros = uint32_t(std::countr_zero(header->sPixelFormat.dwRBitMask));
358 uint32_t gmask_zeros = uint32_t(std::countr_zero(header->sPixelFormat.dwGBitMask));
359 uint32_t bmask_zeros = uint32_t(std::countr_zero(header->sPixelFormat.dwBBitMask));
360 uint32_t amask_zeros = uint32_t(std::countr_zero(header->sPixelFormat.dwAlphaBitMask));
361 if(keep_rgba) {
362 dds_dest_data = std::unique_ptr<uint8_t[]>(new uint8_t[(dds_full_size / block_size) * 4]);
363 for(uint32_t i = 0; i < dds_full_size / block_size; i++) {
364 uint32_t data = *reinterpret_cast<uint32_t const*>(buffer + buffer_index + i * block_size);
365 uint32_t r = (data & header->sPixelFormat.dwRBitMask) >> rmask_zeros;
366 uint32_t g = (data & header->sPixelFormat.dwGBitMask) >> gmask_zeros;
367 uint32_t b = (data & header->sPixelFormat.dwBBitMask) >> bmask_zeros;
368 uint32_t a = (data & header->sPixelFormat.dwAlphaBitMask) >> amask_zeros;
369 dds_dest_data[i * 4 + 0] = static_cast<uint8_t>(r);
370 dds_dest_data[i * 4 + 1] = static_cast<uint8_t>(g);
371 dds_dest_data[i * 4 + 2] = static_cast<uint8_t>(b);
372 dds_dest_data[i * 4 + 3] = is_alpha ? static_cast<uint8_t>(a) : 0xff;
373 }
374 s3tc_format = s3tc_format_layout = GL_RGBA;
375 } else {
376 dds_dest_data = std::unique_ptr<uint8_t[]>(new uint8_t[(dds_full_size / block_size) * 3]);
377 for(uint32_t i = 0; i < dds_full_size / block_size; i++) {
378 uint32_t data = *reinterpret_cast<uint32_t const*>(buffer + buffer_index + i * block_size);
379 uint32_t r = (data & header->sPixelFormat.dwRBitMask) >> rmask_zeros;
380 uint32_t g = (data & header->sPixelFormat.dwGBitMask) >> gmask_zeros;
381 uint32_t b = (data & header->sPixelFormat.dwBBitMask) >> bmask_zeros;
382 uint32_t a = (data & header->sPixelFormat.dwAlphaBitMask) >> amask_zeros;
383 dds_dest_data[i * 3 + 0] = static_cast<uint8_t>(r);
384 dds_dest_data[i * 3 + 1] = static_cast<uint8_t>(g);
385 dds_dest_data[i * 3 + 2] = static_cast<uint8_t>(b);
386 }
387 s3tc_format = s3tc_format_layout = GL_RGB;
388 }
389 break;
390 }
391 default:
392 {
393 dds_dest_data = std::unique_ptr<uint8_t[]>(new uint8_t[(dds_full_size / block_size) * 4]);
394 break;
395 }
396 }
397 glTexImage2D(GL_TEXTURE_2D, 0, s3tc_format, width, height, 0, s3tc_format_layout, s3tc_type, dds_dest_data.get());
398 uint32_t dest_buffer_index = (dds_main_size / block_size) * (keep_rgba ? 4 : 3);
399 /* upload the mipmaps, if we have them */
400 for(uint32_t i = 1; i <= mipmaps; ++i) {
401 uint32_t w = std::max<uint32_t>(width >> i, 1);
402 uint32_t h = std::max<uint32_t>(height >> i, 1);
403 /* upload this mipmap */
404 uint32_t mip_size = w * h * (keep_rgba ? 4 : 3);
405 glTexImage2D(GL_TEXTURE_2D, i, s3tc_format, w, h, 0, s3tc_format_layout, s3tc_type, dds_dest_data.get() + dest_buffer_index);
406 /* and move to the next mipmap */
407 dest_buffer_index += mip_size;
408 }
409 } else {
410 glCompressedTexImage2D(GL_TEXTURE_2D, 0, s3tc_format, width, height, 0, dds_main_size, buffer + buffer_index);
411 buffer_index += dds_main_size;
412 /* upload the mipmaps, if we have them */
413 for(uint32_t i = 1; i <= mipmaps; ++i) {
414 uint32_t w = std::max<uint32_t>(width >> i, 1);
415 uint32_t h = std::max<uint32_t>(height >> i, 1);
416 /* upload this mipmap */
417 uint32_t mip_size = ((w + 3) / 4) * ((h + 3) / 4) * block_size;
418 glCompressedTexImage2D(GL_TEXTURE_2D, i, s3tc_format, w, h, 0, mip_size, buffer + buffer_index);
419 /* and move to the next mipmap */
420 buffer_index += mip_size;
421 }
422 }
423 return texid;
424 }
425 return 0;
426 }
427
428 GLuint SOIL_direct_load_DDS_array_from_memory(unsigned char const* const buffer, uint32_t buffer_length, uint32_t& width, uint32_t& height, int soil_flags, uint32_t tiles_x, uint32_t tiles_y) {
429 /* file reading variables */
430 uint32_t block_size = 16;
431 if(buffer_length < sizeof(DDS_header)) {
432 return 0;
433 }
434
435 /* try reading in the header */
436 DDS_header const* header = reinterpret_cast<DDS_header const*>(buffer);
437 uint32_t buffer_index = sizeof(DDS_header);
438 uint32_t palette_index = buffer_index;
439
440 /* validate the header (warning, "goto"'s ahead, shield your eyes!!) */
441 if(header->dwMagic != (('D' << 0) | ('D' << 8) | ('S' << 16) | (' ' << 24))) {
442 return 0;
443 }
444 if(header->dwSize != 124) {
445 return 0;
446 }
447 /* I need all of these */
449 if((header->dwFlags & flag) != flag) {
450 return 0;
451 }
452 /* According to the MSDN spec, the dwFlags should contain
453 DDSD_LINEARSIZE if it's compressed, or DDSD_PITCH if
454 uncompressed. Some DDS writers do not conform to the
455 spec, so I need to make my reader more tolerant */
456 if(header->sPixelFormat.dwSize != 32) {
457 return 0;
458 }
459 /* I need one of these */
460 bool is_alpha = (header->sPixelFormat.dwFlags & (DDPF_ALPHAPIXELS)) != 0;
461 bool uncompressed = (header->sPixelFormat.dwFlags & DDPF_FOURCC) == 0;
462 if((header->sPixelFormat.dwFlags & (DDPF_FOURCC | DDPF_RGB | DDPF_PALETTEINDEXED8)) == 0) {
463 return 0;
464 }
465 /* make sure it is a type we can upload */
466 if((header->sPixelFormat.dwFlags & DDPF_FOURCC) &&
467 !((header->sPixelFormat.dwFourCC == (('D' << 0) | ('X' << 8) | ('T' << 16) | ('1' << 24)))
468 || (header->sPixelFormat.dwFourCC == (('D' << 0) | ('X' << 8) | ('T' << 16) | ('3' << 24)))
469 || (header->sPixelFormat.dwFourCC == (('D' << 0) | ('X' << 8) | ('T' << 16) | ('5' << 24))))) {
470 return 0;
471 }
472 if((header->sCaps.dwCaps1 & DDSCAPS_TEXTURE) == 0) {
473 return 0;
474 }
475 if((header->sCaps.dwCaps2 & DDSCAPS2_CUBEMAP) != 0) {
476 return 0;
477 }
478 /* OK, validated the header, let's load the image data */
479 width = header->dwWidth;
480 height = header->dwHeight;
481
482 GLint s3tc_format = 0; //How we want to give it to shaders
483 GLint s3tc_format_layout = 0; //How's it laid on memory
484 GLint s3tc_type = GL_UNSIGNED_BYTE;
485 uint32_t dds_main_size = 0;
486 if(uncompressed) {
487 block_size = 3;
488 if(is_alpha) {
489 block_size = 4;
490 if(header->sPixelFormat.dwRGBBitCount == 16) {
491 //s3tc_format_layout = GL_RGBA;
492 //s3tc_type = GL_UNSIGNED_BYTE;
493 block_size = 2;
494 }
495 }
496 if((header->sPixelFormat.dwFlags & DDPF_PALETTEINDEXED8) != 0) {
497 block_size = 1;
498 // skip the palette
499 palette_index = buffer_index;
500 buffer_index += 4 * 256;
501 }
502 //pitch = (width * (header->sPixelFormat.dwRGBBitCount) + 7) / 8;
503 dds_main_size = width * height * block_size;
504 } else {
505 /* can we even handle direct uploading to OpenGL DXT compressed images? */
506 /* well, we know it is DXT1/3/5, because we checked above */
507 switch((header->sPixelFormat.dwFourCC >> 24) - '0') {
508 case 1:
509 s3tc_format = SOIL_RGBA_S3TC_DXT1;
510 block_size = 8;
511 break;
512 case 3:
513 s3tc_format = SOIL_RGBA_S3TC_DXT3;
514 block_size = 16;
515 break;
516 case 5:
517 s3tc_format = SOIL_RGBA_S3TC_DXT5;
518 block_size = 16;
519 break;
520 }
521 dds_main_size = ((width + 3) >> 2) * ((height + 3) >> 2) * block_size;
522 }
523
524 uint32_t dds_full_size = dds_main_size;
525 uint32_t mipmaps = 0;
526 if((header->sCaps.dwCaps1 & DDSCAPS_MIPMAP) != 0 && (header->dwMipMapCount > 1)) {
527 mipmaps = header->dwMipMapCount - 1;
528 for(uint32_t i = 1; i <= mipmaps; ++i) {
529 uint32_t w = std::max<uint32_t>(width >> i, 1);
530 uint32_t h = std::max<uint32_t>(height >> i, 1);
531 if(uncompressed) {
532 /* uncompressed DDS, simple MIPmap size calculation */
533 dds_full_size += w * h * block_size;
534 } else {
535 /* compressed DDS, MIPmap size calculation is block based */
536 dds_full_size += ((w + 3) / 4) * ((h + 3) / 4) * block_size;
537 }
538 }
539 }
540 /* do this for each face of the cubemap! */
541 if(buffer_index + dds_full_size <= uint32_t(buffer_length)) {
542 /* got the image data RAM, create or use an existing OpenGL texture handle */
543 GLuint texid = 0;
544 glGenTextures(1, &texid);
545 /* bind an OpenGL texture ID */
546 glBindTexture(GL_TEXTURE_2D_ARRAY, texid);
547 if(!texid)
548 return 0;
549 /* did I have MIPmaps? */
550 if(mipmaps > 0) {
551 /* instruct OpenGL to use the MIPmaps */
552 glTexParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
553 glTexParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_NEAREST);
554 } else {
555 /* instruct OpenGL _NOT_ to use the MIPmaps */
556 glTexParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
557 glTexParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
558 }
559 /* does the user want clamping, or wrapping? */
560 if((soil_flags & SOIL_FLAG_TEXTURE_REPEATS) != 0) {
561 glTexParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_WRAP_S, GL_REPEAT);
562 glTexParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_WRAP_T, GL_REPEAT);
563 glTexParameteri(GL_TEXTURE_2D_ARRAY, SOIL_TEXTURE_WRAP_R, GL_REPEAT);
564 } else {
565 glTexParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
566 glTexParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
567 glTexParameteri(GL_TEXTURE_2D_ARRAY, SOIL_TEXTURE_WRAP_R, GL_CLAMP_TO_EDGE);
568 }
569 glPixelStorei(GL_UNPACK_ROW_LENGTH, width);
570 glPixelStorei(GL_UNPACK_IMAGE_HEIGHT, height);
571 /* upload the main chunk */
572 if(uncompressed) {
573 /* TODO: make keep_rgba return false if we can compress it to 3-components without affecting alignment */
574 bool keep_rgba = true;
575 /* and remember, DXT uncompressed uses BGR(A), so swap to (A)BGR for ALL MIPmap levels */
576 std::unique_ptr<uint8_t[]> dds_dest_data = std::unique_ptr<uint8_t[]>(new uint8_t[dds_full_size]);
577 switch(block_size) {
578 case 1:
579 {
580 if(keep_rgba) {
581 dds_dest_data = std::unique_ptr<uint8_t[]>(new uint8_t[(dds_full_size / block_size) * 4]);
582 for(uint32_t i = 0; i < dds_full_size / block_size; i++) {
583 uint8_t pidx = buffer[buffer_index + i];
584 dds_dest_data[i * 4 + 0] = buffer[palette_index + pidx * 4 + 0];
585 dds_dest_data[i * 4 + 1] = buffer[palette_index + pidx * 4 + 1];
586 dds_dest_data[i * 4 + 2] = buffer[palette_index + pidx * 4 + 2];
587 dds_dest_data[i * 4 + 3] = is_alpha ? buffer[palette_index + pidx * 4 + 3] : 0xff;
588 }
589 s3tc_format = s3tc_format_layout = GL_RGBA;
590 } else {
591 dds_dest_data = std::unique_ptr<uint8_t[]>(new uint8_t[(dds_full_size / block_size) * 3]);
592 for(uint32_t i = 0; i < dds_full_size / block_size; i++) {
593 uint8_t pidx = buffer[buffer_index + i];
594 dds_dest_data[i * 3 + 0] = buffer[palette_index + pidx * 4 + 0];
595 dds_dest_data[i * 3 + 1] = buffer[palette_index + pidx * 4 + 1];
596 dds_dest_data[i * 3 + 2] = buffer[palette_index + pidx * 4 + 2];
597 }
598 s3tc_format = s3tc_format_layout = GL_RGB;
599 }
600 break;
601 }
602 case 2:
603 {
604 uint16_t mr1 = uint16_t(header->sPixelFormat.dwRBitMask >> std::countr_zero(header->sPixelFormat.dwRBitMask));
605 float mr2 = mr1 == 0 ? 0.f : 255.f / float(mr1);
606 uint16_t mg1 = uint16_t(header->sPixelFormat.dwGBitMask >> std::countr_zero(header->sPixelFormat.dwGBitMask));
607 float mg2 = mg1 == 0 ? 0.f : 255.f / float(mg1);
608 uint16_t mb1 = uint16_t(header->sPixelFormat.dwBBitMask >> std::countr_zero(header->sPixelFormat.dwBBitMask));
609 float mb2 = mb1 == 0 ? 0.f : 255.f / float(mb1);
610 uint16_t ma1 = uint16_t(header->sPixelFormat.dwAlphaBitMask >> std::countr_zero(header->sPixelFormat.dwAlphaBitMask));
611 float ma2 = ma1 == 0 ? 0.f : 255.f / float(ma1);
612 uint16_t rmask_zeros = uint16_t(std::countr_zero(header->sPixelFormat.dwRBitMask));
613 uint16_t gmask_zeros = uint16_t(std::countr_zero(header->sPixelFormat.dwGBitMask));
614 uint16_t bmask_zeros = uint16_t(std::countr_zero(header->sPixelFormat.dwBBitMask));
615 uint16_t amask_zeros = uint16_t(std::countr_zero(header->sPixelFormat.dwAlphaBitMask));
616 if(keep_rgba) {
617 dds_dest_data = std::unique_ptr<uint8_t[]>(new uint8_t[(dds_full_size / block_size) * 4]);
618 for(uint32_t i = 0; i < dds_full_size / block_size; i++) {
619 uint16_t data = *reinterpret_cast<uint16_t const*>(buffer + buffer_index + i * block_size);
620 uint16_t r = (data & header->sPixelFormat.dwRBitMask) >> rmask_zeros;
621 uint16_t g = (data & header->sPixelFormat.dwGBitMask) >> gmask_zeros;
622 uint16_t b = (data & header->sPixelFormat.dwBBitMask) >> bmask_zeros;
623 uint16_t a = (data & header->sPixelFormat.dwAlphaBitMask) >> amask_zeros;
624 dds_dest_data[i * 4 + 0] = uint8_t(float(r) * mr2);
625 dds_dest_data[i * 4 + 1] = uint8_t(float(g) * mg2);
626 dds_dest_data[i * 4 + 2] = uint8_t(float(b) * mb2);
627 dds_dest_data[i * 4 + 3] = is_alpha ? uint8_t(float(a) * ma2) : 0xff;
628 }
629 s3tc_format = s3tc_format_layout = GL_RGBA;
630 } else {
631 dds_dest_data = std::unique_ptr<uint8_t[]>(new uint8_t[(dds_full_size / block_size) * 3]);
632 for(uint32_t i = 0; i < dds_full_size / block_size; i++) {
633 uint16_t data = *reinterpret_cast<uint16_t const*>(buffer + buffer_index + i * block_size);
634 uint16_t r = (data & header->sPixelFormat.dwRBitMask) >> rmask_zeros;
635 uint16_t g = (data & header->sPixelFormat.dwGBitMask) >> gmask_zeros;
636 uint16_t b = (data & header->sPixelFormat.dwBBitMask) >> bmask_zeros;
637 uint16_t a = (data & header->sPixelFormat.dwAlphaBitMask) >> amask_zeros;
638 dds_dest_data[i * 3 + 0] = uint8_t(float(r) * mr2);
639 dds_dest_data[i * 3 + 1] = uint8_t(float(g) * mg2);
640 dds_dest_data[i * 3 + 2] = uint8_t(float(b) * mb2);
641 }
642 s3tc_format = s3tc_format_layout = GL_RGB;
643 }
644 break;
645 }
646 case 3:
647 {
648 uint32_t rmask_zeros = uint32_t(std::countr_zero(header->sPixelFormat.dwRBitMask));
649 uint32_t gmask_zeros = uint32_t(std::countr_zero(header->sPixelFormat.dwGBitMask));
650 uint32_t bmask_zeros = uint32_t(std::countr_zero(header->sPixelFormat.dwBBitMask));
651 uint32_t amask_zeros = uint32_t(std::countr_zero(header->sPixelFormat.dwAlphaBitMask));
652 if(keep_rgba) {
653 dds_dest_data = std::unique_ptr<uint8_t[]>(new uint8_t[(dds_full_size / block_size) * 4]);
654 for(uint32_t i = 0; i < dds_full_size / block_size; i++) {
655 auto ptr = buffer + buffer_index + i * block_size;
656 uint32_t data = uint32_t((ptr[2] << 16) | (ptr[1] << 8) | ptr[0]);
657 uint32_t r = (data & header->sPixelFormat.dwRBitMask) >> rmask_zeros;
658 uint32_t g = (data & header->sPixelFormat.dwGBitMask) >> gmask_zeros;
659 uint32_t b = (data & header->sPixelFormat.dwBBitMask) >> bmask_zeros;
660 uint32_t a = (data & header->sPixelFormat.dwAlphaBitMask) >> amask_zeros;
661 dds_dest_data[i * 4 + 0] = static_cast<uint8_t>(r);
662 dds_dest_data[i * 4 + 1] = static_cast<uint8_t>(g);
663 dds_dest_data[i * 4 + 2] = static_cast<uint8_t>(b);
664 dds_dest_data[i * 4 + 3] = is_alpha ? static_cast<uint8_t>(a) : 0xff;
665 }
666 s3tc_format = s3tc_format_layout = GL_RGBA;
667 } else {
668 dds_dest_data = std::unique_ptr<uint8_t[]>(new uint8_t[(dds_full_size / block_size) * 3]);
669 for(uint32_t i = 0; i < dds_full_size / block_size; i++) {
670 auto ptr = buffer + buffer_index + i * block_size;
671 uint32_t data = uint32_t((ptr[2] << 16) | (ptr[1] << 8) | ptr[0]);
672 uint32_t r = (data & header->sPixelFormat.dwRBitMask) >> rmask_zeros;
673 uint32_t g = (data & header->sPixelFormat.dwGBitMask) >> gmask_zeros;
674 uint32_t b = (data & header->sPixelFormat.dwBBitMask) >> bmask_zeros;
675 uint32_t a = (data & header->sPixelFormat.dwAlphaBitMask) >> amask_zeros;
676 dds_dest_data[i * 3 + 0] = static_cast<uint8_t>(r);
677 dds_dest_data[i * 3 + 1] = static_cast<uint8_t>(g);
678 dds_dest_data[i * 3 + 2] = static_cast<uint8_t>(b);
679 }
680 s3tc_format = s3tc_format_layout = GL_RGB;
681 }
682 break;
683 }
684 case 4:
685 {
686 uint32_t rmask_zeros = uint32_t(std::countr_zero(header->sPixelFormat.dwRBitMask));
687 uint32_t gmask_zeros = uint32_t(std::countr_zero(header->sPixelFormat.dwGBitMask));
688 uint32_t bmask_zeros = uint32_t(std::countr_zero(header->sPixelFormat.dwBBitMask));
689 uint32_t amask_zeros = uint32_t(std::countr_zero(header->sPixelFormat.dwAlphaBitMask));
690 if(keep_rgba) {
691 dds_dest_data = std::unique_ptr<uint8_t[]>(new uint8_t[(dds_full_size / block_size) * 4]);
692 for(uint32_t i = 0; i < dds_full_size / block_size; i++) {
693 uint32_t data = *reinterpret_cast<uint32_t const*>(buffer + buffer_index + i * block_size);
694 uint32_t r = (data & header->sPixelFormat.dwRBitMask) >> rmask_zeros;
695 uint32_t g = (data & header->sPixelFormat.dwGBitMask) >> gmask_zeros;
696 uint32_t b = (data & header->sPixelFormat.dwBBitMask) >> bmask_zeros;
697 uint32_t a = (data & header->sPixelFormat.dwAlphaBitMask) >> amask_zeros;
698 dds_dest_data[i * 4 + 0] = static_cast<uint8_t>(r);
699 dds_dest_data[i * 4 + 1] = static_cast<uint8_t>(g);
700 dds_dest_data[i * 4 + 2] = static_cast<uint8_t>(b);
701 dds_dest_data[i * 4 + 3] = is_alpha ? static_cast<uint8_t>(a) : 0xff;
702 }
703 s3tc_format = s3tc_format_layout = GL_RGBA;
704 } else {
705 dds_dest_data = std::unique_ptr<uint8_t[]>(new uint8_t[(dds_full_size / block_size) * 3]);
706 for(uint32_t i = 0; i < dds_full_size / block_size; i++) {
707 uint32_t data = *reinterpret_cast<uint32_t const*>(buffer + buffer_index + i * block_size);
708 uint32_t r = (data & header->sPixelFormat.dwRBitMask) >> rmask_zeros;
709 uint32_t g = (data & header->sPixelFormat.dwGBitMask) >> gmask_zeros;
710 uint32_t b = (data & header->sPixelFormat.dwBBitMask) >> bmask_zeros;
711 uint32_t a = (data & header->sPixelFormat.dwAlphaBitMask) >> amask_zeros;
712 dds_dest_data[i * 3 + 0] = static_cast<uint8_t>(r);
713 dds_dest_data[i * 3 + 1] = static_cast<uint8_t>(g);
714 dds_dest_data[i * 3 + 2] = static_cast<uint8_t>(b);
715 }
716 s3tc_format = s3tc_format_layout = GL_RGB;
717 }
718 break;
719 }
720 default:
721 {
722 dds_dest_data = std::unique_ptr<uint8_t[]>(new uint8_t[(dds_full_size / block_size) * 4]);
723 break;
724 }
725 }
726 size_t p_dx = width / tiles_x; // Pixels of each tile in x
727 size_t p_dy = height / tiles_y; // Pixels of each tile in y
728 for(uint32_t x = 0; x < tiles_x; x++) {
729 for(uint32_t y = 0; y < tiles_y; y++) {
730 uint32_t offset = uint32_t(x * p_dy * width + y * p_dx * (keep_rgba ? 4 : 3));
731 glTexSubImage3D(GL_TEXTURE_2D_ARRAY, 0, 0, 0, GLint(x * tiles_x + y), GLsizei(p_dx), GLsizei(p_dy), 1, s3tc_format, s3tc_type, dds_dest_data.get() + offset);
732 }
733 }
734 //glTexImage2D(GL_TEXTURE_2D_ARRAY, 0, s3tc_format, width, height, 0, s3tc_format_layout, s3tc_type, dds_dest_data.get());
735 //uint32_t dest_buffer_index = (dds_main_size / block_size) * (keep_rgba ? 4 : 3);
736 /* upload the mipmaps, if we have them */
737 /*
738 for(uint32_t i = 1; i <= mipmaps; ++i) {
739 uint32_t w = std::max<uint32_t>(width >> i, 1);
740 uint32_t h = std::max<uint32_t>(height >> i, 1);
741 // upload this mipmap
742 uint32_t mip_size = w * h * (keep_rgba ? 4 : 3);
743 glTexImage2D(GL_TEXTURE_2D_ARRAY, i, s3tc_format, w, h, 0, s3tc_format_layout, s3tc_type, dds_dest_data.get() + dest_buffer_index);
744 // and move to the next mipmap
745 dest_buffer_index += mip_size;
746 }*/
747 //
748 } else {
749 size_t p_dx = width / tiles_x; // Pixels of each tile in x
750 size_t p_dy = height / tiles_y; // Pixels of each tile in y
751 glCompressedTexImage3D(GL_TEXTURE_2D_ARRAY, 0, s3tc_format, GLsizei(p_dx), GLsizei(p_dy), GLsizei(tiles_x * tiles_y), 0, GLsizei(dds_main_size), buffer);
752 //glCompressedTexImage2D(GL_TEXTURE_2D_ARRAY, 0, s3tc_format, width, height, 0, dds_main_size, buffer + buffer_index);
753 buffer_index += dds_main_size;
754 /* upload the mipmaps, if we have them */
755 /*for(uint32_t i = 1; i <= mipmaps; ++i) {
756 uint32_t w = std::max<uint32_t>(width >> i, 1);
757 uint32_t h = std::max<uint32_t>(height >> i, 1);
758 // upload this mipmap
759 uint32_t mip_size = ((w + 3) / 4) * ((h + 3) / 4) * block_size;
760 glCompressedTexImage2D(GL_TEXTURE_2D_ARRAY, i, s3tc_format, w, h, 0, mip_size, buffer + buffer_index);
761 // and move to the next mipmap
762 buffer_index += mip_size;
763 }*/
764 }
765 glPixelStorei(GL_UNPACK_ROW_LENGTH, 0);
766 glPixelStorei(GL_UNPACK_IMAGE_HEIGHT, 0);
767 return texid;
768 }
769 return 0;
770 }
771
773 STBI_FREE(data);
774 data = nullptr;
775}
776
777texture::texture(texture&& other) noexcept {
778 channels = other.channels;
779 loaded = other.loaded;
780 size_x = other.size_x;
781 size_y = other.size_y;
782 data = other.data;
783 texture_handle = other.texture_handle;
784
785 other.data = nullptr;
786}
788 channels = other.channels;
789 loaded = other.loaded;
790 size_x = other.size_x;
791 size_y = other.size_y;
792 data = other.data;
793 texture_handle = other.texture_handle;
794
795 other.data = nullptr;
796 return *this;
797}
798
800 assert(loaded);
801 return texture_handle;
802}
803
804GLuint load_file_and_return_handle(native_string const& native_name, simple_fs::file_system const& fs, texture& asset_texture, bool keep_data) {
805 auto name_length = native_name.length();
806
807 auto root = get_root(fs);
808 if(name_length > 4) { // try loading as a dds
809 auto dds_name = native_name;
810 if(auto pos = dds_name.find_last_of('.'); pos != native_string::npos) {
811 dds_name[pos + 1] = NATIVE('d');
812 dds_name[pos + 2] = NATIVE('d');
813 dds_name[pos + 3] = NATIVE('s');
814 dds_name.resize(pos + 4);
815 }
816 auto file = open_file(root, dds_name);
817 if(file) {
818 auto content = simple_fs::view_contents(*file);
819
820 uint32_t w = 0;
821 uint32_t h = 0;
822 asset_texture.texture_handle = SOIL_direct_load_DDS_from_memory(reinterpret_cast<uint8_t const*>(content.data), content.file_size, w, h, 0);
823
824 if(asset_texture.texture_handle) {
825 asset_texture.channels = 4;
826 asset_texture.size_x = int32_t(w);
827 asset_texture.size_y = int32_t(h);
828 asset_texture.loaded = true;
829
830 if(keep_data) {
831 asset_texture.data = static_cast<uint8_t*>(STBI_MALLOC(4 * w * h));
832 glGetTextureImage(asset_texture.texture_handle, 0, GL_RGBA, GL_UNSIGNED_BYTE, static_cast<int32_t>(4 * w * h),
833 asset_texture.data);
834 }
835 return asset_texture.texture_handle;
836 }
837 }
838 }
839
840 auto file = open_file(root, native_name);
841 if(!file && name_length > 4) {
842 auto png_name = native_name;
843 if(auto pos = png_name.find_last_of('.'); pos != native_string::npos) {
844 png_name[pos + 1] = NATIVE('p');
845 png_name[pos + 2] = NATIVE('n');
846 png_name[pos + 3] = NATIVE('g');
847 png_name.resize(pos + 4);
848 }
849 file = open_file(root, png_name);
850 }
851 if(file) {
852 auto content = simple_fs::view_contents(*file);
853
854 int32_t file_channels = 4;
855
856 asset_texture.data = stbi_load_from_memory(reinterpret_cast<uint8_t const*>(content.data), int32_t(content.file_size),
857 &(asset_texture.size_x), &(asset_texture.size_y), &file_channels, 4);
858
859 asset_texture.channels = 4;
860 asset_texture.loaded = true;
861
862 glGenTextures(1, &asset_texture.texture_handle);
863 if(asset_texture.texture_handle) {
864 glBindTexture(GL_TEXTURE_2D, asset_texture.texture_handle);
865
866 glTexStorage2D(GL_TEXTURE_2D, 1, GL_RGBA8, asset_texture.size_x, asset_texture.size_y);
867 glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, asset_texture.size_x, asset_texture.size_y, GL_RGBA, GL_UNSIGNED_BYTE,
868 asset_texture.data);
869
870 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
871 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
872 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
873 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
874
875 glBindTexture(GL_TEXTURE_2D, 0);
876 }
877
878 if(!keep_data) {
879 STBI_FREE(asset_texture.data);
880 asset_texture.data = nullptr;
881 }
882
883 return asset_texture.texture_handle;
884 }
885 asset_texture.loaded = true; // because we tried to load it (and failed) and trying again will be wasteful
886 return 0;
887}
888
890 switch(type) {
893 return NATIVE("");
895 return NATIVE("_communist");
897 return NATIVE("_fascist");
899 return NATIVE("_monarchy");
901 return NATIVE("_republic");
902 // Non-vanilla
904 return NATIVE("_theocracy");
906 return NATIVE("_special");
908 return NATIVE("_spare");
910 return NATIVE("_populist");
912 return NATIVE("_realm");
914 return NATIVE("_other");
916 return NATIVE("_monarchy2");
918 return NATIVE("_monarchy3");
920 return NATIVE("_republic2");
922 return NATIVE("_republic3");
924 return NATIVE("_communist2");
926 return NATIVE("_communist3");
928 return NATIVE("_fascist2");
930 return NATIVE("_fascist3");
932 return NATIVE("_theocracy2");
934 return NATIVE("_theocracy3");
936 return NATIVE("_cosmetic_1");
938 return NATIVE("_cosmetic_2");
940 return NATIVE("_colonial");
942 return NATIVE("_nationalist");
944 return NATIVE("_sectarian");
946 return NATIVE("_socialist");
948 return NATIVE("_dominion");
950 return NATIVE("_agrarism");
952 return NATIVE("_national_syndicalist");
954 return NATIVE("_theocratic");
956 return NATIVE("_slot1");
958 return NATIVE("_slot2");
960 return NATIVE("_slot3");
962 return NATIVE("_slot4");
964 return NATIVE("_anarcho_liberal");
966 return NATIVE("_green");
968 return NATIVE("_traditionalist");
970 return NATIVE("_ultranationalist");
971 default:
972 return NATIVE("");
973
974 }
975}
976
977GLuint get_flag_handle(sys::state& state, dcon::national_identity_id nat_id, culture::flag_type type) {
978 auto masq_nat_id = state.world.nation_get_masquerade_identity(state.world.national_identity_get_nation_from_identity_holder(nat_id));
979 if(!masq_nat_id) {
980 masq_nat_id = nat_id;
981 }
982
983 auto const offset = culture::get_remapped_flag_type(state, type);
984 dcon::texture_id id = dcon::texture_id{ dcon::texture_id::value_base_t(state.ui_defs.textures.size() + (1 + masq_nat_id.id.index()) * state.flag_types.size() + offset) };
985 if(state.open_gl.asset_textures[id].loaded) {
986 return state.open_gl.asset_textures[id].texture_handle;
987 } else { // load from file
988 native_string file_str;
989 file_str += NATIVE("gfx");
990 file_str += NATIVE_DIR_SEPARATOR;
991 file_str += NATIVE("flags");
992 file_str += NATIVE_DIR_SEPARATOR;
993 file_str += simple_fs::win1250_to_native(nations::int_to_tag(state.world.national_identity_get_identifying_int(masq_nat_id)));
994 native_string default_file_str = file_str;
995 file_str += flag_type_to_name(state, type);
996 GLuint p_tex = load_file_and_return_handle(file_str + NATIVE(".png"), state.common_fs, state.open_gl.asset_textures[id], false);
997 if(!p_tex) {
998 p_tex = load_file_and_return_handle(file_str + NATIVE(".tga"), state.common_fs, state.open_gl.asset_textures[id], false);
999 if(!p_tex) {
1000 p_tex = load_file_and_return_handle(default_file_str + NATIVE(".png"), state.common_fs, state.open_gl.asset_textures[id], false);
1001 if(!p_tex) {
1002 return load_file_and_return_handle(default_file_str + NATIVE(".tga"), state.common_fs, state.open_gl.asset_textures[id], false);
1003 }
1004 }
1005 }
1006 return p_tex;
1007 }
1008}
1009
1010GLuint get_rebel_flag_handle(sys::state& state, dcon::rebel_faction_id faction) {
1011 dcon::rebel_type_fat_id rtype = state.world.rebel_faction_get_type(faction);
1012 dcon::ideology_fat_id ideology = rtype.get_ideology();
1013
1014 if(!ideology) {
1015 return get_flag_handle(state, state.national_definitions.rebel_id, culture::flag_type::default_flag);
1016 }
1017
1018 GLuint o_tex = state.ui_state.rebel_flags[ideology.id.index()];
1019 if (o_tex != 0) {
1020 return o_tex;
1021 } else {
1022 dcon::texture_id new_id{ dcon::texture_id::value_base_t(state.open_gl.asset_textures.size()) };
1023 state.open_gl.asset_textures.emplace_back();
1024 dcon::texture_id id = new_id;
1025
1026 native_string file_str;
1027 file_str += NATIVE("assets");
1028 file_str += NATIVE_DIR_SEPARATOR;
1029 file_str += NATIVE("flags");
1030 file_str += NATIVE_DIR_SEPARATOR;
1031 file_str += NATIVE("REB");
1032 native_string default_file_str = file_str;
1033
1034 std::string_view name = state.to_string_view(state.world.ideology_get_name(ideology));
1035 file_str += NATIVE("_") + simple_fs::utf8_to_native(name);
1036
1037 GLuint p_tex = load_file_and_return_handle(file_str + NATIVE(".png"), state.common_fs, state.open_gl.asset_textures[id], false);
1038 if(!p_tex) {
1039 p_tex = load_file_and_return_handle(default_file_str + NATIVE(".png"), state.common_fs, state.open_gl.asset_textures[id], false);
1040 assert(p_tex);
1041 state.ui_state.rebel_flags[ideology.id.index()] = p_tex;
1042 return state.ui_state.rebel_flags[ideology.id.index()];
1043 }
1044 state.ui_state.rebel_flags[ideology.id.index()] = p_tex;
1045 return state.ui_state.rebel_flags[ideology.id.index()];
1046 }
1047}
1048
1049GLuint get_late_load_texture_handle(sys::state& state, dcon::texture_id& id, std::string_view asset_name) {
1050 if(id && state.open_gl.asset_textures[id].loaded) {
1051 return state.open_gl.asset_textures[id].texture_handle;
1052 } else {
1053 if(auto it = state.open_gl.late_loaded_map.find(std::string(asset_name)); it != state.open_gl.late_loaded_map.end()) {
1054 id = it->second;
1055 return state.open_gl.asset_textures[id].texture_handle;
1056 }
1057 dcon::texture_id new_id{ dcon::texture_id::value_base_t(state.open_gl.asset_textures.size()) };
1058 state.open_gl.asset_textures.emplace_back();
1059 id = new_id;
1060 state.open_gl.late_loaded_map.insert_or_assign(std::string(asset_name), new_id);
1062 return load_file_and_return_handle(nname, state.common_fs, state.open_gl.asset_textures.back(), false);
1063 }
1064}
1065
1066GLuint get_texture_handle(sys::state& state, dcon::texture_id id, bool keep_data) {
1067 if(state.open_gl.asset_textures[id].loaded) {
1068 return state.open_gl.asset_textures[id].texture_handle;
1069 } else { // load from file
1070 auto fname = state.ui_defs.textures[id];
1071 auto fname_view = state.to_string_view(fname);
1072 auto native_name = simple_fs::win1250_to_native(fname_view);
1073
1074 return load_file_and_return_handle(native_name, state.common_fs, state.open_gl.asset_textures[id], keep_data);
1075 } // end else (not already loaded)
1076}
1077
1078data_texture::data_texture(int32_t sz, int32_t ch) {
1079 size = sz;
1080 channels = ch;
1081 data = new uint8_t[size * channels];
1082
1083 glGenTextures(1, &texture_handle);
1084 glBindTexture(GL_TEXTURE_2D, texture_handle);
1085
1086 if(channels == 3) {
1087 glTexStorage2D(GL_TEXTURE_2D, 1, GL_RGB8, size, 1);
1088 } else if(channels == 4) {
1089 glTexStorage2D(GL_TEXTURE_2D, 1, GL_RGBA8, size, 1);
1090 } else if(channels == 2) {
1091 glTexStorage2D(GL_TEXTURE_2D, 1, GL_RG8, size, 1);
1092 } else {
1093 glTexStorage2D(GL_TEXTURE_2D, 1, GL_R8, size, 1);
1094 }
1095 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
1096 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
1097 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
1098 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
1099
1100 glBindTexture(GL_TEXTURE_2D, 0);
1101}
1102
1104 delete[] data;
1105 data = nullptr;
1106}
1107
1109 if(data && data_updated) {
1110 glBindTexture(GL_TEXTURE_2D, texture_handle);
1111 if(channels == 3) {
1112 glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, size, 1, GL_RGB, GL_UNSIGNED_BYTE, data);
1113 } else if(channels == 4) {
1114 glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, size, 1, GL_RGBA, GL_UNSIGNED_BYTE, data);
1115 } else if(channels == 2) {
1116 glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, size, 1, GL_RG, GL_UNSIGNED_BYTE, data);
1117 } else {
1118 glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, size, 1, GL_RED, GL_UNSIGNED_BYTE, data);
1119 }
1120 data_updated = false;
1121 glBindTexture(GL_TEXTURE_2D, 0);
1122 }
1123 return texture_handle;
1124}
1125
1127 data = other.data;
1128 size = other.size;
1129 channels = other.channels;
1130 texture_handle = other.texture_handle;
1131
1132 other.data = nullptr;
1133}
1134
1136 data = other.data;
1137 size = other.size;
1138 channels = other.channels;
1139 texture_handle = other.texture_handle;
1140
1141 other.data = nullptr;
1142
1143 return *this;
1144}
1145
1147 auto content = simple_fs::view_contents(f);
1148
1149 int32_t file_channels = 4;
1150 int32_t size_x = 0;
1151 int32_t size_y = 0;
1152 uint8_t* data = stbi_load_from_memory(reinterpret_cast<uint8_t const*>(content.data), int32_t(content.file_size), &(size_x), &(size_y), &file_channels, 4);
1153 uint32_t ftexid = 0;
1154
1155 glGenTextures(1, &ftexid);
1156 if(data && ftexid) {
1157 glBindTexture(GL_TEXTURE_2D, ftexid);
1158
1159 glTexStorage2D(GL_TEXTURE_2D, 1, GL_RGBA8, size_x, size_y);
1160 glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, size_x, size_y, GL_RGBA, GL_UNSIGNED_BYTE, data);
1161
1162 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
1163 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
1164 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
1165 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
1166 }
1167
1168 STBI_FREE(data);
1169
1170 return font_texture_result{ ftexid, uint32_t(size_x) };
1171}
1172
1173} // namespace ogl
data_texture & operator=(data_texture const &)=delete
int32_t channels
Definition: texture.hpp:63
uint8_t * data
Definition: texture.hpp:61
data_texture(int32_t sz, int32_t ch)
Definition: texture.cpp:1078
uint8_t * data
Definition: texture.hpp:32
texture & operator=(texture const &)=delete
GLuint get_texture_handle() const
Definition: texture.cpp:799
int32_t size_y
Definition: texture.hpp:34
int32_t size_x
Definition: texture.hpp:33
int32_t channels
Definition: texture.hpp:35
bool loaded
Definition: texture.hpp:37
#define assert(condition)
Definition: debug.h:74
uint32_t get_remapped_flag_type(sys::state const &state, flag_type type)
Definition: culture.cpp:778
std::string int_to_tag(uint32_t v)
Definition: nations.hpp:14
GLuint get_late_load_texture_handle(sys::state &state, dcon::texture_id &id, std::string_view asset_name)
Definition: texture.cpp:1049
GLuint get_rebel_flag_handle(sys::state &state, dcon::rebel_faction_id faction)
Definition: texture.cpp:1010
GLuint SOIL_direct_load_DDS_array_from_memory(unsigned char const *const buffer, uint32_t buffer_length, uint32_t &width, uint32_t &height, int soil_flags, uint32_t tiles_x, uint32_t tiles_y)
Definition: texture.cpp:428
GLuint load_file_and_return_handle(native_string const &native_name, simple_fs::file_system const &fs, texture &asset_texture, bool keep_data)
Definition: texture.cpp:804
GLuint SOIL_direct_load_DDS_from_memory(unsigned char const *const buffer, uint32_t buffer_length, uint32_t &width, uint32_t &height, int soil_flags)
Definition: texture.cpp:101
@ SOIL_FLAG_TEXTURE_REPEATS
Definition: texture.hpp:23
GLuint get_texture_handle(sys::state &state, dcon::texture_id id, bool keep_data)
Definition: texture.cpp:1066
native_string flag_type_to_name(sys::state &state, culture::flag_type type)
Definition: texture.cpp:889
font_texture_result make_font_texture(simple_fs::file &f)
Definition: texture.cpp:1146
GLuint get_flag_handle(sys::state &state, dcon::national_identity_id nat_id, culture::flag_type type)
Definition: texture.cpp:977
native_string win1250_to_native(std::string_view data_in)
native_string utf8_to_native(std::string_view data_in)
file_contents view_contents(file const &f)
#define NATIVE(X)
std::string native_string
#define NATIVE_DIR_SEPARATOR
uint uint32_t
uchar uint8_t
unsigned int dwFlags
Definition: texture.cpp:71
unsigned int dwCaps1
Definition: texture.cpp:93
unsigned int dwGBitMask
Definition: texture.cpp:86
unsigned int dwCaps2
Definition: texture.cpp:94
unsigned int dwWidth
Definition: texture.cpp:73
unsigned int dwSize
Definition: texture.cpp:70
unsigned int dwPitchOrLinearSize
Definition: texture.cpp:74
unsigned int dwRGBBitCount
Definition: texture.cpp:84
unsigned int dwMagic
Definition: texture.cpp:69
unsigned int dwHeight
Definition: texture.cpp:72
unsigned int dwReserved2
Definition: texture.cpp:98
unsigned int dwBBitMask
Definition: texture.cpp:87
unsigned int dwMipMapCount
Definition: texture.cpp:76
unsigned int dwReserved
Definition: texture.cpp:96
unsigned int dwDepth
Definition: texture.cpp:75
unsigned int dwAlphaBitMask
Definition: texture.cpp:88
unsigned int dwRBitMask
Definition: texture.cpp:85
unsigned int dwDDSX
Definition: texture.cpp:95
unsigned int dwFourCC
Definition: texture.cpp:83
Holds important data about the game world, state, and other data regarding windowing,...
#define DDSD_WIDTH
Definition: texture.cpp:27
#define SOIL_TEXTURE_WRAP_R
Definition: texture.cpp:64
#define DDSD_PIXELFORMAT
Definition: texture.cpp:29
#define SOIL_RGBA_S3TC_DXT3
Definition: texture.cpp:61
#define DDSCAPS_MIPMAP
Definition: texture.cpp:44
#define DDSD_HEIGHT
Definition: texture.cpp:26
#define SOIL_RGBA_S3TC_DXT1
Definition: texture.cpp:60
#define DDPF_FOURCC
Definition: texture.cpp:36
#define DDPF_RGB
Definition: texture.cpp:37
#define DDSCAPS2_CUBEMAP
Definition: texture.cpp:48
#define DDPF_PALETTEINDEXED8
Definition: texture.cpp:38
#define DDPF_ALPHAPIXELS
Definition: texture.cpp:35
#define DDSCAPS_TEXTURE
Definition: texture.cpp:43
#define SOIL_RGBA_S3TC_DXT5
Definition: texture.cpp:62
#define DDSD_CAPS
Definition: texture.cpp:25