Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
godotengine
GitHub Repository: godotengine/godot
Path: blob/master/modules/ktx/texture_loader_ktx.cpp
10277 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
37
#include <ktx.h>
38
#include <vk_format.h>
39
40
KTX_error_code ktx_read(ktxStream *stream, void *dst, const ktx_size_t count) {
41
Ref<FileAccess> *f = reinterpret_cast<Ref<FileAccess> *>(stream->data.custom_ptr.address);
42
(*f)->get_buffer(reinterpret_cast<uint8_t *>(dst), count);
43
return KTX_SUCCESS;
44
}
45
46
KTX_error_code ktx_skip(ktxStream *stream, const ktx_size_t count) {
47
Ref<FileAccess> *f = reinterpret_cast<Ref<FileAccess> *>(stream->data.custom_ptr.address);
48
for (ktx_size_t i = 0; i < count; ++i) {
49
(*f)->get_8();
50
}
51
return KTX_SUCCESS;
52
}
53
54
KTX_error_code ktx_write(ktxStream *stream, const void *src, const ktx_size_t size, const ktx_size_t count) {
55
Ref<FileAccess> *f = reinterpret_cast<Ref<FileAccess> *>(stream->data.custom_ptr.address);
56
(*f)->store_buffer(reinterpret_cast<const uint8_t *>(src), size * count);
57
return KTX_SUCCESS;
58
}
59
60
KTX_error_code ktx_getpos(ktxStream *stream, ktx_off_t *const offset) {
61
Ref<FileAccess> *f = reinterpret_cast<Ref<FileAccess> *>(stream->data.custom_ptr.address);
62
*offset = (*f)->get_position();
63
return KTX_SUCCESS;
64
}
65
66
KTX_error_code ktx_setpos(ktxStream *stream, const ktx_off_t offset) {
67
Ref<FileAccess> *f = reinterpret_cast<Ref<FileAccess> *>(stream->data.custom_ptr.address);
68
(*f)->seek(offset);
69
return KTX_SUCCESS;
70
}
71
72
KTX_error_code ktx_getsize(ktxStream *stream, ktx_size_t *const size) {
73
Ref<FileAccess> *f = reinterpret_cast<Ref<FileAccess> *>(stream->data.custom_ptr.address);
74
*size = (*f)->get_length();
75
return KTX_SUCCESS;
76
}
77
78
void ktx_destruct(ktxStream *stream) {
79
(void)stream;
80
}
81
82
static Ref<Image> load_from_file_access(Ref<FileAccess> f, Error *r_error) {
83
ktxStream ktx_stream;
84
ktx_stream.read = ktx_read;
85
ktx_stream.skip = ktx_skip;
86
ktx_stream.write = ktx_write;
87
ktx_stream.getpos = ktx_getpos;
88
ktx_stream.setpos = ktx_setpos;
89
ktx_stream.getsize = ktx_getsize;
90
ktx_stream.destruct = ktx_destruct;
91
ktx_stream.type = eStreamTypeCustom;
92
ktx_stream.data.custom_ptr.address = &f;
93
ktx_stream.data.custom_ptr.allocatorAddress = nullptr;
94
ktx_stream.data.custom_ptr.size = 0;
95
ktx_stream.readpos = 0;
96
ktx_stream.closeOnDestruct = false;
97
ktxTexture *ktx_texture;
98
KTX_error_code result = ktxTexture_CreateFromStream(&ktx_stream,
99
KTX_TEXTURE_CREATE_LOAD_IMAGE_DATA_BIT,
100
&ktx_texture);
101
if (result != KTX_SUCCESS) {
102
ERR_FAIL_V_MSG(Ref<Resource>(), "Invalid or unsupported KTX texture file.");
103
}
104
105
if (ktx_texture->numDimensions != 2) {
106
ktxTexture_Destroy(ktx_texture);
107
ERR_FAIL_V_MSG(Ref<Resource>(), "Unsupported non-2D KTX texture file.");
108
}
109
110
if (ktx_texture->isCubemap || ktx_texture->numFaces != 1) {
111
ktxTexture_Destroy(ktx_texture);
112
ERR_FAIL_V_MSG(Ref<Resource>(), "Unsupported cube map KTX texture file.");
113
}
114
115
if (ktx_texture->isArray) {
116
ktxTexture_Destroy(ktx_texture);
117
ERR_FAIL_V_MSG(Ref<Resource>(), "Unsupported array KTX texture file.");
118
}
119
120
uint32_t width = ktx_texture->baseWidth;
121
uint32_t height = ktx_texture->baseHeight;
122
uint32_t mipmaps = ktx_texture->numLevels;
123
Image::Format format;
124
bool srgb = false;
125
126
switch (ktx_texture->classId) {
127
case ktxTexture1_c:
128
switch (((ktxTexture1 *)ktx_texture)->glInternalformat) {
129
case GL_LUMINANCE:
130
format = Image::FORMAT_L8;
131
break;
132
case GL_LUMINANCE_ALPHA:
133
format = Image::FORMAT_LA8;
134
break;
135
case GL_SRGB8:
136
format = Image::FORMAT_RGB8;
137
srgb = true;
138
break;
139
case GL_SRGB8_ALPHA8:
140
format = Image::FORMAT_RGBA8;
141
srgb = true;
142
break;
143
case GL_R8:
144
case GL_R8UI:
145
format = Image::FORMAT_R8;
146
break;
147
case GL_RG8:
148
format = Image::FORMAT_RG8;
149
break;
150
case GL_RGB8:
151
format = Image::FORMAT_RGB8;
152
break;
153
case GL_RGBA8:
154
format = Image::FORMAT_RGBA8;
155
break;
156
case GL_RGBA4:
157
format = Image::FORMAT_RGBA4444;
158
break;
159
case GL_RGB565:
160
format = Image::FORMAT_RGB565;
161
break;
162
case GL_R32F:
163
format = Image::FORMAT_RF;
164
break;
165
case GL_RG32F:
166
format = Image::FORMAT_RGF;
167
break;
168
case GL_RGB32F:
169
format = Image::FORMAT_RGBF;
170
break;
171
case GL_RGBA32F:
172
format = Image::FORMAT_RGBAF;
173
break;
174
case GL_R16F:
175
format = Image::FORMAT_RH;
176
break;
177
case GL_RG16F:
178
format = Image::FORMAT_RGH;
179
break;
180
case GL_RGB16F:
181
format = Image::FORMAT_RGBH;
182
break;
183
case GL_RGBA16F:
184
format = Image::FORMAT_RGBAH;
185
break;
186
case GL_RGB9_E5:
187
format = Image::FORMAT_RGBE9995;
188
break;
189
case GL_COMPRESSED_RGB_S3TC_DXT1_EXT:
190
case GL_COMPRESSED_RGBA_S3TC_DXT1_EXT:
191
format = Image::FORMAT_DXT1;
192
break;
193
case GL_COMPRESSED_RGBA_S3TC_DXT3_EXT:
194
format = Image::FORMAT_DXT3;
195
break;
196
case GL_COMPRESSED_RGBA_S3TC_DXT5_EXT:
197
format = Image::FORMAT_DXT5;
198
break;
199
case GL_COMPRESSED_RED_RGTC1:
200
format = Image::FORMAT_RGTC_R;
201
break;
202
case GL_COMPRESSED_RG_RGTC2:
203
format = Image::FORMAT_RGTC_RG;
204
break;
205
case GL_COMPRESSED_RGB_BPTC_UNSIGNED_FLOAT:
206
format = Image::FORMAT_BPTC_RGBFU;
207
break;
208
case GL_COMPRESSED_RGBA_BPTC_UNORM:
209
format = Image::FORMAT_BPTC_RGBA;
210
break;
211
case GL_ETC1_RGB8_OES:
212
format = Image::FORMAT_ETC;
213
break;
214
case GL_COMPRESSED_R11_EAC:
215
format = Image::FORMAT_ETC2_R11;
216
break;
217
// Decompression is not supported for this format.
218
/*case GL_COMPRESSED_SIGNED_R11_EAC:
219
format = Image::FORMAT_ETC2_R11S;
220
break;*/
221
case GL_COMPRESSED_RG11_EAC:
222
format = Image::FORMAT_ETC2_RG11;
223
break;
224
// Decompression is not supported for this format.
225
/*case GL_COMPRESSED_SIGNED_RG11_EAC:
226
format = Image::FORMAT_ETC2_RG11S;
227
break;*/
228
case GL_COMPRESSED_RGB8_ETC2:
229
format = Image::FORMAT_ETC2_RGB8;
230
break;
231
case GL_COMPRESSED_RGBA8_ETC2_EAC:
232
format = Image::FORMAT_ETC2_RGBA8;
233
break;
234
// Decompression is not supported for this format.
235
/*case GL_COMPRESSED_RGB8_PUNCHTHROUGH_ALPHA1_ETC2:
236
format = Image::FORMAT_ETC2_RGB8A1;
237
break;*/
238
case GL_COMPRESSED_SRGB8_ALPHA8_ASTC_4x4_KHR:
239
format = Image::FORMAT_ASTC_4x4;
240
break;
241
case GL_COMPRESSED_RGBA_ASTC_4x4_KHR:
242
format = Image::FORMAT_ASTC_4x4_HDR;
243
break;
244
case GL_COMPRESSED_SRGB8_ALPHA8_ASTC_8x8_KHR:
245
format = Image::FORMAT_ASTC_8x8;
246
break;
247
case GL_COMPRESSED_RGBA_ASTC_8x8_KHR:
248
format = Image::FORMAT_ASTC_8x8_HDR;
249
break;
250
default:
251
ktxTexture_Destroy(ktx_texture);
252
ERR_FAIL_V_MSG(Ref<Resource>(), "Unsupported format " + itos(((ktxTexture1 *)ktx_texture)->glInternalformat) + " of KTX1 texture file.");
253
}
254
break;
255
case ktxTexture2_c: {
256
ktxTexture2 *ktx_texture2 = reinterpret_cast<ktxTexture2 *>(ktx_texture);
257
if (ktx_texture2->vkFormat == VK_FORMAT_UNDEFINED) {
258
if (!ktxTexture2_NeedsTranscoding(ktx_texture2)) {
259
ktxTexture_Destroy(ktx_texture);
260
ERR_FAIL_V_MSG(Ref<Resource>(), "Invalid VK_FORMAT_UNDEFINED of KTX2 texture file.");
261
}
262
ktx_transcode_fmt_e ktxfmt;
263
switch (ktxTexture2_GetNumComponents(ktx_texture2)) {
264
case 1: {
265
if (ktxTexture2_GetOETF_e(ktx_texture2) == KHR_DF_TRANSFER_SRGB) { // TODO srgb native support
266
ktxfmt = KTX_TTF_RGBA32;
267
} else if (RS::get_singleton()->has_os_feature("rgtc")) {
268
ktxfmt = KTX_TTF_BC4_R;
269
} else {
270
ktxfmt = KTX_TTF_RGBA32;
271
}
272
break;
273
}
274
case 2: {
275
if (ktxTexture2_GetOETF_e(ktx_texture2) == KHR_DF_TRANSFER_SRGB) { // TODO srgb native support
276
ktxfmt = KTX_TTF_RGBA32;
277
} else if (RS::get_singleton()->has_os_feature("rgtc")) {
278
ktxfmt = KTX_TTF_BC5_RG;
279
} else {
280
ktxfmt = KTX_TTF_RGBA32;
281
}
282
break;
283
}
284
case 3: {
285
if (ktxTexture2_GetOETF_e(ktx_texture2) == KHR_DF_TRANSFER_SRGB) { // TODO: srgb native support
286
ktxfmt = KTX_TTF_RGBA32;
287
} else if (RS::get_singleton()->has_os_feature("bptc")) {
288
ktxfmt = KTX_TTF_BC7_RGBA;
289
} else if (RS::get_singleton()->has_os_feature("s3tc")) {
290
ktxfmt = KTX_TTF_BC1_RGB;
291
} else if (RS::get_singleton()->has_os_feature("etc2")) {
292
ktxfmt = KTX_TTF_ETC1_RGB;
293
} else {
294
ktxfmt = KTX_TTF_RGBA32;
295
}
296
break;
297
}
298
case 4: {
299
if (ktxTexture2_GetOETF_e(ktx_texture2) == KHR_DF_TRANSFER_SRGB) { // TODO srgb native support
300
ktxfmt = KTX_TTF_RGBA32;
301
} else if (RS::get_singleton()->has_os_feature("astc")) {
302
ktxfmt = KTX_TTF_ASTC_4x4_RGBA;
303
} else if (RS::get_singleton()->has_os_feature("bptc")) {
304
ktxfmt = KTX_TTF_BC7_RGBA;
305
} else if (RS::get_singleton()->has_os_feature("s3tc")) {
306
ktxfmt = KTX_TTF_BC3_RGBA;
307
} else if (RS::get_singleton()->has_os_feature("etc2")) {
308
ktxfmt = KTX_TTF_ETC2_RGBA;
309
} else {
310
ktxfmt = KTX_TTF_RGBA32;
311
}
312
break;
313
}
314
default: {
315
ktxTexture_Destroy(ktx_texture);
316
ERR_FAIL_V_MSG(Ref<Resource>(), "Invalid components of KTX2 texture file.");
317
}
318
}
319
result = ktxTexture2_TranscodeBasis(ktx_texture2, ktxfmt, 0);
320
if (result != KTX_SUCCESS) {
321
ktxTexture_Destroy(ktx_texture);
322
ERR_FAIL_V_MSG(Ref<Resource>(), "Failed to transcode KTX2 texture file.");
323
}
324
}
325
switch (ktx_texture2->vkFormat) {
326
case VK_FORMAT_R8_UNORM:
327
format = Image::FORMAT_L8;
328
break;
329
case VK_FORMAT_R8G8_UNORM:
330
format = Image::FORMAT_LA8;
331
break;
332
case VK_FORMAT_R8G8B8_SRGB:
333
format = Image::FORMAT_RGB8;
334
srgb = true;
335
break;
336
case VK_FORMAT_R8G8B8A8_SRGB:
337
format = Image::FORMAT_RGBA8;
338
srgb = true;
339
break;
340
case VK_FORMAT_R8_UINT:
341
format = Image::FORMAT_R8;
342
break;
343
case VK_FORMAT_R8G8_UINT:
344
format = Image::FORMAT_RG8;
345
break;
346
case VK_FORMAT_R8G8B8_UINT:
347
format = Image::FORMAT_RGB8;
348
break;
349
case VK_FORMAT_R8G8B8A8_UINT:
350
format = Image::FORMAT_RGBA8;
351
break;
352
case VK_FORMAT_R4G4B4A4_UNORM_PACK16:
353
format = Image::FORMAT_RGBA4444;
354
break;
355
case VK_FORMAT_R5G6B5_UNORM_PACK16:
356
format = Image::FORMAT_RGB565;
357
break;
358
case VK_FORMAT_R32_SFLOAT:
359
format = Image::FORMAT_RF;
360
break;
361
case VK_FORMAT_R32G32_SFLOAT:
362
format = Image::FORMAT_RGF;
363
break;
364
case VK_FORMAT_R32G32B32_SFLOAT:
365
format = Image::FORMAT_RGBF;
366
break;
367
case VK_FORMAT_R32G32B32A32_SFLOAT:
368
format = Image::FORMAT_RGBAF;
369
break;
370
case VK_FORMAT_R16_SFLOAT:
371
format = Image::FORMAT_RH;
372
break;
373
case VK_FORMAT_R16G16_SFLOAT:
374
format = Image::FORMAT_RGH;
375
break;
376
case VK_FORMAT_R16G16B16_SFLOAT:
377
format = Image::FORMAT_RGBH;
378
break;
379
case VK_FORMAT_R16G16B16A16_SFLOAT:
380
format = Image::FORMAT_RGBAH;
381
break;
382
case VK_FORMAT_E5B9G9R9_UFLOAT_PACK32:
383
format = Image::FORMAT_RGBE9995;
384
break;
385
case VK_FORMAT_BC1_RGB_UNORM_BLOCK:
386
case VK_FORMAT_BC1_RGBA_UNORM_BLOCK:
387
format = Image::FORMAT_DXT1;
388
break;
389
case VK_FORMAT_BC2_UNORM_BLOCK:
390
format = Image::FORMAT_DXT3;
391
break;
392
case VK_FORMAT_BC3_UNORM_BLOCK:
393
format = Image::FORMAT_DXT5;
394
break;
395
case VK_FORMAT_BC4_UNORM_BLOCK:
396
format = Image::FORMAT_RGTC_R;
397
break;
398
case VK_FORMAT_BC5_UNORM_BLOCK:
399
format = Image::FORMAT_RGTC_RG;
400
break;
401
case VK_FORMAT_BC6H_UFLOAT_BLOCK:
402
format = Image::FORMAT_BPTC_RGBFU;
403
break;
404
case VK_FORMAT_BC6H_SFLOAT_BLOCK:
405
format = Image::FORMAT_BPTC_RGBF;
406
break;
407
case VK_FORMAT_BC7_UNORM_BLOCK:
408
format = Image::FORMAT_BPTC_RGBA;
409
break;
410
case VK_FORMAT_EAC_R11_UNORM_BLOCK:
411
format = Image::FORMAT_ETC2_R11;
412
break;
413
// Decompression is not supported for this format.
414
/*case VK_FORMAT_EAC_R11_SNORM_BLOCK:
415
format = Image::FORMAT_ETC2_R11S;
416
break;*/
417
case VK_FORMAT_EAC_R11G11_UNORM_BLOCK:
418
format = Image::FORMAT_ETC2_RG11;
419
break;
420
// Decompression is not supported for this format.
421
/*case VK_FORMAT_EAC_R11G11_SNORM_BLOCK:
422
format = Image::FORMAT_ETC2_RG11S;
423
break;*/
424
case VK_FORMAT_ETC2_R8G8B8_UNORM_BLOCK:
425
format = Image::FORMAT_ETC2_RGB8;
426
break;
427
case VK_FORMAT_ETC2_R8G8B8A8_UNORM_BLOCK:
428
format = Image::FORMAT_ETC2_RGBA8;
429
break;
430
// Decompression is not supported for this format.
431
/*case VK_FORMAT_ETC2_R8G8B8A1_UNORM_BLOCK:
432
format = Image::FORMAT_ETC2_RGB8A1;
433
break;*/
434
case VK_FORMAT_ASTC_4x4_SRGB_BLOCK:
435
format = Image::FORMAT_ASTC_4x4;
436
break;
437
case VK_FORMAT_ASTC_4x4_UNORM_BLOCK:
438
format = Image::FORMAT_ASTC_4x4_HDR;
439
break;
440
case VK_FORMAT_ASTC_8x8_SRGB_BLOCK:
441
format = Image::FORMAT_ASTC_8x8;
442
break;
443
case VK_FORMAT_ASTC_8x8_UNORM_BLOCK:
444
format = Image::FORMAT_ASTC_8x8_HDR;
445
break;
446
default:
447
ktxTexture_Destroy(ktx_texture);
448
ERR_FAIL_V_MSG(Ref<Resource>(), "Unsupported format " + itos(((ktxTexture2 *)ktx_texture)->vkFormat) + " of KTX2 texture file.");
449
break;
450
}
451
break;
452
}
453
default:
454
ktxTexture_Destroy(ktx_texture);
455
ERR_FAIL_V_MSG(Ref<Resource>(), "Unsupported version KTX texture file.");
456
break;
457
}
458
459
Vector<uint8_t> src_data;
460
461
// KTX use 4-bytes padding, don't use mipmaps if padding is effective
462
// TODO: unpad dynamically
463
int pixel_size = Image::get_format_pixel_size(format);
464
int pixel_rshift = Image::get_format_pixel_rshift(format);
465
int block = Image::get_format_block_size(format);
466
int minw, minh;
467
Image::get_format_min_pixel_size(format, minw, minh);
468
int w = width;
469
int h = height;
470
for (uint32_t i = 0; i < mipmaps; ++i) {
471
ktx_size_t mip_size = ktxTexture_GetImageSize(ktx_texture, i);
472
size_t bw = w % block != 0 ? w + (block - w % block) : w;
473
size_t bh = h % block != 0 ? h + (block - h % block) : h;
474
size_t s = bw * bh;
475
s *= pixel_size;
476
s >>= pixel_rshift;
477
if (mip_size != static_cast<ktx_size_t>(s)) {
478
if (!i) {
479
ktxTexture_Destroy(ktx_texture);
480
ERR_FAIL_V_MSG(Ref<Resource>(), "Unsupported padded KTX texture file.");
481
}
482
mipmaps = 1;
483
break;
484
}
485
w = MAX(minw, w >> 1);
486
h = MAX(minh, h >> 1);
487
}
488
489
for (uint32_t i = 0; i < mipmaps; ++i) {
490
ktx_size_t mip_size = ktxTexture_GetImageSize(ktx_texture, i);
491
ktx_size_t offset;
492
if (ktxTexture_GetImageOffset(ktx_texture, i, 0, 0, &offset) != KTX_SUCCESS) {
493
ktxTexture_Destroy(ktx_texture);
494
ERR_FAIL_V_MSG(Ref<Resource>(), "Invalid KTX texture file.");
495
}
496
int prev_size = src_data.size();
497
src_data.resize(prev_size + mip_size);
498
memcpy(src_data.ptrw() + prev_size, ktxTexture_GetData(ktx_texture) + offset, mip_size);
499
}
500
501
Ref<Image> img = memnew(Image(width, height, mipmaps - 1, format, src_data));
502
if (srgb) {
503
img->srgb_to_linear();
504
}
505
506
if (r_error) {
507
*r_error = OK;
508
}
509
510
ktxTexture_Destroy(ktx_texture);
511
return img;
512
}
513
514
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) {
515
if (r_error) {
516
*r_error = ERR_CANT_OPEN;
517
}
518
519
Error err;
520
Ref<FileAccess> f = FileAccess::open(p_path, FileAccess::READ, &err);
521
if (f.is_null()) {
522
return Ref<Resource>();
523
}
524
525
Ref<FileAccess> fref(f);
526
if (r_error) {
527
*r_error = ERR_FILE_CORRUPT;
528
}
529
530
ERR_FAIL_COND_V_MSG(err != OK, Ref<Resource>(), "Unable to open KTX texture file '" + p_path + "'.");
531
Ref<Image> img = load_from_file_access(f, r_error);
532
Ref<ImageTexture> texture = ImageTexture::create_from_image(img);
533
return texture;
534
}
535
536
static Ref<Image> _ktx_mem_loader_func(const uint8_t *p_ktx, int p_size) {
537
Ref<FileAccessMemory> f;
538
f.instantiate();
539
f->open_custom(p_ktx, p_size);
540
Error err;
541
Ref<Image> img = load_from_file_access(f, &err);
542
ERR_FAIL_COND_V(err, Ref<Image>());
543
return img;
544
}
545
546
void ResourceFormatKTX::get_recognized_extensions(List<String> *p_extensions) const {
547
p_extensions->push_back("ktx");
548
p_extensions->push_back("ktx2");
549
}
550
551
bool ResourceFormatKTX::handles_type(const String &p_type) const {
552
return ClassDB::is_parent_class(p_type, "Texture2D");
553
}
554
555
String ResourceFormatKTX::get_resource_type(const String &p_path) const {
556
if (p_path.get_extension().to_lower() == "ktx" || p_path.get_extension().to_lower() == "ktx2") {
557
return "ImageTexture";
558
}
559
return "";
560
}
561
562
ResourceFormatKTX::ResourceFormatKTX() {
563
Image::_ktx_mem_loader_func = _ktx_mem_loader_func;
564
}
565
566