Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
godotengine
GitHub Repository: godotengine/godot
Path: blob/master/thirdparty/libktx/lib/texture1.c
9903 views
1
/* -*- tab-width: 4; -*- */
2
/* vi: set sw=2 ts=4 expandtab: */
3
4
/*
5
* Copyright 2019-2020 The Khronos Group Inc.
6
* SPDX-License-Identifier: Apache-2.0
7
*/
8
9
/**
10
* @internal
11
* @file
12
* @~English
13
*
14
* @brief ktxTexture1 implementation. Support for KTX format.
15
*
16
* @author Mark Callow, www.edgewise-consulting.com
17
*/
18
19
#if defined(_WIN32)
20
#define _CRT_SECURE_NO_WARNINGS
21
#endif
22
23
#include <stdlib.h>
24
#include <string.h>
25
26
#include "dfdutils/dfd.h"
27
#include "ktx.h"
28
#include "ktxint.h"
29
#include "filestream.h"
30
#include "memstream.h"
31
#include "texture1.h"
32
#include "unused.h"
33
#include "gl_format.h"
34
35
typedef struct ktxTexture1_private {
36
ktx_bool_t _needSwap;
37
} ktxTexture1_private;
38
39
struct ktxTexture_vtbl ktxTexture1_vtbl;
40
struct ktxTexture_vtblInt ktxTexture1_vtblInt;
41
42
static KTX_error_code
43
ktxTexture1_constructCommon(ktxTexture1* This)
44
{
45
assert(This != NULL);
46
47
This->classId = ktxTexture1_c;
48
This->vtbl = &ktxTexture1_vtbl;
49
This->_protected->_vtbl = ktxTexture1_vtblInt;
50
This->_private = (ktxTexture1_private*)malloc(sizeof(ktxTexture1_private));
51
if (This->_private == NULL) {
52
return KTX_OUT_OF_MEMORY;
53
}
54
memset(This->_private, 0, sizeof(*This->_private));
55
56
return KTX_SUCCESS;
57
}
58
59
/**
60
* @memberof ktxTexture1 @private
61
* @copydoc ktxTexture2_construct
62
*/
63
static KTX_error_code
64
ktxTexture1_construct(ktxTexture1* This,
65
const ktxTextureCreateInfo* const createInfo,
66
ktxTextureCreateStorageEnum storageAllocation)
67
{
68
ktxTexture_protected* prtctd;
69
ktxFormatSize formatSize;
70
GLuint typeSize;
71
GLenum glFormat;
72
KTX_error_code result;
73
74
memset(This, 0, sizeof(*This));
75
76
This->glInternalformat = createInfo->glInternalformat;
77
glGetFormatSize(This->glInternalformat, &formatSize);
78
if (formatSize.blockSizeInBits == 0) {
79
// Most likely a deprecated legacy format.
80
return KTX_UNSUPPORTED_TEXTURE_TYPE;
81
}
82
glFormat= glGetFormatFromInternalFormat(createInfo->glInternalformat);
83
if (glFormat == GL_INVALID_VALUE) {
84
return KTX_INVALID_VALUE;
85
}
86
result = ktxTexture_construct(ktxTexture(This), createInfo, &formatSize);
87
if (result != KTX_SUCCESS)
88
return result;
89
90
result = ktxTexture1_constructCommon(This);
91
if (result != KTX_SUCCESS)
92
return result;
93
prtctd = This->_protected;
94
95
This->isCompressed
96
= (formatSize.flags & KTX_FORMAT_SIZE_COMPRESSED_BIT);
97
if (This->isCompressed) {
98
This->glFormat = 0;
99
This->glBaseInternalformat = glFormat;
100
This->glType = 0;
101
prtctd->_typeSize = 1;
102
} else {
103
This->glBaseInternalformat = This->glFormat = glFormat;
104
This->glType
105
= glGetTypeFromInternalFormat(createInfo->glInternalformat);
106
if (This->glType == GL_INVALID_VALUE) {
107
result = KTX_INVALID_VALUE;
108
goto cleanup;
109
}
110
typeSize = glGetTypeSizeFromType(This->glType);
111
assert(typeSize != GL_INVALID_VALUE);
112
113
/* Do some sanity checking */
114
if (typeSize != 1 &&
115
typeSize != 2 &&
116
typeSize != 4)
117
{
118
/* Only 8, 16, and 32-bit types are supported for byte-swapping.
119
* See UNPACK_SWAP_BYTES & table 8.4 in the OpenGL 4.4 spec.
120
*/
121
result = KTX_INVALID_VALUE;
122
goto cleanup;
123
}
124
prtctd->_typeSize = typeSize;
125
}
126
127
if (storageAllocation == KTX_TEXTURE_CREATE_ALLOC_STORAGE) {
128
This->dataSize
129
= ktxTexture_calcDataSizeTexture(ktxTexture(This));
130
This->pData = malloc(This->dataSize);
131
if (This->pData == NULL) {
132
result = KTX_OUT_OF_MEMORY;
133
goto cleanup;
134
}
135
}
136
return result;
137
138
cleanup:
139
ktxTexture1_destruct(This);
140
ktxTexture_destruct(ktxTexture(This));
141
return result;
142
}
143
144
/**
145
* @memberof ktxTexture1 @private
146
* @brief Construct a ktxTexture1 from a ktxStream reading from a KTX source.
147
*
148
* The KTX header, that must have been read prior to calling this, is passed
149
* to the function.
150
*
151
* The stream object is copied into the constructed ktxTexture1.
152
*
153
* The create flag KTX_TEXTURE_CREATE_LOAD_IMAGE_DATA_BIT should not be set,
154
* if the ktxTexture1 is ultimately to be uploaded to OpenGL or Vulkan. This
155
* will minimize memory usage by allowing, for example, loading the images
156
* directly from the source into a Vulkan staging buffer.
157
*
158
* The create flag KTX_TEXTURE_CREATE_RAW_KVDATA_BIT should not be used. It is
159
* provided solely to enable implementation of the @e libktx v1 API on top of
160
* ktxTexture1.
161
*
162
* @param[in] This pointer to a ktxTexture1-sized block of memory to
163
* initialize.
164
* @param[in] pStream pointer to the stream to read.
165
* @param[in] pHeader pointer to a KTX header that has already been read from
166
* the stream.
167
* @param[in] createFlags bitmask requesting specific actions during creation.
168
*
169
* @return KTX_SUCCESS on success, other KTX_* enum values on error.
170
*
171
* @exception KTX_FILE_DATA_ERROR
172
* Source data is inconsistent with the KTX
173
* specification.
174
* @exception KTX_FILE_READ_ERROR
175
* An error occurred while reading the source.
176
* @exception KTX_FILE_UNEXPECTED_EOF
177
* Not enough data in the source.
178
* @exception KTX_OUT_OF_MEMORY Not enough memory to load either the images or
179
* the key-value data.
180
* @exception KTX_UNKNOWN_FILE_FORMAT
181
* The source is not in KTX format.
182
* @exception KTX_UNSUPPORTED_TEXTURE_TYPE
183
* The source describes a texture type not
184
* supported by OpenGL or Vulkan, e.g, a 3D array.
185
*/
186
KTX_error_code
187
ktxTexture1_constructFromStreamAndHeader(ktxTexture1* This, ktxStream* pStream,
188
KTX_header* pHeader,
189
ktxTextureCreateFlags createFlags)
190
{
191
ktxTexture1_private* private;
192
KTX_error_code result;
193
KTX_supplemental_info suppInfo;
194
ktxStream* stream;
195
ktx_off_t pos;
196
ktx_size_t size;
197
ktxFormatSize formatSize;
198
199
assert(pHeader != NULL && pStream != NULL);
200
201
memset(This, 0, sizeof(*This));
202
result = ktxTexture_constructFromStream(ktxTexture(This), pStream, createFlags);
203
if (result != KTX_SUCCESS)
204
return result;
205
result = ktxTexture1_constructCommon(This);
206
if (result != KTX_SUCCESS) {
207
ktxTexture_destruct(ktxTexture(This));
208
return result;
209
}
210
211
private = This->_private;
212
stream = ktxTexture1_getStream(This);
213
214
result = ktxCheckHeader1_(pHeader, &suppInfo);
215
if (result != KTX_SUCCESS)
216
goto cleanup;
217
218
/*
219
* Initialize from pHeader info.
220
*/
221
This->glFormat = pHeader->glFormat;
222
This->glInternalformat = pHeader->glInternalformat;
223
This->glType = pHeader->glType;
224
glGetFormatSize(This->glInternalformat, &formatSize);
225
if (formatSize.blockSizeInBits == 0) {
226
// Most likely a deprecated legacy format.
227
result = KTX_UNSUPPORTED_TEXTURE_TYPE;
228
goto cleanup;
229
}
230
This->_protected->_formatSize = formatSize;
231
This->glBaseInternalformat = pHeader->glBaseInternalformat;
232
// Can these be done by a ktxTexture_constructFromStream?
233
This->numDimensions = suppInfo.textureDimension;
234
This->baseWidth = pHeader->pixelWidth;
235
assert(suppInfo.textureDimension > 0 && suppInfo.textureDimension < 4);
236
switch (suppInfo.textureDimension) {
237
case 1:
238
This->baseHeight = This->baseDepth = 1;
239
break;
240
case 2:
241
This->baseHeight = pHeader->pixelHeight;
242
This->baseDepth = 1;
243
break;
244
case 3:
245
This->baseHeight = pHeader->pixelHeight;
246
This->baseDepth = pHeader->pixelDepth;
247
break;
248
}
249
if (pHeader->numberOfArrayElements > 0) {
250
This->numLayers = pHeader->numberOfArrayElements;
251
This->isArray = KTX_TRUE;
252
} else {
253
This->numLayers = 1;
254
This->isArray = KTX_FALSE;
255
}
256
This->numFaces = pHeader->numberOfFaces;
257
if (pHeader->numberOfFaces == 6)
258
This->isCubemap = KTX_TRUE;
259
else
260
This->isCubemap = KTX_FALSE;
261
This->numLevels = pHeader->numberOfMipLevels;
262
This->isCompressed = suppInfo.compressed;
263
This->generateMipmaps = suppInfo.generateMipmaps;
264
if (pHeader->endianness == KTX_ENDIAN_REF_REV)
265
private->_needSwap = KTX_TRUE;
266
This->_protected->_typeSize = pHeader->glTypeSize;
267
268
/*
269
* Make an empty hash list.
270
*/
271
ktxHashList_Construct(&This->kvDataHead);
272
/*
273
* Load KVData.
274
*/
275
if (pHeader->bytesOfKeyValueData > 0) {
276
if (!(createFlags & KTX_TEXTURE_CREATE_SKIP_KVDATA_BIT)) {
277
ktx_uint32_t kvdLen = pHeader->bytesOfKeyValueData;
278
ktx_uint8_t* pKvd;
279
280
pKvd = malloc(kvdLen);
281
if (pKvd == NULL) {
282
result = KTX_OUT_OF_MEMORY;
283
goto cleanup;
284
}
285
286
result = stream->read(stream, pKvd, kvdLen);
287
if (result != KTX_SUCCESS)
288
goto cleanup;
289
290
if (private->_needSwap) {
291
/* Swap the counts inside the key & value data. */
292
ktx_uint8_t* src = pKvd;
293
ktx_uint8_t* end = pKvd + kvdLen;
294
while (src < end) {
295
ktx_uint32_t* pKeyAndValueByteSize = (ktx_uint32_t*)src;
296
_ktxSwapEndian32(pKeyAndValueByteSize, 1);
297
src += _KTX_PAD4(*pKeyAndValueByteSize);
298
}
299
}
300
301
if (!(createFlags & KTX_TEXTURE_CREATE_RAW_KVDATA_BIT)) {
302
char* orientation;
303
ktx_uint32_t orientationLen;
304
305
result = ktxHashList_Deserialize(&This->kvDataHead,
306
kvdLen, pKvd);
307
free(pKvd);
308
if (result != KTX_SUCCESS) {
309
goto cleanup;
310
}
311
312
result = ktxHashList_FindValue(&This->kvDataHead,
313
KTX_ORIENTATION_KEY,
314
&orientationLen,
315
(void**)&orientation);
316
assert(result != KTX_INVALID_VALUE);
317
if (result == KTX_SUCCESS) {
318
ktx_uint32_t count;
319
char orient[4] = {0, 0, 0, 0};
320
321
count = sscanf(orientation, KTX_ORIENTATION3_FMT,
322
&orient[0],
323
&orient[1],
324
&orient[2]);
325
326
if (count > This->numDimensions) {
327
// KTX 1 is less strict than KTX2 so there is a chance
328
// of having more dimensions than needed.
329
count = This->numDimensions;
330
}
331
switch (This->numDimensions) {
332
case 3:
333
This->orientation.z = orient[2];
334
FALLTHROUGH;
335
case 2:
336
This->orientation.y = orient[1];
337
FALLTHROUGH;
338
case 1:
339
This->orientation.x = orient[0];
340
}
341
}
342
} else {
343
This->kvDataLen = kvdLen;
344
This->kvData = pKvd;
345
}
346
} else {
347
stream->skip(stream, pHeader->bytesOfKeyValueData);
348
}
349
}
350
351
/*
352
* Get the size of the image data.
353
*/
354
result = stream->getsize(stream, &size);
355
if (result != KTX_SUCCESS)
356
goto cleanup;
357
358
result = stream->getpos(stream, &pos);
359
if (result != KTX_SUCCESS)
360
goto cleanup;
361
362
/* Remove space for faceLodSize fields */
363
This->dataSize = size - pos - This->numLevels * sizeof(ktx_uint32_t);
364
365
/*
366
* Load the images, if requested.
367
*/
368
if (createFlags & KTX_TEXTURE_CREATE_LOAD_IMAGE_DATA_BIT) {
369
result = ktxTexture1_LoadImageData(This, NULL, 0);
370
}
371
if (result == KTX_SUCCESS)
372
return result;
373
374
cleanup:
375
ktxTexture1_destruct(This);
376
return result;
377
}
378
379
/**
380
* @memberof ktxTexture1 @private
381
* @brief Construct a ktxTexture1 from a ktxStream reading from a KTX source.
382
*
383
* The stream object is copied into the constructed ktxTexture1.
384
*
385
* The create flag KTX_TEXTURE_CREATE_LOAD_IMAGE_DATA_BIT should not be set,
386
* if the ktxTexture1 is ultimately to be uploaded to OpenGL or Vulkan. This
387
* will minimize memory usage by allowing, for example, loading the images
388
* directly from the source into a Vulkan staging buffer.
389
*
390
* The create flag KTX_TEXTURE_CREATE_RAW_KVDATA_BIT should not be used. It is
391
* provided solely to enable implementation of the @e libktx v1 API on top of
392
* ktxTexture1.
393
*
394
* @param[in] This pointer to a ktxTexture1-sized block of memory to
395
* initialize.
396
* @param[in] pStream pointer to the stream to read.
397
* @param[in] createFlags bitmask requesting specific actions during creation.
398
*
399
* @return KTX_SUCCESS on success, other KTX_* enum values on error.
400
*
401
* @exception KTX_FILE_READ_ERROR
402
* An error occurred while reading the source.
403
*
404
* For other exceptions see ktxTexture1_constructFromStreamAndHeader().
405
*/
406
static KTX_error_code
407
ktxTexture1_constructFromStream(ktxTexture1* This, ktxStream* pStream,
408
ktxTextureCreateFlags createFlags)
409
{
410
KTX_header header;
411
KTX_error_code result;
412
413
// Read header.
414
result = pStream->read(pStream, &header, KTX_HEADER_SIZE);
415
if (result != KTX_SUCCESS)
416
return result;
417
418
return ktxTexture1_constructFromStreamAndHeader(This, pStream,
419
&header, createFlags);
420
}
421
422
/**
423
* @memberof ktxTexture1 @private
424
* @brief Construct a ktxTexture1 from a stdio stream reading from a KTX source.
425
*
426
* See ktxTextureInt_constructFromStream for details.
427
*
428
* @note Do not close the stdio stream until you are finished with the texture
429
* object.
430
*
431
* @param[in] This pointer to a ktxTextureInt-sized block of memory to
432
* initialize.
433
* @param[in] stdioStream a stdio FILE pointer opened on the source.
434
* @param[in] createFlags bitmask requesting specific actions during creation.
435
*
436
* @return KTX_SUCCESS on success, other KTX_* enum values on error.
437
*
438
* @exception KTX_INVALID_VALUE Either @p stdiostream or @p This is null.
439
*
440
* For other exceptions, see ktxTexture_constructFromStream().
441
*/
442
static KTX_error_code
443
ktxTexture1_constructFromStdioStream(ktxTexture1* This, FILE* stdioStream,
444
ktxTextureCreateFlags createFlags)
445
{
446
ktxStream stream;
447
KTX_error_code result;
448
449
if (stdioStream == NULL || This == NULL)
450
return KTX_INVALID_VALUE;
451
452
result = ktxFileStream_construct(&stream, stdioStream, KTX_FALSE);
453
if (result == KTX_SUCCESS)
454
result = ktxTexture1_constructFromStream(This, &stream, createFlags);
455
return result;
456
}
457
458
/**
459
* @memberof ktxTexture1 @private
460
* @brief Construct a ktxTexture1 from a named KTX file.
461
*
462
* The file name must be encoded in utf-8. On Windows convert unicode names
463
* to utf-8 with @c WideCharToMultiByte(CP_UTF8, ...) before calling.
464
*
465
* See ktxTextureInt_constructFromStream for details.
466
*
467
* @param[in] This pointer to a ktxTextureInt-sized block of memory to
468
* initialize.
469
* @param[in] filename pointer to a char array containing the file name.
470
* @param[in] createFlags bitmask requesting specific actions during creation.
471
*
472
* @return KTX_SUCCESS on success, other KTX_* enum values on error.
473
*
474
* @exception KTX_FILE_OPEN_FAILED The file could not be opened.
475
* @exception KTX_INVALID_VALUE @p filename is @c NULL.
476
*
477
* For other exceptions, see ktxTexture_constructFromStream().
478
*/
479
static KTX_error_code
480
ktxTexture1_constructFromNamedFile(ktxTexture1* This,
481
const char* const filename,
482
ktxTextureCreateFlags createFlags)
483
{
484
FILE* file;
485
ktxStream stream;
486
KTX_error_code result;
487
488
if (This == NULL || filename == NULL)
489
return KTX_INVALID_VALUE;
490
491
file = ktxFOpenUTF8(filename, "rb");
492
if (!file)
493
return KTX_FILE_OPEN_FAILED;
494
495
result = ktxFileStream_construct(&stream, file, KTX_TRUE);
496
if (result == KTX_SUCCESS)
497
result = ktxTexture1_constructFromStream(This, &stream, createFlags);
498
499
return result;
500
}
501
502
/**
503
* @memberof ktxTexture1 @private
504
* @brief Construct a ktxTexture1 from KTX-formatted data in memory.
505
*
506
* See ktxTextureInt_constructFromStream for details.
507
*
508
* @param[in] This pointer to a ktxTextureInt-sized block of memory to
509
* initialize.
510
* @param[in] bytes pointer to the memory containing the serialized KTX data.
511
* @param[in] size length of the KTX data in bytes.
512
* @param[in] createFlags bitmask requesting specific actions during creation.
513
*
514
* @return KTX_SUCCESS on success, other KTX_* enum values on error.
515
*
516
* @exception KTX_INVALID_VALUE Either @p bytes is NULL or @p size is 0.
517
*
518
* For other exceptions, see ktxTexture_constructFromStream().
519
*/
520
static KTX_error_code
521
ktxTexture1_constructFromMemory(ktxTexture1* This,
522
const ktx_uint8_t* bytes, ktx_size_t size,
523
ktxTextureCreateFlags createFlags)
524
{
525
ktxStream stream;
526
KTX_error_code result;
527
528
if (bytes == NULL || size == 0)
529
return KTX_INVALID_VALUE;
530
531
result = ktxMemStream_construct_ro(&stream, bytes, size);
532
if (result == KTX_SUCCESS)
533
result = ktxTexture1_constructFromStream(This, &stream, createFlags);
534
535
return result;
536
}
537
538
void
539
ktxTexture1_destruct(ktxTexture1* This)
540
{
541
if (This->_private) free(This->_private);
542
ktxTexture_destruct(ktxTexture(This));
543
}
544
545
/**
546
* @defgroup reader Reader
547
* @brief Read KTX-formatted data.
548
* @{
549
*/
550
551
/**
552
* @memberof ktxTexture1
553
* @ingroup writer
554
* @brief Create a new empty ktxTexture1.
555
*
556
* The address of the newly created ktxTexture1 is written to the location
557
* pointed at by @p newTex.
558
*
559
* @param[in] createInfo pointer to a ktxTextureCreateInfo struct with
560
* information describing the texture.
561
* @param[in] storageAllocation
562
* enum indicating whether or not to allocate storage
563
* for the texture images.
564
* @param[in,out] newTex pointer to a location in which store the address of
565
* the newly created texture.
566
*
567
* @return KTX_SUCCESS on success, other KTX_* enum values on error.
568
*
569
* @exception KTX_INVALID_VALUE @c glInternalFormat in @p createInfo is not a
570
* valid OpenGL internal format value.
571
* @exception KTX_INVALID_VALUE @c numDimensions in @p createInfo is not 1, 2
572
* or 3.
573
* @exception KTX_INVALID_VALUE One of <tt>base{Width,Height,Depth}</tt> in
574
* @p createInfo is 0.
575
* @exception KTX_INVALID_VALUE @c numFaces in @p createInfo is not 1 or 6.
576
* @exception KTX_INVALID_VALUE @c numLevels in @p createInfo is 0.
577
* @exception KTX_INVALID_OPERATION
578
* The <tt>base{Width,Height,Depth}</tt> specified
579
* in @p createInfo are inconsistent with
580
* @c numDimensions.
581
* @exception KTX_INVALID_OPERATION
582
* @p createInfo is requesting a 3D array or
583
* 3D cubemap texture.
584
* @exception KTX_INVALID_OPERATION
585
* @p createInfo is requesting a cubemap with
586
* non-square or non-2D images.
587
* @exception KTX_INVALID_OPERATION
588
* @p createInfo is requesting more mip levels
589
* than needed for the specified
590
* <tt>base{Width,Height,Depth}</tt>.
591
* @exception KTX_OUT_OF_MEMORY Not enough memory for the texture's images.
592
*/
593
KTX_error_code
594
ktxTexture1_Create(const ktxTextureCreateInfo* const createInfo,
595
ktxTextureCreateStorageEnum storageAllocation,
596
ktxTexture1** newTex)
597
{
598
KTX_error_code result;
599
600
if (newTex == NULL)
601
return KTX_INVALID_VALUE;
602
603
ktxTexture1* tex = (ktxTexture1*)malloc(sizeof(ktxTexture1));
604
if (tex == NULL)
605
return KTX_OUT_OF_MEMORY;
606
607
result = ktxTexture1_construct(tex, createInfo, storageAllocation);
608
if (result != KTX_SUCCESS) {
609
free(tex);
610
} else {
611
*newTex = tex;
612
}
613
return result;
614
}
615
616
/**
617
* @memberof ktxTexture1
618
* @~English
619
* @brief Create a ktxTexture1 from a stdio stream reading from a KTX source.
620
*
621
* The address of a newly created texture reflecting the contents of the
622
* stdio stream is written to the location pointed at by @p newTex.
623
*
624
* The create flag KTX_TEXTURE_CREATE_LOAD_IMAGE_DATA_BIT should not be set,
625
* if the ktxTexture1 is ultimately to be uploaded to OpenGL or Vulkan. This
626
* will minimize memory usage by allowing, for example, loading the images
627
* directly from the source into a Vulkan staging buffer.
628
*
629
* The create flag KTX_TEXTURE_CREATE_RAW_KVDATA_BIT should not be used. It is
630
* provided solely to enable implementation of the @e libktx v1 API on top of
631
* ktxTexture1.
632
*
633
* @param[in] stdioStream stdio FILE pointer created from the desired file.
634
* @param[in] createFlags bitmask requesting specific actions during creation.
635
* @param[in,out] newTex pointer to a location in which store the address of
636
* the newly created texture.
637
*
638
* @return KTX_SUCCESS on success, other KTX_* enum values on error.
639
*
640
* @exception KTX_INVALID_VALUE @p newTex is @c NULL.
641
* @exception KTX_FILE_DATA_ERROR
642
* Source data is inconsistent with the KTX
643
* specification.
644
* @exception KTX_FILE_READ_ERROR
645
* An error occurred while reading the source.
646
* @exception KTX_FILE_UNEXPECTED_EOF
647
* Not enough data in the source.
648
* @exception KTX_OUT_OF_MEMORY Not enough memory to create the texture object,
649
* load the images or load the key-value data.
650
* @exception KTX_UNKNOWN_FILE_FORMAT
651
* The source is not in KTX format.
652
* @exception KTX_UNSUPPORTED_TEXTURE_TYPE
653
* The source describes a texture type not
654
* supported by OpenGL or Vulkan, e.g, a 3D array.
655
*/
656
KTX_error_code
657
ktxTexture1_CreateFromStdioStream(FILE* stdioStream,
658
ktxTextureCreateFlags createFlags,
659
ktxTexture1** newTex)
660
{
661
KTX_error_code result;
662
if (newTex == NULL)
663
return KTX_INVALID_VALUE;
664
665
ktxTexture1* tex = (ktxTexture1*)malloc(sizeof(ktxTexture1));
666
if (tex == NULL)
667
return KTX_OUT_OF_MEMORY;
668
669
result = ktxTexture1_constructFromStdioStream(tex, stdioStream,
670
createFlags);
671
if (result == KTX_SUCCESS)
672
*newTex = (ktxTexture1*)tex;
673
else {
674
free(tex);
675
*newTex = NULL;
676
}
677
return result;
678
}
679
680
/**
681
* @memberof ktxTexture1
682
* @~English
683
* @brief Create a ktxTexture1 from a named KTX file.
684
*
685
* The address of a newly created texture reflecting the contents of the
686
* file is written to the location pointed at by @p newTex.
687
*
688
* The file name must be encoded in utf-8. On Windows convert unicode names
689
* to utf-8 with @c WideCharToMultiByte(CP_UTF8, ...) before calling.
690
*
691
* The create flag KTX_TEXTURE_CREATE_LOAD_IMAGE_DATA_BIT should not be set,
692
* if the ktxTexture1 is ultimately to be uploaded to OpenGL or Vulkan. This
693
* will minimize memory usage by allowing, for example, loading the images
694
* directly from the source into a Vulkan staging buffer.
695
*
696
* The create flag KTX_TEXTURE_CREATE_RAW_KVDATA_BIT should not be used. It is
697
* provided solely to enable implementation of the @e libktx v1 API on top of
698
* ktxTexture1.
699
*
700
* @param[in] filename pointer to a char array containing the file name.
701
* @param[in] createFlags bitmask requesting specific actions during creation.
702
* @param[in,out] newTex pointer to a location in which store the address of
703
* the newly created texture.
704
*
705
* @return KTX_SUCCESS on success, other KTX_* enum values on error.
706
*
707
* @exception KTX_FILE_OPEN_FAILED The file could not be opened.
708
* @exception KTX_INVALID_VALUE @p filename is @c NULL.
709
*
710
* For other exceptions, see ktxTexture1_CreateFromStdioStream().
711
*/
712
KTX_error_code
713
ktxTexture1_CreateFromNamedFile(const char* const filename,
714
ktxTextureCreateFlags createFlags,
715
ktxTexture1** newTex)
716
{
717
KTX_error_code result;
718
719
if (newTex == NULL)
720
return KTX_INVALID_VALUE;
721
722
ktxTexture1* tex = (ktxTexture1*)malloc(sizeof(ktxTexture1));
723
if (tex == NULL)
724
return KTX_OUT_OF_MEMORY;
725
726
result = ktxTexture1_constructFromNamedFile(tex, filename, createFlags);
727
if (result == KTX_SUCCESS)
728
*newTex = (ktxTexture1*)tex;
729
else {
730
free(tex);
731
*newTex = NULL;
732
}
733
return result;
734
}
735
736
/**
737
* @memberof ktxTexture1
738
* @~English
739
* @brief Create a ktxTexture1 from KTX-formatted data in memory.
740
*
741
* The address of a newly created texture reflecting the contents of the
742
* serialized KTX data is written to the location pointed at by @p newTex.
743
*
744
* The create flag KTX_TEXTURE_CREATE_LOAD_IMAGE_DATA_BIT should not be set,
745
* if the ktxTexture1 is ultimately to be uploaded to OpenGL or Vulkan. This
746
* will minimize memory usage by allowing, for example, loading the images
747
* directly from the source into a Vulkan staging buffer.
748
*
749
* The create flag KTX_TEXTURE_CREATE_RAW_KVDATA_BIT should not be used. It is
750
* provided solely to enable implementation of the @e libktx v1 API on top of
751
* ktxTexture1.
752
*
753
* @param[in] bytes pointer to the memory containing the serialized KTX data.
754
* @param[in] size length of the KTX data in bytes.
755
* @param[in] createFlags bitmask requesting specific actions during creation.
756
* @param[in,out] newTex pointer to a location in which store the address of
757
* the newly created texture.
758
*
759
* @return KTX_SUCCESS on success, other KTX_* enum values on error.
760
*
761
* @exception KTX_INVALID_VALUE Either @p bytes is NULL or @p size is 0.
762
*
763
* For other exceptions, see ktxTexture1_CreateFromStdioStream().
764
*/
765
KTX_error_code
766
ktxTexture1_CreateFromMemory(const ktx_uint8_t* bytes, ktx_size_t size,
767
ktxTextureCreateFlags createFlags,
768
ktxTexture1** newTex)
769
{
770
KTX_error_code result;
771
if (newTex == NULL)
772
return KTX_INVALID_VALUE;
773
774
ktxTexture1* tex = (ktxTexture1*)malloc(sizeof(ktxTexture1));
775
if (tex == NULL)
776
return KTX_OUT_OF_MEMORY;
777
778
result = ktxTexture1_constructFromMemory(tex, bytes, size,
779
createFlags);
780
if (result == KTX_SUCCESS)
781
*newTex = (ktxTexture1*)tex;
782
else {
783
free(tex);
784
*newTex = NULL;
785
}
786
return result;
787
}
788
789
/**
790
* @memberof ktxTexture1
791
* @~English
792
* @brief Create a ktxTexture1 from KTX-formatted data from a `ktxStream`.
793
*
794
* The address of a newly created texture reflecting the contents of the
795
* serialized KTX data is written to the location pointed at by @p newTex.
796
*
797
* The create flag KTX_TEXTURE_CREATE_LOAD_IMAGE_DATA_BIT should not be set,
798
* if the ktxTexture1 is ultimately to be uploaded to OpenGL or Vulkan. This
799
* will minimize memory usage by allowing, for example, loading the images
800
* directly from the source into a Vulkan staging buffer.
801
*
802
* The create flag KTX_TEXTURE_CREATE_RAW_KVDATA_BIT should not be used. It is
803
* provided solely to enable implementation of the @e libktx v1 API on top of
804
* ktxTexture1.
805
*
806
* @param[in] pStream pointer to the stream to read KTX data from.
807
* @param[in] createFlags bitmask requesting specific actions during creation.
808
* @param[in,out] newTex pointer to a location in which store the address of
809
* the newly created texture.
810
*
811
* @return KTX_SUCCESS on success, other KTX_* enum values on error.
812
*
813
* For exceptions, see ktxTexture1_CreateFromStdioStream().
814
*/
815
KTX_error_code
816
ktxTexture1_CreateFromStream(ktxStream* pStream,
817
ktxTextureCreateFlags createFlags,
818
ktxTexture1** newTex)
819
{
820
KTX_error_code result;
821
if (newTex == NULL)
822
return KTX_INVALID_VALUE;
823
824
ktxTexture1* tex = (ktxTexture1*)malloc(sizeof(ktxTexture1));
825
if (tex == NULL)
826
return KTX_OUT_OF_MEMORY;
827
828
result = ktxTexture1_constructFromStream(tex, pStream, createFlags);
829
if (result == KTX_SUCCESS)
830
*newTex = (ktxTexture1*)tex;
831
else {
832
free(tex);
833
*newTex = NULL;
834
}
835
return result;
836
}
837
838
/**
839
* @memberof ktxTexture1
840
* @~English
841
* @brief Destroy a ktxTexture1 object.
842
*
843
* This frees the memory associated with the texture contents and the memory
844
* of the ktxTexture1 object. This does @e not delete any OpenGL or Vulkan
845
* texture objects created by ktxTexture1_GLUpload or ktxTexture1_VkUpload.
846
*
847
* @param[in] This pointer to the ktxTexture1 object to destroy
848
*/
849
void
850
ktxTexture1_Destroy(ktxTexture1* This)
851
{
852
ktxTexture1_destruct(This);
853
free(This);
854
}
855
856
/**
857
* @memberof ktxTexture @private
858
* @~English
859
* @brief Calculate the size of the image data for the specified number
860
* of levels.
861
*
862
* The data size is the sum of the sizes of each level up to the number
863
* specified and includes any @c mipPadding.
864
*
865
* @param[in] This pointer to the ktxTexture object of interest.
866
* @param[in] levels number of levels whose data size to return.
867
*
868
* @return the data size in bytes.
869
*/
870
ktx_size_t
871
ktxTexture1_calcDataSizeLevels(ktxTexture1* This, ktx_uint32_t levels)
872
{
873
ktx_uint32_t i;
874
ktx_size_t dataSize = 0;
875
876
assert(This != NULL);
877
assert(levels <= This->numLevels);
878
for (i = 0; i < levels; i++) {
879
ktx_size_t levelSize = ktxTexture_calcLevelSize(ktxTexture(This), i,
880
KTX_FORMAT_VERSION_ONE);
881
/* mipPadding. NOTE: this adds padding after the last level too. */
882
#if KTX_GL_UNPACK_ALIGNMENT != 4
883
dataSize += _KTX_PAD4(levelSize);
884
#else
885
dataSize += levelSize;
886
#endif
887
}
888
return dataSize;
889
}
890
891
/**
892
* @memberof ktxTexture1 @private
893
* @~English
894
*
895
* @copydoc ktxTexture::ktxTexture_doCalcFaceLodSize
896
*/
897
ktx_size_t
898
ktxTexture1_calcFaceLodSize(ktxTexture1* This, ktx_uint32_t level)
899
{
900
return ktxTexture_doCalcFaceLodSize(ktxTexture(This), level,
901
KTX_FORMAT_VERSION_ONE);
902
}
903
904
/**
905
* @memberof ktxTexture @private
906
* @~English
907
* @brief Return the offset of a level in bytes from the start of the image
908
* data in a ktxTexture.
909
*
910
* The caclulated size does not include space for storing the @c imageSize
911
* fields of each mip level.
912
*
913
* @param[in] This pointer to the ktxTexture object of interest.
914
* @param[in] level level whose offset to return.
915
* @param[in] fv enum specifying format version for which to calculate
916
* image size.
917
*
918
* @return the data size in bytes.
919
*/
920
ktx_size_t
921
ktxTexture1_calcLevelOffset(ktxTexture1* This, ktx_uint32_t level)
922
{
923
assert (This != NULL);
924
assert (level < This->numLevels);
925
return ktxTexture1_calcDataSizeLevels(This, level);
926
}
927
928
/**
929
* @memberof ktxTexture1
930
* @~English
931
* @brief Find the offset of an image within a ktxTexture's image data.
932
*
933
* As there is no such thing as a 3D cubemap we make the 3rd location parameter
934
* do double duty.
935
*
936
* @param[in] This pointer to the ktxTexture object of interest.
937
* @param[in] level mip level of the image.
938
* @param[in] layer array layer of the image.
939
* @param[in] faceSlice cube map face or depth slice of the image.
940
* @param[in,out] pOffset pointer to location to store the offset.
941
*
942
* @return KTX_SUCCESS on success, other KTX_* enum values on error.
943
*
944
* @exception KTX_INVALID_OPERATION
945
* @p level, @p layer or @p faceSlice exceed the
946
* dimensions of the texture.
947
* @exception KTX_INVALID_VALID @p This is NULL.
948
*/
949
KTX_error_code
950
ktxTexture1_GetImageOffset(ktxTexture1* This, ktx_uint32_t level,
951
ktx_uint32_t layer, ktx_uint32_t faceSlice,
952
ktx_size_t* pOffset)
953
{
954
955
if (This == NULL)
956
return KTX_INVALID_VALUE;
957
958
if (level >= This->numLevels || layer >= This->numLayers)
959
return KTX_INVALID_OPERATION;
960
961
if (This->isCubemap) {
962
if (faceSlice >= This->numFaces)
963
return KTX_INVALID_OPERATION;
964
} else {
965
ktx_uint32_t maxSlice = MAX(1, This->baseDepth >> level);
966
if (faceSlice >= maxSlice)
967
return KTX_INVALID_OPERATION;
968
}
969
970
// Get the size of the data up to the start of the indexed level.
971
*pOffset = ktxTexture_calcDataSizeLevels(ktxTexture(This), level);
972
973
// All layers, faces & slices within a level are the same size.
974
if (layer != 0) {
975
ktx_size_t layerSize;
976
layerSize = ktxTexture_layerSize(ktxTexture(This), level,
977
KTX_FORMAT_VERSION_ONE);
978
*pOffset += layer * layerSize;
979
}
980
if (faceSlice != 0) {
981
ktx_size_t imageSize;
982
imageSize = ktxTexture_GetImageSize(ktxTexture(This), level);
983
#if (KTX_GL_UNPACK_ALIGNMENT != 4)
984
if (This->isCubemap)
985
_KTX_PAD4(imageSize); // Account for cubePadding.
986
#endif
987
*pOffset += faceSlice * imageSize;
988
}
989
990
return KTX_SUCCESS;
991
}
992
993
/**
994
* @memberof ktxTexture1
995
* @~English
996
* @brief Return the total size in bytes of the uncompressed data of a ktxTexture1.
997
*
998
* This always returns the value of @c This->dataSize. The function is provided for
999
* symmetry with ktxTexture2.
1000
*
1001
* @param[in] This pointer to the ktxTexture1 object of interest.
1002
* @return The size of the data in the texture.
1003
*/
1004
ktx_size_t
1005
ktxTexture1_GetDataSizeUncompressed(ktxTexture1* This)
1006
{
1007
return This->dataSize;
1008
}
1009
1010
/**
1011
* @memberof ktxTexture1
1012
* @~English
1013
* @brief Calculate & return the size in bytes of an image at the specified
1014
* mip level.
1015
*
1016
* For arrays, this is the size of a layer, for cubemaps, the size of a face
1017
* and for 3D textures, the size of a depth slice.
1018
*
1019
* The size reflects the padding of each row to KTX_GL_UNPACK_ALIGNMENT.
1020
*
1021
* @param[in] This pointer to the ktxTexture1 object of interest.
1022
* @param[in] level level of interest.
1023
*/
1024
ktx_size_t
1025
ktxTexture1_GetImageSize(ktxTexture1* This, ktx_uint32_t level)
1026
{
1027
return ktxTexture_calcImageSize(ktxTexture(This), level,
1028
KTX_FORMAT_VERSION_ONE);
1029
}
1030
1031
/**
1032
* @memberof ktxTexture1
1033
* @~English
1034
* @brief Calculate & return the size in bytes of all the images in the specified
1035
* mip level.
1036
*
1037
* For arrays, this is the size of all layers in the level, for cubemaps, the size of all
1038
* faces in the level and for 3D textures, the size of all depth slices in the level.
1039
*
1040
* The size reflects the padding of each row to KTX_GL_UNPACK_ALIGNMENT.
1041
*
1042
* @param[in] This pointer to the ktxTexture1 object of interest.
1043
* @param[in] level level of interest.
1044
*/
1045
ktx_size_t
1046
ktxTexture1_GetLevelSize(ktxTexture1* This, ktx_uint32_t level)
1047
{
1048
return ktxTexture_calcLevelSize(ktxTexture(This), level,
1049
KTX_FORMAT_VERSION_ONE);
1050
}
1051
1052
/**
1053
* @memberof ktxTexture1 @private
1054
* @~English
1055
* @brief Return the size of the primitive type of a single color component
1056
*
1057
* @param[in] This pointer to the ktxTexture1 object of interest.
1058
*
1059
* @return the type size in bytes.
1060
*/
1061
ktx_uint32_t
1062
ktxTexture1_glTypeSize(ktxTexture1* This)
1063
{
1064
assert(This != NULL);
1065
return This->_protected->_typeSize;
1066
}
1067
1068
/**
1069
* @memberof ktxTexture1
1070
* @~English
1071
* @brief Iterate over the mip levels in a ktxTexture1 object.
1072
*
1073
* This is almost identical to @ref ktxTexture::ktxTexture_IterateLevelFaces
1074
* "ktxTexture_IterateLevelFaces". The difference is that the blocks of image
1075
* data for non-array cube maps include all faces of a mip level.
1076
*
1077
* This function works even if @p This->pData == 0 so it can be used to
1078
* obtain offsets and sizes for each level by callers who have loaded the data
1079
* externally.
1080
*
1081
* @param[in] This handle of the 1 opened on the data.
1082
* @param[in,out] iterCb the address of a callback function which is called
1083
* with the data for each image block.
1084
* @param[in,out] userdata the address of application-specific data which is
1085
* passed to the callback along with the image data.
1086
*
1087
* @return KTX_SUCCESS on success, other KTX_* enum values on error. The
1088
* following are returned directly by this function. @p iterCb may
1089
* return these for other causes or may return additional errors.
1090
*
1091
* @exception KTX_FILE_DATA_ERROR Mip level sizes are increasing not
1092
* decreasing
1093
* @exception KTX_INVALID_VALUE @p This is @c NULL or @p iterCb is @c NULL.
1094
*
1095
*/
1096
KTX_error_code
1097
ktxTexture1_IterateLevels(ktxTexture1* This, PFNKTXITERCB iterCb, void* userdata)
1098
{
1099
ktx_uint32_t miplevel;
1100
KTX_error_code result = KTX_SUCCESS;
1101
1102
if (This == NULL)
1103
return KTX_INVALID_VALUE;
1104
1105
if (iterCb == NULL)
1106
return KTX_INVALID_VALUE;
1107
1108
for (miplevel = 0; miplevel < This->numLevels; ++miplevel)
1109
{
1110
GLsizei width, height, depth;
1111
ktx_uint32_t levelSize;
1112
ktx_size_t offset;
1113
1114
/* Array textures have the same number of layers at each mip level. */
1115
width = MAX(1, This->baseWidth >> miplevel);
1116
height = MAX(1, This->baseHeight >> miplevel);
1117
depth = MAX(1, This->baseDepth >> miplevel);
1118
1119
levelSize = (ktx_uint32_t)ktxTexture_calcLevelSize(ktxTexture(This),
1120
miplevel,
1121
KTX_FORMAT_VERSION_ONE);
1122
1123
/* All array layers are passed in a group because that is how
1124
* GL & Vulkan need them. Hence no
1125
* for (layer = 0; layer < This->numLayers)
1126
*/
1127
ktxTexture_GetImageOffset(ktxTexture(This), miplevel, 0, 0, &offset);
1128
result = iterCb(miplevel, 0, width, height, depth,
1129
levelSize, This->pData + offset, userdata);
1130
if (result != KTX_SUCCESS)
1131
break;
1132
}
1133
1134
return result;
1135
}
1136
1137
/**
1138
* @memberof ktxTexture1
1139
* @~English
1140
* @brief Iterate over the images in a ktxTexture1 object while loading the
1141
* image data.
1142
*
1143
* This operates similarly to @ref ktxTexture::ktxTexture_IterateLevelFaces
1144
* "ktxTexture_IterateLevelFaces" except that it loads the images from the
1145
* ktxTexture1's source to a temporary buffer while iterating. The callback
1146
* function must copy the image data if it wishes to preserve it as the
1147
* temporary buffer is reused for each level and is freed when this function
1148
* exits.
1149
*
1150
* This function is helpful for reducing memory usage when uploading the data
1151
* to a graphics API.
1152
*
1153
* @param[in] This pointer to the ktxTexture1 object of interest.
1154
* @param[in,out] iterCb the address of a callback function which is called
1155
* with the data for each image.
1156
* @param[in,out] userdata the address of application-specific data which is
1157
* passed to the callback along with the image data.
1158
*
1159
* @return KTX_SUCCESS on success, other KTX_* enum values on error. The
1160
* following are returned directly by this function. @p iterCb may
1161
* return these for other causes or may return additional errors.
1162
*
1163
* @exception KTX_FILE_DATA_ERROR mip level sizes are increasing not
1164
* decreasing
1165
* @exception KTX_INVALID_OPERATION the ktxTexture1 was not created from a
1166
* stream, i.e there is no data to load, or
1167
* this ktxTexture1's images have already
1168
* been loaded.
1169
* @exception KTX_INVALID_VALUE @p This is @c NULL or @p iterCb is @c NULL.
1170
* @exception KTX_OUT_OF_MEMORY not enough memory to allocate a block to
1171
* hold the base level image.
1172
*/
1173
KTX_error_code
1174
ktxTexture1_IterateLoadLevelFaces(ktxTexture1* This, PFNKTXITERCB iterCb,
1175
void* userdata)
1176
{
1177
DECLARE_PRIVATE(ktxTexture1);
1178
struct ktxTexture_protected* prtctd = This->_protected;
1179
ktxStream* stream = (ktxStream *)&prtctd->_stream;
1180
ktx_uint32_t dataSize = 0;
1181
ktx_uint32_t miplevel;
1182
KTX_error_code result = KTX_SUCCESS;
1183
void* data = NULL;
1184
1185
if (This == NULL)
1186
return KTX_INVALID_VALUE;
1187
1188
if (This->classId != ktxTexture1_c)
1189
return KTX_INVALID_OPERATION;
1190
1191
if (iterCb == NULL)
1192
return KTX_INVALID_VALUE;
1193
1194
if (prtctd->_stream.data.file == NULL)
1195
// This Texture not created from a stream or images are already loaded.
1196
return KTX_INVALID_OPERATION;
1197
1198
for (miplevel = 0; miplevel < This->numLevels; ++miplevel)
1199
{
1200
ktx_uint32_t faceLodSize;
1201
ktx_uint32_t faceLodSizePadded;
1202
ktx_uint32_t face;
1203
ktx_uint32_t innerIterations;
1204
GLsizei width, height, depth;
1205
1206
/* Array textures have the same number of layers at each mip level. */
1207
width = MAX(1, This->baseWidth >> miplevel);
1208
height = MAX(1, This->baseHeight >> miplevel);
1209
depth = MAX(1, This->baseDepth >> miplevel);
1210
1211
result = stream->read(stream, &faceLodSize, sizeof(ktx_uint32_t));
1212
if (result != KTX_SUCCESS) {
1213
goto cleanup;
1214
}
1215
if (private->_needSwap) {
1216
_ktxSwapEndian32(&faceLodSize, 1);
1217
}
1218
#if (KTX_GL_UNPACK_ALIGNMENT != 4)
1219
faceLodSizePadded = _KTX_PAD4(faceLodSize);
1220
#else
1221
faceLodSizePadded = faceLodSize;
1222
#endif
1223
if (!data) {
1224
/* allocate memory sufficient for the base miplevel */
1225
data = malloc(faceLodSizePadded);
1226
if (!data) {
1227
result = KTX_OUT_OF_MEMORY;
1228
goto cleanup;
1229
}
1230
dataSize = faceLodSizePadded;
1231
}
1232
else if (dataSize < faceLodSizePadded) {
1233
/* subsequent miplevels cannot be larger than the base miplevel */
1234
result = KTX_FILE_DATA_ERROR;
1235
goto cleanup;
1236
}
1237
1238
/* All array layers are passed in a group because that is how
1239
* GL & Vulkan need them. Hence no
1240
* for (layer = 0; layer < This->numLayers)
1241
*/
1242
if (This->isCubemap && !This->isArray)
1243
innerIterations = This->numFaces;
1244
else
1245
innerIterations = 1;
1246
for (face = 0; face < innerIterations; ++face)
1247
{
1248
/* And all z_slices are also passed as a group hence no
1249
* for (z_slice = 0; z_slice < This->depth)
1250
*/
1251
result = stream->read(stream, data, faceLodSizePadded);
1252
if (result != KTX_SUCCESS) {
1253
goto cleanup;
1254
}
1255
1256
/* Perform endianness conversion on texture data */
1257
if (private->_needSwap) {
1258
if (prtctd->_typeSize == 2)
1259
_ktxSwapEndian16((ktx_uint16_t*)data, faceLodSize / 2);
1260
else if (prtctd->_typeSize == 4)
1261
_ktxSwapEndian32((ktx_uint32_t*)data, faceLodSize / 4);
1262
}
1263
1264
result = iterCb(miplevel, face,
1265
width, height, depth,
1266
faceLodSize, data, userdata);
1267
}
1268
}
1269
1270
cleanup:
1271
free(data);
1272
// No further need for this.
1273
stream->destruct(stream);
1274
1275
return result;
1276
}
1277
1278
/**
1279
* @memberof ktxTexture1
1280
* @~English
1281
* @brief Load all the image data from the ktxTexture1's source.
1282
*
1283
* The data is loaded into the provided buffer or to an internally allocated
1284
* buffer, if @p pBuffer is @c NULL.
1285
*
1286
* @param[in] This pointer to the ktxTexture object of interest.
1287
* @param[in] pBuffer pointer to the buffer in which to load the image data.
1288
* @param[in] bufSize size of the buffer pointed at by @p pBuffer.
1289
*
1290
* @return KTX_SUCCESS on success, other KTX_* enum values on error.
1291
*
1292
* @exception KTX_INVALID_VALUE @p This is NULL.
1293
* @exception KTX_INVALID_VALUE @p bufSize is less than the the image data size.
1294
* @exception KTX_INVALID_OPERATION
1295
* The data has already been loaded or the
1296
* ktxTexture was not created from a KTX source.
1297
* @exception KTX_OUT_OF_MEMORY Insufficient memory for the image data.
1298
*/
1299
KTX_error_code
1300
ktxTexture1_LoadImageData(ktxTexture1* This,
1301
ktx_uint8_t* pBuffer, ktx_size_t bufSize)
1302
{
1303
DECLARE_PROTECTED(ktxTexture);
1304
DECLARE_PRIVATE(ktxTexture1);
1305
ktx_uint32_t miplevel;
1306
ktx_uint8_t* pDest;
1307
ktx_uint8_t* pDestEnd;
1308
KTX_error_code result = KTX_SUCCESS;
1309
1310
if (This == NULL)
1311
return KTX_INVALID_VALUE;
1312
1313
if (prtctd->_stream.data.file == NULL)
1314
// This Texture not created from a stream or images already loaded;
1315
return KTX_INVALID_OPERATION;
1316
1317
if (pBuffer == NULL) {
1318
This->pData = malloc(This->dataSize);
1319
if (This->pData == NULL)
1320
return KTX_OUT_OF_MEMORY;
1321
pDest = This->pData;
1322
pDestEnd = pDest + This->dataSize;
1323
} else if (bufSize < This->dataSize) {
1324
return KTX_INVALID_VALUE;
1325
} else {
1326
pDest = pBuffer;
1327
pDestEnd = pBuffer + bufSize;
1328
}
1329
1330
// Need to loop through for correct byte swapping
1331
for (miplevel = 0; miplevel < This->numLevels; ++miplevel)
1332
{
1333
ktx_uint32_t faceLodSize;
1334
ktx_uint32_t faceLodSizePadded;
1335
ktx_uint32_t face;
1336
ktx_uint32_t innerIterations;
1337
1338
result = prtctd->_stream.read(&prtctd->_stream, &faceLodSize,
1339
sizeof(ktx_uint32_t));
1340
if (result != KTX_SUCCESS) {
1341
goto cleanup;
1342
}
1343
if (private->_needSwap) {
1344
_ktxSwapEndian32(&faceLodSize, 1);
1345
}
1346
#if (KTX_GL_UNPACK_ALIGNMENT != 4)
1347
faceLodSizePadded = _KTX_PAD4(faceLodSize);
1348
#else
1349
faceLodSizePadded = faceLodSize;
1350
#endif
1351
1352
if (This->isCubemap && !This->isArray)
1353
innerIterations = This->numFaces;
1354
else
1355
innerIterations = 1;
1356
for (face = 0; face < innerIterations; ++face)
1357
{
1358
if (pDest + faceLodSizePadded > pDestEnd) {
1359
result = KTX_INVALID_VALUE;
1360
goto cleanup;
1361
}
1362
result = prtctd->_stream.read(&prtctd->_stream, pDest,
1363
faceLodSizePadded);
1364
if (result != KTX_SUCCESS) {
1365
goto cleanup;
1366
}
1367
1368
/* Perform endianness conversion on texture data */
1369
if (private->_needSwap) {
1370
if (prtctd->_typeSize == 2)
1371
_ktxSwapEndian16((ktx_uint16_t*)pDest, faceLodSize / 2);
1372
else if (prtctd->_typeSize == 4)
1373
_ktxSwapEndian32((ktx_uint32_t*)pDest, faceLodSize / 4);
1374
}
1375
1376
pDest += faceLodSizePadded;
1377
}
1378
}
1379
1380
cleanup:
1381
// No further need for This->
1382
prtctd->_stream.destruct(&prtctd->_stream);
1383
return result;
1384
}
1385
1386
ktx_bool_t
1387
ktxTexture1_NeedsTranscoding(ktxTexture1* This)
1388
{
1389
UNUSED(This);
1390
return KTX_FALSE;
1391
}
1392
1393
#if !KTX_FEATURE_WRITE
1394
1395
/*
1396
* Stubs for writer functions that return a proper error code
1397
*/
1398
1399
KTX_error_code
1400
ktxTexture1_SetImageFromMemory(ktxTexture1* This, ktx_uint32_t level,
1401
ktx_uint32_t layer, ktx_uint32_t faceSlice,
1402
const ktx_uint8_t* src, ktx_size_t srcSize)
1403
{
1404
UNUSED(This);
1405
UNUSED(level);
1406
UNUSED(layer);
1407
UNUSED(faceSlice);
1408
UNUSED(src);
1409
UNUSED(srcSize);
1410
return KTX_INVALID_OPERATION;
1411
}
1412
1413
KTX_error_code
1414
ktxTexture1_SetImageFromStdioStream(ktxTexture1* This, ktx_uint32_t level,
1415
ktx_uint32_t layer, ktx_uint32_t faceSlice,
1416
FILE* src, ktx_size_t srcSize)
1417
{
1418
UNUSED(This);
1419
UNUSED(level);
1420
UNUSED(layer);
1421
UNUSED(faceSlice);
1422
UNUSED(src);
1423
UNUSED(srcSize);
1424
return KTX_INVALID_OPERATION;
1425
}
1426
1427
KTX_error_code
1428
ktxTexture1_WriteToStdioStream(ktxTexture1* This, FILE* dstsstr)
1429
{
1430
UNUSED(This);
1431
UNUSED(dstsstr);
1432
return KTX_INVALID_OPERATION;
1433
}
1434
1435
KTX_error_code
1436
ktxTexture1_WriteToNamedFile(ktxTexture1* This, const char* const dstname)
1437
{
1438
UNUSED(This);
1439
UNUSED(dstname);
1440
return KTX_INVALID_OPERATION;
1441
}
1442
1443
KTX_error_code
1444
ktxTexture1_WriteToMemory(ktxTexture1* This,
1445
ktx_uint8_t** ppDstBytes, ktx_size_t* pSize)
1446
{
1447
UNUSED(This);
1448
UNUSED(ppDstBytes);
1449
UNUSED(pSize);
1450
return KTX_INVALID_OPERATION;
1451
}
1452
1453
KTX_error_code
1454
ktxTexture1_WriteToStream(ktxTexture1* This,
1455
ktxStream* dststr)
1456
{
1457
UNUSED(This);
1458
UNUSED(dststr);
1459
return KTX_INVALID_OPERATION;
1460
}
1461
1462
#endif
1463
1464
/*
1465
* Initialized here at the end to avoid the need for multiple declarations of
1466
* these functions.
1467
*/
1468
1469
struct ktxTexture_vtblInt ktxTexture1_vtblInt = {
1470
(PFNCALCDATASIZELEVELS)ktxTexture1_calcDataSizeLevels,
1471
(PFNCALCFACELODSIZE)ktxTexture1_calcFaceLodSize,
1472
(PFNCALCLEVELOFFSET)ktxTexture1_calcLevelOffset
1473
};
1474
1475
struct ktxTexture_vtbl ktxTexture1_vtbl = {
1476
(PFNKTEXDESTROY)ktxTexture1_Destroy,
1477
(PFNKTEXGETIMAGEOFFSET)ktxTexture1_GetImageOffset,
1478
(PFNKTEXGETDATASIZEUNCOMPRESSED)ktxTexture1_GetDataSizeUncompressed,
1479
(PFNKTEXGETIMAGESIZE)ktxTexture1_GetImageSize,
1480
(PFNKTEXGETLEVELSIZE)ktxTexture1_GetLevelSize,
1481
(PFNKTEXITERATELEVELS)ktxTexture1_IterateLevels,
1482
(PFNKTEXITERATELOADLEVELFACES)ktxTexture1_IterateLoadLevelFaces,
1483
(PFNKTEXNEEDSTRANSCODING)ktxTexture1_NeedsTranscoding,
1484
(PFNKTEXLOADIMAGEDATA)ktxTexture1_LoadImageData,
1485
(PFNKTEXSETIMAGEFROMMEMORY)ktxTexture1_SetImageFromMemory,
1486
(PFNKTEXSETIMAGEFROMSTDIOSTREAM)ktxTexture1_SetImageFromStdioStream,
1487
(PFNKTEXWRITETOSTDIOSTREAM)ktxTexture1_WriteToStdioStream,
1488
(PFNKTEXWRITETONAMEDFILE)ktxTexture1_WriteToNamedFile,
1489
(PFNKTEXWRITETOMEMORY)ktxTexture1_WriteToMemory,
1490
(PFNKTEXWRITETOSTREAM)ktxTexture1_WriteToStream,
1491
};
1492
1493
/** @} */
1494
1495
1496