aboutsummaryrefslogtreecommitdiff
path: root/raylib/src/external/rl_gputex.h
diff options
context:
space:
mode:
Diffstat (limited to 'raylib/src/external/rl_gputex.h')
-rw-r--r--raylib/src/external/rl_gputex.h826
1 files changed, 826 insertions, 0 deletions
diff --git a/raylib/src/external/rl_gputex.h b/raylib/src/external/rl_gputex.h
new file mode 100644
index 0000000..4043a92
--- /dev/null
+++ b/raylib/src/external/rl_gputex.h
@@ -0,0 +1,826 @@
1/**********************************************************************************************
2*
3* rl_gputex v1.0 - GPU compressed textures loading and saving
4*
5* DESCRIPTION:
6*
7* Load GPU compressed image data from image files provided as memory data arrays,
8* data is loaded compressed, ready to be loaded into GPU.
9*
10* Note that some file formats (DDS, PVR, KTX) also support uncompressed data storage.
11* In those cases data is loaded uncompressed and format is returned.
12*
13* TODO:
14* - Implement raylib function: rlGetGlTextureFormats(), required by rl_save_ktx_to_memory()
15* - Review rl_load_ktx_from_memory() to support KTX v2.2 specs
16*
17* CONFIGURATION:
18*
19* #define RL_GPUTEX_SUPPORT_DDS
20* #define RL_GPUTEX_SUPPORT_PKM
21* #define RL_GPUTEX_SUPPORT_KTX
22* #define RL_GPUTEX_SUPPORT_PVR
23* #define RL_GPUTEX_SUPPORT_ASTC
24* Define desired file formats to be supported
25*
26*
27* LICENSE: zlib/libpng
28*
29* Copyright (c) 2013-2022 Ramon Santamaria (@raysan5)
30*
31* This software is provided "as-is", without any express or implied warranty. In no event
32* will the authors be held liable for any damages arising from the use of this software.
33*
34* Permission is granted to anyone to use this software for any purpose, including commercial
35* applications, and to alter it and redistribute it freely, subject to the following restrictions:
36*
37* 1. The origin of this software must not be misrepresented; you must not claim that you
38* wrote the original software. If you use this software in a product, an acknowledgment
39* in the product documentation would be appreciated but is not required.
40*
41* 2. Altered source versions must be plainly marked as such, and must not be misrepresented
42* as being the original software.
43*
44* 3. This notice may not be removed or altered from any source distribution.
45*
46**********************************************************************************************/
47
48#ifndef RL_GPUTEX_H
49#define RL_GPUTEX_H
50
51#ifndef RLAPI
52 #define RLAPI // Functions defined as 'extern' by default (implicit specifiers)
53#endif
54
55//----------------------------------------------------------------------------------
56// Module Functions Declaration
57//----------------------------------------------------------------------------------
58#if defined(__cplusplus)
59extern "C" { // Prevents name mangling of functions
60#endif
61
62// Load image data from memory data files
63RLAPI void *rl_load_dds_from_memory(const unsigned char *file_data, unsigned int file_size, int *width, int *height, int *format, int *mips);
64RLAPI void *rl_load_pkm_from_memory(const unsigned char *file_data, unsigned int file_size, int *width, int *height, int *format, int *mips);
65RLAPI void *rl_load_ktx_from_memory(const unsigned char *file_data, unsigned int file_size, int *width, int *height, int *format, int *mips);
66RLAPI void *rl_load_pvr_from_memory(const unsigned char *file_data, unsigned int file_size, int *width, int *height, int *format, int *mips);
67RLAPI void *rl_load_astc_from_memory(const unsigned char *file_data, unsigned int file_size, int *width, int *height, int *format, int *mips);
68
69RLAPI int rl_save_ktx_to_memory(const char *fileName, void *data, int width, int height, int format, int mipmaps); // Save image data as KTX file
70
71#if defined(__cplusplus)
72}
73#endif
74
75#endif // RL_GPUTEX_H
76
77
78/***********************************************************************************
79*
80* RL_GPUTEX IMPLEMENTATION
81*
82************************************************************************************/
83
84#if defined(RL_GPUTEX_IMPLEMENTATION)
85
86// Simple log system to avoid RPNG_LOG() calls if required
87// NOTE: Avoiding those calls, also avoids const strings memory usage
88#define RL_GPUTEX_SHOW_LOG_INFO
89#if defined(RL_GPUTEX_SHOW_LOG_INFO) && !defined(LOG)
90#define LOG(...) printf(__VA_ARGS__)
91#else
92#define LOG(...)
93#endif
94
95//----------------------------------------------------------------------------------
96// Module Internal Functions Declaration
97//----------------------------------------------------------------------------------
98// Get pixel data size in bytes for certain pixel format
99static int get_pixel_data_size(int width, int height, int format);
100
101//----------------------------------------------------------------------------------
102// Module Functions Definition
103//----------------------------------------------------------------------------------
104#if defined(RL_GPUTEX_SUPPORT_DDS)
105// Loading DDS from memory image data (compressed or uncompressed)
106void *rl_load_dds_from_memory(const unsigned char *file_data, unsigned int file_size, int *width, int *height, int *format, int *mips)
107{
108 void *image_data = NULL; // Image data pointer
109 int image_pixel_size = 0; // Image pixel size
110
111 unsigned char *file_data_ptr = (unsigned char *)file_data;
112
113 // Required extension:
114 // GL_EXT_texture_compression_s3tc
115
116 // Supported tokens (defined by extensions)
117 // GL_COMPRESSED_RGB_S3TC_DXT1_EXT 0x83F0
118 // GL_COMPRESSED_RGBA_S3TC_DXT1_EXT 0x83F1
119 // GL_COMPRESSED_RGBA_S3TC_DXT3_EXT 0x83F2
120 // GL_COMPRESSED_RGBA_S3TC_DXT5_EXT 0x83F3
121
122 #define FOURCC_DXT1 0x31545844 // Equivalent to "DXT1" in ASCII
123 #define FOURCC_DXT3 0x33545844 // Equivalent to "DXT3" in ASCII
124 #define FOURCC_DXT5 0x35545844 // Equivalent to "DXT5" in ASCII
125
126 // DDS Pixel Format
127 typedef struct {
128 unsigned int size;
129 unsigned int flags;
130 unsigned int fourcc;
131 unsigned int rgb_bit_count;
132 unsigned int r_bit_mask;
133 unsigned int g_bit_mask;
134 unsigned int b_bit_mask;
135 unsigned int a_bit_mask;
136 } dds_pixel_format;
137
138 // DDS Header (124 bytes)
139 typedef struct {
140 unsigned int size;
141 unsigned int flags;
142 unsigned int height;
143 unsigned int width;
144 unsigned int pitch_or_linear_size;
145 unsigned int depth;
146 unsigned int mipmap_count;
147 unsigned int reserved1[11];
148 dds_pixel_format ddspf;
149 unsigned int caps;
150 unsigned int caps2;
151 unsigned int caps3;
152 unsigned int caps4;
153 unsigned int reserved2;
154 } dds_header;
155
156 if (file_data_ptr != NULL)
157 {
158 // Verify the type of file
159 unsigned char *dds_header_id = file_data_ptr;
160 file_data_ptr += 4;
161
162 if ((dds_header_id[0] != 'D') || (dds_header_id[1] != 'D') || (dds_header_id[2] != 'S') || (dds_header_id[3] != ' '))
163 {
164 LOG("WARNING: IMAGE: DDS file data not valid");
165 }
166 else
167 {
168 dds_header *header = (dds_header *)file_data_ptr;
169
170 file_data_ptr += sizeof(dds_header); // Skip header
171
172 *width = header->width;
173 *height = header->height;
174
175 if (*width % 4 != 0) LOG("WARNING: IMAGE: DDS file width must be multiple of 4. Image will not display correctly");
176 if (*height % 4 != 0) LOG("WARNING: IMAGE: DDS file height must be multiple of 4. Image will not display correctly");
177
178 image_pixel_size = header->width*header->height;
179
180 if (header->mipmap_count == 0) *mips = 1; // Parameter not used
181 else *mips = header->mipmap_count;
182
183 if (header->ddspf.rgb_bit_count == 16) // 16bit mode, no compressed
184 {
185 if (header->ddspf.flags == 0x40) // No alpha channel
186 {
187 int data_size = image_pixel_size*sizeof(unsigned short);
188 if (header->mipmap_count > 1) data_size = data_size + data_size / 3;
189 image_data = RL_MALLOC(data_size);
190
191 memcpy(image_data, file_data_ptr, data_size);
192
193 *format = PIXELFORMAT_UNCOMPRESSED_R5G6B5;
194 }
195 else if (header->ddspf.flags == 0x41) // With alpha channel
196 {
197 if (header->ddspf.a_bit_mask == 0x8000) // 1bit alpha
198 {
199 int data_size = image_pixel_size*sizeof(unsigned short);
200 if (header->mipmap_count > 1) data_size = data_size + data_size / 3;
201 image_data = RL_MALLOC(data_size);
202
203 memcpy(image_data, file_data_ptr, data_size);
204
205 unsigned char alpha = 0;
206
207 // NOTE: Data comes as A1R5G5B5, it must be reordered to R5G5B5A1
208 for (int i = 0; i < image_pixel_size; i++)
209 {
210 alpha = ((unsigned short *)image_data)[i] >> 15;
211 ((unsigned short *)image_data)[i] = ((unsigned short *)image_data)[i] << 1;
212 ((unsigned short *)image_data)[i] += alpha;
213 }
214
215 *format = PIXELFORMAT_UNCOMPRESSED_R5G5B5A1;
216 }
217 else if (header->ddspf.a_bit_mask == 0xf000) // 4bit alpha
218 {
219 int data_size = image_pixel_size*sizeof(unsigned short);
220 if (header->mipmap_count > 1) data_size = data_size + data_size / 3;
221 image_data = RL_MALLOC(data_size);
222
223 memcpy(image_data, file_data_ptr, data_size);
224
225 unsigned char alpha = 0;
226
227 // NOTE: Data comes as A4R4G4B4, it must be reordered R4G4B4A4
228 for (int i = 0; i < image_pixel_size; i++)
229 {
230 alpha = ((unsigned short *)image_data)[i] >> 12;
231 ((unsigned short *)image_data)[i] = ((unsigned short *)image_data)[i] << 4;
232 ((unsigned short *)image_data)[i] += alpha;
233 }
234
235 *format = PIXELFORMAT_UNCOMPRESSED_R4G4B4A4;
236 }
237 }
238 }
239 else if ((header->ddspf.flags == 0x40) && (header->ddspf.rgb_bit_count == 24)) // DDS_RGB, no compressed
240 {
241 int data_size = image_pixel_size*3*sizeof(unsigned char);
242 if (header->mipmap_count > 1) data_size = data_size + data_size / 3;
243 image_data = RL_MALLOC(data_size);
244
245 memcpy(image_data, file_data_ptr, data_size);
246
247 *format = PIXELFORMAT_UNCOMPRESSED_R8G8B8;
248 }
249 else if ((header->ddspf.flags == 0x41) && (header->ddspf.rgb_bit_count == 32)) // DDS_RGBA, no compressed
250 {
251 int data_size = image_pixel_size*4*sizeof(unsigned char);
252 if (header->mipmap_count > 1) data_size = data_size + data_size / 3;
253 image_data = RL_MALLOC(data_size);
254
255 memcpy(image_data, file_data_ptr, data_size);
256
257 unsigned char blue = 0;
258
259 // NOTE: Data comes as A8R8G8B8, it must be reordered R8G8B8A8 (view next comment)
260 // DirecX understand ARGB as a 32bit DWORD but the actual memory byte alignment is BGRA
261 // So, we must realign B8G8R8A8 to R8G8B8A8
262 for (int i = 0; i < image_pixel_size*4; i += 4)
263 {
264 blue = ((unsigned char *)image_data)[i];
265 ((unsigned char *)image_data)[i] = ((unsigned char *)image_data)[i + 2];
266 ((unsigned char *)image_data)[i + 2] = blue;
267 }
268
269 *format = PIXELFORMAT_UNCOMPRESSED_R8G8B8A8;
270 }
271 else if (((header->ddspf.flags == 0x04) || (header->ddspf.flags == 0x05)) && (header->ddspf.fourcc > 0)) // Compressed
272 {
273 int data_size = 0;
274
275 // Calculate data size, including all mipmaps
276 if (header->mipmap_count > 1) data_size = header->pitch_or_linear_size + header->pitch_or_linear_size / 3;
277 else data_size = header->pitch_or_linear_size;
278
279 image_data = RL_MALLOC(data_size*sizeof(unsigned char));
280
281 memcpy(image_data, file_data_ptr, data_size);
282
283 switch (header->ddspf.fourcc)
284 {
285 case FOURCC_DXT1:
286 {
287 if (header->ddspf.flags == 0x04) *format = PIXELFORMAT_COMPRESSED_DXT1_RGB;
288 else *format = PIXELFORMAT_COMPRESSED_DXT1_RGBA;
289 } break;
290 case FOURCC_DXT3: *format = PIXELFORMAT_COMPRESSED_DXT3_RGBA; break;
291 case FOURCC_DXT5: *format = PIXELFORMAT_COMPRESSED_DXT5_RGBA; break;
292 default: break;
293 }
294 }
295 }
296 }
297
298 return image_data;
299}
300#endif
301
302#if defined(RL_GPUTEX_SUPPORT_PKM)
303// Loading PKM image data (ETC1/ETC2 compression)
304// NOTE: KTX is the standard Khronos Group compression format (ETC1/ETC2, mipmaps)
305// PKM is a much simpler file format used mainly to contain a single ETC1/ETC2 compressed image (no mipmaps)
306void *rl_load_pkm_from_memory(const unsigned char *file_data, unsigned int file_size, int *width, int *height, int *format, int *mips)
307{
308 void *image_data = NULL; // Image data pointer
309
310 unsigned char *file_data_ptr = (unsigned char *)file_data;
311
312 // Required extensions:
313 // GL_OES_compressed_ETC1_RGB8_texture (ETC1) (OpenGL ES 2.0)
314 // GL_ARB_ES3_compatibility (ETC2/EAC) (OpenGL ES 3.0)
315
316 // Supported tokens (defined by extensions)
317 // GL_ETC1_RGB8_OES 0x8D64
318 // GL_COMPRESSED_RGB8_ETC2 0x9274
319 // GL_COMPRESSED_RGBA8_ETC2_EAC 0x9278
320
321 // PKM file (ETC1) Header (16 bytes)
322 typedef struct {
323 char id[4]; // "PKM "
324 char version[2]; // "10" or "20"
325 unsigned short format; // Data format (big-endian) (Check list below)
326 unsigned short width; // Texture width (big-endian) (orig_width rounded to multiple of 4)
327 unsigned short height; // Texture height (big-endian) (orig_height rounded to multiple of 4)
328 unsigned short orig_width; // Original width (big-endian)
329 unsigned short orig_height; // Original height (big-endian)
330 } pkm_header;
331
332 // Formats list
333 // version 10: format: 0=ETC1_RGB, [1=ETC1_RGBA, 2=ETC1_RGB_MIP, 3=ETC1_RGBA_MIP] (not used)
334 // version 20: format: 0=ETC1_RGB, 1=ETC2_RGB, 2=ETC2_RGBA_OLD, 3=ETC2_RGBA, 4=ETC2_RGBA1, 5=ETC2_R, 6=ETC2_RG, 7=ETC2_SIGNED_R, 8=ETC2_SIGNED_R
335
336 // NOTE: The extended width and height are the widths rounded up to a multiple of 4.
337 // NOTE: ETC is always 4bit per pixel (64 bit for each 4x4 block of pixels)
338
339 if (file_data_ptr != NULL)
340 {
341 pkm_header *header = (pkm_header *)file_data_ptr;
342
343 if ((header->id[0] != 'P') || (header->id[1] != 'K') || (header->id[2] != 'M') || (header->id[3] != ' '))
344 {
345 LOG("WARNING: IMAGE: PKM file data not valid");
346 }
347 else
348 {
349 file_data_ptr += sizeof(pkm_header); // Skip header
350
351 // NOTE: format, width and height come as big-endian, data must be swapped to little-endian
352 header->format = ((header->format & 0x00FF) << 8) | ((header->format & 0xFF00) >> 8);
353 header->width = ((header->width & 0x00FF) << 8) | ((header->width & 0xFF00) >> 8);
354 header->height = ((header->height & 0x00FF) << 8) | ((header->height & 0xFF00) >> 8);
355
356 *width = header->width;
357 *height = header->height;
358 *mips = 1;
359
360 int bpp = 4;
361 if (header->format == 3) bpp = 8;
362
363 int data_size = (*width)*(*height)*bpp/8; // Total data size in bytes
364
365 image_data = RL_MALLOC(data_size*sizeof(unsigned char));
366
367 memcpy(image_data, file_data_ptr, data_size);
368
369 if (header->format == 0) *format = PIXELFORMAT_COMPRESSED_ETC1_RGB;
370 else if (header->format == 1) *format = PIXELFORMAT_COMPRESSED_ETC2_RGB;
371 else if (header->format == 3) *format = PIXELFORMAT_COMPRESSED_ETC2_EAC_RGBA;
372 }
373 }
374
375 return image_data;
376}
377#endif
378
379#if defined(RL_GPUTEX_SUPPORT_KTX)
380// Load KTX compressed image data (ETC1/ETC2 compression)
381// TODO: Review KTX loading, many things changed!
382void *rl_load_ktx_from_memory(const unsigned char *file_data, unsigned int file_size, int *width, int *height, int *format, int *mips)
383{
384 void *image_data = NULL; // Image data pointer
385
386 unsigned char *file_data_ptr = (unsigned char *)file_data;
387
388 // Required extensions:
389 // GL_OES_compressed_ETC1_RGB8_texture (ETC1)
390 // GL_ARB_ES3_compatibility (ETC2/EAC)
391
392 // Supported tokens (defined by extensions)
393 // GL_ETC1_RGB8_OES 0x8D64
394 // GL_COMPRESSED_RGB8_ETC2 0x9274
395 // GL_COMPRESSED_RGBA8_ETC2_EAC 0x9278
396
397 // KTX file Header (64 bytes)
398 // v1.1 - https://www.khronos.org/opengles/sdk/tools/KTX/file_format_spec/
399 // v2.0 - http://github.khronos.org/KTX-Specification/
400
401 // KTX 1.1 Header
402 // TODO: Support KTX 2.2 specs!
403 typedef struct {
404 char id[12]; // Identifier: "«KTX 11»\r\n\x1A\n"
405 unsigned int endianness; // Little endian: 0x01 0x02 0x03 0x04
406 unsigned int gl_type; // For compressed textures, glType must equal 0
407 unsigned int gl_type_size; // For compressed texture data, usually 1
408 unsigned int gl_format; // For compressed textures is 0
409 unsigned int gl_internal_format; // Compressed internal format
410 unsigned int gl_base_internal_format; // Same as glFormat (RGB, RGBA, ALPHA...)
411 unsigned int width; // Texture image width in pixels
412 unsigned int height; // Texture image height in pixels
413 unsigned int depth; // For 2D textures is 0
414 unsigned int elements; // Number of array elements, usually 0
415 unsigned int faces; // Cubemap faces, for no-cubemap = 1
416 unsigned int mipmap_levels; // Non-mipmapped textures = 1
417 unsigned int key_value_data_size; // Used to encode any arbitrary data...
418 } ktx_header;
419
420 // NOTE: Before start of every mipmap data block, we have: unsigned int data_size
421
422 if (file_data_ptr != NULL)
423 {
424 ktx_header *header = (ktx_header *)file_data_ptr;
425
426 if ((header->id[1] != 'K') || (header->id[2] != 'T') || (header->id[3] != 'X') ||
427 (header->id[4] != ' ') || (header->id[5] != '1') || (header->id[6] != '1'))
428 {
429 LOG("WARNING: IMAGE: KTX file data not valid");
430 }
431 else
432 {
433 file_data_ptr += sizeof(ktx_header); // Move file data pointer
434
435 *width = header->width;
436 *height = header->height;
437 *mips = header->mipmap_levels;
438
439 file_data_ptr += header->key_value_data_size; // Skip value data size
440
441 int data_size = ((int *)file_data_ptr)[0];
442 file_data_ptr += sizeof(int);
443
444 image_data = RL_MALLOC(data_size*sizeof(unsigned char));
445
446 memcpy(image_data, file_data_ptr, data_size);
447
448 if (header->gl_internal_format == 0x8D64) *format = PIXELFORMAT_COMPRESSED_ETC1_RGB;
449 else if (header->gl_internal_format == 0x9274) *format = PIXELFORMAT_COMPRESSED_ETC2_RGB;
450 else if (header->gl_internal_format == 0x9278) *format = PIXELFORMAT_COMPRESSED_ETC2_EAC_RGBA;
451
452 // TODO: Support uncompressed data formats? Right now it returns format = 0!
453 }
454 }
455
456 return image_data;
457}
458
459// Save image data as KTX file
460// NOTE: By default KTX 1.1 spec is used, 2.0 is still on draft (01Oct2018)
461// TODO: Review KTX saving, many things changed!
462int rl_save_ktx(const char *file_name, void *data, int width, int height, int format, int mipmaps)
463{
464 // KTX file Header (64 bytes)
465 // v1.1 - https://www.khronos.org/opengles/sdk/tools/KTX/file_format_spec/
466 // v2.0 - http://github.khronos.org/KTX-Specification/ - Final specs by 2021-04-18
467 typedef struct {
468 char id[12]; // Identifier: "«KTX 11»\r\n\x1A\n" // KTX 2.0: "«KTX 22»\r\n\x1A\n"
469 unsigned int endianness; // Little endian: 0x01 0x02 0x03 0x04
470 unsigned int gl_type; // For compressed textures, glType must equal 0
471 unsigned int gl_type_size; // For compressed texture data, usually 1
472 unsigned int gl_format; // For compressed textures is 0
473 unsigned int gl_internal_format; // Compressed internal format
474 unsigned int gl_base_internal_format; // Same as glFormat (RGB, RGBA, ALPHA...) // KTX 2.0: UInt32 vkFormat
475 unsigned int width; // Texture image width in pixels
476 unsigned int height; // Texture image height in pixels
477 unsigned int depth; // For 2D textures is 0
478 unsigned int elements; // Number of array elements, usually 0
479 unsigned int faces; // Cubemap faces, for no-cubemap = 1
480 unsigned int mipmap_levels; // Non-mipmapped textures = 1
481 unsigned int key_value_data_size; // Used to encode any arbitrary data... // KTX 2.0: UInt32 levelOrder - ordering of the mipmap levels, usually 0
482 // KTX 2.0: UInt32 supercompressionScheme - 0 (None), 1 (Crunch CRN), 2 (Zlib DEFLATE)...
483 // KTX 2.0 defines additional header elements...
484 } ktx_header;
485
486 // Calculate file data_size required
487 int data_size = sizeof(ktx_header);
488
489 for (int i = 0, w = width, h = height; i < mipmaps; i++)
490 {
491 data_size += get_pixel_data_size(w, h, format);
492 w /= 2; h /= 2;
493 }
494
495 unsigned char *file_data = RL_CALLOC(data_size, 1);
496 unsigned char *file_data_ptr = file_data;
497
498 ktx_header header = { 0 };
499
500 // KTX identifier (v1.1)
501 //unsigned char id[12] = { '«', 'K', 'T', 'X', ' ', '1', '1', '»', '\r', '\n', '\x1A', '\n' };
502 //unsigned char id[12] = { 0xAB, 0x4B, 0x54, 0x58, 0x20, 0x31, 0x31, 0xBB, 0x0D, 0x0A, 0x1A, 0x0A };
503
504 const char ktx_identifier[12] = { 0xAB, 'K', 'T', 'X', ' ', '1', '1', 0xBB, '\r', '\n', 0x1A, '\n' };
505
506 // Get the image header
507 memcpy(header.id, ktx_identifier, 12); // KTX 1.1 signature
508 header.endianness = 0;
509 header.gl_type = 0; // Obtained from format
510 header.gl_type_size = 1;
511 header.gl_format = 0; // Obtained from format
512 header.gl_internal_format = 0; // Obtained from format
513 header.gl_base_internal_format = 0;
514 header.width = width;
515 header.height = height;
516 header.depth = 0;
517 header.elements = 0;
518 header.faces = 1;
519 header.mipmap_levels = mipmaps; // If it was 0, it means mipmaps should be generated on loading (not for compressed formats)
520 header.key_value_data_size = 0; // No extra data after the header
521
522 rlGetGlTextureFormats(format, &header.gl_internal_format, &header.gl_format, &header.gl_type); // rlgl module function
523 header.gl_base_internal_format = header.gl_format; // KTX 1.1 only
524
525 // NOTE: We can save into a .ktx all PixelFormats supported by raylib, including compressed formats like DXT, ETC or ASTC
526
527 if (header.gl_format == -1) LOG("WARNING: IMAGE: GL format not supported for KTX export (%i)", header.gl_format);
528 else
529 {
530 memcpy(file_data_ptr, &header, sizeof(ktx_header));
531 file_data_ptr += sizeof(ktx_header);
532
533 int temp_width = width;
534 int temp_height = height;
535 int data_offset = 0;
536
537 // Save all mipmaps data
538 for (int i = 0; i < mipmaps; i++)
539 {
540 unsigned int data_size = get_pixel_data_size(temp_width, temp_height, format);
541
542 memcpy(file_data_ptr, &data_size, sizeof(unsigned int));
543 memcpy(file_data_ptr + 4, (unsigned char *)data + data_offset, data_size);
544
545 temp_width /= 2;
546 temp_height /= 2;
547 data_offset += data_size;
548 file_data_ptr += (4 + data_size);
549 }
550 }
551
552 // Save file data to file
553 int success = false;
554 FILE *file = fopen(file_name, "wb");
555
556 if (file != NULL)
557 {
558 unsigned int count = (unsigned int)fwrite(file_data, sizeof(unsigned char), data_size, file);
559
560 if (count == 0) LOG("WARNING: FILEIO: [%s] Failed to write file", file_name);
561 else if (count != data_size) LOG("WARNING: FILEIO: [%s] File partially written", file_name);
562 else LOG("INFO: FILEIO: [%s] File saved successfully", file_name);
563
564 int result = fclose(file);
565 if (result == 0) success = true;
566 }
567 else LOG("WARNING: FILEIO: [%s] Failed to open file", file_name);
568
569 RL_FREE(file_data); // Free file data buffer
570
571 // If all data has been written correctly to file, success = 1
572 return success;
573}
574#endif
575
576#if defined(RL_GPUTEX_SUPPORT_PVR)
577// Loading PVR image data (uncompressed or PVRT compression)
578// NOTE: PVR v2 not supported, use PVR v3 instead
579void *rl_load_pvr_from_memory(const unsigned char *file_data, unsigned int file_size, int *width, int *height, int *format, int *mips)
580{
581 void *image_data = NULL; // Image data pointer
582
583 unsigned char *file_data_ptr = (unsigned char *)file_data;
584
585 // Required extension:
586 // GL_IMG_texture_compression_pvrtc
587
588 // Supported tokens (defined by extensions)
589 // GL_COMPRESSED_RGB_PVRTC_4BPPV1_IMG 0x8C00
590 // GL_COMPRESSED_RGBA_PVRTC_4BPPV1_IMG 0x8C02
591
592#if 0 // Not used...
593 // PVR file v2 Header (52 bytes)
594 typedef struct {
595 unsigned int headerLength;
596 unsigned int height;
597 unsigned int width;
598 unsigned int numMipmaps;
599 unsigned int flags;
600 unsigned int dataLength;
601 unsigned int bpp;
602 unsigned int bitmaskRed;
603 unsigned int bitmaskGreen;
604 unsigned int bitmaskBlue;
605 unsigned int bitmaskAlpha;
606 unsigned int pvrTag;
607 unsigned int numSurfs;
608 } PVRHeaderV2;
609#endif
610
611 // PVR file v3 Header (52 bytes)
612 // NOTE: After it could be metadata (15 bytes?)
613 typedef struct {
614 char id[4];
615 unsigned int flags;
616 unsigned char channels[4]; // pixelFormat high part
617 unsigned char channel_depth[4]; // pixelFormat low part
618 unsigned int color_space;
619 unsigned int channel_type;
620 unsigned int height;
621 unsigned int width;
622 unsigned int depth;
623 unsigned int num_surfaces;
624 unsigned int num_faces;
625 unsigned int num_mipmaps;
626 unsigned int metadata_size;
627 } pvr_header;
628
629#if 0 // Not used...
630 // Metadata (usually 15 bytes)
631 typedef struct {
632 unsigned int devFOURCC;
633 unsigned int key;
634 unsigned int data_size; // Not used?
635 unsigned char *data; // Not used?
636 } PVRMetadata;
637#endif
638
639 if (file_data_ptr != NULL)
640 {
641 // Check PVR image version
642 unsigned char pvr_version = file_data_ptr[0];
643
644 // Load different PVR data formats
645 if (pvr_version == 0x50)
646 {
647 pvr_header *header = (pvr_header *)file_data_ptr;
648
649 if ((header->id[0] != 'P') || (header->id[1] != 'V') || (header->id[2] != 'R') || (header->id[3] != 3))
650 {
651 LOG("WARNING: IMAGE: PVR file data not valid");
652 }
653 else
654 {
655 file_data_ptr += sizeof(pvr_header); // Skip header
656
657 *width = header->width;
658 *height = header->height;
659 *mips = header->num_mipmaps;
660
661 // Check data format
662 if (((header->channels[0] == 'l') && (header->channels[1] == 0)) && (header->channel_depth[0] == 8)) *format = PIXELFORMAT_UNCOMPRESSED_GRAYSCALE;
663 else if (((header->channels[0] == 'l') && (header->channels[1] == 'a')) && ((header->channel_depth[0] == 8) && (header->channel_depth[1] == 8))) *format = PIXELFORMAT_UNCOMPRESSED_GRAY_ALPHA;
664 else if ((header->channels[0] == 'r') && (header->channels[1] == 'g') && (header->channels[2] == 'b'))
665 {
666 if (header->channels[3] == 'a')
667 {
668 if ((header->channel_depth[0] == 5) && (header->channel_depth[1] == 5) && (header->channel_depth[2] == 5) && (header->channel_depth[3] == 1)) *format = PIXELFORMAT_UNCOMPRESSED_R5G5B5A1;
669 else if ((header->channel_depth[0] == 4) && (header->channel_depth[1] == 4) && (header->channel_depth[2] == 4) && (header->channel_depth[3] == 4)) *format = PIXELFORMAT_UNCOMPRESSED_R4G4B4A4;
670 else if ((header->channel_depth[0] == 8) && (header->channel_depth[1] == 8) && (header->channel_depth[2] == 8) && (header->channel_depth[3] == 8)) *format = PIXELFORMAT_UNCOMPRESSED_R8G8B8A8;
671 }
672 else if (header->channels[3] == 0)
673 {
674 if ((header->channel_depth[0] == 5) && (header->channel_depth[1] == 6) && (header->channel_depth[2] == 5)) *format = PIXELFORMAT_UNCOMPRESSED_R5G6B5;
675 else if ((header->channel_depth[0] == 8) && (header->channel_depth[1] == 8) && (header->channel_depth[2] == 8)) *format = PIXELFORMAT_UNCOMPRESSED_R8G8B8;
676 }
677 }
678 else if (header->channels[0] == 2) *format = PIXELFORMAT_COMPRESSED_PVRT_RGB;
679 else if (header->channels[0] == 3) *format = PIXELFORMAT_COMPRESSED_PVRT_RGBA;
680
681 file_data_ptr += header->metadata_size; // Skip meta data header
682
683 // Calculate data size (depends on format)
684 int bpp = 0;
685 switch (*format)
686 {
687 case PIXELFORMAT_UNCOMPRESSED_GRAYSCALE: bpp = 8; break;
688 case PIXELFORMAT_UNCOMPRESSED_GRAY_ALPHA:
689 case PIXELFORMAT_UNCOMPRESSED_R5G5B5A1:
690 case PIXELFORMAT_UNCOMPRESSED_R5G6B5:
691 case PIXELFORMAT_UNCOMPRESSED_R4G4B4A4: bpp = 16; break;
692 case PIXELFORMAT_UNCOMPRESSED_R8G8B8A8: bpp = 32; break;
693 case PIXELFORMAT_UNCOMPRESSED_R8G8B8: bpp = 24; break;
694 case PIXELFORMAT_COMPRESSED_PVRT_RGB:
695 case PIXELFORMAT_COMPRESSED_PVRT_RGBA: bpp = 4; break;
696 default: break;
697 }
698
699 int data_size = (*width)*(*height)*bpp/8; // Total data size in bytes
700 image_data = RL_MALLOC(data_size*sizeof(unsigned char));
701
702 memcpy(image_data, file_data_ptr, data_size);
703 }
704 }
705 else if (pvr_version == 52) LOG("INFO: IMAGE: PVRv2 format not supported, update your files to PVRv3");
706 }
707
708 return image_data;
709}
710#endif
711
712#if defined(RL_GPUTEX_SUPPORT_ASTC)
713// Load ASTC compressed image data (ASTC compression)
714void *rl_load_astc_from_memory(const unsigned char *file_data, unsigned int file_size, int *width, int *height, int *format, int *mips)
715{
716 void *image_data = NULL; // Image data pointer
717
718 unsigned char *file_data_ptr = (unsigned char *)file_data;
719
720 // Required extensions:
721 // GL_KHR_texture_compression_astc_hdr
722 // GL_KHR_texture_compression_astc_ldr
723
724 // Supported tokens (defined by extensions)
725 // GL_COMPRESSED_RGBA_ASTC_4x4_KHR 0x93b0
726 // GL_COMPRESSED_RGBA_ASTC_8x8_KHR 0x93b7
727
728 // ASTC file Header (16 bytes)
729 typedef struct {
730 unsigned char id[4]; // Signature: 0x13 0xAB 0xA1 0x5C
731 unsigned char blockX; // Block X dimensions
732 unsigned char blockY; // Block Y dimensions
733 unsigned char blockZ; // Block Z dimensions (1 for 2D images)
734 unsigned char width[3]; // void *width in pixels (24bit value)
735 unsigned char height[3]; // void *height in pixels (24bit value)
736 unsigned char length[3]; // void *Z-size (1 for 2D images)
737 } astc_header;
738
739 if (file_data_ptr != NULL)
740 {
741 astc_header *header = (astc_header *)file_data_ptr;
742
743 if ((header->id[3] != 0x5c) || (header->id[2] != 0xa1) || (header->id[1] != 0xab) || (header->id[0] != 0x13))
744 {
745 LOG("WARNING: IMAGE: ASTC file data not valid");
746 }
747 else
748 {
749 file_data_ptr += sizeof(astc_header); // Skip header
750
751 // NOTE: Assuming Little Endian (could it be wrong?)
752 *width = 0x00000000 | ((int)header->width[2] << 16) | ((int)header->width[1] << 8) | ((int)header->width[0]);
753 *height = 0x00000000 | ((int)header->height[2] << 16) | ((int)header->height[1] << 8) | ((int)header->height[0]);
754 *mips = 1; // NOTE: ASTC format only contains one mipmap level
755
756 // NOTE: Each block is always stored in 128bit so we can calculate the bpp
757 int bpp = 128/(header->blockX*header->blockY);
758
759 // NOTE: Currently we only support 2 blocks configurations: 4x4 and 8x8
760 if ((bpp == 8) || (bpp == 2))
761 {
762 int data_size = (*width)*(*height)*bpp/8; // Data size in bytes
763
764 image_data = RL_MALLOC(data_size*sizeof(unsigned char));
765
766 memcpy(image_data, file_data_ptr, data_size);
767
768 if (bpp == 8) *format = PIXELFORMAT_COMPRESSED_ASTC_4x4_RGBA;
769 else if (bpp == 2) *format = PIXELFORMAT_COMPRESSED_ASTC_8x8_RGBA;
770 }
771 else LOG("WARNING: IMAGE: ASTC block size configuration not supported");
772 }
773 }
774
775 return image_data;
776}
777#endif
778
779//----------------------------------------------------------------------------------
780// Module Internal Functions Definition
781//----------------------------------------------------------------------------------
782// Get pixel data size in bytes for certain pixel format
783static int get_pixel_data_size(int width, int height, int format)
784{
785 int data_size = 0; // Size in bytes
786 int bpp = 0; // Bits per pixel
787
788 switch (format)
789 {
790 case PIXELFORMAT_UNCOMPRESSED_GRAYSCALE: bpp = 8; break;
791 case PIXELFORMAT_UNCOMPRESSED_GRAY_ALPHA:
792 case PIXELFORMAT_UNCOMPRESSED_R5G6B5:
793 case PIXELFORMAT_UNCOMPRESSED_R5G5B5A1:
794 case PIXELFORMAT_UNCOMPRESSED_R4G4B4A4: bpp = 16; break;
795 case PIXELFORMAT_UNCOMPRESSED_R8G8B8A8: bpp = 32; break;
796 case PIXELFORMAT_UNCOMPRESSED_R8G8B8: bpp = 24; break;
797 case PIXELFORMAT_UNCOMPRESSED_R32: bpp = 32; break;
798 case PIXELFORMAT_UNCOMPRESSED_R32G32B32: bpp = 32*3; break;
799 case PIXELFORMAT_UNCOMPRESSED_R32G32B32A32: bpp = 32*4; break;
800 case PIXELFORMAT_COMPRESSED_DXT1_RGB:
801 case PIXELFORMAT_COMPRESSED_DXT1_RGBA:
802 case PIXELFORMAT_COMPRESSED_ETC1_RGB:
803 case PIXELFORMAT_COMPRESSED_ETC2_RGB:
804 case PIXELFORMAT_COMPRESSED_PVRT_RGB:
805 case PIXELFORMAT_COMPRESSED_PVRT_RGBA: bpp = 4; break;
806 case PIXELFORMAT_COMPRESSED_DXT3_RGBA:
807 case PIXELFORMAT_COMPRESSED_DXT5_RGBA:
808 case PIXELFORMAT_COMPRESSED_ETC2_EAC_RGBA:
809 case PIXELFORMAT_COMPRESSED_ASTC_4x4_RGBA: bpp = 8; break;
810 case PIXELFORMAT_COMPRESSED_ASTC_8x8_RGBA: bpp = 2; break;
811 default: break;
812 }
813
814 data_size = width*height*bpp/8; // Total data size in bytes
815
816 // Most compressed formats works on 4x4 blocks,
817 // if texture is smaller, minimum dataSize is 8 or 16
818 if ((width < 4) && (height < 4))
819 {
820 if ((format >= PIXELFORMAT_COMPRESSED_DXT1_RGB) && (format < PIXELFORMAT_COMPRESSED_DXT3_RGBA)) data_size = 8;
821 else if ((format >= PIXELFORMAT_COMPRESSED_DXT3_RGBA) && (format < PIXELFORMAT_COMPRESSED_ASTC_8x8_RGBA)) data_size = 16;
822 }
823
824 return data_size;
825}
826#endif // RL_GPUTEX_IMPLEMENTATION

Generated with cgit - Back to sebastiano.tronto.net