Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
godotengine
GitHub Repository: godotengine/godot
Path: blob/master/modules/ktx/texture_loader_ktx.cpp
11389 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_R16:
190
format = Image::FORMAT_R16;
191
break;
192
case GL_RG16:
193
format = Image::FORMAT_RG16;
194
break;
195
case GL_RGB16:
196
format = Image::FORMAT_RGB16;
197
break;
198
case GL_RGBA16:
199
format = Image::FORMAT_RGBA16;
200
break;
201
case GL_R16UI:
202
format = Image::FORMAT_R16I;
203
break;
204
case GL_RG16UI:
205
format = Image::FORMAT_RG16I;
206
break;
207
case GL_RGB16UI:
208
format = Image::FORMAT_RGB16I;
209
break;
210
case GL_RGBA16UI:
211
format = Image::FORMAT_RGBA16I;
212
break;
213
case GL_COMPRESSED_RGB_S3TC_DXT1_EXT:
214
case GL_COMPRESSED_RGBA_S3TC_DXT1_EXT:
215
format = Image::FORMAT_DXT1;
216
break;
217
case GL_COMPRESSED_RGBA_S3TC_DXT3_EXT:
218
format = Image::FORMAT_DXT3;
219
break;
220
case GL_COMPRESSED_RGBA_S3TC_DXT5_EXT:
221
format = Image::FORMAT_DXT5;
222
break;
223
case GL_COMPRESSED_RED_RGTC1:
224
format = Image::FORMAT_RGTC_R;
225
break;
226
case GL_COMPRESSED_RG_RGTC2:
227
format = Image::FORMAT_RGTC_RG;
228
break;
229
case GL_COMPRESSED_RGB_BPTC_UNSIGNED_FLOAT:
230
format = Image::FORMAT_BPTC_RGBFU;
231
break;
232
case GL_COMPRESSED_RGBA_BPTC_UNORM:
233
format = Image::FORMAT_BPTC_RGBA;
234
break;
235
case GL_ETC1_RGB8_OES:
236
format = Image::FORMAT_ETC;
237
break;
238
case GL_COMPRESSED_R11_EAC:
239
format = Image::FORMAT_ETC2_R11;
240
break;
241
// Decompression is not supported for this format.
242
/*case GL_COMPRESSED_SIGNED_R11_EAC:
243
format = Image::FORMAT_ETC2_R11S;
244
break;*/
245
case GL_COMPRESSED_RG11_EAC:
246
format = Image::FORMAT_ETC2_RG11;
247
break;
248
// Decompression is not supported for this format.
249
/*case GL_COMPRESSED_SIGNED_RG11_EAC:
250
format = Image::FORMAT_ETC2_RG11S;
251
break;*/
252
case GL_COMPRESSED_RGB8_ETC2:
253
format = Image::FORMAT_ETC2_RGB8;
254
break;
255
case GL_COMPRESSED_RGBA8_ETC2_EAC:
256
format = Image::FORMAT_ETC2_RGBA8;
257
break;
258
// Decompression is not supported for this format.
259
/*case GL_COMPRESSED_RGB8_PUNCHTHROUGH_ALPHA1_ETC2:
260
format = Image::FORMAT_ETC2_RGB8A1;
261
break;*/
262
case GL_COMPRESSED_SRGB8_ALPHA8_ASTC_4x4_KHR:
263
format = Image::FORMAT_ASTC_4x4;
264
break;
265
case GL_COMPRESSED_RGBA_ASTC_4x4_KHR:
266
format = Image::FORMAT_ASTC_4x4_HDR;
267
break;
268
case GL_COMPRESSED_SRGB8_ALPHA8_ASTC_8x8_KHR:
269
format = Image::FORMAT_ASTC_8x8;
270
break;
271
case GL_COMPRESSED_RGBA_ASTC_8x8_KHR:
272
format = Image::FORMAT_ASTC_8x8_HDR;
273
break;
274
default:
275
ktxTexture_Destroy(ktx_texture);
276
ERR_FAIL_V_MSG(Ref<Resource>(), "Unsupported format " + itos(((ktxTexture1 *)ktx_texture)->glInternalformat) + " of KTX1 texture file.");
277
}
278
break;
279
case ktxTexture2_c: {
280
ktxTexture2 *ktx_texture2 = reinterpret_cast<ktxTexture2 *>(ktx_texture);
281
if (ktx_texture2->vkFormat == VK_FORMAT_UNDEFINED) {
282
if (!ktxTexture2_NeedsTranscoding(ktx_texture2)) {
283
ktxTexture_Destroy(ktx_texture);
284
ERR_FAIL_V_MSG(Ref<Resource>(), "Invalid VK_FORMAT_UNDEFINED of KTX2 texture file.");
285
}
286
ktx_transcode_fmt_e ktxfmt;
287
switch (ktxTexture2_GetNumComponents(ktx_texture2)) {
288
case 1: {
289
if (ktxTexture2_GetOETF_e(ktx_texture2) == KHR_DF_TRANSFER_SRGB) { // TODO srgb native support
290
ktxfmt = KTX_TTF_RGBA32;
291
} else if (RS::get_singleton()->has_os_feature("rgtc")) {
292
ktxfmt = KTX_TTF_BC4_R;
293
} else {
294
ktxfmt = KTX_TTF_RGBA32;
295
}
296
break;
297
}
298
case 2: {
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("rgtc")) {
302
ktxfmt = KTX_TTF_BC5_RG;
303
} else {
304
ktxfmt = KTX_TTF_RGBA32;
305
}
306
break;
307
}
308
case 3: {
309
if (ktxTexture2_GetOETF_e(ktx_texture2) == KHR_DF_TRANSFER_SRGB) { // TODO: srgb native support
310
ktxfmt = KTX_TTF_RGBA32;
311
} else if (RS::get_singleton()->has_os_feature("bptc")) {
312
ktxfmt = KTX_TTF_BC7_RGBA;
313
} else if (RS::get_singleton()->has_os_feature("s3tc")) {
314
ktxfmt = KTX_TTF_BC1_RGB;
315
} else if (RS::get_singleton()->has_os_feature("etc2")) {
316
ktxfmt = KTX_TTF_ETC1_RGB;
317
} else {
318
ktxfmt = KTX_TTF_RGBA32;
319
}
320
break;
321
}
322
case 4: {
323
if (ktxTexture2_GetOETF_e(ktx_texture2) == KHR_DF_TRANSFER_SRGB) { // TODO srgb native support
324
ktxfmt = KTX_TTF_RGBA32;
325
} else if (RS::get_singleton()->has_os_feature("astc")) {
326
ktxfmt = KTX_TTF_ASTC_4x4_RGBA;
327
} else if (RS::get_singleton()->has_os_feature("bptc")) {
328
ktxfmt = KTX_TTF_BC7_RGBA;
329
} else if (RS::get_singleton()->has_os_feature("s3tc")) {
330
ktxfmt = KTX_TTF_BC3_RGBA;
331
} else if (RS::get_singleton()->has_os_feature("etc2")) {
332
ktxfmt = KTX_TTF_ETC2_RGBA;
333
} else {
334
ktxfmt = KTX_TTF_RGBA32;
335
}
336
break;
337
}
338
default: {
339
ktxTexture_Destroy(ktx_texture);
340
ERR_FAIL_V_MSG(Ref<Resource>(), "Invalid components of KTX2 texture file.");
341
}
342
}
343
result = ktxTexture2_TranscodeBasis(ktx_texture2, ktxfmt, 0);
344
if (result != KTX_SUCCESS) {
345
ktxTexture_Destroy(ktx_texture);
346
ERR_FAIL_V_MSG(Ref<Resource>(), "Failed to transcode KTX2 texture file.");
347
}
348
}
349
switch (ktx_texture2->vkFormat) {
350
case VK_FORMAT_R8_UNORM:
351
format = Image::FORMAT_L8;
352
break;
353
case VK_FORMAT_R8G8_UNORM:
354
format = Image::FORMAT_LA8;
355
break;
356
case VK_FORMAT_R8G8B8_SRGB:
357
format = Image::FORMAT_RGB8;
358
srgb = true;
359
break;
360
case VK_FORMAT_R8G8B8A8_SRGB:
361
format = Image::FORMAT_RGBA8;
362
srgb = true;
363
break;
364
case VK_FORMAT_R8_UINT:
365
format = Image::FORMAT_R8;
366
break;
367
case VK_FORMAT_R8G8_UINT:
368
format = Image::FORMAT_RG8;
369
break;
370
case VK_FORMAT_R8G8B8_UINT:
371
format = Image::FORMAT_RGB8;
372
break;
373
case VK_FORMAT_R8G8B8A8_UINT:
374
format = Image::FORMAT_RGBA8;
375
break;
376
case VK_FORMAT_R4G4B4A4_UNORM_PACK16:
377
format = Image::FORMAT_RGBA4444;
378
break;
379
case VK_FORMAT_R5G6B5_UNORM_PACK16:
380
format = Image::FORMAT_RGB565;
381
break;
382
case VK_FORMAT_R32_SFLOAT:
383
format = Image::FORMAT_RF;
384
break;
385
case VK_FORMAT_R32G32_SFLOAT:
386
format = Image::FORMAT_RGF;
387
break;
388
case VK_FORMAT_R32G32B32_SFLOAT:
389
format = Image::FORMAT_RGBF;
390
break;
391
case VK_FORMAT_R32G32B32A32_SFLOAT:
392
format = Image::FORMAT_RGBAF;
393
break;
394
case VK_FORMAT_R16_SFLOAT:
395
format = Image::FORMAT_RH;
396
break;
397
case VK_FORMAT_R16G16_SFLOAT:
398
format = Image::FORMAT_RGH;
399
break;
400
case VK_FORMAT_R16G16B16_SFLOAT:
401
format = Image::FORMAT_RGBH;
402
break;
403
case VK_FORMAT_R16G16B16A16_SFLOAT:
404
format = Image::FORMAT_RGBAH;
405
break;
406
case VK_FORMAT_E5B9G9R9_UFLOAT_PACK32:
407
format = Image::FORMAT_RGBE9995;
408
break;
409
case VK_FORMAT_R16_UNORM:
410
format = Image::FORMAT_R16;
411
break;
412
case VK_FORMAT_R16G16_UNORM:
413
format = Image::FORMAT_RG16;
414
break;
415
case VK_FORMAT_R16G16B16_UNORM:
416
format = Image::FORMAT_RGB16;
417
break;
418
case VK_FORMAT_R16G16B16A16_UNORM:
419
format = Image::FORMAT_RGBA16;
420
break;
421
case VK_FORMAT_R16_UINT:
422
format = Image::FORMAT_R16I;
423
break;
424
case VK_FORMAT_R16G16_UINT:
425
format = Image::FORMAT_RG16I;
426
break;
427
case VK_FORMAT_R16G16B16_UINT:
428
format = Image::FORMAT_RGB16I;
429
break;
430
case VK_FORMAT_R16G16B16A16_UINT:
431
format = Image::FORMAT_RGBA16I;
432
break;
433
case VK_FORMAT_BC1_RGB_UNORM_BLOCK:
434
case VK_FORMAT_BC1_RGBA_UNORM_BLOCK:
435
format = Image::FORMAT_DXT1;
436
break;
437
case VK_FORMAT_BC2_UNORM_BLOCK:
438
format = Image::FORMAT_DXT3;
439
break;
440
case VK_FORMAT_BC3_UNORM_BLOCK:
441
format = Image::FORMAT_DXT5;
442
break;
443
case VK_FORMAT_BC4_UNORM_BLOCK:
444
format = Image::FORMAT_RGTC_R;
445
break;
446
case VK_FORMAT_BC5_UNORM_BLOCK:
447
format = Image::FORMAT_RGTC_RG;
448
break;
449
case VK_FORMAT_BC6H_UFLOAT_BLOCK:
450
format = Image::FORMAT_BPTC_RGBFU;
451
break;
452
case VK_FORMAT_BC6H_SFLOAT_BLOCK:
453
format = Image::FORMAT_BPTC_RGBF;
454
break;
455
case VK_FORMAT_BC7_UNORM_BLOCK:
456
format = Image::FORMAT_BPTC_RGBA;
457
break;
458
case VK_FORMAT_EAC_R11_UNORM_BLOCK:
459
format = Image::FORMAT_ETC2_R11;
460
break;
461
// Decompression is not supported for this format.
462
/*case VK_FORMAT_EAC_R11_SNORM_BLOCK:
463
format = Image::FORMAT_ETC2_R11S;
464
break;*/
465
case VK_FORMAT_EAC_R11G11_UNORM_BLOCK:
466
format = Image::FORMAT_ETC2_RG11;
467
break;
468
// Decompression is not supported for this format.
469
/*case VK_FORMAT_EAC_R11G11_SNORM_BLOCK:
470
format = Image::FORMAT_ETC2_RG11S;
471
break;*/
472
case VK_FORMAT_ETC2_R8G8B8_UNORM_BLOCK:
473
format = Image::FORMAT_ETC2_RGB8;
474
break;
475
case VK_FORMAT_ETC2_R8G8B8A8_UNORM_BLOCK:
476
format = Image::FORMAT_ETC2_RGBA8;
477
break;
478
// Decompression is not supported for this format.
479
/*case VK_FORMAT_ETC2_R8G8B8A1_UNORM_BLOCK:
480
format = Image::FORMAT_ETC2_RGB8A1;
481
break;*/
482
case VK_FORMAT_ASTC_4x4_SRGB_BLOCK:
483
format = Image::FORMAT_ASTC_4x4;
484
break;
485
case VK_FORMAT_ASTC_4x4_UNORM_BLOCK:
486
format = Image::FORMAT_ASTC_4x4_HDR;
487
break;
488
case VK_FORMAT_ASTC_8x8_SRGB_BLOCK:
489
format = Image::FORMAT_ASTC_8x8;
490
break;
491
case VK_FORMAT_ASTC_8x8_UNORM_BLOCK:
492
format = Image::FORMAT_ASTC_8x8_HDR;
493
break;
494
default:
495
ktxTexture_Destroy(ktx_texture);
496
ERR_FAIL_V_MSG(Ref<Resource>(), "Unsupported format " + itos(((ktxTexture2 *)ktx_texture)->vkFormat) + " of KTX2 texture file.");
497
break;
498
}
499
break;
500
}
501
default:
502
ktxTexture_Destroy(ktx_texture);
503
ERR_FAIL_V_MSG(Ref<Resource>(), "Unsupported version KTX texture file.");
504
break;
505
}
506
507
Vector<uint8_t> src_data;
508
509
// KTX use 4-bytes padding, don't use mipmaps if padding is effective
510
// TODO: unpad dynamically
511
int pixel_size = Image::get_format_pixel_size(format);
512
int pixel_rshift = Image::get_format_pixel_rshift(format);
513
int block = Image::get_format_block_size(format);
514
int minw, minh;
515
Image::get_format_min_pixel_size(format, minw, minh);
516
int w = width;
517
int h = height;
518
for (uint32_t i = 0; i < mipmaps; ++i) {
519
ktx_size_t mip_size = ktxTexture_GetImageSize(ktx_texture, i);
520
size_t bw = w % block != 0 ? w + (block - w % block) : w;
521
size_t bh = h % block != 0 ? h + (block - h % block) : h;
522
size_t s = bw * bh;
523
s *= pixel_size;
524
s >>= pixel_rshift;
525
if (mip_size != static_cast<ktx_size_t>(s)) {
526
if (!i) {
527
ktxTexture_Destroy(ktx_texture);
528
ERR_FAIL_V_MSG(Ref<Resource>(), "Unsupported padded KTX texture file.");
529
}
530
mipmaps = 1;
531
break;
532
}
533
w = MAX(minw, w >> 1);
534
h = MAX(minh, h >> 1);
535
}
536
537
for (uint32_t i = 0; i < mipmaps; ++i) {
538
ktx_size_t mip_size = ktxTexture_GetImageSize(ktx_texture, i);
539
ktx_size_t offset;
540
if (ktxTexture_GetImageOffset(ktx_texture, i, 0, 0, &offset) != KTX_SUCCESS) {
541
ktxTexture_Destroy(ktx_texture);
542
ERR_FAIL_V_MSG(Ref<Resource>(), "Invalid KTX texture file.");
543
}
544
int prev_size = src_data.size();
545
src_data.resize(prev_size + mip_size);
546
memcpy(src_data.ptrw() + prev_size, ktxTexture_GetData(ktx_texture) + offset, mip_size);
547
}
548
549
Ref<Image> img = memnew(Image(width, height, mipmaps - 1, format, src_data));
550
if (srgb) {
551
img->srgb_to_linear();
552
}
553
554
if (r_error) {
555
*r_error = OK;
556
}
557
558
ktxTexture_Destroy(ktx_texture);
559
return img;
560
}
561
562
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) {
563
if (r_error) {
564
*r_error = ERR_CANT_OPEN;
565
}
566
567
Error err;
568
Ref<FileAccess> f = FileAccess::open(p_path, FileAccess::READ, &err);
569
if (f.is_null()) {
570
return Ref<Resource>();
571
}
572
573
Ref<FileAccess> fref(f);
574
if (r_error) {
575
*r_error = ERR_FILE_CORRUPT;
576
}
577
578
ERR_FAIL_COND_V_MSG(err != OK, Ref<Resource>(), "Unable to open KTX texture file '" + p_path + "'.");
579
Ref<Image> img = load_from_file_access(f, r_error);
580
Ref<ImageTexture> texture = ImageTexture::create_from_image(img);
581
return texture;
582
}
583
584
static Ref<Image> _ktx_mem_loader_func(const uint8_t *p_ktx, int p_size) {
585
Ref<FileAccessMemory> f;
586
f.instantiate();
587
f->open_custom(p_ktx, p_size);
588
Error err;
589
Ref<Image> img = load_from_file_access(f, &err);
590
ERR_FAIL_COND_V(err, Ref<Image>());
591
return img;
592
}
593
594
void ResourceFormatKTX::get_recognized_extensions(List<String> *p_extensions) const {
595
p_extensions->push_back("ktx");
596
p_extensions->push_back("ktx2");
597
}
598
599
bool ResourceFormatKTX::handles_type(const String &p_type) const {
600
return ClassDB::is_parent_class(p_type, "Texture2D");
601
}
602
603
String ResourceFormatKTX::get_resource_type(const String &p_path) const {
604
if (p_path.get_extension().to_lower() == "ktx" || p_path.get_extension().to_lower() == "ktx2") {
605
return "ImageTexture";
606
}
607
return "";
608
}
609
610
ResourceFormatKTX::ResourceFormatKTX() {
611
Image::_ktx_mem_loader_func = _ktx_mem_loader_func;
612
}
613
614