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