Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
godotengine
GitHub Repository: godotengine/godot
Path: blob/master/modules/ktx/texture_loader_ktx.cpp
20959 views
1
/**************************************************************************/
2
/* texture_loader_ktx.cpp */
3
/**************************************************************************/
4
/* This file is part of: */
5
/* GODOT ENGINE */
6
/* https://godotengine.org */
7
/**************************************************************************/
8
/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
9
/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
10
/* */
11
/* Permission is hereby granted, free of charge, to any person obtaining */
12
/* a copy of this software and associated documentation files (the */
13
/* "Software"), to deal in the Software without restriction, including */
14
/* without limitation the rights to use, copy, modify, merge, publish, */
15
/* distribute, sublicense, and/or sell copies of the Software, and to */
16
/* permit persons to whom the Software is furnished to do so, subject to */
17
/* the following conditions: */
18
/* */
19
/* The above copyright notice and this permission notice shall be */
20
/* included in all copies or substantial portions of the Software. */
21
/* */
22
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
23
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
24
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */
25
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
26
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
27
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
28
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
29
/**************************************************************************/
30
31
#include "texture_loader_ktx.h"
32
33
#include "core/io/file_access.h"
34
#include "core/io/file_access_memory.h"
35
#include "scene/resources/image_texture.h"
36
#include "servers/rendering/rendering_server.h"
37
38
#include <ktx.h>
39
#include <vk_format.h>
40
41
KTX_error_code ktx_read(ktxStream *stream, void *dst, const ktx_size_t count) {
42
Ref<FileAccess> *f = reinterpret_cast<Ref<FileAccess> *>(stream->data.custom_ptr.address);
43
(*f)->get_buffer(reinterpret_cast<uint8_t *>(dst), count);
44
return KTX_SUCCESS;
45
}
46
47
KTX_error_code ktx_skip(ktxStream *stream, const ktx_size_t count) {
48
Ref<FileAccess> *f = reinterpret_cast<Ref<FileAccess> *>(stream->data.custom_ptr.address);
49
for (ktx_size_t i = 0; i < count; ++i) {
50
(*f)->get_8();
51
}
52
return KTX_SUCCESS;
53
}
54
55
KTX_error_code ktx_write(ktxStream *stream, const void *src, const ktx_size_t size, const ktx_size_t count) {
56
Ref<FileAccess> *f = reinterpret_cast<Ref<FileAccess> *>(stream->data.custom_ptr.address);
57
(*f)->store_buffer(reinterpret_cast<const uint8_t *>(src), size * count);
58
return KTX_SUCCESS;
59
}
60
61
KTX_error_code ktx_getpos(ktxStream *stream, ktx_off_t *const offset) {
62
Ref<FileAccess> *f = reinterpret_cast<Ref<FileAccess> *>(stream->data.custom_ptr.address);
63
*offset = (*f)->get_position();
64
return KTX_SUCCESS;
65
}
66
67
KTX_error_code ktx_setpos(ktxStream *stream, const ktx_off_t offset) {
68
Ref<FileAccess> *f = reinterpret_cast<Ref<FileAccess> *>(stream->data.custom_ptr.address);
69
(*f)->seek(offset);
70
return KTX_SUCCESS;
71
}
72
73
KTX_error_code ktx_getsize(ktxStream *stream, ktx_size_t *const size) {
74
Ref<FileAccess> *f = reinterpret_cast<Ref<FileAccess> *>(stream->data.custom_ptr.address);
75
*size = (*f)->get_length();
76
return KTX_SUCCESS;
77
}
78
79
void ktx_destruct(ktxStream *stream) {
80
(void)stream;
81
}
82
83
static Ref<Image> load_from_file_access(Ref<FileAccess> f, Error *r_error) {
84
ktxStream ktx_stream;
85
ktx_stream.read = ktx_read;
86
ktx_stream.skip = ktx_skip;
87
ktx_stream.write = ktx_write;
88
ktx_stream.getpos = ktx_getpos;
89
ktx_stream.setpos = ktx_setpos;
90
ktx_stream.getsize = ktx_getsize;
91
ktx_stream.destruct = ktx_destruct;
92
ktx_stream.type = eStreamTypeCustom;
93
ktx_stream.data.custom_ptr.address = &f;
94
ktx_stream.data.custom_ptr.allocatorAddress = nullptr;
95
ktx_stream.data.custom_ptr.size = 0;
96
ktx_stream.readpos = 0;
97
ktx_stream.closeOnDestruct = false;
98
ktxTexture *ktx_texture;
99
KTX_error_code result = ktxTexture_CreateFromStream(&ktx_stream,
100
KTX_TEXTURE_CREATE_LOAD_IMAGE_DATA_BIT,
101
&ktx_texture);
102
if (result != KTX_SUCCESS) {
103
ERR_FAIL_V_MSG(Ref<Resource>(), "Invalid or unsupported KTX texture file.");
104
}
105
106
if (ktx_texture->numDimensions != 2) {
107
ktxTexture_Destroy(ktx_texture);
108
ERR_FAIL_V_MSG(Ref<Resource>(), "Unsupported non-2D KTX texture file.");
109
}
110
111
if (ktx_texture->isCubemap || ktx_texture->numFaces != 1) {
112
ktxTexture_Destroy(ktx_texture);
113
ERR_FAIL_V_MSG(Ref<Resource>(), "Unsupported cube map KTX texture file.");
114
}
115
116
if (ktx_texture->isArray) {
117
ktxTexture_Destroy(ktx_texture);
118
ERR_FAIL_V_MSG(Ref<Resource>(), "Unsupported array KTX texture file.");
119
}
120
121
uint32_t width = ktx_texture->baseWidth;
122
uint32_t height = ktx_texture->baseHeight;
123
uint32_t mipmaps = ktx_texture->numLevels;
124
Image::Format format;
125
bool srgb = false;
126
127
switch (ktx_texture->classId) {
128
case ktxTexture1_c:
129
switch (((ktxTexture1 *)ktx_texture)->glInternalformat) {
130
case GL_LUMINANCE:
131
format = Image::FORMAT_L8;
132
break;
133
case GL_LUMINANCE_ALPHA:
134
format = Image::FORMAT_LA8;
135
break;
136
case GL_SRGB8:
137
format = Image::FORMAT_RGB8;
138
srgb = true;
139
break;
140
case GL_SRGB8_ALPHA8:
141
format = Image::FORMAT_RGBA8;
142
srgb = true;
143
break;
144
case GL_R8:
145
case GL_R8UI:
146
format = Image::FORMAT_R8;
147
break;
148
case GL_RG8:
149
format = Image::FORMAT_RG8;
150
break;
151
case GL_RGB8:
152
format = Image::FORMAT_RGB8;
153
break;
154
case GL_RGBA8:
155
format = Image::FORMAT_RGBA8;
156
break;
157
case GL_RGBA4:
158
format = Image::FORMAT_RGBA4444;
159
break;
160
case GL_RGB565:
161
format = Image::FORMAT_RGB565;
162
break;
163
case GL_R32F:
164
format = Image::FORMAT_RF;
165
break;
166
case GL_RG32F:
167
format = Image::FORMAT_RGF;
168
break;
169
case GL_RGB32F:
170
format = Image::FORMAT_RGBF;
171
break;
172
case GL_RGBA32F:
173
format = Image::FORMAT_RGBAF;
174
break;
175
case GL_R16F:
176
format = Image::FORMAT_RH;
177
break;
178
case GL_RG16F:
179
format = Image::FORMAT_RGH;
180
break;
181
case GL_RGB16F:
182
format = Image::FORMAT_RGBH;
183
break;
184
case GL_RGBA16F:
185
format = Image::FORMAT_RGBAH;
186
break;
187
case GL_RGB9_E5:
188
format = Image::FORMAT_RGBE9995;
189
break;
190
case GL_R16:
191
format = Image::FORMAT_R16;
192
break;
193
case GL_RG16:
194
format = Image::FORMAT_RG16;
195
break;
196
case GL_RGB16:
197
format = Image::FORMAT_RGB16;
198
break;
199
case GL_RGBA16:
200
format = Image::FORMAT_RGBA16;
201
break;
202
case GL_R16UI:
203
format = Image::FORMAT_R16I;
204
break;
205
case GL_RG16UI:
206
format = Image::FORMAT_RG16I;
207
break;
208
case GL_RGB16UI:
209
format = Image::FORMAT_RGB16I;
210
break;
211
case GL_RGBA16UI:
212
format = Image::FORMAT_RGBA16I;
213
break;
214
case GL_COMPRESSED_RGB_S3TC_DXT1_EXT:
215
case GL_COMPRESSED_RGBA_S3TC_DXT1_EXT:
216
format = Image::FORMAT_DXT1;
217
break;
218
case GL_COMPRESSED_RGBA_S3TC_DXT3_EXT:
219
format = Image::FORMAT_DXT3;
220
break;
221
case GL_COMPRESSED_RGBA_S3TC_DXT5_EXT:
222
format = Image::FORMAT_DXT5;
223
break;
224
case GL_COMPRESSED_RED_RGTC1:
225
format = Image::FORMAT_RGTC_R;
226
break;
227
case GL_COMPRESSED_RG_RGTC2:
228
format = Image::FORMAT_RGTC_RG;
229
break;
230
case GL_COMPRESSED_RGB_BPTC_UNSIGNED_FLOAT:
231
format = Image::FORMAT_BPTC_RGBFU;
232
break;
233
case GL_COMPRESSED_RGBA_BPTC_UNORM:
234
format = Image::FORMAT_BPTC_RGBA;
235
break;
236
case GL_ETC1_RGB8_OES:
237
format = Image::FORMAT_ETC;
238
break;
239
case GL_COMPRESSED_R11_EAC:
240
format = Image::FORMAT_ETC2_R11;
241
break;
242
// Decompression is not supported for this format.
243
/*case GL_COMPRESSED_SIGNED_R11_EAC:
244
format = Image::FORMAT_ETC2_R11S;
245
break;*/
246
case GL_COMPRESSED_RG11_EAC:
247
format = Image::FORMAT_ETC2_RG11;
248
break;
249
// Decompression is not supported for this format.
250
/*case GL_COMPRESSED_SIGNED_RG11_EAC:
251
format = Image::FORMAT_ETC2_RG11S;
252
break;*/
253
case GL_COMPRESSED_RGB8_ETC2:
254
format = Image::FORMAT_ETC2_RGB8;
255
break;
256
case GL_COMPRESSED_RGBA8_ETC2_EAC:
257
format = Image::FORMAT_ETC2_RGBA8;
258
break;
259
// Decompression is not supported for this format.
260
/*case GL_COMPRESSED_RGB8_PUNCHTHROUGH_ALPHA1_ETC2:
261
format = Image::FORMAT_ETC2_RGB8A1;
262
break;*/
263
case GL_COMPRESSED_SRGB8_ALPHA8_ASTC_4x4_KHR:
264
format = Image::FORMAT_ASTC_4x4;
265
break;
266
case GL_COMPRESSED_RGBA_ASTC_4x4_KHR:
267
format = Image::FORMAT_ASTC_4x4_HDR;
268
break;
269
case GL_COMPRESSED_SRGB8_ALPHA8_ASTC_8x8_KHR:
270
format = Image::FORMAT_ASTC_8x8;
271
break;
272
case GL_COMPRESSED_RGBA_ASTC_8x8_KHR:
273
format = Image::FORMAT_ASTC_8x8_HDR;
274
break;
275
default:
276
ktxTexture_Destroy(ktx_texture);
277
ERR_FAIL_V_MSG(Ref<Resource>(), "Unsupported format " + itos(((ktxTexture1 *)ktx_texture)->glInternalformat) + " of KTX1 texture file.");
278
}
279
break;
280
case ktxTexture2_c: {
281
ktxTexture2 *ktx_texture2 = reinterpret_cast<ktxTexture2 *>(ktx_texture);
282
if (ktx_texture2->vkFormat == VK_FORMAT_UNDEFINED) {
283
if (!ktxTexture2_NeedsTranscoding(ktx_texture2)) {
284
ktxTexture_Destroy(ktx_texture);
285
ERR_FAIL_V_MSG(Ref<Resource>(), "Invalid VK_FORMAT_UNDEFINED of KTX2 texture file.");
286
}
287
ktx_transcode_fmt_e ktxfmt;
288
switch (ktxTexture2_GetNumComponents(ktx_texture2)) {
289
case 1: {
290
if (ktxTexture2_GetOETF_e(ktx_texture2) == KHR_DF_TRANSFER_SRGB) { // TODO srgb native support
291
ktxfmt = KTX_TTF_RGBA32;
292
} else if (RS::get_singleton()->has_os_feature("rgtc")) {
293
ktxfmt = KTX_TTF_BC4_R;
294
} else {
295
ktxfmt = KTX_TTF_RGBA32;
296
}
297
break;
298
}
299
case 2: {
300
if (ktxTexture2_GetOETF_e(ktx_texture2) == KHR_DF_TRANSFER_SRGB) { // TODO srgb native support
301
ktxfmt = KTX_TTF_RGBA32;
302
} else if (RS::get_singleton()->has_os_feature("rgtc")) {
303
ktxfmt = KTX_TTF_BC5_RG;
304
} else {
305
ktxfmt = KTX_TTF_RGBA32;
306
}
307
break;
308
}
309
case 3: {
310
if (ktxTexture2_GetOETF_e(ktx_texture2) == KHR_DF_TRANSFER_SRGB) { // TODO: srgb native support
311
ktxfmt = KTX_TTF_RGBA32;
312
} else if (RS::get_singleton()->has_os_feature("bptc")) {
313
ktxfmt = KTX_TTF_BC7_RGBA;
314
} else if (RS::get_singleton()->has_os_feature("s3tc")) {
315
ktxfmt = KTX_TTF_BC1_RGB;
316
} else if (RS::get_singleton()->has_os_feature("etc2")) {
317
ktxfmt = KTX_TTF_ETC1_RGB;
318
} else {
319
ktxfmt = KTX_TTF_RGBA32;
320
}
321
break;
322
}
323
case 4: {
324
if (ktxTexture2_GetOETF_e(ktx_texture2) == KHR_DF_TRANSFER_SRGB) { // TODO srgb native support
325
ktxfmt = KTX_TTF_RGBA32;
326
} else if (RS::get_singleton()->has_os_feature("astc")) {
327
ktxfmt = KTX_TTF_ASTC_4x4_RGBA;
328
} else if (RS::get_singleton()->has_os_feature("bptc")) {
329
ktxfmt = KTX_TTF_BC7_RGBA;
330
} else if (RS::get_singleton()->has_os_feature("s3tc")) {
331
ktxfmt = KTX_TTF_BC3_RGBA;
332
} else if (RS::get_singleton()->has_os_feature("etc2")) {
333
ktxfmt = KTX_TTF_ETC2_RGBA;
334
} else {
335
ktxfmt = KTX_TTF_RGBA32;
336
}
337
break;
338
}
339
default: {
340
ktxTexture_Destroy(ktx_texture);
341
ERR_FAIL_V_MSG(Ref<Resource>(), "Invalid components of KTX2 texture file.");
342
}
343
}
344
result = ktxTexture2_TranscodeBasis(ktx_texture2, ktxfmt, 0);
345
if (result != KTX_SUCCESS) {
346
ktxTexture_Destroy(ktx_texture);
347
ERR_FAIL_V_MSG(Ref<Resource>(), "Failed to transcode KTX2 texture file.");
348
}
349
}
350
switch (ktx_texture2->vkFormat) {
351
case VK_FORMAT_R8_UNORM:
352
format = Image::FORMAT_L8;
353
break;
354
case VK_FORMAT_R8G8_UNORM:
355
format = Image::FORMAT_LA8;
356
break;
357
case VK_FORMAT_R8G8B8_SRGB:
358
format = Image::FORMAT_RGB8;
359
srgb = true;
360
break;
361
case VK_FORMAT_R8G8B8A8_SRGB:
362
format = Image::FORMAT_RGBA8;
363
srgb = true;
364
break;
365
case VK_FORMAT_R8_UINT:
366
format = Image::FORMAT_R8;
367
break;
368
case VK_FORMAT_R8G8_UINT:
369
format = Image::FORMAT_RG8;
370
break;
371
case VK_FORMAT_R8G8B8_UINT:
372
format = Image::FORMAT_RGB8;
373
break;
374
case VK_FORMAT_R8G8B8A8_UINT:
375
format = Image::FORMAT_RGBA8;
376
break;
377
case VK_FORMAT_R4G4B4A4_UNORM_PACK16:
378
format = Image::FORMAT_RGBA4444;
379
break;
380
case VK_FORMAT_R5G6B5_UNORM_PACK16:
381
format = Image::FORMAT_RGB565;
382
break;
383
case VK_FORMAT_R32_SFLOAT:
384
format = Image::FORMAT_RF;
385
break;
386
case VK_FORMAT_R32G32_SFLOAT:
387
format = Image::FORMAT_RGF;
388
break;
389
case VK_FORMAT_R32G32B32_SFLOAT:
390
format = Image::FORMAT_RGBF;
391
break;
392
case VK_FORMAT_R32G32B32A32_SFLOAT:
393
format = Image::FORMAT_RGBAF;
394
break;
395
case VK_FORMAT_R16_SFLOAT:
396
format = Image::FORMAT_RH;
397
break;
398
case VK_FORMAT_R16G16_SFLOAT:
399
format = Image::FORMAT_RGH;
400
break;
401
case VK_FORMAT_R16G16B16_SFLOAT:
402
format = Image::FORMAT_RGBH;
403
break;
404
case VK_FORMAT_R16G16B16A16_SFLOAT:
405
format = Image::FORMAT_RGBAH;
406
break;
407
case VK_FORMAT_E5B9G9R9_UFLOAT_PACK32:
408
format = Image::FORMAT_RGBE9995;
409
break;
410
case VK_FORMAT_R16_UNORM:
411
format = Image::FORMAT_R16;
412
break;
413
case VK_FORMAT_R16G16_UNORM:
414
format = Image::FORMAT_RG16;
415
break;
416
case VK_FORMAT_R16G16B16_UNORM:
417
format = Image::FORMAT_RGB16;
418
break;
419
case VK_FORMAT_R16G16B16A16_UNORM:
420
format = Image::FORMAT_RGBA16;
421
break;
422
case VK_FORMAT_R16_UINT:
423
format = Image::FORMAT_R16I;
424
break;
425
case VK_FORMAT_R16G16_UINT:
426
format = Image::FORMAT_RG16I;
427
break;
428
case VK_FORMAT_R16G16B16_UINT:
429
format = Image::FORMAT_RGB16I;
430
break;
431
case VK_FORMAT_R16G16B16A16_UINT:
432
format = Image::FORMAT_RGBA16I;
433
break;
434
case VK_FORMAT_BC1_RGB_UNORM_BLOCK:
435
case VK_FORMAT_BC1_RGBA_UNORM_BLOCK:
436
format = Image::FORMAT_DXT1;
437
break;
438
case VK_FORMAT_BC2_UNORM_BLOCK:
439
format = Image::FORMAT_DXT3;
440
break;
441
case VK_FORMAT_BC3_UNORM_BLOCK:
442
format = Image::FORMAT_DXT5;
443
break;
444
case VK_FORMAT_BC4_UNORM_BLOCK:
445
format = Image::FORMAT_RGTC_R;
446
break;
447
case VK_FORMAT_BC5_UNORM_BLOCK:
448
format = Image::FORMAT_RGTC_RG;
449
break;
450
case VK_FORMAT_BC6H_UFLOAT_BLOCK:
451
format = Image::FORMAT_BPTC_RGBFU;
452
break;
453
case VK_FORMAT_BC6H_SFLOAT_BLOCK:
454
format = Image::FORMAT_BPTC_RGBF;
455
break;
456
case VK_FORMAT_BC7_UNORM_BLOCK:
457
format = Image::FORMAT_BPTC_RGBA;
458
break;
459
case VK_FORMAT_EAC_R11_UNORM_BLOCK:
460
format = Image::FORMAT_ETC2_R11;
461
break;
462
// Decompression is not supported for this format.
463
/*case VK_FORMAT_EAC_R11_SNORM_BLOCK:
464
format = Image::FORMAT_ETC2_R11S;
465
break;*/
466
case VK_FORMAT_EAC_R11G11_UNORM_BLOCK:
467
format = Image::FORMAT_ETC2_RG11;
468
break;
469
// Decompression is not supported for this format.
470
/*case VK_FORMAT_EAC_R11G11_SNORM_BLOCK:
471
format = Image::FORMAT_ETC2_RG11S;
472
break;*/
473
case VK_FORMAT_ETC2_R8G8B8_UNORM_BLOCK:
474
format = Image::FORMAT_ETC2_RGB8;
475
break;
476
case VK_FORMAT_ETC2_R8G8B8A8_UNORM_BLOCK:
477
format = Image::FORMAT_ETC2_RGBA8;
478
break;
479
// Decompression is not supported for this format.
480
/*case VK_FORMAT_ETC2_R8G8B8A1_UNORM_BLOCK:
481
format = Image::FORMAT_ETC2_RGB8A1;
482
break;*/
483
case VK_FORMAT_ASTC_4x4_SRGB_BLOCK:
484
format = Image::FORMAT_ASTC_4x4;
485
break;
486
case VK_FORMAT_ASTC_4x4_UNORM_BLOCK:
487
format = Image::FORMAT_ASTC_4x4_HDR;
488
break;
489
case VK_FORMAT_ASTC_8x8_SRGB_BLOCK:
490
format = Image::FORMAT_ASTC_8x8;
491
break;
492
case VK_FORMAT_ASTC_8x8_UNORM_BLOCK:
493
format = Image::FORMAT_ASTC_8x8_HDR;
494
break;
495
default:
496
ktxTexture_Destroy(ktx_texture);
497
ERR_FAIL_V_MSG(Ref<Resource>(), "Unsupported format " + itos(((ktxTexture2 *)ktx_texture)->vkFormat) + " of KTX2 texture file.");
498
break;
499
}
500
break;
501
}
502
default:
503
ktxTexture_Destroy(ktx_texture);
504
ERR_FAIL_V_MSG(Ref<Resource>(), "Unsupported version KTX texture file.");
505
break;
506
}
507
508
Vector<uint8_t> src_data;
509
510
// KTX use 4-bytes padding, don't use mipmaps if padding is effective
511
// TODO: unpad dynamically
512
int pixel_size = Image::get_format_pixel_size(format);
513
int pixel_rshift = Image::get_format_pixel_rshift(format);
514
int block = Image::get_format_block_size(format);
515
int minw, minh;
516
Image::get_format_min_pixel_size(format, minw, minh);
517
int w = width;
518
int h = height;
519
for (uint32_t i = 0; i < mipmaps; ++i) {
520
ktx_size_t mip_size = ktxTexture_GetImageSize(ktx_texture, i);
521
size_t bw = w % block != 0 ? w + (block - w % block) : w;
522
size_t bh = h % block != 0 ? h + (block - h % block) : h;
523
size_t s = bw * bh;
524
s *= pixel_size;
525
s >>= pixel_rshift;
526
if (mip_size != static_cast<ktx_size_t>(s)) {
527
if (!i) {
528
ktxTexture_Destroy(ktx_texture);
529
ERR_FAIL_V_MSG(Ref<Resource>(), "Unsupported padded KTX texture file.");
530
}
531
mipmaps = 1;
532
break;
533
}
534
w = MAX(minw, w >> 1);
535
h = MAX(minh, h >> 1);
536
}
537
538
for (uint32_t i = 0; i < mipmaps; ++i) {
539
ktx_size_t mip_size = ktxTexture_GetImageSize(ktx_texture, i);
540
ktx_size_t offset;
541
if (ktxTexture_GetImageOffset(ktx_texture, i, 0, 0, &offset) != KTX_SUCCESS) {
542
ktxTexture_Destroy(ktx_texture);
543
ERR_FAIL_V_MSG(Ref<Resource>(), "Invalid KTX texture file.");
544
}
545
int prev_size = src_data.size();
546
src_data.resize(prev_size + mip_size);
547
memcpy(src_data.ptrw() + prev_size, ktxTexture_GetData(ktx_texture) + offset, mip_size);
548
}
549
550
Ref<Image> img = memnew(Image(width, height, mipmaps - 1, format, src_data));
551
if (srgb) {
552
img->srgb_to_linear();
553
}
554
555
if (r_error) {
556
*r_error = OK;
557
}
558
559
ktxTexture_Destroy(ktx_texture);
560
return img;
561
}
562
563
Ref<Resource> ResourceFormatKTX::load(const String &p_path, const String &p_original_path, Error *r_error, bool p_use_sub_threads, float *r_progress, CacheMode p_cache_mode) {
564
if (r_error) {
565
*r_error = ERR_CANT_OPEN;
566
}
567
568
Error err;
569
Ref<FileAccess> f = FileAccess::open(p_path, FileAccess::READ, &err);
570
if (f.is_null()) {
571
return Ref<Resource>();
572
}
573
574
Ref<FileAccess> fref(f);
575
if (r_error) {
576
*r_error = ERR_FILE_CORRUPT;
577
}
578
579
ERR_FAIL_COND_V_MSG(err != OK, Ref<Resource>(), "Unable to open KTX texture file '" + p_path + "'.");
580
Ref<Image> img = load_from_file_access(f, r_error);
581
Ref<ImageTexture> texture = ImageTexture::create_from_image(img);
582
return texture;
583
}
584
585
static Ref<Image> _ktx_mem_loader_func(const uint8_t *p_ktx, int p_size) {
586
Ref<FileAccessMemory> f;
587
f.instantiate();
588
f->open_custom(p_ktx, p_size);
589
Error err;
590
Ref<Image> img = load_from_file_access(f, &err);
591
ERR_FAIL_COND_V(err, Ref<Image>());
592
return img;
593
}
594
595
void ResourceFormatKTX::get_recognized_extensions(List<String> *p_extensions) const {
596
p_extensions->push_back("ktx");
597
p_extensions->push_back("ktx2");
598
}
599
600
bool ResourceFormatKTX::handles_type(const String &p_type) const {
601
return ClassDB::is_parent_class(p_type, "Texture2D");
602
}
603
604
String ResourceFormatKTX::get_resource_type(const String &p_path) const {
605
if (p_path.has_extension("ktx") || p_path.has_extension("ktx2")) {
606
return "ImageTexture";
607
}
608
return "";
609
}
610
611
ResourceFormatKTX::ResourceFormatKTX() {
612
Image::_ktx_mem_loader_func = _ktx_mem_loader_func;
613
}
614
615