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
100GLuint SOIL_direct_load_DDS_from_memory(unsigned char const* const buffer, uint32_t buffer_length, uint32_t& width, uint32_t& height, int soil_flags) {
101 /* file reading variables */
102 uint32_t block_size = 16;
103 uint32_t flag;
104 if(buffer_length < sizeof(DDS_header)) {
105 return 0;
106 }
107
108 /* try reading in the header */
109 DDS_header header;
110 std::memcpy((void*)(&header), (void const*)buffer, sizeof(DDS_header));
111 uint32_t buffer_index = sizeof(DDS_header);
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 ALICE_DDSD_LINEARSIZE if it's compressed, or ALICE_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 */
134 return 0;
135 }
136 /* make sure it is a type we can upload */
137 if((header.sPixelFormat.dwFlags & ALICE_DDPF_FOURCC) &&
138 !((header.sPixelFormat.dwFourCC == (('D' << 0) | ('X' << 8) | ('T' << 16) | ('1' << 24))) ||
139 (header.sPixelFormat.dwFourCC == (('D' << 0) | ('X' << 8) | ('T' << 16) | ('3' << 24))) ||
140 (header.sPixelFormat.dwFourCC == (('D' << 0) | ('X' << 8) | ('T' << 16) | ('5' << 24))))) {
141 return 0;
142 }
143 if((header.sCaps.dwCaps1 & ALICE_DDSCAPS_TEXTURE) == 0) {
144 return 0;
145 }
146 if((header.sCaps.dwCaps2 & ALICE_DDSCAPS2_CUBEMAP) != 0) {
147 return 0;
148 }
149 /* OK, validated the header, let's load the image data */
150 width = header.dwWidth;
151 height = header.dwHeight;
152 bool uncompressed = (header.sPixelFormat.dwFlags & ALICE_DDPF_FOURCC) == 0;
153 GLint s3tc_format = 0; //How we want to give it to shaders
154 GLint s3tc_format_layout = 0; //How's it laid on memory
155 GLint s3tc_type = GL_UNSIGNED_BYTE;
156 uint32_t dds_main_size = 0;
157 if(uncompressed) {
158 s3tc_format = GL_RGB;
159 s3tc_format_layout = GL_RGB;
160 block_size = 3;
162 s3tc_format = GL_RGBA;
163 s3tc_format_layout = GL_RGBA;
164 block_size = 4;
165 if(header.sPixelFormat.dwRGBBitCount == 16) {
166 //s3tc_format_layout = GL_RGBA;
167 //s3tc_type = GL_UNSIGNED_BYTE;
168 block_size = 2;
169 }
170 }
171 dds_main_size = width * height * block_size;
172 } else {
173 /* can we even handle direct uploading to OpenGL DXT compressed images? */
174 //
175 // TODO: properly restore this check
176 //
177
178 // if(query_DXT_capability() != SOIL_CAPABILITY_PRESENT) {
179 // return 0;
180 // }
181 /* well, we know it is DXT1/3/5, because we checked above */
182 switch((header.sPixelFormat.dwFourCC >> 24) - '0') {
183 case 1:
184 s3tc_format = SOIL_RGBA_S3TC_DXT1;
185 block_size = 8;
186 break;
187 case 3:
188 s3tc_format = SOIL_RGBA_S3TC_DXT3;
189 block_size = 16;
190 break;
191 case 5:
192 s3tc_format = SOIL_RGBA_S3TC_DXT5;
193 block_size = 16;
194 break;
195 default:
196 break;
197 }
198 dds_main_size = ((width + 3) >> 2) * ((height + 3) >> 2) * block_size;
199 }
200 uint32_t dds_full_size = dds_main_size;
201 uint32_t mipmaps = 0;
202 if((header.sCaps.dwCaps1 & ALICE_DDSCAPS_MIPMAP) != 0 && (header.dwMipMapCount > 1)) {
203 mipmaps = header.dwMipMapCount - 1;
204 for(uint32_t i = 1; i <= mipmaps; ++i) {
205 uint32_t w = std::max<uint32_t>(width >> i, 1);
206 uint32_t h = std::max<uint32_t>(height >> i, 1);
207 if(uncompressed) {
208 /* uncompressed DDS, simple MIPmap size calculation */
209 dds_full_size += w * h * block_size;
210 } else {
211 /* compressed DDS, MIPmap size calculation is block based */
212 dds_full_size += ((w + 3) / 4) * ((h + 3) / 4) * block_size;
213 }
214 }
215 }
216 /* do this for each face of the cubemap! */
217 if(buffer_index + dds_full_size <= uint32_t(buffer_length)) {
218 /* got the image data RAM, create or use an existing OpenGL texture handle */
219 GLuint texid = 0;
220 glGenTextures(1, &texid);
221 /* bind an OpenGL texture ID */
222 glBindTexture(GL_TEXTURE_2D, texid);
223 if(!texid)
224 return 0;
225 /* did I have MIPmaps? */
226 if(mipmaps > 0) {
227 /* instruct OpenGL to use the MIPmaps */
228 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
229 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_NEAREST);
230 } else {
231 /* instruct OpenGL _NOT_ to use the MIPmaps */
232 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
233 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
234 }
235 /* does the user want clamping, or wrapping? */
236 if((soil_flags & SOIL_FLAG_TEXTURE_REPEATS) != 0) {
237 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
238 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
239 glTexParameteri(GL_TEXTURE_2D, SOIL_TEXTURE_WRAP_R, GL_REPEAT);
240 } else {
241 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
242 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
243 glTexParameteri(GL_TEXTURE_2D, SOIL_TEXTURE_WRAP_R, GL_CLAMP_TO_EDGE);
244 }
245 /* upload the main chunk */
246 if(uncompressed) {
247 /* and remember, DXT uncompressed uses BGR(A), so swap to (A)BGR for ALL MIPmap levels */
248 std::unique_ptr<uint8_t[]> dds_dest_data = std::unique_ptr<uint8_t[]>(new uint8_t[dds_full_size]);
249 switch(block_size) {
250 case 4:
251 {
252 for(uint32_t i = 0; i < dds_full_size; i += block_size) {
253 uint32_t data = *(uint32_t const*)(buffer + buffer_index + i);
254 uint32_t r = (data & header.sPixelFormat.dwRBitMask) >> std::countr_zero(header.sPixelFormat.dwRBitMask);
255 uint32_t g = (data & header.sPixelFormat.dwGBitMask) >> std::countr_zero(header.sPixelFormat.dwGBitMask);
256 uint32_t b = (data & header.sPixelFormat.dwBBitMask) >> std::countr_zero(header.sPixelFormat.dwBBitMask);
257 uint32_t a = (data & header.sPixelFormat.dwAlphaBitMask) >> std::countr_zero(header.sPixelFormat.dwAlphaBitMask);
258 dds_dest_data[i + 0] = static_cast<uint8_t>(r);
259 dds_dest_data[i + 1] = static_cast<uint8_t>(g);
260 dds_dest_data[i + 2] = static_cast<uint8_t>(b);
261 dds_dest_data[i + 3] = static_cast<uint8_t>(a);
262 }
263 break;
264 }
265 case 2:
266 {
267 dds_dest_data.reset();
268 dds_dest_data = std::unique_ptr<uint8_t[]>(new uint8_t[dds_full_size * 2]);
269 uint16_t mr1 = uint16_t(header.sPixelFormat.dwRBitMask >> std::countr_zero(header.sPixelFormat.dwRBitMask));
270 float mr2 = mr1 == 0 ? 0.f : 255.f / float(mr1);
271 uint16_t mg1 = uint16_t(header.sPixelFormat.dwGBitMask >> std::countr_zero(header.sPixelFormat.dwGBitMask));
272 float mg2 = mg1 == 0 ? 0.f : 255.f / float(mg1);
273 uint16_t mb1 = uint16_t(header.sPixelFormat.dwBBitMask >> std::countr_zero(header.sPixelFormat.dwBBitMask));
274 float mb2 = mb1 == 0 ? 0.f : 255.f / float(mb1);
275 uint16_t ma1 = uint16_t(header.sPixelFormat.dwAlphaBitMask >> std::countr_zero(header.sPixelFormat.dwAlphaBitMask));
276 float ma2 = ma1 == 0 ? 0.f : 255.f / float(ma1);
277 for(uint32_t i = 0; i < dds_full_size; i += block_size) {
278 uint16_t data = *(uint16_t const*)(buffer + buffer_index + i);
279 uint16_t r = (data & header.sPixelFormat.dwRBitMask) >> std::countr_zero(header.sPixelFormat.dwRBitMask);
280 uint16_t g = (data & header.sPixelFormat.dwGBitMask) >> std::countr_zero(header.sPixelFormat.dwGBitMask);
281 uint16_t b = (data & header.sPixelFormat.dwBBitMask) >> std::countr_zero(header.sPixelFormat.dwBBitMask);
282 uint16_t a = (data & header.sPixelFormat.dwAlphaBitMask) >> std::countr_zero(header.sPixelFormat.dwAlphaBitMask);
283 dds_dest_data[i * 2 + 0] = uint8_t(float(r) * mr2);
284 dds_dest_data[i * 2 + 1] = uint8_t(float(g) * mg2);
285 dds_dest_data[i * 2 + 2] = uint8_t(float(b) * mb2);
286 dds_dest_data[i * 2 + 3] = uint8_t(float(a) * ma2);
287 }
288 break;
289 }
290 default:
291 {
292 std::memcpy(dds_dest_data.get(), buffer + buffer_index, dds_full_size);
293 for(uint32_t i = 0; i < dds_full_size; i += block_size) {
294 uint8_t temp = dds_dest_data[i];
295 dds_dest_data[i] = dds_dest_data[i + 2];
296 dds_dest_data[i + 2] = temp;
297 }
298 break;
299 }
300 }
301 glTexImage2D(GL_TEXTURE_2D, 0, s3tc_format, width, height, 0, s3tc_format_layout, s3tc_type, dds_dest_data.get());
302 uint32_t buffer_offset = dds_main_size * (block_size == 2 ? 2 : 1);
303 /* upload the mipmaps, if we have them */
304 for(uint32_t i = 1; i <= mipmaps; ++i) {
305 uint32_t w = std::max<uint32_t>(width >> i, 1);
306 uint32_t h = std::max<uint32_t>(height >> i, 1);
307 /* upload this mipmap */
308 uint32_t mip_size = w * h * block_size;
309 switch(block_size) {
310 case 2:
311 mip_size = w * h * 4;
312 break;
313 default:
314 break;
315 }
316 glTexImage2D(GL_TEXTURE_2D, i, s3tc_format, w, h, 0, s3tc_format_layout, s3tc_type, dds_dest_data.get() + buffer_offset);
317 /* and move to the next mipmap */
318 buffer_offset += mip_size;
319 }
320 } else {
321 glCompressedTexImage2D(GL_TEXTURE_2D, 0, s3tc_format, width, height, 0, dds_main_size, buffer + buffer_index);
322 buffer_index += dds_main_size;
323 /* upload the mipmaps, if we have them */
324 for(uint32_t i = 1; i <= mipmaps; ++i) {
325 uint32_t w = std::max<uint32_t>(width >> i, 1);
326 uint32_t h = std::max<uint32_t>(height >> i, 1);
327 /* upload this mipmap */
328 uint32_t mip_size = ((w + 3) / 4) * ((h + 3) / 4) * block_size;
329 glCompressedTexImage2D(GL_TEXTURE_2D, i, s3tc_format, w, h, 0, mip_size, buffer + buffer_index);
330 /* and move to the next mipmap */
331 buffer_index += mip_size;
332 }
333 }
334 return texid;
335 }
336 return 0;
337}
338
340 STBI_FREE(data);
341 data = nullptr;
342}
343
344texture::texture(texture&& other) noexcept {
345 channels = other.channels;
346 loaded = other.loaded;
347 size_x = other.size_x;
348 size_y = other.size_y;
349 data = other.data;
350 texture_handle = other.texture_handle;
351
352 other.data = nullptr;
353}
355 channels = other.channels;
356 loaded = other.loaded;
357 size_x = other.size_x;
358 size_y = other.size_y;
359 data = other.data;
360 texture_handle = other.texture_handle;
361
362 other.data = nullptr;
363 return *this;
364}
365
367 assert(loaded);
368 return texture_handle;
369}
370
371GLuint load_file_and_return_handle(native_string const& native_name, simple_fs::file_system const& fs, texture& asset_texture, bool keep_data) {
372 auto name_length = native_name.length();
373
374 auto root = get_root(fs);
375 if(name_length > 4) { // try loading as a dds
376 auto dds_name = native_name;
377 if(auto pos = dds_name.find_last_of('.'); pos != native_string::npos) {
378 dds_name[pos + 1] = NATIVE('d');
379 dds_name[pos + 2] = NATIVE('d');
380 dds_name[pos + 3] = NATIVE('s');
381 dds_name.resize(pos + 4);
382 }
383 auto file = open_file(root, dds_name);
384 if(file) {
385 auto content = simple_fs::view_contents(*file);
386
387 uint32_t w = 0;
388 uint32_t h = 0;
389 asset_texture.texture_handle = SOIL_direct_load_DDS_from_memory(reinterpret_cast<uint8_t const*>(content.data), content.file_size, w, h, 0);
390
391 if(asset_texture.texture_handle) {
392 asset_texture.channels = 4;
393 asset_texture.size_x = int32_t(w);
394 asset_texture.size_y = int32_t(h);
395 asset_texture.loaded = true;
396
397 if(keep_data) {
398 asset_texture.data = static_cast<uint8_t*>(STBI_MALLOC(4 * w * h));
399 glGetTextureImage(asset_texture.texture_handle, 0, GL_RGBA, GL_UNSIGNED_BYTE, static_cast<int32_t>(4 * w * h),
400 asset_texture.data);
401 }
402 return asset_texture.texture_handle;
403 }
404 }
405 }
406
407 auto file = open_file(root, native_name);
408 if(!file && name_length > 4) {
409 auto png_name = native_name;
410 if(auto pos = png_name.find_last_of('.'); pos != native_string::npos) {
411 png_name[pos + 1] = NATIVE('p');
412 png_name[pos + 2] = NATIVE('n');
413 png_name[pos + 3] = NATIVE('g');
414 png_name.resize(pos + 4);
415 }
416 file = open_file(root, png_name);
417 }
418 if(file) {
419 auto content = simple_fs::view_contents(*file);
420
421 int32_t file_channels = 4;
422
423 asset_texture.data = stbi_load_from_memory(reinterpret_cast<uint8_t const*>(content.data), int32_t(content.file_size),
424 &(asset_texture.size_x), &(asset_texture.size_y), &file_channels, 4);
425
426 asset_texture.channels = 4;
427 asset_texture.loaded = true;
428
429 glGenTextures(1, &asset_texture.texture_handle);
430 if(asset_texture.texture_handle) {
431 glBindTexture(GL_TEXTURE_2D, asset_texture.texture_handle);
432
433 glTexStorage2D(GL_TEXTURE_2D, 1, GL_RGBA8, asset_texture.size_x, asset_texture.size_y);
434 glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, asset_texture.size_x, asset_texture.size_y, GL_RGBA, GL_UNSIGNED_BYTE,
435 asset_texture.data);
436
437 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
438 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
439 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
440 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
441
442 glBindTexture(GL_TEXTURE_2D, 0);
443 }
444
445 if(!keep_data) {
446 STBI_FREE(asset_texture.data);
447 asset_texture.data = nullptr;
448 }
449
450 return asset_texture.texture_handle;
451 }
452 asset_texture.loaded = true; // because we tried to load it (and failed) and trying again will be wasteful
453 return 0;
454}
455
457 switch(type) {
460 return NATIVE("");
462 return NATIVE("_communist");
464 return NATIVE("_fascist");
466 return NATIVE("_monarchy");
468 return NATIVE("_republic");
469 // Non-vanilla
471 return NATIVE("_theocracy");
473 return NATIVE("_special");
475 return NATIVE("_spare");
477 return NATIVE("_populist");
479 return NATIVE("_realm");
481 return NATIVE("_other");
483 return NATIVE("_monarchy2");
485 return NATIVE("_monarchy3");
487 return NATIVE("_republic2");
489 return NATIVE("_republic3");
491 return NATIVE("_communist2");
493 return NATIVE("_communist3");
495 return NATIVE("_fascist2");
497 return NATIVE("_fascist3");
499 return NATIVE("_theocracy2");
501 return NATIVE("_theocracy3");
503 return NATIVE("_cosmetic_1");
505 return NATIVE("_cosmetic_2");
507 return NATIVE("_colonial");
509 return NATIVE("_nationalist");
511 return NATIVE("_sectarian");
513 return NATIVE("_socialist");
515 return NATIVE("_dominion");
517 return NATIVE("_agrarism");
519 return NATIVE("_national_syndicalist");
521 return NATIVE("_theocratic");
523 return NATIVE("_slot1");
525 return NATIVE("_slot2");
527 return NATIVE("_slot3");
529 return NATIVE("_slot4");
531 return NATIVE("_anarcho_liberal");
533 return NATIVE("_green");
535 return NATIVE("_traditionalist");
537 return NATIVE("_ultranationalist");
538 default:
539 return NATIVE("");
540
541 }
542}
543
544GLuint get_flag_handle(sys::state& state, dcon::national_identity_id nat_id, culture::flag_type type) {
545 auto masq_nat_id = state.world.nation_get_masquerade_identity(state.world.national_identity_get_nation_from_identity_holder(nat_id));
546 if(!masq_nat_id) {
547 masq_nat_id = nat_id;
548 }
549
550 auto const offset = culture::get_remapped_flag_type(state, type);
551 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) };
552 if(state.open_gl.asset_textures[id].loaded) {
553 return state.open_gl.asset_textures[id].texture_handle;
554 } else { // load from file
555 native_string file_str;
556 file_str += NATIVE("gfx");
557 file_str += NATIVE_DIR_SEPARATOR;
558 file_str += NATIVE("flags");
559 file_str += NATIVE_DIR_SEPARATOR;
560 file_str += simple_fs::win1250_to_native(nations::int_to_tag(state.world.national_identity_get_identifying_int(masq_nat_id)));
561 native_string default_file_str = file_str;
562 file_str += flag_type_to_name(state, type);
563 GLuint p_tex = load_file_and_return_handle(file_str + NATIVE(".png"), state.common_fs, state.open_gl.asset_textures[id], false);
564 if(!p_tex) {
565 p_tex = load_file_and_return_handle(file_str + NATIVE(".tga"), state.common_fs, state.open_gl.asset_textures[id], false);
566 if(!p_tex) {
567 p_tex = load_file_and_return_handle(default_file_str + NATIVE(".png"), state.common_fs, state.open_gl.asset_textures[id], false);
568 if(!p_tex) {
569 return load_file_and_return_handle(default_file_str + NATIVE(".tga"), state.common_fs, state.open_gl.asset_textures[id], false);
570 }
571 }
572 }
573 return p_tex;
574 }
575}
576
577GLuint get_texture_handle(sys::state& state, dcon::texture_id id, bool keep_data) {
578 if(state.open_gl.asset_textures[id].loaded) {
579 return state.open_gl.asset_textures[id].texture_handle;
580 } else { // load from file
581 auto fname = state.ui_defs.textures[id];
582 auto fname_view = state.to_string_view(fname);
583 auto native_name = simple_fs::win1250_to_native(fname_view);
584
585 return load_file_and_return_handle(native_name, state.common_fs, state.open_gl.asset_textures[id], keep_data);
586 } // end else (not already loaded)
587}
588
589data_texture::data_texture(int32_t sz, int32_t ch) {
590 size = sz;
591 channels = ch;
592 data = new uint8_t[size * channels];
593
594 glGenTextures(1, &texture_handle);
595 glBindTexture(GL_TEXTURE_2D, texture_handle);
596
597 if(channels == 3) {
598 glTexStorage2D(GL_TEXTURE_2D, 1, GL_RGB8, size, 1);
599 } else if(channels == 4) {
600 glTexStorage2D(GL_TEXTURE_2D, 1, GL_RGBA8, size, 1);
601 } else if(channels == 2) {
602 glTexStorage2D(GL_TEXTURE_2D, 1, GL_RG8, size, 1);
603 } else {
604 glTexStorage2D(GL_TEXTURE_2D, 1, GL_R8, size, 1);
605 }
606 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
607 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
608 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
609 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
610
611 glBindTexture(GL_TEXTURE_2D, 0);
612}
613
615 delete[] data;
616 data = nullptr;
617}
618
620 if(data && data_updated) {
621 glBindTexture(GL_TEXTURE_2D, texture_handle);
622 if(channels == 3) {
623 glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, size, 1, GL_RGB, GL_UNSIGNED_BYTE, data);
624 } else if(channels == 4) {
625 glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, size, 1, GL_RGBA, GL_UNSIGNED_BYTE, data);
626 } else if(channels == 2) {
627 glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, size, 1, GL_RG, GL_UNSIGNED_BYTE, data);
628 } else {
629 glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, size, 1, GL_RED, GL_UNSIGNED_BYTE, data);
630 }
631 data_updated = false;
632 glBindTexture(GL_TEXTURE_2D, 0);
633 }
634 return texture_handle;
635}
636
638 data = other.data;
639 size = other.size;
640 channels = other.channels;
641 texture_handle = other.texture_handle;
642
643 other.data = nullptr;
644}
645
647 data = other.data;
648 size = other.size;
649 channels = other.channels;
650 texture_handle = other.texture_handle;
651
652 other.data = nullptr;
653
654 return *this;
655}
656
658 auto content = simple_fs::view_contents(f);
659
660 int32_t file_channels = 4;
661 int32_t size_x = 0;
662 int32_t size_y = 0;
663 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);
664 uint32_t ftexid = 0;
665
666 glGenTextures(1, &ftexid);
667 if(data && ftexid) {
668 glBindTexture(GL_TEXTURE_2D, ftexid);
669
670 glTexStorage2D(GL_TEXTURE_2D, 1, GL_RGBA8, size_x, size_y);
671 glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, size_x, size_y, GL_RGBA, GL_UNSIGNED_BYTE, data);
672
673 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
674 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
675 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
676 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
677 }
678
679 STBI_FREE(data);
680
681 return font_texture_result{ ftexid, uint32_t(size_x) };
682}
683
684} // namespace ogl
data_texture & operator=(data_texture const &)=delete
GLuint handle()
Definition: texture.cpp:619
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:589
uint8_t * data
Definition: texture.hpp:29
texture & operator=(texture const &)=delete
GLuint get_texture_handle() const
Definition: texture.cpp:366
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
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:371
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:100
@ SOIL_FLAG_TEXTURE_REPEATS
Definition: texture.hpp:20
GLuint get_texture_handle(sys::state &state, dcon::texture_id id, bool keep_data)
Definition: texture.cpp:577
native_string flag_type_to_name(sys::state &state, culture::flag_type type)
Definition: texture.cpp:456
font_texture_result make_font_texture(simple_fs::file &f)
Definition: texture.cpp:657
GLuint get_flag_handle(sys::state &state, dcon::national_identity_id nat_id, culture::flag_type type)
Definition: texture.cpp:544
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
struct ogl::DDS_header::@1 sPixelFormat
unsigned int dwHeight
Definition: texture.cpp:71
struct ogl::DDS_header::@2 sCaps
unsigned int dwReserved2
Definition: texture.cpp:97
unsigned int dwBBitMask
Definition: texture.cpp:86
unsigned int dwMipMapCount
Definition: texture.cpp:75
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
#define SOIL_TEXTURE_WRAP_R
Definition: texture.cpp:63
#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 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