Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
godotengine
GitHub Repository: godotengine/godot
Path: blob/master/thirdparty/libktx/lib/texture.c
9906 views
1
/* -*- tab-width: 4; -*- */
2
/* vi: set sw=2 ts=4 expandtab: */
3
4
/*
5
* Copyright 2018-2020 Mark Callow.
6
* SPDX-License-Identifier: Apache-2.0
7
*/
8
9
/**
10
* @internal
11
* @file
12
* @~English
13
*
14
* @brief ktxTexture implementation.
15
*
16
* @author Mark Callow, www.edgewise-consulting.com
17
*/
18
19
#if defined(_WIN32)
20
#define _CRT_SECURE_NO_WARNINGS
21
#ifndef __cplusplus
22
#undef inline
23
#define inline __inline
24
#endif // __cplusplus
25
#endif
26
27
#include <assert.h>
28
#include <math.h>
29
#include <stdlib.h>
30
#include <string.h>
31
32
#include "ktx.h"
33
#include "ktxint.h"
34
#include "formatsize.h"
35
#include "filestream.h"
36
#include "memstream.h"
37
#include "texture1.h"
38
#include "texture2.h"
39
#include "unused.h"
40
41
ktx_size_t ktxTexture_GetDataSize(ktxTexture* This);
42
43
static ktx_uint32_t padRow(ktx_uint32_t* rowBytes);
44
45
/**
46
* @memberof ktxTexture @private
47
* @~English
48
* @brief Construct (initialize) a ktxTexture base class instance.
49
*
50
* @param[in] This pointer to a ktxTexture-sized block of memory to
51
* initialize.
52
* @param[in] createInfo pointer to a ktxTextureCreateInfo struct with
53
* information describing the texture.
54
* @param[in] formatSize pointer to a ktxFormatSize giving size information
55
* about the texture's elements.
56
*
57
* @return KTX_SUCCESS on success, other KTX_* enum values on error.
58
*
59
* @exception KTX_INVALID_VALUE @c glInternalFormat in @p createInfo is not a
60
* valid OpenGL internal format value.
61
* @exception KTX_INVALID_VALUE @c numDimensions in @p createInfo is not 1, 2
62
* or 3.
63
* @exception KTX_INVALID_VALUE One of <tt>base{Width,Height,Depth}</tt> in
64
* @p createInfo is 0.
65
* @exception KTX_INVALID_VALUE @c numFaces in @p createInfo is not 1 or 6.
66
* @exception KTX_INVALID_VALUE @c numLevels in @p createInfo is 0.
67
* @exception KTX_INVALID_OPERATION
68
* The <tt>base{Width,Height,Depth}</tt> specified
69
* in @p createInfo are inconsistent with
70
* @c numDimensions.
71
* @exception KTX_INVALID_OPERATION
72
* @p createInfo is requesting a 3D array or
73
* 3D cubemap texture.
74
* @exception KTX_INVALID_OPERATION
75
* @p createInfo is requesting a cubemap with
76
* non-square or non-2D images.
77
* @exception KTX_INVALID_OPERATION
78
* @p createInfo is requesting more mip levels
79
* than needed for the specified
80
* <tt>base{Width,Height,Depth}</tt>.
81
* @exception KTX_OUT_OF_MEMORY Not enough memory for the texture.
82
*/
83
KTX_error_code
84
ktxTexture_construct(ktxTexture* This,
85
const ktxTextureCreateInfo* const createInfo,
86
ktxFormatSize* formatSize)
87
{
88
DECLARE_PROTECTED(ktxTexture);
89
90
memset(This, 0, sizeof(*This));
91
This->_protected = (struct ktxTexture_protected*)malloc(sizeof(*prtctd));
92
if (!This->_protected)
93
return KTX_OUT_OF_MEMORY;
94
prtctd = This->_protected;
95
memset(prtctd, 0, sizeof(*prtctd));
96
memcpy(&prtctd->_formatSize, formatSize, sizeof(prtctd->_formatSize));
97
98
This->isCompressed = (formatSize->flags & KTX_FORMAT_SIZE_COMPRESSED_BIT);
99
100
This->orientation.x = KTX_ORIENT_X_RIGHT;
101
This->orientation.y = KTX_ORIENT_Y_DOWN;
102
This->orientation.z = KTX_ORIENT_Z_OUT;
103
104
/* Check texture dimensions. KTX files can store 8 types of textures:
105
* 1D, 2D, 3D, cube, and array variants of these.
106
*/
107
if (createInfo->numDimensions < 1 || createInfo->numDimensions > 3)
108
return KTX_INVALID_VALUE;
109
110
if (createInfo->baseWidth == 0 || createInfo->baseHeight == 0
111
|| createInfo->baseDepth == 0)
112
return KTX_INVALID_VALUE;
113
114
switch (createInfo->numDimensions) {
115
case 1:
116
if (createInfo->baseHeight > 1 || createInfo->baseDepth > 1)
117
return KTX_INVALID_OPERATION;
118
break;
119
120
case 2:
121
if (createInfo->baseDepth > 1)
122
return KTX_INVALID_OPERATION;
123
break;
124
125
case 3:
126
/* 3D array textures and 3D cubemaps are not supported by either
127
* OpenGL or Vulkan.
128
*/
129
if (createInfo->isArray || createInfo->numFaces != 1
130
|| createInfo->numLayers != 1)
131
return KTX_INVALID_OPERATION;
132
break;
133
}
134
This->numDimensions = createInfo->numDimensions;
135
This->baseWidth = createInfo->baseWidth;
136
This->baseDepth = createInfo->baseDepth;
137
This->baseHeight = createInfo->baseHeight;
138
139
if (createInfo->numLayers == 0)
140
return KTX_INVALID_VALUE;
141
This->numLayers = createInfo->numLayers;
142
This->isArray = createInfo->isArray;
143
144
if (createInfo->numFaces == 6) {
145
if (This->numDimensions != 2) {
146
/* cube map needs 2D faces */
147
return KTX_INVALID_OPERATION;
148
}
149
if (createInfo->baseWidth != createInfo->baseHeight) {
150
/* cube maps require square images */
151
return KTX_INVALID_OPERATION;
152
}
153
This->isCubemap = KTX_TRUE;
154
} else if (createInfo->numFaces != 1) {
155
/* numFaces must be either 1 or 6 */
156
return KTX_INVALID_VALUE;
157
}
158
This->numFaces = createInfo->numFaces;
159
160
/* Check number of mipmap levels */
161
if (createInfo->numLevels == 0)
162
return KTX_INVALID_VALUE;
163
This->numLevels = createInfo->numLevels;
164
This->generateMipmaps = createInfo->generateMipmaps;
165
166
if (createInfo->numLevels > 1) {
167
GLuint max_dim = MAX(MAX(createInfo->baseWidth, createInfo->baseHeight),
168
createInfo->baseDepth);
169
if (max_dim < ((GLuint)1 << (This->numLevels - 1)))
170
{
171
/* Can't have more mip levels than 1 + log2(max(width, height, depth)) */
172
return KTX_INVALID_OPERATION;
173
}
174
}
175
176
ktxHashList_Construct(&This->kvDataHead);
177
return KTX_SUCCESS;
178
}
179
180
/**
181
* @memberof ktxTexture @private
182
* @~English
183
* @brief Construct (initialize) the part of a ktxTexture base class that is
184
* not related to the stream contents.
185
*
186
* @param[in] This pointer to a ktxTexture-sized block of memory to
187
* initialize.
188
*
189
* @return KTX_SUCCESS on success, other KTX_* enum values on error.
190
*/
191
KTX_error_code
192
ktxTexture_constructFromStream(ktxTexture* This, ktxStream* pStream,
193
ktxTextureCreateFlags createFlags)
194
{
195
ktxStream* stream;
196
UNUSED(createFlags); // Reference to keep compiler happy.
197
198
assert(This != NULL);
199
assert(pStream->data.mem != NULL);
200
assert(pStream->type == eStreamTypeFile
201
|| pStream->type == eStreamTypeMemory
202
|| pStream->type == eStreamTypeCustom);
203
204
This->_protected = (struct ktxTexture_protected *)
205
malloc(sizeof(struct ktxTexture_protected));
206
stream = ktxTexture_getStream(This);
207
// Copy stream info into struct for later use.
208
*stream = *pStream;
209
210
This->orientation.x = KTX_ORIENT_X_RIGHT;
211
This->orientation.y = KTX_ORIENT_Y_DOWN;
212
This->orientation.z = KTX_ORIENT_Z_OUT;
213
214
return KTX_SUCCESS;
215
}
216
217
218
/**
219
* @memberof ktxTexture @private
220
* @~English
221
* @brief Free the memory associated with the texture contents
222
*
223
* @param[in] This pointer to the ktxTextureInt whose texture contents are
224
* to be freed.
225
*/
226
void
227
ktxTexture_destruct(ktxTexture* This)
228
{
229
ktxStream stream = *(ktxTexture_getStream(This));
230
231
if (stream.data.file != NULL)
232
stream.destruct(&stream);
233
if (This->kvDataHead != NULL)
234
ktxHashList_Destruct(&This->kvDataHead);
235
if (This->kvData != NULL)
236
free(This->kvData);
237
if (This->pData != NULL)
238
free(This->pData);
239
free(This->_protected);
240
}
241
242
243
/**
244
* @defgroup reader Reader
245
* @brief Read KTX-formatted data.
246
* @{
247
*/
248
249
typedef enum { KTX1, KTX2 } ktxFileType_;
250
typedef union {
251
KTX_header ktx;
252
KTX_header2 ktx2;
253
} ktxHeaderUnion_;
254
255
/**
256
* @memberof ktxTexture @private
257
* @~English
258
* @brief Determine if stream data is KTX1 or KTX2.
259
*
260
* @param pStream pointer to the ktxStream to examine.
261
* @param pFileType pointer to a ktxFileType enum where the type of the data
262
* will be written.
263
* @param pHeader pointer to a ktxHeaderUnion where the header info. will be
264
* written.
265
*/
266
static KTX_error_code
267
ktxDetermineFileType_(ktxStream* pStream, ktxFileType_* pFileType,
268
ktxHeaderUnion_* pHeader)
269
{
270
ktx_uint8_t ktx_ident_ref[12] = KTX_IDENTIFIER_REF;
271
ktx_uint8_t ktx2_ident_ref[12] = KTX2_IDENTIFIER_REF;
272
KTX_error_code result;
273
274
assert(pStream != NULL && pFileType != NULL);
275
assert(pStream->data.mem != NULL);
276
assert(pStream->type == eStreamTypeFile
277
|| pStream->type == eStreamTypeMemory
278
|| pStream->type == eStreamTypeCustom);
279
280
result = pStream->read(pStream, pHeader, sizeof(ktx2_ident_ref));
281
if (result == KTX_SUCCESS) {
282
#if BIG_ENDIAN
283
// byte swap the heaader fields
284
#endif
285
// Compare identifier, is this a KTX or KTX2 file?
286
if (!memcmp(pHeader->ktx.identifier, ktx_ident_ref, 12)) {
287
*pFileType = KTX1;
288
} else if (!memcmp(pHeader->ktx2.identifier, ktx2_ident_ref, 12)) {
289
*pFileType = KTX2;
290
} else {
291
return KTX_UNKNOWN_FILE_FORMAT;
292
}
293
// Read rest of header.
294
if (*pFileType == KTX1) {
295
// Read rest of header.
296
result = pStream->read(pStream, &pHeader->ktx.endianness,
297
KTX_HEADER_SIZE - sizeof(ktx_ident_ref));
298
} else {
299
result = pStream->read(pStream, &pHeader->ktx2.vkFormat,
300
KTX2_HEADER_SIZE - sizeof(ktx2_ident_ref));
301
}
302
}
303
return result;
304
}
305
306
/**
307
* @memberof ktxTexture
308
* @~English
309
* @brief Create a ktx1 or ktx2 texture according to the stream
310
* data.
311
*
312
* See @ref ktxTexture1::ktxTexture1_CreateFromStream
313
* "ktxTexture1_CreateFromStream" or
314
* @ref ktxTexture2::ktxTexture2_CreateFromStream
315
* "ktxTexture2_CreateFromStream" for details.
316
*/
317
KTX_error_code
318
ktxTexture_CreateFromStream(ktxStream* pStream,
319
ktxTextureCreateFlags createFlags,
320
ktxTexture** newTex)
321
{
322
ktxHeaderUnion_ header;
323
ktxFileType_ fileType;
324
KTX_error_code result;
325
ktxTexture* tex;
326
327
result = ktxDetermineFileType_(pStream, &fileType, &header);
328
if (result != KTX_SUCCESS)
329
return result;
330
331
if (fileType == KTX1) {
332
ktxTexture1* tex1 = (ktxTexture1*)malloc(sizeof(ktxTexture1));
333
if (tex1 == NULL)
334
return KTX_OUT_OF_MEMORY;
335
memset(tex1, 0, sizeof(ktxTexture1));
336
result = ktxTexture1_constructFromStreamAndHeader(tex1, pStream,
337
&header.ktx,
338
createFlags);
339
tex = ktxTexture(tex1);
340
} else {
341
ktxTexture2* tex2 = (ktxTexture2*)malloc(sizeof(ktxTexture2));
342
if (tex2 == NULL)
343
return KTX_OUT_OF_MEMORY;
344
memset(tex2, 0, sizeof(ktxTexture2));
345
result = ktxTexture2_constructFromStreamAndHeader(tex2, pStream,
346
&header.ktx2,
347
createFlags);
348
tex = ktxTexture(tex2);
349
}
350
351
if (result == KTX_SUCCESS)
352
*newTex = (ktxTexture*)tex;
353
else {
354
free(tex);
355
*newTex = NULL;
356
}
357
return result;
358
}
359
360
/**
361
* @memberof ktxTexture
362
* @~English
363
* @brief Create a ktxTexture1 or ktxTexture2 from a stdio stream according
364
* to the stream data.
365
*
366
* See @ref ktxTexture1::ktxTexture1_CreateFromStdioStream
367
* "ktxTexture1_CreateFromStdioStream" or
368
* @ref ktxTexture2::ktxTexture2_CreateFromStdioStream
369
* "ktxTexture2_CreateFromStdioStream" for details.
370
*/
371
KTX_error_code
372
ktxTexture_CreateFromStdioStream(FILE* stdioStream,
373
ktxTextureCreateFlags createFlags,
374
ktxTexture** newTex)
375
{
376
ktxStream stream;
377
KTX_error_code result;
378
379
if (stdioStream == NULL || newTex == NULL)
380
return KTX_INVALID_VALUE;
381
382
result = ktxFileStream_construct(&stream, stdioStream, KTX_FALSE);
383
if (result == KTX_SUCCESS) {
384
result = ktxTexture_CreateFromStream(&stream, createFlags, newTex);
385
}
386
return result;
387
}
388
389
/**
390
* @memberof ktxTexture
391
* @~English
392
* @brief Create a ktxTexture1 or ktxTexture2 from a named KTX file according
393
* to the file contents.
394
*
395
* See @ref ktxTexture1::ktxTexture1_CreateFromNamedFile
396
* "ktxTexture1_CreateFromNamedFile" or
397
* @ref ktxTexture2::ktxTexture2_CreateFromNamedFile
398
* "ktxTexture2_CreateFromNamedFile" for details.
399
*/
400
KTX_error_code
401
ktxTexture_CreateFromNamedFile(const char* const filename,
402
ktxTextureCreateFlags createFlags,
403
ktxTexture** newTex)
404
{
405
KTX_error_code result;
406
ktxStream stream;
407
FILE* file;
408
409
if (filename == NULL || newTex == NULL)
410
return KTX_INVALID_VALUE;
411
412
file = ktxFOpenUTF8(filename, "rb");
413
if (!file)
414
return KTX_FILE_OPEN_FAILED;
415
416
result = ktxFileStream_construct(&stream, file, KTX_TRUE);
417
if (result == KTX_SUCCESS) {
418
result = ktxTexture_CreateFromStream(&stream, createFlags, newTex);
419
}
420
return result;
421
}
422
423
/**
424
* @memberof ktxTexture
425
* @~English
426
* @brief Create a ktxTexture1 or ktxTexture2 from KTX-formatted data in memory
427
* according to the data contents.
428
*
429
* See @ref ktxTexture1::ktxTexture1_CreateFromMemory
430
* "ktxTexture1_CreateFromMemory" or
431
* @ref ktxTexture2::ktxTexture2_CreateFromMemory
432
* "ktxTexture2_CreateFromMemory" for details.
433
*/
434
KTX_error_code
435
ktxTexture_CreateFromMemory(const ktx_uint8_t* bytes, ktx_size_t size,
436
ktxTextureCreateFlags createFlags,
437
ktxTexture** newTex)
438
{
439
KTX_error_code result;
440
ktxStream stream;
441
442
if (bytes == NULL || newTex == NULL || size == 0)
443
return KTX_INVALID_VALUE;
444
445
result = ktxMemStream_construct_ro(&stream, bytes, size);
446
if (result == KTX_SUCCESS) {
447
result = ktxTexture_CreateFromStream(&stream, createFlags, newTex);
448
}
449
return result;}
450
451
452
/**
453
* @memberof ktxTexture
454
* @~English
455
* @brief Return a pointer to the texture image data.
456
*
457
* @param[in] This pointer to the ktxTexture object of interest.
458
*/
459
ktx_uint8_t*
460
ktxTexture_GetData(ktxTexture* This)
461
{
462
return This->pData;
463
}
464
465
/**
466
* @memberof ktxTexture
467
* @~English
468
* @brief Return the total size of the texture image data in bytes.
469
*
470
* For a ktxTexture2 with supercompressionScheme != KTX_SS_NONE this will
471
* return the deflated size of the data.
472
*
473
* @param[in] This pointer to the ktxTexture object of interest.
474
*/
475
ktx_size_t
476
ktxTexture_GetDataSize(ktxTexture* This)
477
{
478
assert(This != NULL);
479
return This->dataSize;
480
}
481
482
/**
483
* @memberof ktxTexture
484
* @~English
485
* @brief Return the size in bytes of an elements of a texture's
486
* images.
487
*
488
* For uncompressed textures an element is one texel. For compressed
489
* textures it is one block.
490
*
491
* @param[in] This pointer to the ktxTexture object of interest.
492
*/
493
ktx_uint32_t
494
ktxTexture_GetElementSize(ktxTexture* This)
495
{
496
assert (This != NULL);
497
498
return (This->_protected->_formatSize.blockSizeInBits / 8);
499
}
500
501
/**
502
* @memberof ktxTexture @private
503
* @~English
504
* @brief Calculate & return the size in bytes of an image at the specified
505
* mip level.
506
*
507
* For arrays, this is the size of layer, for cubemaps, the size of a face
508
* and for 3D textures, the size of a depth slice.
509
*
510
* The size reflects the padding of each row to KTX_GL_UNPACK_ALIGNMENT.
511
*
512
* @param[in] This pointer to the ktxTexture object of interest.
513
* @param[in] level level of interest.
514
* @param[in] fv enum specifying format version for which to calculate
515
* image size.
516
*/
517
ktx_size_t
518
ktxTexture_calcImageSize(ktxTexture* This, ktx_uint32_t level,
519
ktxFormatVersionEnum fv)
520
{
521
DECLARE_PROTECTED(ktxTexture);
522
struct blockCount {
523
ktx_uint32_t x, y;
524
} blockCount;
525
ktx_uint32_t blockSizeInBytes;
526
ktx_uint32_t rowBytes;
527
528
assert (This != NULL);
529
530
float levelWidth = (float)(This->baseWidth >> level);
531
float levelHeight = (float)(This->baseHeight >> level);
532
// Round up to next whole block. We can't use KTX_PADN because some of
533
// the block sizes are not powers of 2.
534
blockCount.x
535
= (ktx_uint32_t)ceilf(levelWidth / prtctd->_formatSize.blockWidth);
536
blockCount.y
537
= (ktx_uint32_t)ceilf(levelHeight / prtctd->_formatSize.blockHeight);
538
blockCount.x = MAX(prtctd->_formatSize.minBlocksX, blockCount.x);
539
blockCount.y = MAX(prtctd->_formatSize.minBlocksY, blockCount.y);
540
541
blockSizeInBytes = prtctd->_formatSize.blockSizeInBits / 8;
542
543
if (prtctd->_formatSize.flags & KTX_FORMAT_SIZE_COMPRESSED_BIT) {
544
assert(This->isCompressed);
545
return blockCount.x * blockCount.y * blockSizeInBytes;
546
} else {
547
assert(prtctd->_formatSize.blockWidth == 1U
548
&& prtctd->_formatSize.blockHeight == 1U
549
&& prtctd->_formatSize.blockDepth == 1U);
550
rowBytes = blockCount.x * blockSizeInBytes;
551
if (fv == KTX_FORMAT_VERSION_ONE)
552
(void)padRow(&rowBytes);
553
return rowBytes * blockCount.y;
554
}
555
}
556
557
/**
558
* @memberof ktxTexture
559
* @~English
560
* @brief Iterate over the levels or faces in a ktxTexture object.
561
*
562
* Blocks of image data are passed to an application-supplied callback
563
* function. This is not a strict per-image iteration. Rather it reflects how
564
* OpenGL needs the images. For most textures the block of data includes all
565
* images of a mip level which implies all layers of an array. However, for
566
* non-array cube map textures the block is a single face of the mip level,
567
* i.e the callback is called once for each face.
568
*
569
* This function works even if @p This->pData == 0 so it can be used to
570
* obtain offsets and sizes for each level by callers who have loaded the data
571
* externally.
572
*
573
* @param[in] This pointer to the ktxTexture object of interest.
574
* @param[in,out] iterCb the address of a callback function which is called
575
* with the data for each image block.
576
* @param[in,out] userdata the address of application-specific data which is
577
* passed to the callback along with the image data.
578
*
579
* @return KTX_SUCCESS on success, other KTX_* enum values on error. The
580
* following are returned directly by this function. @p iterCb may
581
* return these for other causes or may return additional errors.
582
*
583
* @exception KTX_FILE_DATA_ERROR Mip level sizes are increasing not
584
* decreasing
585
* @exception KTX_INVALID_VALUE @p This is @c NULL or @p iterCb is @c NULL.
586
*
587
*/
588
KTX_error_code
589
ktxTexture_IterateLevelFaces(ktxTexture* This, PFNKTXITERCB iterCb,
590
void* userdata)
591
{
592
ktx_uint32_t miplevel;
593
KTX_error_code result = KTX_SUCCESS;
594
595
if (This == NULL)
596
return KTX_INVALID_VALUE;
597
598
if (iterCb == NULL)
599
return KTX_INVALID_VALUE;
600
601
for (miplevel = 0; miplevel < This->numLevels; ++miplevel)
602
{
603
ktx_uint32_t faceLodSize;
604
ktx_uint32_t face;
605
ktx_uint32_t innerIterations;
606
GLsizei width, height, depth;
607
608
/* Array textures have the same number of layers at each mip level. */
609
width = MAX(1, This->baseWidth >> miplevel);
610
height = MAX(1, This->baseHeight >> miplevel);
611
depth = MAX(1, This->baseDepth >> miplevel);
612
613
faceLodSize = (ktx_uint32_t)ktxTexture_calcFaceLodSize(
614
This, miplevel);
615
616
/* All array layers are passed in a group because that is how
617
* GL & Vulkan need them. Hence no
618
* for (layer = 0; layer < This->numLayers)
619
*/
620
if (This->isCubemap && !This->isArray)
621
innerIterations = This->numFaces;
622
else
623
innerIterations = 1;
624
for (face = 0; face < innerIterations; ++face)
625
{
626
/* And all z_slices are also passed as a group hence no
627
* for (slice = 0; slice < This->depth)
628
*/
629
ktx_size_t offset;
630
631
ktxTexture_GetImageOffset(This, miplevel, 0, face, &offset);
632
result = iterCb(miplevel, face,
633
width, height, depth,
634
faceLodSize, This->pData + offset, userdata);
635
636
if (result != KTX_SUCCESS)
637
break;
638
}
639
}
640
641
return result;
642
}
643
644
/**
645
* @internal
646
* @brief Calculate and apply the padding needed to comply with
647
* KTX_GL_UNPACK_ALIGNMENT.
648
*
649
* For uncompressed textures, KTX format specifies KTX_GL_UNPACK_ALIGNMENT = 4.
650
*
651
* @param[in,out] rowBytes pointer to variable containing the packed no. of
652
* bytes in a row. The no. of bytes after padding
653
* is written into this location.
654
* @return the no. of bytes of padding.
655
*/
656
static ktx_uint32_t
657
padRow(ktx_uint32_t* rowBytes)
658
{
659
ktx_uint32_t rowPadding;
660
661
assert (rowBytes != NULL);
662
663
rowPadding = _KTX_PAD_UNPACK_ALIGN_LEN(*rowBytes);
664
*rowBytes += rowPadding;
665
return rowPadding;
666
}
667
668
/**
669
* @memberof ktxTexture @private
670
* @~English
671
* @brief Calculate the size of an array layer at the specified mip level.
672
*
673
* The size of a layer is the size of an image * either the number of faces
674
* or the number of depth slices. This is the size of a layer as needed to
675
* find the offset within the array of images of a level and layer so the size
676
* reflects any @c cubePadding.
677
*
678
* @param[in] This pointer to the ktxTexture object of interest.
679
* @param[in] level level whose layer size to return.
680
*
681
* @return the layer size in bytes.
682
*/
683
ktx_size_t
684
ktxTexture_layerSize(ktxTexture* This, ktx_uint32_t level,
685
ktxFormatVersionEnum fv)
686
{
687
/*
688
* As there are no 3D cubemaps, the image's z block count will always be
689
* 1 for cubemaps and numFaces will always be 1 for 3D textures so the
690
* multiply is safe. 3D cubemaps, if they existed, would require
691
* imageSize * (blockCount.z + This->numFaces);
692
*/
693
DECLARE_PROTECTED(ktxTexture);
694
ktx_uint32_t blockCountZ;
695
ktx_size_t imageSize, layerSize;
696
697
assert (This != NULL);
698
assert (prtctd->_formatSize.blockDepth != 0);
699
700
blockCountZ = ((This->baseDepth >> level) + prtctd->_formatSize.blockDepth - 1) / prtctd->_formatSize.blockDepth;
701
blockCountZ = MAX(1, blockCountZ);
702
imageSize = ktxTexture_calcImageSize(This, level, fv);
703
layerSize = imageSize * blockCountZ;
704
if (fv == KTX_FORMAT_VERSION_ONE && KTX_GL_UNPACK_ALIGNMENT != 4) {
705
if (This->isCubemap && !This->isArray) {
706
/* cubePadding. NOTE: this adds padding after the last face too. */
707
layerSize += _KTX_PAD4(layerSize);
708
}
709
}
710
return layerSize * This->numFaces;
711
}
712
713
/**
714
* @memberof ktxTexture @private
715
* @~English
716
* @brief Calculate the size of the specified mip level.
717
*
718
* The size of a level is the size of a layer * the number of layers.
719
*
720
* @param[in] This pointer to the ktxTexture object of interest.
721
* @param[in] level level whose layer size to return.
722
*
723
* @return the level size in bytes.
724
*/
725
ktx_size_t
726
ktxTexture_calcLevelSize(ktxTexture* This, ktx_uint32_t level,
727
ktxFormatVersionEnum fv)
728
{
729
assert (This != NULL);
730
assert (level < This->numLevels);
731
return ktxTexture_layerSize(This, level, fv) * This->numLayers;
732
}
733
734
/**
735
* @memberof ktxTexture @private
736
* @~English
737
* @brief Calculate the faceLodSize of the specified mip level.
738
*
739
* The faceLodSize of a level for most textures is the size of a level. For
740
* non-array cube map textures is the size of a face. This is the size that
741
* must be provided to OpenGL when uploading textures. Faces get uploaded 1
742
* at a time while all layers of an array or all slices of a 3D texture are
743
* uploaded together.
744
*
745
* @param[in] This pointer to the ktxTexture object of interest.
746
* @param[in] level level whose layer size to return.
747
*
748
* @return the faceLodSize size in bytes.
749
*/
750
ktx_size_t
751
ktxTexture_doCalcFaceLodSize(ktxTexture* This, ktx_uint32_t level,
752
ktxFormatVersionEnum fv)
753
{
754
/*
755
* For non-array cubemaps this is the size of a face. For everything
756
* else it is the size of the level.
757
*/
758
if (This->isCubemap && !This->isArray)
759
return ktxTexture_calcImageSize(This, level, fv);
760
else
761
return ktxTexture_calcLevelSize(This, level, fv);
762
}
763
764
765
/**
766
* @memberof ktxTexture @private
767
* @~English
768
* @brief Return the number of bytes needed to store all the image data for
769
* a ktxTexture.
770
*
771
* The caclulated size does not include space for storing the @c imageSize
772
* fields of each mip level.
773
*
774
* @param[in] This pointer to the ktxTexture object of interest.
775
* @param[in] fv enum specifying format version for which to calculate
776
* image size.
777
*
778
* @return the data size in bytes.
779
*/
780
ktx_size_t
781
ktxTexture_calcDataSizeTexture(ktxTexture* This)
782
{
783
assert (This != NULL);
784
return ktxTexture_calcDataSizeLevels(This, This->numLevels);
785
}
786
787
/**
788
* @memberof ktxTexture @private
789
* @~English
790
* @brief Get information about rows of an uncompresssed texture image at a
791
* specified level.
792
*
793
* For an image at @p level of a ktxTexture provide the number of rows, the
794
* packed (unpadded) number of bytes in a row and the padding necessary to
795
* comply with KTX_GL_UNPACK_ALIGNMENT.
796
*
797
* @param[in] This pointer to the ktxTexture object of interest.
798
* @param[in] level level of interest.
799
* @param[in,out] numRows pointer to location to store the number of rows.
800
* @param[in,out] pRowLengthBytes pointer to location to store number of bytes
801
* in a row.
802
* @param[in.out] pRowPadding pointer to location to store the number of bytes
803
* of padding.
804
*/
805
void
806
ktxTexture_rowInfo(ktxTexture* This, ktx_uint32_t level,
807
ktx_uint32_t* numRows, ktx_uint32_t* pRowLengthBytes,
808
ktx_uint32_t* pRowPadding)
809
{
810
DECLARE_PROTECTED(ktxTexture);
811
struct blockCount {
812
ktx_uint32_t x;
813
} blockCount;
814
815
assert (This != NULL);
816
817
assert(!This->isCompressed);
818
assert(prtctd->_formatSize.blockWidth == 1U
819
&& prtctd->_formatSize.blockHeight == 1U
820
&& prtctd->_formatSize.blockDepth == 1U);
821
822
blockCount.x = MAX(1, (This->baseWidth / prtctd->_formatSize.blockWidth) >> level);
823
*numRows = MAX(1, (This->baseHeight / prtctd->_formatSize.blockHeight) >> level);
824
825
*pRowLengthBytes = blockCount.x * prtctd->_formatSize.blockSizeInBits / 8;
826
*pRowPadding = padRow(pRowLengthBytes);
827
}
828
829
/**
830
* @memberof ktxTexture
831
* @~English
832
* @brief Return pitch between rows of a texture image level in bytes.
833
*
834
* For uncompressed textures the pitch is the number of bytes between
835
* rows of texels. For compressed textures it is the number of bytes
836
* between rows of blocks. The value is padded to GL_UNPACK_ALIGNMENT,
837
* if necessary. For all currently known compressed formats padding
838
* will not be necessary.
839
*
840
* @param[in] This pointer to the ktxTexture object of interest.
841
* @param[in] level level of interest.
842
*
843
* @return the row pitch in bytes.
844
*/
845
ktx_uint32_t
846
ktxTexture_GetRowPitch(ktxTexture* This, ktx_uint32_t level)
847
{
848
DECLARE_PROTECTED(ktxTexture)
849
struct blockCount {
850
ktx_uint32_t x;
851
} blockCount;
852
ktx_uint32_t pitch;
853
854
blockCount.x = MAX(1, (This->baseWidth / prtctd->_formatSize.blockWidth) >> level);
855
pitch = blockCount.x * prtctd->_formatSize.blockSizeInBits / 8;
856
(void)padRow(&pitch);
857
858
return pitch;
859
}
860
861
/**
862
* @memberof ktxTexture @private
863
* @~English
864
* @brief Query if a ktxTexture has an active stream.
865
*
866
* Tests if a ktxTexture has unread image data. The internal stream is closed
867
* once all the images have been read.
868
*
869
* @param[in] This pointer to the ktxTexture object of interest.
870
*
871
* @return KTX_TRUE if there is an active stream, KTX_FALSE otherwise.
872
*/
873
ktx_bool_t
874
ktxTexture_isActiveStream(ktxTexture* This)
875
{
876
assert(This != NULL);
877
ktxStream* stream = ktxTexture_getStream(This);
878
return stream->data.file != NULL;
879
}
880
881
/** @} */
882
883
884