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 ALICE_DDSD_CAPS 0x00000001
26#define ALICE_DDSD_HEIGHT 0x00000002
27#define ALICE_DDSD_WIDTH 0x00000004
28#define ALICE_DDSD_PITCH 0x00000008
29#define ALICE_DDSD_PIXELFORMAT 0x00001000
30#define ALICE_DDSD_MIPMAPCOUNT 0x00020000
31#define ALICE_DDSD_LINEARSIZE 0x00080000
32#define ALICE_DDSD_DEPTH 0x00800000
33
34/* DirectDraw Pixel Format */
35#define ALICE_DDPF_ALPHAPIXELS 0x00000001
36#define ALICE_DDPF_FOURCC 0x00000004
37#define ALICE_DDPF_RGB 0x00000040
38
39/* The dwCaps1 member of the ALICE_DDSCAPS2 structure can be
40 set to one or more of the following values. */
41#define ALICE_DDSCAPS_COMPLEX 0x00000008
42#define ALICE_DDSCAPS_TEXTURE 0x00001000
43#define ALICE_DDSCAPS_MIPMAP 0x00400000
44
45 /* The dwCaps2 member of the ALICE_DDSCAPS2 structure can be
46 set to one or more of the following values. */
47#define ALICE_DDSCAPS2_CUBEMAP 0x00000200
48#define ALICE_DDSCAPS2_CUBEMAP_POSITIVEX 0x00000400
49#define ALICE_DDSCAPS2_CUBEMAP_NEGATIVEX 0x00000800
50#define ALICE_DDSCAPS2_CUBEMAP_POSITIVEY 0x00001000
51#define ALICE_DDSCAPS2_CUBEMAP_NEGATIVEY 0x00002000
52#define ALICE_DDSCAPS2_CUBEMAP_POSITIVEZ 0x00004000
53#define ALICE_DDSCAPS2_CUBEMAP_NEGATIVEZ 0x00008000
54#define ALICE_DDSCAPS2_VOLUME 0x00200000
55
56#define SOIL_GL_SRGB 0x8C40
57#define SOIL_GL_SRGB_ALPHA 0x8C42
58#define SOIL_RGB_S3TC_DXT1 0x83F0
59#define SOIL_RGBA_S3TC_DXT1 0x83F1
60#define SOIL_RGBA_S3TC_DXT3 0x83F2
61#define SOIL_RGBA_S3TC_DXT5 0x83F3
62
63#define SOIL_TEXTURE_WRAP_R 0x8072
64#define SOIL_CLAMP_TO_EDGE 0x812F
65#define SOIL_REFLECTION_MAP 0x8512
66
67typedef struct {
68 unsigned int dwMagic;
69 unsigned int dwSize;
70 unsigned int dwFlags;
71 unsigned int dwHeight;
72 unsigned int dwWidth;
73 unsigned int dwPitchOrLinearSize;
74 unsigned int dwDepth;
75 unsigned int dwMipMapCount;
76 unsigned int dwReserved1[11];
77
78 /* DDPIXELFORMAT */
79 struct {
80 unsigned int dwSize;
81 unsigned int dwFlags;
82 unsigned int dwFourCC;
83 unsigned int dwRGBBitCount;
84 unsigned int dwRBitMask;
85 unsigned int dwGBitMask;
86 unsigned int dwBBitMask;
87 unsigned int dwAlphaBitMask;
88 } sPixelFormat;
89
90 /* DDCAPS2 */
91 struct {
92 unsigned int dwCaps1;
93 unsigned int dwCaps2;
94 unsigned int dwDDSX;
95 unsigned int dwReserved;
96 } sCaps;
97 unsigned int dwReserved2;
99
100enum {
105
106#ifndef APIENTRY
107#define APIENTRY
108#endif
109
110typedef void (APIENTRY* P_SOIL_GLCOMPRESSEDTEXIMAGE2DPROC) (GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLint border, GLsizei imageSize, const GLvoid* data);
111
113 static int32_t has_DXT_capability = SOIL_CAPABILITY_UNKNOWN;
114 //static P_SOIL_GLCOMPRESSEDTEXIMAGE2DPROC soilGlCompressedTexImage2D = NULL;
115
116 /* check for the capability */
117 if(has_DXT_capability == SOIL_CAPABILITY_UNKNOWN) {
118 /* we haven't yet checked for the capability, do so */
119 if(NULL == strstr(
120 (char const*)glGetString(GL_EXTENSIONS),
121 "GL_EXT_texture_compression_s3tc")) {
122 /* not there, flag the failure */
123 has_DXT_capability = SOIL_CAPABILITY_NONE;
124 } else {
125 /* and find the address of the extension function */
126 P_SOIL_GLCOMPRESSEDTEXIMAGE2DPROC ext_addr = NULL;
127#ifdef WIN32
129 wglGetProcAddress
130 (
131 "glCompressedTexImage2DARB"
132 );
133#elif defined(__APPLE__) || defined(__APPLE_CC__)
134 /* I can't test this Apple stuff! */
135 CFBundleRef bundle;
136 CFURLRef bundleURL =
137 CFURLCreateWithFileSystemPath(
138 kCFAllocatorDefault,
139 CFSTR("/System/Library/Frameworks/OpenGL.framework"),
140 kCFURLPOSIXPathStyle,
141 true);
142 CFStringRef extensionName =
143 CFStringCreateWithCString(
144 kCFAllocatorDefault,
145 "glCompressedTexImage2DARB",
146 kCFStringEncodingASCII);
147 bundle = CFBundleCreate(kCFAllocatorDefault, bundleURL);
148 assert(bundle != NULL);
150 CFBundleGetFunctionPointerForName
151 (
152 bundle, extensionName
153 );
154 CFRelease(bundleURL);
155 CFRelease(extensionName);
156 CFRelease(bundle);
157#else
158 ext_addr = (P_SOIL_GLCOMPRESSEDTEXIMAGE2DPROC)(1);
159#endif
160 /* Flag it so no checks needed later */
161 if(NULL == ext_addr) {
162 /* hmm, not good!! This should not happen, but does on my
163 laptop's VIA chipset. The GL_EXT_texture_compression_s3tc
164 spec requires that ARB_texture_compression be present too.
165 this means I can upload and have the OpenGL drive do the
166 conversion, but I can't use my own routines or load DDS files
167 from disk and upload them directly [8^( */
168 has_DXT_capability = SOIL_CAPABILITY_NONE;
169 } else {
170 /* all's well! */
171 //soilGlCompressedTexImage2D = ext_addr;
172 has_DXT_capability = SOIL_CAPABILITY_PRESENT;
173 }
174 }
175 }
176 /* let the user know if we can do DXT or not */
177 return has_DXT_capability;
178}
179
180GLuint SOIL_direct_load_DDS_from_memory(unsigned char const* const buffer, uint32_t buffer_length, uint32_t& width, uint32_t& height, int soil_flags) {
181 /* file reading variables */
182 uint32_t block_size = 16;
183 uint32_t flag;
184 if(buffer_length < sizeof(DDS_header)) {
185 return 0;
186 }
187
188 /* try reading in the header */
189 DDS_header header;
190 std::memcpy((void*)(&header), (void const*)buffer, sizeof(DDS_header));
191 uint32_t buffer_index = sizeof(DDS_header);
192
193 /* validate the header (warning, "goto"'s ahead, shield your eyes!!) */
194 if(header.dwMagic != (('D' << 0) | ('D' << 8) | ('S' << 16) | (' ' << 24))) {
195 return 0;
196 }
197 if(header.dwSize != 124) {
198 return 0;
199 }
200 /* I need all of these */
202 if((header.dwFlags & flag) != flag) {
203 return 0;
204 }
205 /* According to the MSDN spec, the dwFlags should contain
206 ALICE_DDSD_LINEARSIZE if it's compressed, or ALICE_DDSD_PITCH if
207 uncompressed. Some DDS writers do not conform to the
208 spec, so I need to make my reader more tolerant */
209 if(header.sPixelFormat.dwSize != 32) {
210 return 0;
211 }
212 /* I need one of these */
214 return 0;
215 }
216 /* make sure it is a type we can upload */
217 if((header.sPixelFormat.dwFlags & ALICE_DDPF_FOURCC) &&
218 !((header.sPixelFormat.dwFourCC == (('D' << 0) | ('X' << 8) | ('T' << 16) | ('1' << 24))) ||
219 (header.sPixelFormat.dwFourCC == (('D' << 0) | ('X' << 8) | ('T' << 16) | ('3' << 24))) ||
220 (header.sPixelFormat.dwFourCC == (('D' << 0) | ('X' << 8) | ('T' << 16) | ('5' << 24))))) {
221 return 0;
222 }
223 if((header.sCaps.dwCaps1 & ALICE_DDSCAPS_TEXTURE) == 0) {
224 return 0;
225 }
226 if((header.sCaps.dwCaps2 & ALICE_DDSCAPS2_CUBEMAP) != 0) {
227 return 0;
228 }
229 /* OK, validated the header, let's load the image data */
230 width = header.dwWidth;
231 height = header.dwHeight;
232 bool uncompressed = (header.sPixelFormat.dwFlags & ALICE_DDPF_FOURCC) == 0;
233 GLint s3tc_format = 0; //How we want to give it to shaders
234 GLint s3tc_format_layout = 0; //How's it laid on memory
235 GLint s3tc_type = GL_UNSIGNED_BYTE;
236 uint32_t dds_main_size = 0;
237 if(uncompressed) {
238 s3tc_format = GL_RGB;
239 s3tc_format_layout = GL_RGB;
240 block_size = 3;
242 s3tc_format = GL_RGBA;
243 s3tc_format_layout = GL_RGBA;
244 block_size = 4;
245 if(header.sPixelFormat.dwRGBBitCount == 16) {
246 //s3tc_format_layout = GL_RGBA;
247 //s3tc_type = GL_UNSIGNED_BYTE;
248 block_size = 2;
249 }
250 }
251 dds_main_size = width * height * block_size;
252 } else {
253 /* can we even handle direct uploading to OpenGL DXT compressed images? */
255 return 0;
256 }
257 /* well, we know it is DXT1/3/5, because we checked above */
258 switch((header.sPixelFormat.dwFourCC >> 24) - '0') {
259 case 1:
260 s3tc_format = SOIL_RGBA_S3TC_DXT1;
261 block_size = 8;
262 break;
263 case 3:
264 s3tc_format = SOIL_RGBA_S3TC_DXT3;
265 block_size = 16;
266 break;
267 case 5:
268 s3tc_format = SOIL_RGBA_S3TC_DXT5;
269 block_size = 16;
270 break;
271 default:
272 return 0;
273 break;
274 }
275 dds_main_size = ((width + 3) >> 2) * ((height + 3) >> 2) * block_size;
276 }
277 uint32_t dds_full_size = dds_main_size;
278 uint32_t mipmaps = 0;
279 if((header.sCaps.dwCaps1 & ALICE_DDSCAPS_MIPMAP) != 0 && (header.dwMipMapCount > 1)) {
280 mipmaps = header.dwMipMapCount - 1;
281 for(uint32_t i = 1; i <= mipmaps; ++i) {
282 uint32_t w = std::max<uint32_t>(width >> i, 1);
283 uint32_t h = std::max<uint32_t>(height >> i, 1);
284 if(uncompressed) {
285 /* uncompressed DDS, simple MIPmap size calculation */
286 dds_full_size += w * h * block_size;
287 } else {
288 /* compressed DDS, MIPmap size calculation is block based */
289 dds_full_size += ((w + 3) / 4) * ((h + 3) / 4) * block_size;
290 }
291 }
292 }
293 /* do this for each face of the cubemap! */
294 if(buffer_index + dds_full_size <= uint32_t(buffer_length)) {
295 /* got the image data RAM, create or use an existing OpenGL texture handle */
296 GLuint texid = 0;
297 glGenTextures(1, &texid);
298 /* bind an OpenGL texture ID */
299 glBindTexture(GL_TEXTURE_2D, texid);
300 if(!texid)
301 return 0;
302 /* did I have MIPmaps? */
303
304 //if(mipmaps > 0) {
305 // glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
306 // glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_NEAREST);
307 //} else {
308
309 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
310 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
311
312 // }
313 /* does the user want clamping, or wrapping? */
314 if((soil_flags & SOIL_FLAG_TEXTURE_REPEATS) != 0) {
315 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
316 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
317 // glTexParameteri(GL_TEXTURE_2D, SOIL_TEXTURE_WRAP_R, GL_REPEAT);
318 } else {
319 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
320 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
321 // glTexParameteri(GL_TEXTURE_2D, SOIL_TEXTURE_WRAP_R, GL_CLAMP_TO_EDGE);
322 }
323 /* upload the main chunk */
324 if(uncompressed) {
325 /* and remember, DXT uncompressed uses BGR(A), so swap to (A)BGR for ALL MIPmap levels */
326 std::unique_ptr<uint8_t[]> dds_dest_data = std::unique_ptr<uint8_t[]>(new uint8_t[dds_full_size]);
327 switch(block_size) {
328 case 4:
329 {
330 assert(dds_full_size % 4 == 0);
331 for(uint32_t i = 0; i < dds_full_size; i += block_size) {
332 assert(buffer_index + i + uint32_t(4) <= buffer_length);
333 uint32_t data = *(uint32_t const*)(buffer + buffer_index + i);
334 uint32_t r = (data & header.sPixelFormat.dwRBitMask) >> std::countr_zero(header.sPixelFormat.dwRBitMask);
335 uint32_t g = (data & header.sPixelFormat.dwGBitMask) >> std::countr_zero(header.sPixelFormat.dwGBitMask);
336 uint32_t b = (data & header.sPixelFormat.dwBBitMask) >> std::countr_zero(header.sPixelFormat.dwBBitMask);
337 uint32_t a = (data & header.sPixelFormat.dwAlphaBitMask) >> std::countr_zero(header.sPixelFormat.dwAlphaBitMask);
338 dds_dest_data[i + 0] = static_cast<uint8_t>(r);
339 dds_dest_data[i + 1] = static_cast<uint8_t>(g);
340 dds_dest_data[i + 2] = static_cast<uint8_t>(b);
341 dds_dest_data[i + 3] = static_cast<uint8_t>(a);
342 }
343 break;
344 }
345 case 2:
346 {
347 dds_dest_data.reset();
348 dds_dest_data = std::unique_ptr<uint8_t[]>(new uint8_t[dds_full_size * 2]);
349 uint16_t mr1 = uint16_t(header.sPixelFormat.dwRBitMask >> std::countr_zero(header.sPixelFormat.dwRBitMask));
350 float mr2 = mr1 == 0 ? 0.f : 255.f / float(mr1);
351 uint16_t mg1 = uint16_t(header.sPixelFormat.dwGBitMask >> std::countr_zero(header.sPixelFormat.dwGBitMask));
352 float mg2 = mg1 == 0 ? 0.f : 255.f / float(mg1);
353 uint16_t mb1 = uint16_t(header.sPixelFormat.dwBBitMask >> std::countr_zero(header.sPixelFormat.dwBBitMask));
354 float mb2 = mb1 == 0 ? 0.f : 255.f / float(mb1);
355 uint16_t ma1 = uint16_t(header.sPixelFormat.dwAlphaBitMask >> std::countr_zero(header.sPixelFormat.dwAlphaBitMask));
356 float ma2 = ma1 == 0 ? 0.f : 255.f / float(ma1);
357 for(uint32_t i = 0; i < dds_full_size; i += block_size) {
358 assert(buffer_index + i + uint32_t(2) <= buffer_length);
359 uint16_t data = *(uint16_t const*)(buffer + buffer_index + i);
360 uint16_t r = (data & header.sPixelFormat.dwRBitMask) >> std::countr_zero(header.sPixelFormat.dwRBitMask);
361 uint16_t g = (data & header.sPixelFormat.dwGBitMask) >> std::countr_zero(header.sPixelFormat.dwGBitMask);
362 uint16_t b = (data & header.sPixelFormat.dwBBitMask) >> std::countr_zero(header.sPixelFormat.dwBBitMask);
363 uint16_t a = (data & header.sPixelFormat.dwAlphaBitMask) >> std::countr_zero(header.sPixelFormat.dwAlphaBitMask);
364 dds_dest_data[i * 2 + 0] = uint8_t(float(r) * mr2);
365 dds_dest_data[i * 2 + 1] = uint8_t(float(g) * mg2);
366 dds_dest_data[i * 2 + 2] = uint8_t(float(b) * mb2);
367 dds_dest_data[i * 2 + 3] = uint8_t(float(a) * ma2);
368 }
369 break;
370 }
371 default:
372 {
373 assert(dds_full_size <= buffer_length);
374 std::memcpy(dds_dest_data.get(), buffer + buffer_index, dds_full_size);
375 for(uint32_t i = 0; i+2 < dds_full_size; i += block_size) {
376 uint8_t temp = dds_dest_data[i];
377 dds_dest_data[i] = dds_dest_data[i + 2];
378 dds_dest_data[i + 2] = temp;
379 }
380 break;
381 }
382 }
383 glTexImage2D(GL_TEXTURE_2D, 0, s3tc_format, width, height, 0, s3tc_format_layout, s3tc_type, dds_dest_data.get());
384 uint32_t buffer_offset = dds_main_size * (block_size == 2 ? 2 : 1);
385 /* upload the mipmaps, if we have them */
386
387 /*
388 for(uint32_t i = 1; i <= mipmaps; ++i) {
389 uint32_t w = std::max<uint32_t>(width >> i, 1);
390 uint32_t h = std::max<uint32_t>(height >> i, 1);
391 uint32_t mip_size = w * h * block_size;
392 switch(block_size) {
393 case 2:
394 mip_size = w * h * 4;
395 break;
396 default:
397 break;
398 }
399 glTexImage2D(GL_TEXTURE_2D, i, s3tc_format, w, h, 0, s3tc_format_layout, s3tc_type, dds_dest_data.get() + buffer_offset);
400 buffer_offset += mip_size;
401 }
402 */
403 } else {
404 assert(buffer_index + dds_main_size <= buffer_length);
405 if(buffer_index + dds_main_size > buffer_length)
406 return 0;
407
408 glCompressedTexImage2D(GL_TEXTURE_2D, 0, s3tc_format, width, height, 0, dds_main_size, buffer + buffer_index);
409 buffer_index += dds_main_size;
410
411 /* upload the mipmaps, if we have them */
412 /*
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 uint32_t mip_size = ((w + 3) / 4) * ((h + 3) / 4) * block_size;
417 glCompressedTexImage2D(GL_TEXTURE_2D, i, s3tc_format, w, h, 0, mip_size, buffer + buffer_index);
418 buffer_index += mip_size;
419 }
420 */
421 }
422 return texid;
423 }
424 return 0;
425}
426
428 STBI_FREE(data);
429 data = nullptr;
430}
431
432texture::texture(texture&& other) noexcept {
433 channels = other.channels;
434 loaded = other.loaded;
435 size_x = other.size_x;
436 size_y = other.size_y;
437 data = other.data;
438 texture_handle = other.texture_handle;
439
440 other.data = nullptr;
441}
443 channels = other.channels;
444 loaded = other.loaded;
445 size_x = other.size_x;
446 size_y = other.size_y;
447 data = other.data;
448 texture_handle = other.texture_handle;
449
450 other.data = nullptr;
451 return *this;
452}
453
455 assert(loaded);
456 return texture_handle;
457}
458
459GLuint load_file_and_return_handle(native_string const& native_name, simple_fs::file_system const& fs, texture& asset_texture, bool keep_data) {
460 auto name_length = native_name.length();
461
462 auto root = get_root(fs);
463 if(name_length > 4) { // try loading as a dds
464 auto dds_name = native_name;
465 if(auto pos = dds_name.find_last_of('.'); pos != native_string::npos) {
466 dds_name[pos + 1] = NATIVE('d');
467 dds_name[pos + 2] = NATIVE('d');
468 dds_name[pos + 3] = NATIVE('s');
469 dds_name.resize(pos + 4);
470 }
471 auto file = open_file(root, dds_name);
472 if(file) {
473 auto content = simple_fs::view_contents(*file);
474
475 uint32_t w = 0;
476 uint32_t h = 0;
477 asset_texture.texture_handle = SOIL_direct_load_DDS_from_memory(reinterpret_cast<uint8_t const*>(content.data), content.file_size, w, h, 0);
478
479 if(asset_texture.texture_handle) {
480 asset_texture.channels = 4;
481 asset_texture.size_x = int32_t(w);
482 asset_texture.size_y = int32_t(h);
483 asset_texture.loaded = true;
484
485 if(keep_data) {
486 asset_texture.data = static_cast<uint8_t*>(STBI_MALLOC(4 * w * h));
487 glGetTextureImage(asset_texture.texture_handle, 0, GL_RGBA, GL_UNSIGNED_BYTE, static_cast<int32_t>(4 * w * h),
488 asset_texture.data);
489 }
490 return asset_texture.texture_handle;
491 }
492 }
493 }
494
495 auto file = open_file(root, native_name);
496 if(!file && name_length > 4) {
497 auto png_name = native_name;
498 if(auto pos = png_name.find_last_of('.'); pos != native_string::npos) {
499 png_name[pos + 1] = NATIVE('p');
500 png_name[pos + 2] = NATIVE('n');
501 png_name[pos + 3] = NATIVE('g');
502 png_name.resize(pos + 4);
503 }
504 file = open_file(root, png_name);
505 }
506 if(file) {
507 auto content = simple_fs::view_contents(*file);
508
509 int32_t file_channels = 4;
510
511 asset_texture.data = stbi_load_from_memory(reinterpret_cast<uint8_t const*>(content.data), int32_t(content.file_size),
512 &(asset_texture.size_x), &(asset_texture.size_y), &file_channels, 4);
513
514 asset_texture.channels = 4;
515 asset_texture.loaded = true;
516
517 glGenTextures(1, &asset_texture.texture_handle);
518 if(asset_texture.texture_handle) {
519 glBindTexture(GL_TEXTURE_2D, asset_texture.texture_handle);
520
521 glTexStorage2D(GL_TEXTURE_2D, 1, GL_RGBA8, asset_texture.size_x, asset_texture.size_y);
522 glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, asset_texture.size_x, asset_texture.size_y, GL_RGBA, GL_UNSIGNED_BYTE,
523 asset_texture.data);
524
525 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
526 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
527 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
528 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
529
530 glBindTexture(GL_TEXTURE_2D, 0);
531 }
532
533 if(!keep_data) {
534 STBI_FREE(asset_texture.data);
535 asset_texture.data = nullptr;
536 }
537
538 return asset_texture.texture_handle;
539 }
540 asset_texture.loaded = true; // because we tried to load it (and failed) and trying again will be wasteful
541 return 0;
542}
543
545 switch(type) {
548 return NATIVE("");
550 return NATIVE("_communist");
552 return NATIVE("_fascist");
554 return NATIVE("_monarchy");
556 return NATIVE("_republic");
557 // Non-vanilla
559 return NATIVE("_theocracy");
561 return NATIVE("_special");
563 return NATIVE("_spare");
565 return NATIVE("_populist");
567 return NATIVE("_realm");
569 return NATIVE("_other");
571 return NATIVE("_monarchy2");
573 return NATIVE("_monarchy3");
575 return NATIVE("_republic2");
577 return NATIVE("_republic3");
579 return NATIVE("_communist2");
581 return NATIVE("_communist3");
583 return NATIVE("_fascist2");
585 return NATIVE("_fascist3");
587 return NATIVE("_theocracy2");
589 return NATIVE("_theocracy3");
591 return NATIVE("_cosmetic_1");
593 return NATIVE("_cosmetic_2");
595 return NATIVE("_colonial");
597 return NATIVE("_nationalist");
599 return NATIVE("_sectarian");
601 return NATIVE("_socialist");
603 return NATIVE("_dominion");
605 return NATIVE("_agrarism");
607 return NATIVE("_national_syndicalist");
609 return NATIVE("_theocratic");
611 return NATIVE("_slot1");
613 return NATIVE("_slot2");
615 return NATIVE("_slot3");
617 return NATIVE("_slot4");
619 return NATIVE("_anarcho_liberal");
621 return NATIVE("_green");
623 return NATIVE("_traditionalist");
625 return NATIVE("_ultranationalist");
626 default:
627 return NATIVE("");
628
629 }
630}
631
632GLuint get_flag_handle(sys::state& state, dcon::national_identity_id nat_id, culture::flag_type type) {
633 auto masq_nat_id = state.world.nation_get_masquerade_identity(state.world.national_identity_get_nation_from_identity_holder(nat_id));
634 if(!masq_nat_id) {
635 masq_nat_id = nat_id;
636 }
637
638 auto const offset = culture::get_remapped_flag_type(state, type);
639 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) };
640 if(state.open_gl.asset_textures[id].loaded) {
641 return state.open_gl.asset_textures[id].texture_handle;
642 } else { // load from file
643 native_string file_str;
644 file_str += NATIVE("gfx");
645 file_str += NATIVE_DIR_SEPARATOR;
646 file_str += NATIVE("flags");
647 file_str += NATIVE_DIR_SEPARATOR;
648 file_str += simple_fs::win1250_to_native(nations::int_to_tag(state.world.national_identity_get_identifying_int(masq_nat_id)));
649 native_string default_file_str = file_str;
650 file_str += flag_type_to_name(state, type);
651 GLuint p_tex = load_file_and_return_handle(file_str + NATIVE(".png"), state.common_fs, state.open_gl.asset_textures[id], false);
652 if(!p_tex) {
653 p_tex = load_file_and_return_handle(file_str + NATIVE(".tga"), state.common_fs, state.open_gl.asset_textures[id], false);
654 if(!p_tex) {
655 p_tex = load_file_and_return_handle(default_file_str + NATIVE(".png"), state.common_fs, state.open_gl.asset_textures[id], false);
656 if(!p_tex) {
657 return load_file_and_return_handle(default_file_str + NATIVE(".tga"), state.common_fs, state.open_gl.asset_textures[id], false);
658 }
659 }
660 }
661 return p_tex;
662 }
663}
664
665GLuint get_texture_handle(sys::state& state, dcon::texture_id id, bool keep_data) {
666 if(state.open_gl.asset_textures[id].loaded) {
667 return state.open_gl.asset_textures[id].texture_handle;
668 } else { // load from file
669 auto fname = state.ui_defs.textures[id];
670 auto fname_view = state.to_string_view(fname);
671 auto native_name = simple_fs::win1250_to_native(fname_view);
672
673 return load_file_and_return_handle(native_name, state.common_fs, state.open_gl.asset_textures[id], keep_data);
674 } // end else (not already loaded)
675}
676
677data_texture::data_texture(int32_t sz, int32_t ch) {
678 size = sz;
679 channels = ch;
680 data = new uint8_t[size * channels];
681
682 glGenTextures(1, &texture_handle);
683 glBindTexture(GL_TEXTURE_2D, texture_handle);
684
685 if(channels == 3) {
686 glTexStorage2D(GL_TEXTURE_2D, 1, GL_RGB8, size, 1);
687 } else if(channels == 4) {
688 glTexStorage2D(GL_TEXTURE_2D, 1, GL_RGBA8, size, 1);
689 } else if(channels == 2) {
690 glTexStorage2D(GL_TEXTURE_2D, 1, GL_RG8, size, 1);
691 } else {
692 glTexStorage2D(GL_TEXTURE_2D, 1, GL_R8, size, 1);
693 }
694 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
695 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
696 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
697 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
698
699 glBindTexture(GL_TEXTURE_2D, 0);
700}
701
703 delete[] data;
704 data = nullptr;
705}
706
708 if(data && data_updated) {
709 glBindTexture(GL_TEXTURE_2D, texture_handle);
710 if(channels == 3) {
711 glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, size, 1, GL_RGB, GL_UNSIGNED_BYTE, data);
712 } else if(channels == 4) {
713 glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, size, 1, GL_RGBA, GL_UNSIGNED_BYTE, data);
714 } else if(channels == 2) {
715 glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, size, 1, GL_RG, GL_UNSIGNED_BYTE, data);
716 } else {
717 glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, size, 1, GL_RED, GL_UNSIGNED_BYTE, data);
718 }
719 data_updated = false;
720 glBindTexture(GL_TEXTURE_2D, 0);
721 }
722 return texture_handle;
723}
724
726 data = other.data;
727 size = other.size;
728 channels = other.channels;
729 texture_handle = other.texture_handle;
730
731 other.data = nullptr;
732}
733
735 data = other.data;
736 size = other.size;
737 channels = other.channels;
738 texture_handle = other.texture_handle;
739
740 other.data = nullptr;
741
742 return *this;
743}
744
746 auto content = simple_fs::view_contents(f);
747
748 int32_t file_channels = 4;
749 int32_t size_x = 0;
750 int32_t size_y = 0;
751 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);
752 uint32_t ftexid = 0;
753
754 glGenTextures(1, &ftexid);
755 if(data && ftexid) {
756 glBindTexture(GL_TEXTURE_2D, ftexid);
757
758 glTexStorage2D(GL_TEXTURE_2D, 1, GL_RGBA8, size_x, size_y);
759 glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, size_x, size_y, GL_RGBA, GL_UNSIGNED_BYTE, data);
760
761 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
762 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
763 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
764 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
765 }
766
767 STBI_FREE(data);
768
769 return font_texture_result{ ftexid, uint32_t(size_x) };
770}
771
772} // namespace ogl
data_texture & operator=(data_texture const &)=delete
GLuint handle()
Definition: texture.cpp:707
int32_t channels
Definition: texture.hpp:58
uint8_t * data
Definition: texture.hpp:56
data_texture(int32_t sz, int32_t ch)
Definition: texture.cpp:677
uint8_t * data
Definition: texture.hpp:29
texture & operator=(texture const &)=delete
GLuint get_texture_handle() const
Definition: texture.cpp:454
int32_t size_y
Definition: texture.hpp:31
int32_t size_x
Definition: texture.hpp:30
int32_t channels
Definition: texture.hpp:32
bool loaded
Definition: texture.hpp:34
#define assert(condition)
Definition: debug.h:74
uint32_t get_remapped_flag_type(sys::state const &state, flag_type type)
Definition: culture.cpp:713
std::string int_to_tag(uint32_t v)
Definition: nations.hpp:10
Definition: color.hpp:6
int query_DXT_capability(void)
Definition: texture.cpp:112
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:459
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:180
GLuint get_texture_handle(sys::state &state, dcon::texture_id id, bool keep_data)
Definition: texture.cpp:665
void(APIENTRY * P_SOIL_GLCOMPRESSEDTEXIMAGE2DPROC)(GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLint border, GLsizei imageSize, const GLvoid *data)
Definition: texture.cpp:110
native_string flag_type_to_name(sys::state &state, culture::flag_type type)
Definition: texture.cpp:544
@ SOIL_CAPABILITY_PRESENT
Definition: texture.cpp:103
@ SOIL_CAPABILITY_UNKNOWN
Definition: texture.cpp:101
@ SOIL_CAPABILITY_NONE
Definition: texture.cpp:102
@ SOIL_FLAG_TEXTURE_REPEATS
Definition: texture.hpp:20
font_texture_result make_font_texture(simple_fs::file &f)
Definition: texture.cpp:745
GLuint get_flag_handle(sys::state &state, dcon::national_identity_id nat_id, culture::flag_type type)
Definition: texture.cpp:632
native_string win1250_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:70
unsigned int dwCaps1
Definition: texture.cpp:92
unsigned int dwGBitMask
Definition: texture.cpp:85
unsigned int dwCaps2
Definition: texture.cpp:93
unsigned int dwWidth
Definition: texture.cpp:72
unsigned int dwSize
Definition: texture.cpp:69
unsigned int dwPitchOrLinearSize
Definition: texture.cpp:73
unsigned int dwRGBBitCount
Definition: texture.cpp:83
unsigned int dwMagic
Definition: texture.cpp:68
unsigned int dwHeight
Definition: texture.cpp:71
unsigned int dwReserved2
Definition: texture.cpp:97
unsigned int dwBBitMask
Definition: texture.cpp:86
unsigned int dwMipMapCount
Definition: texture.cpp:75
struct ogl::DDS_header::@2 sPixelFormat
unsigned int dwReserved
Definition: texture.cpp:95
unsigned int dwDepth
Definition: texture.cpp:74
unsigned int dwAlphaBitMask
Definition: texture.cpp:87
unsigned int dwRBitMask
Definition: texture.cpp:84
unsigned int dwDDSX
Definition: texture.cpp:94
unsigned int dwFourCC
Definition: texture.cpp:82
struct ogl::DDS_header::@3 sCaps
#define ALICE_DDSCAPS_TEXTURE
Definition: texture.cpp:42
#define ALICE_DDPF_ALPHAPIXELS
Definition: texture.cpp:35
#define ALICE_DDPF_FOURCC
Definition: texture.cpp:36
#define SOIL_RGBA_S3TC_DXT3
Definition: texture.cpp:60
#define APIENTRY
Definition: texture.cpp:107
#define SOIL_RGBA_S3TC_DXT1
Definition: texture.cpp:59
#define ALICE_DDSD_WIDTH
Definition: texture.cpp:27
#define ALICE_DDSD_PIXELFORMAT
Definition: texture.cpp:29
#define ALICE_DDPF_RGB
Definition: texture.cpp:37
#define ALICE_DDSD_CAPS
Definition: texture.cpp:25
#define ALICE_DDSCAPS2_CUBEMAP
Definition: texture.cpp:47
#define ALICE_DDSCAPS_MIPMAP
Definition: texture.cpp:43
#define SOIL_RGBA_S3TC_DXT5
Definition: texture.cpp:61
#define ALICE_DDSD_HEIGHT
Definition: texture.cpp:26