1// tImagePVR.cpp 
2// 
3// This class knows how to load PowerVR (.pvr) files. It knows the details of the pvr file format and loads the data 
4// into tLayers, optionally decompressing them. Saving is not implemented yet. The layers may be 'stolen' from a 
5// tImagePVR so that excessive memcpys are avoided. After they are stolen the tImagePVR is invalid. The tImagePVR 
6// class supports V1, V2, and V3 pvr files. 
7// 
8// Copyright (c) 2023, 2024 Tristan Grimmer. 
9// Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby 
10// granted, provided that the above copyright notice and this permission notice appear in all copies. 
11// 
12// THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL 
13// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, 
14// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN 
15// AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR 
16// PERFORMANCE OF THIS SOFTWARE. 
17 
18#include <Foundation/tString.h> 
19#include "Image/tImagePVR.h" 
20#include "Image/tPixelUtil.h" 
21#include "Image/tPicture.h" 
22namespace tImage 
23
24 
25 
26namespace tPVR 
27
28 // There are 3 possible headers for V1, V2, and V3 PVR files. V1 and V2 are very similar with V2 having two more 
29 // 4-byte fields than the V1 header. 
30 #pragma pack(push, 1) 
31 
32 struct HeaderV1V2 
33
34 uint32 HeaderSize; // 44 for V1. 52 for V2. 
35 uint32 Height
36 uint32 Width
37 uint32 MipMapCount
38 uint8 PixelFormat
39 uint8 Flags1
40 uint8 Flags2
41 uint8 Flags3
42 uint32 SurfaceSize
43 uint32 BitsPerPixel
44 uint32 RedMask
45 uint32 GreenMask
46 uint32 BlueMask
47 uint32 AlphaMask
48 uint32 FourCC; // Only read for V2 headers. 
49 uint32 NumSurfaces; // Only read for V2 headers. Set to 1 for V1 files. 
50 }; 
51 tStaticAssert(sizeof(HeaderV1V2) == 52); 
52 
53 struct HeaderV3 
54
55 uint32 FourCCVersion; // 'PVR3' for V3. LE = 0x03525650. 
56 uint32 Flags
57 uint64 PixelFormat
58 uint32 ColourSpace; // 0 = Linear RGB. 1 = sRGB (I assume linear alpha for both). 
59 uint32 ChannelType; // Matches PVR3CHANTYPE. 
60 uint32 Height
61 uint32 Width
62 uint32 Depth
63 uint32 NumSurfaces
64 uint32 NumFaces
65 uint32 NumMipmaps
66 uint32 MetaDataSize
67 }; 
68 tStaticAssert(sizeof(HeaderV3) == 52); 
69 #pragma pack(pop) 
70 
71 // These are the PVR legacy (V1 and V2 pvr files) format IDs from the specification document at: 
72 // https://powervr-graphics.github.io/WebGL_SDK/WebGL_SDK/Documentation/Specifications/PVR%20File%20Format.Specification.Legacy.pdf 
73 // The names match the names in the document. 
74 enum PVRLFMT : uint8 
75
76 PVRLFMT_ARGB_4444 = 0x00
77 PVRLFMT_ARGB_1555 = 0x01
78 PVRLFMT_RGB_565 = 0x02
79 PVRLFMT_RGB_555 = 0x03
80 PVRLFMT_RGB_888 = 0x04
81 PVRLFMT_ARGB_8888 = 0x05
82 PVRLFMT_ARGB_8332 = 0x06
83 PVRLFMT_I_8 = 0x07
84 PVRLFMT_AI_88 = 0x08
85 PVRLFMT_1BPP = 0x09
86 PVRLFMT_V_Y1_U_Y0 = 0x0A
87 PVRLFMT_Y1_V_Y0_U = 0x0B
88 PVRLFMT_PVRTC2 = 0x0C, // Better name would be PVRTCIBPP2 but want to match docs. 
89 PVRLFMT_PVRTC4 = 0x0D, // Better name would be PVRTCIBPP4 but want to match docs. 
90 
91 PVRLFMT_ARGB_4444_ALT = 0x10
92 PVRLFMT_ARGB_1555_ALT = 0x11
93 PVRLFMT_ARGB_8888_ALT = 0x12
94 PVRLFMT_RGB_565_ALT = 0x13
95 PVRLFMT_RGB_555_ALT = 0x14
96 PVRLFMT_RGB_888_ALT = 0x15
97 PVRLFMT_I_8_ALT = 0x16
98 PVRLFMT_AI_88_ALT = 0x17
99 PVRLFMT_PVRTC2_ALT = 0x18, // Better name would be PVRTCIBPP2 but want to match docs. 
100 PVRLFMT_PVRTC4_ALT = 0x19, // Better name would be PVRTCIBPP4 but want to match docs. 
101 
102 PVRLFMT_BGRA_8888 = 0x1A
103 PVRLFMT_DXT1 = 0x20
104 PVRLFMT_DXT2 = 0x21
105 PVRLFMT_DXT3 = 0x22
106 PVRLFMT_DXT4 = 0x23
107 PVRLFMT_DXT5 = 0x24
108 PVRLFMT_RGB_332 = 0x25
109 PVRLFMT_AL_44 = 0x26
110 PVRLFMT_LVU_655 = 0x27
111 PVRLFMT_XLVU_8888 = 0x28
112 PVRLFMT_QWVU_8888 = 0x29
113 PVRLFMT_ABGR_2101010 = 0x2A
114 PVRLFMT_ARGB_2101010 = 0x2B
115 PVRLFMT_AWVU_2101010 = 0x2C
116 PVRLFMT_GR_1616 = 0x2D
117 PVRLFMT_VU_1616 = 0x2E
118 PVRLFMT_ABGR_16161616 = 0x2F
119 PVRLFMT_R_16F = 0x30
120 PVRLFMT_GR_1616F = 0x31
121 PVRLFMT_ABGR_16161616F = 0x32
122 PVRLFMT_R_32F = 0x33
123 PVRLFMT_GR_3232F = 0x34
124 PVRLFMT_ABGR_32323232F = 0x35
125 PVRLFMT_ETC = 0x36
126 PVRLFMT_A_8 = 0x40
127 PVRLFMT_VU_88 = 0x41
128 PVRLFMT_L16 = 0x42
129 PVRLFMT_L8 = 0x43
130 PVRLFMT_AL_88 = 0x44
131 PVRLFMT_UYVY = 0x45
132 PVRLFMT_YUY2 = 0x46 
133 }; 
134 
135 // These match the names of the channel type in the official PVR3 filespec found here: 
136 // https://imagination-technologies-cloudfront-assets.s3.eu-west-1.amazonaws.com/website-files/documents/PVR+File+Format.Specification.pdf 
137 enum PVR3CHANTYPE : uint32 
138
139 PVR3CHANTYPE_UnsignedByteNormalised = 0x00000000
140 PVR3CHANTYPE_SignedByteNormalised = 0x00000001
141 PVR3CHANTYPE_UnsignedByte = 0x00000002
142 PVR3CHANTYPE_SignedByte = 0x00000003
143 PVR3CHANTYPE_UnsignedShortNormalised = 0x00000004
144 PVR3CHANTYPE_SignedShortNormalised = 0x00000005
145 PVR3CHANTYPE_UnsignedShort = 0x00000006
146 PVR3CHANTYPE_SignedShort = 0x00000007
147 PVR3CHANTYPE_UnsignedIntegerNormalised = 0x00000008
148 PVR3CHANTYPE_SignedIntegerNormalised = 0x00000009
149 PVR3CHANTYPE_UnsignedInteger = 0x0000000A
150 PVR3CHANTYPE_SignedInteger = 0x0000000B
151 PVR3CHANTYPE_Float = 0x0000000C
152 PVR3CHANTYPE_UnsignedFloat = 0x0000000D // Inferred from files generated by PVRTexTool. Not found in spec doc. 
153 }; 
154 
155 // These match the names of the LS 32-bits of the 64-bit pixel format as specified in the PVR3 file-spec found here: 
156 // https://imagination-technologies-cloudfront-assets.s3.eu-west-1.amazonaws.com/website-files/documents/PVR+File+Format.Specification.pdf 
157 enum PVR3FMT : uint32 
158
159 PVR3FMT_PVRTC_2BPP_RGB = 0x00000000
160 PVR3FMT_PVRTC_2BPP_RGBA = 0x00000001
161 PVR3FMT_PVRTC_4BPP_RGB = 0x00000002
162 PVR3FMT_PVRTC_4BPP_RGBA = 0x00000003
163 PVR3FMT_PVRTC_II_2BPP = 0x00000004
164 PVR3FMT_PVRTC_II_4BPP = 0x00000005
165 PVR3FMT_ETC1 = 0x00000006
166 PVR3FMT_DXT1_BC1 = 0x00000007
167 PVR3FMT_DXT2 = 0x00000008
168 PVR3FMT_DXT3_BC2 = 0x00000009
169 PVR3FMT_DXT4 = 0x0000000A
170 PVR3FMT_DXT5_BC3 = 0x0000000B
171 PVR3FMT_BC4 = 0x0000000C
172 PVR3FMT_BC5 = 0x0000000D
173 PVR3FMT_BC6 = 0x0000000E
174 PVR3FMT_BC7 = 0x0000000F
175 PVR3FMT_UYVY = 0x00000010
176 PVR3FMT_YUY2 = 0x00000011
177 PVR3FMT_BW1BPP = 0x00000012
178 PVR3FMT_R9G9B9E5_Shared_Exponent = 0x00000013
179 PVR3FMT_RGBG8888 = 0x00000014
180 PVR3FMT_GRGB8888 = 0x00000015
181 PVR3FMT_ETC2_RGB = 0x00000016
182 PVR3FMT_ETC2_RGBA = 0x00000017
183 PVR3FMT_ETC2_RGB_A1 = 0x00000018
184 PVR3FMT_EAC_R11 = 0x00000019
185 PVR3FMT_EAC_RG11 = 0x0000001A
186 PVR3FMT_ASTC_4X4 = 0x0000001B
187 PVR3FMT_ASTC_5X4 = 0x0000001C
188 PVR3FMT_ASTC_5X5 = 0x0000001D
189 PVR3FMT_ASTC_6X5 = 0x0000001E
190 PVR3FMT_ASTC_6X6 = 0x0000001F
191 PVR3FMT_ASTC_8X5 = 0x00000020
192 PVR3FMT_ASTC_8X6 = 0x00000021
193 PVR3FMT_ASTC_8X8 = 0x00000022
194 PVR3FMT_ASTC_10X5 = 0x00000023
195 PVR3FMT_ASTC_10X6 = 0x00000024
196 PVR3FMT_ASTC_10X8 = 0x00000025
197 PVR3FMT_ASTC_10X10 = 0x00000026
198 PVR3FMT_ASTC_12X10 = 0x00000027
199 PVR3FMT_ASTC_12X12 = 0x00000028
200 PVR3FMT_ASTC_3X3X3 = 0x00000029
201 PVR3FMT_ASTC_4X3X3 = 0x0000002A
202 PVR3FMT_ASTC_4X4X3 = 0x0000002B
203 PVR3FMT_ASTC_4X4X4 = 0x0000002C
204 PVR3FMT_ASTC_5X4X4 = 0x0000002D
205 PVR3FMT_ASTC_5X5X4 = 0x0000002E
206 PVR3FMT_ASTC_5X5X5 = 0x0000002F
207 PVR3FMT_ASTC_6X5X5 = 0x00000030
208 PVR3FMT_ASTC_6X6X5 = 0x00000031
209 PVR3FMT_ASTC_6X6X6 = 0x00000032
210 
211 PVR3FMT_RGBM = 0x00000035
212 PVR3FMT_RGBD = 0x00000036
213 }; 
214 
215 enum PVR3KEY : uint32 
216
217 PVR3KEY_ATLAS = 0x00000000
218 PVR3KEY_NORMALMAP = 0x00000001
219 PVR3KEY_CUBEMAP = 0x00000002
220 PVR3KEY_ORIENTATION = 0x00000003
221 PVR3KEY_BORDER = 0x00000004
222 PVR3KEY_PADDING = 0x00000005
223 PVR3KEY_UNKNOWN = 0x00000006 
224 }; 
225 
226 int DetermineVersionFromFirstFourBytes(const uint8 bytes[4]); 
227 
228 // Determine the pixel-format and, if possible, the alpha-mode and channel-type. There is no possibility of 
229 // determining the colour-profile for V1V2 file headers but we pass it in anyways so it behaves similarly to the V3 
230 // GetFormatInfo. If the pixel format is returned unspecified the headerFmt is not supported or was invalid. In 
231 // this case the returned colour-profile, alpha-mode, and channel-type will be unspecified. 
232 void GetFormatInfo_FromV1V2Header(tPixelFormat&, tColourProfile&, tAlphaMode&, tChannelType&, const HeaderV1V2&); 
233 
234 // For V3 file headers the channel-type, alpha-mode, and colour-space can always be determined. In addition some 
235 // V3 pixel-formats imply a particular colour space and alpha-mode. In cases where these do not match the required 
236 // type, mode, or space of the pixel-format, the pixel-format's required setting is chosen. 
237 void GetFormatInfo_FromV3Header(tPixelFormat&, tColourProfile&, tAlphaMode&, tChannelType&, const HeaderV3&); 
238 
239 void Flip(tLayer*, bool horizontal); 
240 inline int GetIndex(int x, int y, int w, int h) { tAssert((x >= 0) && (y >= 0) && (x < w) && (y < h)); return y * w + x; } 
241
242 
243 
244int tPVR::DetermineVersionFromFirstFourBytes(const uint8 bytes[4]) 
245
246 if (!bytes
247 return 0
248 
249 uint32 value = *((uint32*)bytes); 
250 if (value == 44
251 return 1
252  
253 if (value == 52
254 return 2
255  
256 if (value == 0x03525650
257 return 3
258 
259 return 0
260
261 
262 
263void tPVR::GetFormatInfo_FromV1V2Header(tPixelFormat& format, tColourProfile& profile, tAlphaMode& alphaMode, tChannelType& chanType, const HeaderV1V2& header
264
265 format = tPixelFormat::Invalid
266 profile = tColourProfile::sRGB
267 alphaMode = tAlphaMode::Unspecified
268 chanType = tChannelType::Unspecified
269 
270 #define C(c) case PVRLFMT_##c 
271 #define F(f) format = tPixelFormat::f; 
272 #define P(p) profile = tColourProfile::p; 
273 #define M(m) alphaMode = tAlphaMode::m; 
274 #define T(t) chanType = tChannelType::t; 
275 switch (header.PixelFormat
276
277 // Commented out PVRLFMT formats are not implemented yet. 
278 // Format Profile AlphaMode ChanType Break 
279 C(ARGB_4444): F(G4B4A4R4) break
280 C(ARGB_1555): F(G3B5A1R5G2) break
281 C(RGB_565): F(G3B5R5G3) break
282 //C(RGB_555): 
283 C(RGB_888): F(R8G8B8) break
284 C(ARGB_8888): F(B8G8R8A8) break
285 //C(ARGB_8332): 
286 C(I_8): F(L8) break
287 C(AI_88): F(A8L8) break
288 //C(1BPP): 
289 //C(V_Y1_U_Y0): 
290 //C(Y1_V_Y0_U): 
291 C(PVRTC2): F(PVRBPP2) break
292 C(PVRTC4): F(PVRBPP4) break
293 
294 C(ARGB_4444_ALT): F(G4B4A4R4) break
295 C(ARGB_1555_ALT): F(G3B5A1R5G2) break
296 C(ARGB_8888_ALT): F(R8G8B8A8) break
297 C(RGB_565_ALT): F(G3B5R5G3) break
298 //C(RGB_555_ALT): 
299 C(RGB_888_ALT): F(R8G8B8) break
300 C(I_8_ALT): F(L8) break
301 C(AI_88_ALT): F(A8L8) break
302 C(PVRTC2_ALT): F(PVRBPP2) break
303 C(PVRTC4_ALT): F(PVRBPP4) break
304 
305 C(BGRA_8888): F(B8G8R8A8) break
306 C(DXT1): F(BC1DXT1) break
307 C(DXT2): F(BC2DXT2DXT3) M(Mult) break
308 C(DXT3): F(BC2DXT2DXT3) break
309 C(DXT4): F(BC3DXT4DXT5) M(Mult) break
310 C(DXT5): F(BC3DXT4DXT5) break
311 //C(RGB_332): 
312 //C(AL_44): 
313 //C(LVU_655): 
314 //C(XLVU_8888): 
315 //C(QWVU_8888): 
316 //C(ABGR_2101010): 
317 //C(ARGB_2101010): 
318 //C(AWVU_2101010): 
319 //C(GR_1616): 
320 //C(VU_1616): 
321 //C(ABGR_16161616): 
322 C(R_16F): F(R16f) P(lRGB) T(SFLOAT) break
323 C(GR_1616F): F(R16G16f) P(lRGB) T(SFLOAT) break
324 C(ABGR_16161616F): F(R16G16B16A16f) P(lRGB) T(SFLOAT) break
325 C(R_32F): F(R32f) P(lRGB) T(SFLOAT) break
326 C(GR_3232F): F(R32G32f) P(lRGB) T(SFLOAT) break
327 C(ABGR_32323232F): F(R32G32B32A32f) P(lRGB) T(SFLOAT) break
328 
329 // V2 ETC1 files generated from PVRTexTool are always in linear space. There is no sRGB option. 
330 C(ETC): F(ETC1) P(lRGB) break
331 C(A_8): F(A8) break
332 //C(VU_88): 
333 //C(L16): 
334 C(L8): F(L8) P(lRGB) T(UINT) break
335 //C(AL_88): 
336 //C(UYVY): 
337 //C(YUY2): 
338 default: P(None) break
339
340 #undef C 
341 #undef F 
342 #undef P 
343 #undef M 
344 #undef T 
345
346 
347 
348void tPVR::GetFormatInfo_FromV3Header(tPixelFormat& format, tColourProfile& profile, tAlphaMode& alphaMode, tChannelType& chanType, const HeaderV3& header
349
350 format = tPixelFormat::Invalid
351 profile = (header.ColourSpace == 0) ? tColourProfile::lRGB : tColourProfile::sRGB
352 alphaMode = (header.Flags & 0x00000002) ? tAlphaMode::Premultiplied : tAlphaMode::Normal
353 chanType = tChannelType::Unspecified
354 
355 #define C(c) case PVR3CHANTYPE_##c 
356 #define T(t) chanType = tChannelType::t; 
357 switch (header.ChannelType
358
359 C(UnsignedByteNormalised): T(UNORM) break
360 C(SignedByteNormalised): T(SNORM) break
361 C(UnsignedByte): T(UINT) break
362 C(SignedByte): T(SINT) break
363 
364 C(UnsignedShortNormalised): T(UNORM) break
365 C(SignedShortNormalised): T(SNORM) break
366 C(UnsignedShort): T(UINT) break
367 C(SignedShort): T(SINT) break
368 
369 C(UnsignedIntegerNormalised): T(UNORM) break
370 C(SignedIntegerNormalised): T(SNORM) break
371 C(UnsignedInteger): T(UINT) break
372 C(SignedInteger): T(SINT) break
373 
374 C(Float): T(SFLOAT) break
375 C(UnsignedFloat): T(UFLOAT) break
376
377 #undef C 
378 #undef T 
379 
380 // For V3 files if the MS 32 bits are 0, the format is determined by the LS 32 bits. 
381 // If the MS 32 do bits are non zero, the MS 32 bits contain the number of bits for 
382 // each channel and the present channels are specified by the LS 32 bits. 
383 uint32 fmtMS32 = header.PixelFormat >> 32
384 uint32 fmtLS32 = header.PixelFormat & 0x00000000FFFFFFFF
385 if (fmtMS32 == 0
386
387 #define C(c) case PVR3FMT_##c 
388 #define F(f) format = tPixelFormat::f; 
389 #define P(p) profile = tColourProfile::p; 
390 #define M(m) alphaMode = tAlphaMode::m; 
391 #define T(t) chanType = tChannelType::t; 
392 switch (fmtLS32
393
394 // Commented out PVRLFMT formats are not implemented yet. Some formats require specific profiles and/or 
395 // alpha-modes. When these are required they override the settings from the header. 
396 // PVR stores alpha on a per-block basis, not the entire image. Images without alpha just happen 
397 // to have all opaque blocks. In either case, the pixel format is the same -- PVRBPP2 or PVRBPP4. 
398 // Format Profile AlphaMode ChanType Break 
399 C(PVRTC_2BPP_RGB): F(PVRBPP2) break
400 C(PVRTC_2BPP_RGBA): F(PVRBPP2) break
401 C(PVRTC_4BPP_RGB): F(PVRBPP4) break
402 C(PVRTC_4BPP_RGBA): F(PVRBPP4) break
403 
404 #ifdef PIXEL_FORMAT_INCLUDE_NOT_IMPLEMENTED 
405 C(PVRTC_II_2BPP): F(PVR2BPP2) break
406 C(PVRTC_II_4BPP): F(PVR2BPP4) break
407 #endif 
408 C(ETC1): F(ETC1) break
409 
410 C(DXT1_BC1): F(BC1DXT1) break
411 C(DXT2): F(BC2DXT2DXT3) M(Mult) break
412 C(DXT3_BC2): F(BC2DXT2DXT3) break
413 C(DXT4): F(BC3DXT4DXT5) M(Mult) break
414 C(DXT5_BC3): F(BC3DXT4DXT5) break
415 C(BC4): P(lRGB) if (chanType == tChannelType::SNORM) F(BC4ATI1S) else F(BC4ATI1U) break
416 C(BC5): P(lRGB) if (chanType == tChannelType::SNORM) F(BC5ATI2S) else F(BC5ATI2U) break
417 C(BC6): F(BC6U) P(HDRa) T(UFLOAT) break; // Not sure whether signed or unsigned. Assuming unsigned. 
418 C(BC7): F(BC7) break
419 //C(UYVY): 
420 //C(YUY2): 
421 //C(BW1BPP): 
422 C(R9G9B9E5_Shared_Exponent): F(E5B9G9R9uf) P(HDRa) T(UFLOAT) break
423 //C(RGBG8888): 
424 //C(GRGB8888): 
425 C(ETC2_RGB): F(ETC2RGB) break
426 C(ETC2_RGBA): F(ETC2RGBA) break
427 C(ETC2_RGB_A1): F(ETC2RGBA1) break
428 C(EAC_R11): if (chanType == tChannelType::SNORM) F(EACR11S) else F(EACR11U) break
429 C(EAC_RG11): if (chanType == tChannelType::SNORM) F(EACRG11S) else F(EACRG11U) break
430 C(ASTC_4X4): F(ASTC4X4) break
431 C(ASTC_5X4): F(ASTC5X4) break
432 C(ASTC_5X5): F(ASTC5X5) break
433 C(ASTC_6X5): F(ASTC6X5) break
434 C(ASTC_6X6): F(ASTC6X6) break
435 C(ASTC_8X5): F(ASTC8X5) break
436 C(ASTC_8X6): F(ASTC8X6) break
437 C(ASTC_8X8): F(ASTC8X8) break
438 C(ASTC_10X5): F(ASTC10X5) break
439 C(ASTC_10X6): F(ASTC10X6) break
440 C(ASTC_10X8): F(ASTC10X8) break
441 C(ASTC_10X10): F(ASTC10X10) break
442 C(ASTC_12X10): F(ASTC12X10) break
443 C(ASTC_12X12): F(ASTC12X12) break
444 //C(ASTC_3X3X3): 
445 //C(ASTC_4X3X3): 
446 //C(ASTC_4X4X3): 
447 //C(ASTC_4X4X4): 
448 //C(ASTC_5X4X4): 
449 //C(ASTC_5X5X4): 
450 //C(ASTC_5X5X5): 
451 //C(ASTC_6X5X5): 
452 //C(ASTC_6X6X5): 
453 //C(ASTC_6X6X6): 
454 C(RGBM): F(R8G8B8M8) P(HDRa) break
455 C(RGBD): F(R8G8B8D8) P(HDRa) break
456 default: P(None) M(None) T(NONE) break
457
458 #undef C 
459 #undef F 
460 #undef P 
461 #undef M 
462 #undef T 
463
464 else 
465
466 // The FourCC and the tSwapEndian32 calls below deal with endianness. The values 
467 // of the literals in the fourCC match the values of the masks in fmtMS32 member. 
468 #define F(f) format = tPixelFormat::f; 
469 #define P(p) profile = tColourProfile::p; 
470 switch (fmtLS32
471
472 case tImage::FourCC(ch0: 'r', ch1: '\0', ch2: '\0', ch3: '\0'): 
473
474 if (chanType == tChannelType::SFLOAT
475
476 switch (fmtMS32
477
478 case tSwapEndian32(val: 0x10000000): F(R16f) P(HDRa) break
479 case tSwapEndian32(val: 0x20000000): F(R32f) P(HDRa) break
480
481
482 else 
483
484 switch (fmtMS32
485
486 case tSwapEndian32(val: 0x10000000): F(R16) P(lRGB) break
487 case tSwapEndian32(val: 0x20000000): F(R32) P(lRGB) break
488
489
490 break
491
492 
493 case tImage::FourCC(ch0: 'r', ch1: 'g', ch2: '\0', ch3: '\0'): 
494
495 if (chanType == tChannelType::SFLOAT
496
497 switch (fmtMS32
498
499 case tSwapEndian32(val: 0x10100000): F(R16G16f) P(HDRa) break
500 case tSwapEndian32(val: 0x20200000): F(R32G32f) P(HDRa) break
501
502
503 else 
504
505 switch (fmtMS32
506
507 case tSwapEndian32(val: 0x10100000): F(R16G16) P(lRGB) break
508 case tSwapEndian32(val: 0x20200000): F(R32G32) P(lRGB) break
509
510
511 break
512
513 
514 case tImage::FourCC(ch0: 'r', ch1: 'g', ch2: 'b', ch3: '\0'): 
515
516 if (chanType == tChannelType::SFLOAT
517
518 switch (fmtMS32
519
520 case tSwapEndian32(val: 0x10101000): F(R16G16B16f) P(HDRa) break
521 case tSwapEndian32(val: 0x20202000): F(R32G32B32f) P(HDRa) break
522
523
524 else 
525
526 switch (fmtMS32
527
528 case tSwapEndian32(val: 0x05060500): F(G3B5R5G3) break; // LE PVR: R5 G6 B5. 
529 case tSwapEndian32(val: 0x10101000): F(R16G16B16) P(lRGB) break
530 case tSwapEndian32(val: 0x20202000): F(R32G32B32) P(lRGB) break
531
532
533 break
534
535 
536 case tImage::FourCC(ch0: 'b', ch1: 'g', ch2: 'r', ch3: '\0'): 
537
538 if (chanType == tChannelType::UFLOAT
539
540 switch (fmtMS32
541
542 case tSwapEndian32(val: 0x0a0b0b00): F(B10G11R11uf) break; // PVR: B10 G11 R11 UFLOAT. 
543
544 break
545
546 break
547
548 
549 case tImage::FourCC(ch0: 'r', ch1: 'g', ch2: 'b', ch3: 'a'): 
550
551 if (chanType == tChannelType::SFLOAT
552
553 switch (fmtMS32
554
555 case tSwapEndian32(val: 0x10101010): F(R16G16B16A16f) break
556 case tSwapEndian32(val: 0x20202020): F(R32G32B32A32f) break
557
558
559 else 
560
561 switch (fmtMS32
562
563 case tSwapEndian32(val: 0x08080808): F(R8G8B8A8) break
564 case tSwapEndian32(val: 0x04040404): F(B4A4R4G4) break
565 case tSwapEndian32(val: 0x05050501): F(G2B5A1R5G3) break
566 case tSwapEndian32(val: 0x10101010): F(R16G16B16A16) P(lRGB) break
567 case tSwapEndian32(val: 0x20202020): F(R32G32B32A32) P(lRGB) break
568
569
570 break
571
572 
573 case tImage::FourCC(ch0: 'a', ch1: 'r', ch2: 'g', ch3: 'b'): 
574
575 switch (fmtMS32
576
577 case tSwapEndian32(val: 0x01050505): F(G3B5A1R5G2) break; // LE PVR: A1 R5 G5 B5. 
578 case tSwapEndian32(val: 0x04040404): F(G4B4A4R4) break; // LE PVR: A4 R4 G4 B4. 
579
580 break
581
582 
583 case tImage::FourCC(ch0: 'b', ch1: 'g', ch2: 'r', ch3: 'a'): 
584
585 switch (fmtMS32
586
587 case tSwapEndian32(val: 0x08080808): F(B8G8R8A8) break; // LE PVR: A1 R5 G5 B5. 
588
589 break
590
591
592 #undef F 
593 #undef P 
594
595 
596 // PVR V3 files do not distinguish between lRGB and HDRa profiles -- it only supports lRGB. While they 
597 // both are linear, Tacent follows the ASTC convention of distinguishing between them by supporting > 1.0 
598 // for HDR profiles. Here, if the type is float and the profile is linear, we switch to HDR. 
599 if ((profile == tColourProfile::lRGB) && ((chanType == tChannelType::UFLOAT) || (chanType == tChannelType::SFLOAT))) 
600 profile = tColourProfile::HDRa
601
602 
603 
604void tPVR::Flip(tLayer* layer, bool horizontal
605
606 if (!layer->IsValid() || (layer->PixelFormat != tPixelFormat::R8G8B8A8)) 
607 return
608 
609 int w = layer->Width
610 int h = layer->Height
611 tPixel4b* srcPixels = (tPixel4b*)layer->Data
612 tPixel4b* newPixels = new tPixel4b[w*h]; 
613 
614 for (int y = 0; y < h; y++) 
615 for (int x = 0; x < w; x++) 
616 newPixels[ GetIndex(x, y, w, h) ] = srcPixels[ GetIndex(x: horizontal ? w-1-x : x, y: horizontal ? y : h-1-y, w, h) ]; 
617 
618 // We modify the existing data just in case layer doesn't own it. 
619 tStd::tMemcpy(dest: layer->Data, src: newPixels, numBytes: w*h*sizeof(tPixel4b)); 
620 delete[] newPixels
621
622 
623 
624void tImagePVR::Clear() 
625
626 // Clear all layers no matter what they're used for. 
627 for (int layer = 0; layer < NumLayers; layer++) 
628 delete Layers[layer]; 
629 
630 // Now delete the layers array. 
631 delete[] Layers
632 Layers = nullptr
633 NumLayers = 0
634 
635 States = 0; // Image will be invalid now since Valid state not set. 
636 PVRVersion = 0
637 AlphaMode = tAlphaMode::Unspecified
638 ChannelType = tChannelType::Unspecified
639 RowReversalOperationPerformed = false
640 
641 NumSurfaces = 0; // For storing arrays of image data. 
642 NumFaces = 0; // For cubemaps. 
643 NumMipmaps = 0
644 
645 Depth = 0; // Number of slices. 
646 Width = 0
647 Height = 0
648 
649 MetaData_Orientation_Flip_X = false
650 MetaData_Orientation_Flip_Y = false
651 
652 tBaseImage::Clear(); 
653
654 
655 
656bool tImagePVR::Set(tPixel4b* pixels, int width, int height, bool steal
657
658 Clear(); 
659 if (!pixels || (width <= 0) || (height <= 0)) 
660 return false
661 
662 PixelFormatSrc = tPixelFormat::R8G8B8A8
663 PixelFormat = tPixelFormat::R8G8B8A8
664 ColourProfileSrc = tColourProfile::sRGB; // We assume pixels must be sRGB. 
665 ColourProfile = tColourProfile::sRGB
666  
667 AlphaMode = tAlphaMode::Normal
668 ChannelType = tChannelType::UNORM
669 RowReversalOperationPerformed = false
670 
671 NumSurfaces = 1
672 NumFaces = 1
673 NumMipmaps = 1
674 Depth = 1
675 Width = width
676 Height = height
677 
678 NumLayers = 1
679 Layers = new tLayer*[1]; 
680 
681 // Order is surface, face, mipmap, slice. 
682 Layers[0] = new tLayer(tPixelFormat::R8G8B8A8, Width, Height, (uint8*)pixels, steal); 
683 
684 SetStateBit(StateBit::Valid); 
685 return true
686
687 
688 
689bool tImagePVR::Set(tFrame* frame, bool steal
690
691 Clear(); 
692 if (!frame || !frame->IsValid()) 
693 return false
694 
695 PixelFormatSrc = frame->PixelFormatSrc
696 PixelFormat = tPixelFormat::R8G8B8A8
697 ColourProfileSrc = tColourProfile::sRGB; // We assume frame must be sRGB. 
698 ColourProfile = tColourProfile::sRGB
699 
700 tPixel4b* pixels = frame->GetPixels(steal); 
701 Set(pixels, width: frame->Width, height: frame->Height, steal); 
702 if (steal
703 delete frame
704 
705 return IsValid(); 
706
707 
708 
709bool tImagePVR::Set(tPicture& picture, bool steal
710
711 Clear(); 
712 if (!picture.IsValid()) 
713 return false
714 
715 PixelFormatSrc = picture.PixelFormatSrc
716 PixelFormat = tPixelFormat::R8G8B8A8
717 // We don't know colour profile of tPicture. 
718 
719 // This is worth some explanation. If steal is true the picture becomes invalid and the 
720 // 'set' call will steal the stolen pixels. If steal is false GetPixels is called and the 
721 // 'set' call will memcpy them out... which makes sure the picture is still valid after and 
722 // no-one is sharing the pixel buffer. We don't check the success of 'set' because it must 
723 // succeed if picture was valid. 
724 tPixel4b* pixels = steal ? picture.StealPixels() : picture.GetPixels(); 
725 bool success = Set(pixels, width: picture.GetWidth(), height: picture.GetHeight(), steal); 
726 tAssert(success); 
727 return true
728
729 
730 
731bool tImagePVR::Load(const tString& pvrFile, const LoadParams& loadParams
732
733 Clear(); 
734 Filename = pvrFile
735 if (tSystem::tGetFileType(file: pvrFile) != tSystem::tFileType::PVR
736
737 SetStateBit(StateBit::Fatal_IncorrectFileType); 
738 return false
739
740 
741 if (!tSystem::tFileExists(file: pvrFile)) 
742
743 SetStateBit(StateBit::Fatal_FileDoesNotExist); 
744 return false
745
746 
747 int pvrSizeBytes = 0
748 uint8* pvrData = (uint8*)tSystem::tLoadFile(file: pvrFile, buffer: 0, fileSize: &pvrSizeBytes); 
749 bool success = Load(pvrFileInMemory: pvrData, numBytes: pvrSizeBytes, loadParams); 
750 delete[] pvrData
751 
752 return success
753
754 
755 
756bool tImagePVR::Load(const uint8* pvrData, int pvrDataSize, const LoadParams& paramsIn
757
758 Clear(); 
759 LoadParams params(paramsIn); 
760 
761 PVRVersion = tPVR::DetermineVersionFromFirstFourBytes(bytes: pvrData); 
762 if (PVRVersion == 0
763
764 SetStateBit(StateBit::Fatal_UnsupportedPVRFileVersion); 
765 return false
766
767 
768 ColourProfile = tColourProfile::Unspecified
769 ColourProfileSrc = tColourProfile::Unspecified
770 AlphaMode = tAlphaMode::Unspecified
771 ChannelType = tChannelType::Unspecified
772 
773 int metaDataSize = 0
774 const uint8* metaData = nullptr
775 const uint8* textureData = nullptr
776 
777 switch (PVRVersion
778
779 case 1
780 case 2
781
782 tPVR::HeaderV1V2* header = (tPVR::HeaderV1V2*)pvrData
783 tPVR::GetFormatInfo_FromV1V2Header(format&: PixelFormatSrc, profile&: ColourProfileSrc, alphaMode&: AlphaMode, chanType&: ChannelType, header: *header); 
784 if (PixelFormatSrc == tPixelFormat::Invalid
785
786 SetStateBit(StateBit::Fatal_PixelFormatNotSupported); 
787 return false
788
789 PixelFormat = PixelFormatSrc
790 ColourProfile = ColourProfileSrc
791 NumSurfaces = (PVRVersion == 2) ? header->NumSurfaces : 1; // NumSurfaces not supported by V1 files. 
792 NumFaces = 1
793 NumMipmaps = header->MipMapCount
794 Depth = 1
795 Width = header->Width
796 Height = header->Height
797 if 
798
799 ((PixelFormat == tPixelFormat::PVRBPP2) || (PixelFormat == tPixelFormat::PVRBPP4)) && 
800 ((Width < 4) || (Height < 4) || !tMath::tIsPower2(v: Width) || !tMath::tIsPower2(v: Height)) 
801
802
803 if (params.Flags & LoadFlag_StrictLoading
804
805 SetStateBit(StateBit::Fatal_V1V2InvalidDimensionsPVRTC1); 
806 return false
807
808 SetStateBit(StateBit::Conditional_V1V2InvalidDimensionsPVRTC1); 
809
810 
811 // Flags are LE order on disk. 
812 uint32 flags = (header->Flags1 << 24) | (header->Flags2 << 16) | (header->Flags1 << 8); 
813 bool hasMipmaps = (flags & 0x00000100) ? true : false
814 bool dataTwiddled = (flags & 0x00000200) ? true : false
815 bool containsNormalData = (flags & 0x00000400) ? true : false
816 bool hasABorder = (flags & 0x00000800) ? true : false
817 bool isACubemap = (flags & 0x00001000) ? true : false; // Every 6 surfaces is one cubemap. 
818 bool mipmapsDebugColour = (flags & 0x00002000) ? true : false
819 bool isAVolumeTexture = (flags & 0x00004000) ? true : false; // NumSurfaces is the number of slices (depth). 
820 bool alphaPresentInPVRTC = (flags & 0x00008000) ? true : false
821 
822 // This is a bit odd, but if a PVR V1 V2 does not have mipmaps it does not set 
823 // the number of mipmaps to 1. It would be cleaner if it did, so we do it here. 
824 if (!hasMipmaps && (NumMipmaps == 0)) 
825 NumMipmaps = 1
826 
827 if ((!hasMipmaps && (NumMipmaps > 1)) || (hasMipmaps && (NumMipmaps <= 1))) 
828
829 if (params.Flags & LoadFlag_StrictLoading
830
831 SetStateBit(StateBit::Fatal_V1V2MipmapFlagInconsistent); 
832 return false
833
834 SetStateBit(StateBit::Conditional_V1V2MipmapFlagInconsistent); 
835 }  
836 
837 if (dataTwiddled
838
839 SetStateBit(StateBit::Fatal_V1V2TwiddlingUnsupported); 
840 return false
841
842 
843 if (isACubemap && (NumSurfaces != 6)) 
844
845 SetStateBit(StateBit::Fatal_V1V2CubemapFlagInconsistent); 
846 return false
847
848 
849 if (isACubemap
850
851 NumFaces = NumSurfaces
852 NumSurfaces = 1
853
854 else if (isAVolumeTexture
855
856 Depth = NumSurfaces
857 NumSurfaces = 1
858
859 
860 int bytesPerSurface = header->SurfaceSize
861 int bitsPerPixel = header->BitsPerPixel
862 
863 // Only check the FourCC magic for V2 files. 
864 if ((PVRVersion == 2) && (header->FourCC != tImage::FourCC(ch0: 'P', ch1: 'V', ch2: 'R', ch3: '!'))) // LE 0x21525650. 
865
866 if (params.Flags & LoadFlag_StrictLoading
867
868 SetStateBit(StateBit::Fatal_V2IncorrectFourCC); 
869 return false
870
871 else 
872
873 SetStateBit(StateBit::Conditional_V2IncorrectFourCC); 
874
875
876 
877 textureData = pvrData + header->HeaderSize
878 break
879
880 
881 case 3
882
883 tPVR::HeaderV3* header = (tPVR::HeaderV3*)pvrData
884 tPVR::GetFormatInfo_FromV3Header(format&: PixelFormatSrc, profile&: ColourProfileSrc, alphaMode&: AlphaMode, chanType&: ChannelType, header: *header); 
885 if (PixelFormatSrc == tPixelFormat::Invalid
886
887 SetStateBit(StateBit::Fatal_PixelFormatNotSupported); 
888 return false
889
890 PixelFormat = PixelFormatSrc
891 ColourProfile = ColourProfileSrc
892 NumSurfaces = header->NumSurfaces
893 NumFaces = header->NumFaces
894 NumMipmaps = header->NumMipmaps
895 Depth = header->Depth
896 Width = header->Width
897 Height = header->Height
898 metaDataSize = header->MetaDataSize
899 metaData = pvrData + sizeof(tPVR::HeaderV3); 
900 textureData = metaData + metaDataSize
901 break
902
903 
904 default
905 SetStateBit(StateBit::Fatal_UnsupportedPVRFileVersion); 
906 return false
907
908 
909 ParseMetaData(metaData, metaDataSize); 
910 
911 NumLayers = NumSurfaces * NumFaces * NumMipmaps * Depth
912 if (NumLayers <= 0
913
914 SetStateBit(StateBit::Fatal_BadHeaderData); 
915 return false
916
917 
918 Layers = new tLayer*[NumLayers]; 
919 for (int l = 0; l < NumLayers; l++) 
920 Layers[l] = nullptr
921 
922 // These return 1 for packed formats. This allows us to treat BC, ASTC, Packed, etc all the same way. 
923 int blockW = tGetBlockWidth(PixelFormatSrc); 
924 int blockH = tGetBlockHeight(PixelFormatSrc); 
925 int bytesPerBlock = tImage::tGetBytesPerBlock(PixelFormatSrc); 
926 const uint8* srcPixelData = textureData
927 
928 // The gamma-compression load flags only apply when decoding. If the gamma mode is auto, we determine here 
929 // whether to apply sRGB compression. If the space is linear and a format that often encodes colours, we apply it. 
930 if (params.Flags & LoadFlag_AutoGamma
931
932 // Clear all related flags. 
933 params.Flags &= ~(LoadFlag_AutoGamma | LoadFlag_SRGBCompression | LoadFlag_GammaCompression); 
934 if (tMath::tIsProfileLinearInRGB(profile: ColourProfileSrc)) 
935
936 // Just cuz it's linear doesn't mean we want to gamma transform. Some formats should be kept linear. 
937 if 
938
939 (PixelFormatSrc != tPixelFormat::A8) && (PixelFormatSrc != tPixelFormat::A8L8) && 
940 (PixelFormatSrc != tPixelFormat::BC4ATI1U) && (PixelFormatSrc != tPixelFormat::BC4ATI1S) && 
941 (PixelFormatSrc != tPixelFormat::BC5ATI2U) && (PixelFormatSrc != tPixelFormat::BC5ATI2S
942
943
944 params.Flags |= LoadFlag_SRGBCompression
945
946
947
948 
949 // The ordering is different depending on V1V2 or V3. We have already checked for unsupported versions. 
950 // Start with a V1V2. NumFaces and Depth have already been adjusted. 
951 if ((PVRVersion == 1) || (PVRVersion == 2)) 
952
953 for (int surf = 0; surf < NumSurfaces; surf++) 
954
955 for (int face = 0; face < NumFaces; face++) 
956
957 int width = Width
958 int height = Height
959 for (int mip = 0; mip < NumMipmaps; mip++) 
960
961 int numBlocksW = tGetNumBlocks(blockWH: blockW, imageWH: width); 
962 int numBlocksH = tGetNumBlocks(blockWH: blockH, imageWH: height); 
963 int numBlocks = numBlocksW*numBlocksH
964 int numBytes = numBlocks * bytesPerBlock
965 for (int slice = 0; slice < Depth; slice++) 
966
967 int index = LayerIdx(surf, face, mip, depth: slice); 
968 tAssert(Layers[index] == nullptr); 
969 tLayer* newLayer = CreateNewLayer(params, srcPixelData, numBytes, width, height); 
970 if (!newLayer
971
972 Clear(); 
973 return false
974
975 Layers[index] = newLayer
976 srcPixelData += numBytes
977
978 width /= 2; tMath::tiClampMin(val&: width, min: 1); 
979 height /= 2; tMath::tiClampMin(val&: height, min: 1); 
980
981
982
983
984 else 
985
986 tAssert(PVRVersion == 3); 
987 int width = Width
988 int height = Height
989 for (int mip = 0; mip < NumMipmaps; mip++) 
990
991 int numBlocksW = tGetNumBlocks(blockWH: blockW, imageWH: width); 
992 int numBlocksH = tGetNumBlocks(blockWH: blockH, imageWH: height); 
993 int numBlocks = numBlocksW*numBlocksH
994 int numBytes = numBlocks * bytesPerBlock
995 for (int surf = 0; surf < NumSurfaces; surf++) 
996
997 for (int face = 0; face < NumFaces; face++) 
998
999 for (int slice = 0; slice < Depth; slice++) 
1000
1001 int index = LayerIdx(surf, face, mip, depth: slice); 
1002 tAssert(Layers[index] == nullptr); 
1003 
1004 // CreateNewLayer is the workhorse. It may or may not decode depending on params. 
1005 tLayer* newLayer = CreateNewLayer(params, srcPixelData, numBytes, width, height); 
1006 if (!newLayer
1007
1008 Clear(); 
1009 return false
1010
1011 Layers[index] = newLayer
1012 srcPixelData += numBytes
1013
1014
1015
1016 width /= 2; tMath::tiClampMin(val&: width, min: 1); 
1017 height /= 2; tMath::tiClampMin(val&: height, min: 1); 
1018
1019
1020 
1021 // The flips and rotates below do not clear the pixel format. 
1022 if ((params.Flags & LoadFlag_MetaDataOrient) && (MetaData_Orientation_Flip_X || MetaData_Orientation_Flip_Y)) 
1023
1024 // The order of the loops doesn't matter here. We just need to hit every layer. 
1025 for (int surf = 0; surf < NumSurfaces; surf++) 
1026
1027 for (int face = 0; face < NumFaces; face++) 
1028
1029 for (int mip = 0; mip < NumMipmaps; mip++) 
1030
1031 for (int slice = 0; slice < Depth; slice++) 
1032
1033 int index = LayerIdx(surf, face, mip, depth: slice); 
1034 tLayer* layer = Layers[index]; 
1035 tAssert(layer != nullptr); 
1036 if (MetaData_Orientation_Flip_X
1037 tPVR::Flip(layer, horizontal: true); 
1038 if (MetaData_Orientation_Flip_Y
1039 tPVR::Flip(layer, horizontal: false); 
1040
1041
1042
1043
1044
1045 
1046 // If we were asked to decode, set the current PixelFormat to the decoded format. 
1047 // Otherwise set the current PixelFormat to be the same as the original PixelFormatSrc. 
1048 PixelFormat = (params.Flags & LoadFlag_Decode) ? tPixelFormat::R8G8B8A8 : PixelFormatSrc
1049 
1050 if (params.Flags & LoadFlag_SRGBCompression) ColourProfile = tColourProfile::sRGB
1051 if (params.Flags & LoadFlag_GammaCompression) ColourProfile = tColourProfile::gRGB
1052 
1053 SetStateBit(StateBit::Valid); 
1054 tAssert(IsValid()); 
1055 return true
1056
1057 
1058 
1059int tImagePVR::LayerIdx(int surf, int face, int mip, int depth) const 
1060
1061 int index = depth + mip*(Depth) + face*(NumMipmaps*Depth) + surf*(NumFaces*NumMipmaps*Depth); 
1062 tAssert(index < NumLayers); 
1063 return index
1064
1065 
1066 
1067tLayer* tImagePVR::CreateNewLayer(const LoadParams& params, const uint8* srcPixelData, int numBytes, int width, int height
1068
1069 tLayer* layer = new tLayer(); 
1070 
1071 bool reverseRowOrderRequested = params.Flags & LoadFlag_ReverseRowOrder
1072 RowReversalOperationPerformed = false
1073 
1074 // For images whose height is not a multiple of the block size it makes it tricky when deoompressing to do 
1075 // the more efficient row reversal here, so we defer it. Packed formats have a block height of 1. Only BC 
1076 // and astc have non-unity block dimensins. 
1077 bool doRowReversalBeforeDecode = false
1078 if (reverseRowOrderRequested
1079
1080 bool canDo = true
1081 if (!CanReverseRowData(PixelFormatSrc, height)) 
1082 canDo = false
1083 doRowReversalBeforeDecode = canDo
1084
1085 
1086 if (doRowReversalBeforeDecode
1087
1088 int blockW = tGetBlockWidth(PixelFormatSrc); 
1089 int blockH = tGetBlockHeight(PixelFormatSrc); 
1090 int numBlocksW = tGetNumBlocks(blockWH: blockW, imageWH: width); 
1091 int numBlocksH = tGetNumBlocks(blockWH: blockH, imageWH: height); 
1092 
1093 uint8* reversedPixelData = tImage::CreateReversedRowData(pixelData: srcPixelData, pixelDataFormat: PixelFormat, numBlocksW, numBlocksH); 
1094 tAssert(reversedPixelData); 
1095 
1096 // We can simply get the layer to steal the memory (the last true arg). 
1097 layer->Set(format: PixelFormatSrc, width, height, data: reversedPixelData, steal: true); 
1098
1099 else 
1100
1101 // Not reversing. Use the current srcPixelData. Note that steal is false here so the data 
1102 // is both copied and owned by the new tLayer. The srcPixelData gets deleted later. 
1103 layer->Set(format: PixelFormatSrc, width, height, data: (uint8*)srcPixelData, steal: false); 
1104
1105 if (doRowReversalBeforeDecode
1106 RowReversalOperationPerformed = true
1107 
1108 // Not asked to decode. We're basically done. 
1109 if (!(params.Flags & LoadFlag_Decode)) 
1110
1111 if (reverseRowOrderRequested && !RowReversalOperationPerformed
1112 SetStateBit(StateBit::Conditional_CouldNotFlipRows); 
1113 
1114 return layer
1115
1116 
1117 // We were asked to decode if we made it here. 
1118 // Spread only applies to single-channel (R-only or L-only) formats. 
1119 bool spread = params.Flags & LoadFlag_SpreadLuminance
1120 
1121 // Decode to 32-bit RGBA. 
1122 bool didRowReversalAfterDecode = false
1123 
1124 // At the end of decoding _either_ decoded4b _or_ decoded4f will be valid, not both. 
1125 // The decoded4b format used for LDR images. 
1126 // The decoded4f format used for HDR images. 
1127 tColour4b* decoded4b = nullptr
1128 tColour4f* decoded4f = nullptr
1129 tAssert(layer->GetDataSize() == numBytes); 
1130 DecodeResult result = DecodePixelData 
1131
1132 layer->PixelFormat, data: layer->Data, dataSize: numBytes
1133 width, height, dstLDR&: decoded4b, dstHDR&: decoded4f, tColourProfile::Auto, RGBM_RGBD_MaxRange: params.MaxRange 
1134 ); 
1135 
1136 if (result != DecodeResult::Success
1137
1138 switch (result
1139
1140 case DecodeResult::PackedDecodeError: SetStateBit(StateBit::Fatal_PackedDecodeError); break
1141 case DecodeResult::BlockDecodeError: SetStateBit(StateBit::Fatal_BCDecodeError); break
1142 case DecodeResult::ASTCDecodeError: SetStateBit(StateBit::Fatal_ASTCDecodeError); break
1143 case DecodeResult::PVRDecodeError: SetStateBit(StateBit::Fatal_PVRDecodeError); break
1144 default: SetStateBit(StateBit::Fatal_PixelFormatNotSupported); break
1145
1146 delete layer
1147 return nullptr
1148
1149 
1150 // Apply any decode flags. 
1151 tAssert(decoded4f || decoded4b); 
1152 bool flagTone = (params.Flags & tImagePVR::LoadFlag_ToneMapExposure) ? true : false
1153 bool flagSRGB = (params.Flags & tImagePVR::LoadFlag_SRGBCompression) ? true : false
1154 bool flagGama = (params.Flags & tImagePVR::LoadFlag_GammaCompression)? true : false
1155 if (decoded4f && (flagTone || flagSRGB || flagGama)) 
1156
1157 for (int p = 0; p < width*height; p++) 
1158
1159 tColour4f& colour = decoded4f[p]; 
1160 if (flagTone
1161 colour.TonemapExposure(exposure: params.Exposure, chans: tCompBit_RGB); 
1162 if (flagSRGB
1163 colour.LinearToSRGB(chans: tCompBit_RGB); 
1164 if (flagGama
1165 colour.LinearToGamma(gamma: params.Gamma, chans: tCompBit_RGB); 
1166
1167
1168 if (decoded4b && (flagSRGB || flagGama)) 
1169
1170 for (int p = 0; p < width*height; p++) 
1171
1172 tColour4f colour(decoded4b[p]); 
1173 if (flagSRGB
1174 colour.LinearToSRGB(chans: tCompBit_RGB); 
1175 if (flagGama
1176 colour.LinearToGamma(gamma: params.Gamma, chans: tCompBit_RGB); 
1177 decoded4b[p].SetR(colour.R); 
1178 decoded4b[p].SetG(colour.G); 
1179 decoded4b[p].SetB(colour.B); 
1180
1181
1182 
1183 // Update the layer with the 32-bit RGBA decoded data. If the data was HDR (float) 
1184 // convert it to 32 bit. Start by getting rid of the existing layer pixel data. 
1185 delete[] layer->Data
1186 if (decoded4f
1187
1188 tAssert(!decoded4b); 
1189 decoded4b = new tColour4b[width*height]; 
1190 for (int p = 0; p < width*height; p++) 
1191 decoded4b[p].Set(decoded4f[p]); 
1192 delete[] decoded4f
1193
1194 
1195 // Possibly spread the L/Red channel. 
1196 if (spread && tIsLuminanceFormat(format: layer->PixelFormat)) 
1197
1198 for (int p = 0; p < width*height; p++) 
1199
1200 decoded4b[p].G = decoded4b[p].R
1201 decoded4b[p].B = decoded4b[p].R
1202
1203
1204 
1205 layer->Data = (uint8*)decoded4b
1206 layer->PixelFormat = tPixelFormat::R8G8B8A8
1207 
1208 // We've got one more chance to reverse the rows here (if we still need to) because we were asked to decode. 
1209 if (reverseRowOrderRequested && !RowReversalOperationPerformed && (layer->PixelFormat == tPixelFormat::R8G8B8A8)) 
1210
1211 // This shouldn't ever fail. Too easy to reverse RGBA 32-bit. 
1212 uint8* reversedRowData = tImage::CreateReversedRowData(pixelData: layer->Data, pixelDataFormat: layer->PixelFormat, numBlocksW: width, numBlocksH: height); 
1213 tAssert(reversedRowData); 
1214 delete[] layer->Data
1215 layer->Data = reversedRowData
1216 didRowReversalAfterDecode = true
1217
1218 
1219 if (reverseRowOrderRequested && !RowReversalOperationPerformed && didRowReversalAfterDecode
1220 RowReversalOperationPerformed = true
1221 
1222 if (reverseRowOrderRequested && !RowReversalOperationPerformed
1223 SetStateBit(StateBit::Conditional_CouldNotFlipRows); 
1224 
1225 return layer
1226
1227 
1228 
1229bool tImagePVR::ParseMetaData(const uint8* metaData, int metaDataSize
1230
1231 if (!metaData || (metaDataSize <= 0)) 
1232 return false
1233 
1234 while (metaDataSize >= 12
1235
1236 uint32 fourCC = *((uint32*)metaData); metaData += 4; metaDataSize -= 4
1237 uint32 key = *((uint32*)metaData); metaData += 4; metaDataSize -= 4
1238 uint32 dataSize = *((uint32*)metaData); metaData += 4; metaDataSize -= 4
1239 
1240 switch (fourCC
1241
1242 case tImage::FourCC(ch0: 'P', ch1: 'V', ch2: 'R', ch3: 3): 
1243
1244 // Most of the built-in meta-data does not affect display of image. Indeed nearly all 
1245 // of the built-in meta-data is not even supported by the official PVRTexTool as of 2023_12_30. 
1246 switch (key
1247
1248 case tPVR::PVR3KEY_ATLAS: break
1249 case tPVR::PVR3KEY_NORMALMAP: break
1250 case tPVR::PVR3KEY_CUBEMAP: break
1251 
1252 case tPVR::PVR3KEY_ORIENTATION
1253 // Three bytes, one for each axis in the order X, Y, Z.  
1254 // X == 0: Increases right. X != 0: Increases left. 
1255 // Y == 0: Increases down. Y != 0: Increases up. 
1256 // X == 0: Increases inward. Z != 0: Increases outward. 
1257 if (dataSize != 3
1258 break
1259 MetaData_Orientation_Flip_X = metaData[0] ? true : false
1260 MetaData_Orientation_Flip_Y = metaData[1] ? true : false
1261 break
1262 
1263 case tPVR::PVR3KEY_BORDER: break
1264 case tPVR::PVR3KEY_PADDING: break
1265 case tPVR::PVR3KEY_UNKNOWN: break
1266
1267 break
1268
1269
1270 
1271 metaData += dataSize; metaDataSize -= dataSize
1272
1273 
1274 return true
1275
1276 
1277 
1278const char* tImagePVR::GetStateDesc(StateBit state
1279
1280 return StateDescriptions[int(state)]; 
1281
1282 
1283 
1284tFrame* tImagePVR::GetFrame(bool steal
1285
1286 // Data must be decoded for this to work. 
1287 tLayer* layer = Layers ? Layers[ LayerIdx(surf: 0) ] : nullptr
1288 if (!IsValid() || (PixelFormat != tPixelFormat::R8G8B8A8) || (layer == nullptr)) 
1289 return nullptr
1290 
1291 tFrame* frame = new tFrame(); 
1292 frame->Width = layer->Width
1293 frame->Height = layer->Height
1294 frame->PixelFormatSrc = PixelFormatSrc
1295 
1296 if (steal
1297
1298 frame->Pixels = (tPixel4b*)layer->StealData(); 
1299 delete layer
1300 Layers[ LayerIdx(surf: 0) ] = nullptr
1301
1302 else 
1303
1304 frame->Pixels = new tPixel4b[frame->Width * frame->Height]; 
1305 tStd::tMemcpy(dest: frame->Pixels, src: (tPixel4b*)layer->Data, numBytes: frame->Width * frame->Height * sizeof(tPixel4b)); 
1306
1307 
1308 return frame
1309
1310 
1311 
1312bool tImagePVR::StealLayers(tList<tLayer>& layers
1313
1314 if (!IsValid() || IsCubemap()) 
1315 return false
1316 
1317 for (int layer = 0; layer < NumLayers; layer++) 
1318
1319 layers.Append(item: Layers[layer]); 
1320 Layers[layer] = nullptr
1321
1322 
1323 Clear(); 
1324 return true
1325
1326 
1327 
1328int tImagePVR::GetLayers(tList<tLayer>& layers) const 
1329
1330 if (!IsValid() || IsCubemap()) 
1331 return 0
1332 
1333 for (int layer = 0; layer < NumLayers; layer++) 
1334 layers.Append(item: Layers[layer]); 
1335 
1336 return NumLayers
1337
1338 
1339 
1340int tImagePVR::StealCubemapLayers(tList<tLayer> layerLists[tFaceIndex_NumFaces], uint32 faceFlags
1341
1342 if (!IsValid() || !IsCubemap() || !faceFlags
1343 return 0
1344 
1345 int faceCount = 0
1346 for (int face = 0; face < tFaceIndex_NumFaces; face++) 
1347
1348 uint32 faceFlag = 1 << face
1349 if (!(faceFlag & faceFlags)) 
1350 continue
1351 
1352 tList<tLayer>& dstLayers = layerLists[face]; 
1353 for (int mip = 0; mip < NumMipmaps; mip++) 
1354
1355 int index = LayerIdx(surf: 0, face, mip, depth: 0); 
1356 tLayer* layer = Layers[index]; 
1357 dstLayers.Append(item: layer); 
1358 Layers[index] = nullptr
1359
1360 faceCount++; 
1361
1362 
1363 Clear(); 
1364 return faceCount
1365
1366 
1367 
1368int tImagePVR::GetCubemapLayers(tList<tLayer> layerLists[tFaceIndex_NumFaces], uint32 faceFlags) const 
1369
1370 if (!IsValid() || !IsCubemap() || !faceFlags
1371 return 0
1372 
1373 int faceCount = 0
1374 for (int face = 0; face < tFaceIndex_NumFaces; face++) 
1375
1376 uint32 faceFlag = 1 << face
1377 if (!(faceFlag & faceFlags)) 
1378 continue
1379 
1380 tList<tLayer>& dstLayers = layerLists[face]; 
1381 for (int mip = 0; mip < NumMipmaps; mip++) 
1382
1383 int index = LayerIdx(surf: 0, face, mip, depth: 0); 
1384 tLayer* layer = Layers[index]; 
1385 dstLayers.Append(item: layer); 
1386
1387 
1388 faceCount++; 
1389
1390 
1391 return faceCount
1392
1393 
1394 
1395const char* tImagePVR::StateDescriptions[] = 
1396
1397 "Valid"
1398 "Conditional Valid. Image rows could not be flipped."
1399 "Conditional Valid. Pixel format specification ill-formed."
1400 "Conditional Valid. V2 Magic FourCC Incorrect."
1401 "Conditional Valid. V1 V2 PVRTC1 non-POT dimension or less than 4."
1402 "Conditional Valid. V1 V2 Mipmap flag doesn't match mipmap count."
1403 "Fatal Error. File does not exist."
1404 "Fatal Error. Incorrect file type. Must be a PVR file."
1405 "Fatal Error. Filesize incorrect."
1406 "Fatal Error. V2 Magic FourCC Incorrect."
1407 "Fatal Error. Incorrect PVR header size."
1408 "Fatal Error. Bad PVR header data."
1409 "Fatal Error. Unsupported PVR file version."
1410 "Fatal Error. V1 V2 PVRTC1 non-POT dimension or less than 4."
1411 "Fatal Error. Pixel format header size incorrect."
1412 "Fatal Error. Pixel format specification incorrect."
1413 "Fatal Error. Unsupported pixel format."
1414 "Fatal Error. V1 V2 Mipmap flag doesn't match mipmap count."
1415 "Fatal Error. V1 V2 Cubemap flag doesn't match map count."
1416 "Fatal Error. V1 V2 Twiddled data not supported."
1417 "Fatal Error. Unable to decode packed pixels."
1418 "Fatal Error. Unable to decode BC pixels."
1419 "Fatal Error. Unable to decode ASTC pixels."
1420 "Fatal Error. Unable to decode PVR pixels." 
1421}; 
1422tStaticAssert(tNumElements(tImagePVR::StateDescriptions) == int(tImagePVR::StateBit::NumStateBits)); 
1423tStaticAssert(int(tImagePVR::StateBit::NumStateBits) <= int(tImagePVR::StateBit::MaxStateBits)); 
1424 
1425 
1426
1427