1// tPixelUtil.cpp 
2// 
3// Helper functions for manipulating and parsing pixel-data in packed and compressed block formats. 
4// 
5// Copyright (c) 2022-2024 Tristan Grimmer. 
6// Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby 
7// granted, provided that the above copyright notice and this permission notice appear in all copies. 
8// 
9// THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL 
10// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, 
11// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN 
12// AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR 
13// PERFORMANCE OF THIS SOFTWARE. 
14 
15#include <Foundation/tAssert.h> 
16#include <Foundation/tStandard.h> 
17#include <Foundation/tSmallFloat.h> 
18#include <System/tMachine.h> 
19#include "Image/tPixelUtil.h" 
20#include "PVRTDecompress/PVRTDecompress.h" 
21#define BCDEC_IMPLEMENTATION 
22#include "bcdec/bcdec.h" 
23#define ETCDEC_IMPLEMENTATION 
24#include "etcdec/etcdec.h" 
25#include "astcenc.h" 
26 
27 
28namespace tImage 
29
30 bool CanReverseRowData_Packed (tPixelFormat); 
31 bool CanReverseRowData_BC (tPixelFormat, int height); 
32 
33 uint8* CreateReversedRowData_Packed (const uint8* pixelData, tPixelFormat pixelDataFormat, int width, int height); 
34 uint8* CreateReversedRowData_BC (const uint8* pixelData, tPixelFormat pixelDataFormat, int numBlocksW, int numBlocksH); 
35 
36 // The BC2 block is the same for DXT2 and DXT3, although we don't support 2 (premultiplied alpha). Size is 128 bits. 
37 #pragma pack(push, 1) 
38 struct BC2Block 
39
40 uint16 AlphaTableRows[4]; // Each alpha is 4 bits. 
41 BC1Block ColourBlock
42 }; 
43 
44 // The BC3 block is the same for DXT4 and 5, although we don't support 4 (premultiplied alpha). Size is 128 bits. 
45 struct BC3Block 
46
47 uint8 Alpha0
48 uint8 Alpha1
49 uint8 AlphaTable[6]; // Each of the 4x4 pixel entries is 3 bits. 
50 BC1Block ColourBlock
51 
52 // These accessors are needed because of the unusual alignment of the 3bit alpha indexes. They each return or set a 
53 // value in [0, 2^12) which represents a single row. The row variable should be in [0, 3] 
54 uint16 GetAlphaRow(int row); 
55 void SetAlphaRow(int row, uint16 val); 
56 
57 }; 
58 #pragma pack(pop) 
59
60 
61 
62tImage::DecodeResult tImage::DecodePixelData(tPixelFormat fmt, const uint8* src, int srcSize, int w, int h, tColour4b*& decoded4b, tColour4f*& decoded4f, tColourProfile profile, float RGBM_RGBD_MaxRange
63
64 if (decoded4b || decoded4f
65 return DecodeResult::BuffersNotClear
66 
67 if (!tIsPackedFormat(format: fmt) && !tIsBCFormat(format: fmt) && !tIsASTCFormat(format: fmt) && !tIsPVRFormat(format: fmt)) 
68 return DecodeResult::UnsupportedFormat
69 
70 if ((w <= 0) || (h <= 0) || !src
71 return DecodeResult::InvalidInput
72 
73 if (tImage::tIsPackedFormat(format: fmt)) 
74
75 return DecodePixelData_Packed(fmt, data: src, dataSize: srcSize, w, h, decoded4b, decoded4f, RGBM_RGBD_MaxRange); 
76
77 else if (tImage::tIsBCFormat(format: fmt)) 
78
79 return DecodePixelData_Block(fmt, data: src, dataSize: srcSize, w, h, decoded4b, decoded4f); 
80
81 else if (tImage::tIsASTCFormat(format: fmt)) 
82
83 return DecodePixelData_ASTC(fmt, data: src, dataSize: srcSize, w, h, decoded4f, profile); 
84
85 else if (tImage::tIsPVRFormat(format: fmt)) 
86
87 return DecodePixelData_PVR(fmt, data: src, dataSize: srcSize, w, h, decoded4b, decoded4f); 
88
89 else // Unsupported PixelFormat 
90
91 return DecodeResult::UnsupportedFormat
92
93 
94 return DecodeResult::Success
95
96 
97 
98tImage::DecodeResult tImage::DecodePixelData_Packed(tPixelFormat fmt, const uint8* src, int srcSize, int w, int h, tColour4b*& decoded4b, tColour4f*& decoded4f, float RGBM_RGBD_MaxRange
99
100 if (decoded4b || decoded4f
101 return DecodeResult::BuffersNotClear
102 
103 if (!tIsPackedFormat(format: fmt)) 
104 return DecodeResult::UnsupportedFormat
105 
106 if ((w <= 0) || (h <= 0) || !src
107 return DecodeResult::InvalidInput
108 
109 switch (fmt
110
111 case tPixelFormat::A8
112 // Convert to 32-bit RGBA with alpha in A and 0s for RGB. 
113 decoded4b = new tColour4b[w*h]; 
114 for (int ij = 0; ij < w*h; ij++) 
115
116 tColour4b col(0u, 0u, 0u, src[ij]); 
117 decoded4b[ij].Set(col); 
118
119 break
120 
121 case tPixelFormat::L8
122 case tPixelFormat::R8
123
124 // Convert to 32-bit RGBA with red or luminance in R and 255 for A. If SpreadLuminance flag set, 
125 // also set luminance or red in the GB channels, if not then GB get 0s. 
126 decoded4b = new tColour4b[w*h]; 
127 for (int ij = 0; ij < w*h; ij++) 
128
129 tColour4b col(src[ij], 0u, 0u, 255u); 
130 decoded4b[ij].Set(col); 
131
132 break
133
134 
135 case tPixelFormat::R8G8
136 decoded4b = new tColour4b[w*h]; 
137 for (int ij = 0; ij < w*h; ij++) 
138
139 tColour4b col(src[ij*2+0], src[ij*2+1], 0u, 255u); 
140 decoded4b[ij].Set(col); 
141
142 break
143 
144 case tPixelFormat::R8G8B8
145 decoded4b = new tColour4b[w*h]; 
146 for (int ij = 0; ij < w*h; ij++) 
147
148 tColour4b col(src[ij*3+0], src[ij*3+1], src[ij*3+2], 255u); 
149 decoded4b[ij].Set(col); 
150
151 break
152  
153 case tPixelFormat::R8G8B8A8
154 decoded4b = new tColour4b[w*h]; 
155 for (int ij = 0; ij < w*h; ij++) 
156
157 tColour4b col(src[ij*4+0], src[ij*4+1], src[ij*4+2], src[ij*4+3]); 
158 decoded4b[ij].Set(col); 
159
160 break
161 
162 case tPixelFormat::B8G8R8
163 decoded4b = new tColour4b[w*h]; 
164 for (int ij = 0; ij < w*h; ij++) 
165
166 tColour4b col(src[ij*3+2], src[ij*3+1], src[ij*3+0], 255u); 
167 decoded4b[ij].Set(col); 
168
169 break
170 
171 case tPixelFormat::B8G8R8A8
172 decoded4b = new tColour4b[w*h]; 
173 for (int ij = 0; ij < w*h; ij++) 
174
175 tColour4b col(src[ij*4+2], src[ij*4+1], src[ij*4+0], src[ij*4+3]); 
176 decoded4b[ij].Set(col); 
177
178 break
179 
180 case tPixelFormat::G3B5R5G3
181 decoded4b = new tColour4b[w*h]; 
182 for (int ij = 0; ij < w*h; ij++) 
183
184 // On an LE machine casting to a uint16 effectively swaps the bytes when doing bit ops. 
185 // This means red will be in the most significant bits -- that's why it looks backwards. 
186 // GGGBBBBB RRRRRGGG in memory is RRRRRGGG GGGBBBBB as a uint16. 
187 uint16 u = *((uint16*)(src+ij*2)); 
188 
189 uint8 r = (u ) >> 11; // 1111 1000 0000 0000 >> 11. 
190 uint8 g = (u & 0x07E0) >> 5; // 0000 0111 1110 0000 >> 5. 
191 uint8 b = (u & 0x001F) ; // 0000 0000 0001 1111 >> 0. 
192 
193 // Normalize to range. 
194 // Careful here, you can't just do bit ops to get the components into position. 
195 // For example, a full red (11111) has to go to 255 (1.0f), and a zero red (00000) to 0(0.0f). 
196 // That is, the normalize has to divide by the range. At first I just masked and shifted the bits 
197 // to the right spot in an 8-bit type, but you don't know what to put in the LSBits. Putting 0s 
198 // would be bad (an 4 bit alpha of 1111 would go to 11110000... suddenly image not fully opaque) 
199 // and putting all 1s would add red (or alpha or whatever) when there was none. Half way won't 
200 // work either. You need the endpoints to work. 
201 float rf = (float(r) / 31.0f); // Max is 2^5 - 1. 
202 float gf = (float(g) / 63.0f); // Max is 2^6 - 1. 
203 float bf = (float(b) / 31.0f); // Max is 2^5 - 1. 
204 tColour4b col(rf, gf, bf, 1.0f); 
205 decoded4b[ij].Set(col); 
206
207 break
208 
209 case tPixelFormat::G4B4A4R4
210 decoded4b = new tColour4b[w*h]; 
211 for (int ij = 0; ij < w*h; ij++) 
212
213 // GGGGBBBB AAAARRRR in memory is AAAARRRR GGGGBBBB as a uint16. 
214 uint16 u = *((uint16*)(src+ij*2)); 
215 uint8 a = (u ) >> 12; // 1111 0000 0000 0000 >> 12. 
216 uint8 r = (u & 0x0F00) >> 8; // 0000 1111 0000 0000 >> 8. 
217 uint8 g = (u & 0x00F0) >> 4; // 0000 0000 1111 0000 >> 4. 
218 uint8 b = (u & 0x000F) ; // 0000 0000 0000 1111 >> 0. 
219 
220 // Normalize to range. See note above. 
221 float af = float(a) / 15.0f; // Max is 2^4 - 1. 
222 float rf = float(r) / 15.0f
223 float gf = float(g) / 15.0f
224 float bf = float(b) / 15.0f
225 
226 tColour4b col(rf, gf, bf, af); 
227 decoded4b[ij].Set(col); 
228
229 break
230 
231 case tPixelFormat::B4A4R4G4
232 decoded4b = new tColour4b[w*h]; 
233 for (int ij = 0; ij < w*h; ij++) 
234
235 // BBBBAAAA RRRRGGGG in memory is RRRRGGGG BBBBAAAA as a uint16. 
236 uint16 u = *((uint16*)(src+ij*2)); 
237 uint8 r = (u ) >> 12; // 1111 0000 0000 0000 >> 12. 
238 uint8 g = (u & 0x0F00) >> 8; // 0000 1111 0000 0000 >> 8. 
239 uint8 b = (u & 0x00F0) >> 4; // 0000 0000 1111 0000 >> 4. 
240 uint8 a = (u & 0x000F) ; // 0000 0000 0000 1111 >> 0. 
241 
242 // Normalize to range. See note above. 
243 float af = float(a) / 15.0f; // Max is 2^4 - 1. 
244 float rf = float(r) / 15.0f
245 float gf = float(g) / 15.0f
246 float bf = float(b) / 15.0f
247 
248 tColour4b col(rf, gf, bf, af); 
249 decoded4b[ij].Set(col); 
250
251 break
252 
253 case tPixelFormat::G3B5A1R5G2
254 decoded4b = new tColour4b[w*h]; 
255 for (int ij = 0; ij < w*h; ij++) 
256
257 // GGGBBBBB ARRRRRGG in memory is ARRRRRGG GGGBBBBB as a uint16. 
258 uint16 u = *((uint16*)(src+ij*2)); 
259 bool a = (u & 0x8000); // 1000 0000 0000 0000. 
260 uint8 r = (u & 0x7C00) >> 10; // 0111 1100 0000 0000 >> 10. 
261 uint8 g = (u & 0x03E0) >> 5; // 0000 0011 1110 0000 >> 5. 
262 uint8 b = (u & 0x001F) ; // 0000 0000 0001 1111 >> 0. 
263 
264 // Normalize to range. See note above. 
265 float rf = float(r) / 31.0f; // Max is 2^5 - 1. 
266 float gf = float(g) / 31.0f
267 float bf = float(b) / 31.0f
268 
269 tColour4b col(rf, gf, bf, a ? 1.0f : 0.0f); 
270 decoded4b[ij].Set(col); 
271
272 break
273 
274 case tPixelFormat::G2B5A1R5G3
275 decoded4b = new tColour4b[w*h]; 
276 for (int ij = 0; ij < w*h; ij++) 
277
278 // GGBBBBBA RRRRRGGG in memory is RRRRRGGG GGBBBBBA as a uint16. 
279 uint16 u = *((uint16*)(src+ij*2)); 
280 uint8 r = (u & 0xF800) >> 11; // 1111 1000 0000 0000 >> 11. 
281 uint8 g = (u & 0x07C0) >> 6; // 0000 0111 1100 0000 >> 6. 
282 uint8 b = (u & 0x003E) >> 1; // 0000 0000 0011 1110 >> 1. 
283 bool a = (u & 0x0001); // 0000 0000 0000 0001. 
284 
285 // Normalize to range. See note above. 
286 float rf = float(r) / 31.0f; // Max is 2^5 - 1. 
287 float gf = float(g) / 31.0f
288 float bf = float(b) / 31.0f
289 
290 tColour4b col(rf, gf, bf, a ? 1.0f : 0.0f); 
291 decoded4b[ij].Set(col); 
292
293 break
294 
295 case tPixelFormat::R16
296
297 decoded4b = new tColour4b[w*h]; 
298 uint16* udata = (uint16*)src
299 for (int ij = 0; ij < w*h; ij++) 
300
301 uint8 r = udata[ij*1 + 0] >> 8
302 tColour4b col(r, 0u, 0u, 255u); 
303 decoded4b[ij].Set(col); 
304
305 break
306
307 
308 case tPixelFormat::R16G16
309
310 decoded4b = new tColour4b[w*h]; 
311 uint16* udata = (uint16*)src
312 for (int ij = 0; ij < w*h; ij++) 
313
314 uint8 r = udata[ij*2 + 0] >> 8
315 uint8 g = udata[ij*2 + 1] >> 8
316 tColour4b col(r, g, 0u, 255u); 
317 decoded4b[ij].Set(col); 
318
319 break
320
321 
322 case tPixelFormat::R16G16B16
323
324 decoded4b = new tColour4b[w*h]; 
325 uint16* udata = (uint16*)src
326 for (int ij = 0; ij < w*h; ij++) 
327
328 uint8 r = udata[ij*3 + 0] >> 8
329 uint8 g = udata[ij*3 + 1] >> 8
330 uint8 b = udata[ij*3 + 2] >> 8
331 tColour4b col(r, g, b, 255u); 
332 decoded4b[ij].Set(col); 
333
334 break
335
336 
337 case tPixelFormat::R16G16B16A16
338
339 decoded4b = new tColour4b[w*h]; 
340 uint16* udata = (uint16*)src
341 for (int ij = 0; ij < w*h; ij++) 
342
343 uint8 r = udata[ij*4 + 0] >> 8
344 uint8 g = udata[ij*4 + 1] >> 8
345 uint8 b = udata[ij*4 + 2] >> 8
346 uint8 a = udata[ij*4 + 3] >> 8
347 tColour4b col(r, g, b, a); 
348 decoded4b[ij].Set(col); 
349
350 break
351
352 
353 case tPixelFormat::R32
354
355 decoded4b = new tColour4b[w*h]; 
356 uint32* udata = (uint32*)src
357 for (int ij = 0; ij < w*h; ij++) 
358
359 uint8 r = udata[ij*1 + 0] >> 24
360 tColour4b col(r, 0u, 0u, 255u); 
361 decoded4b[ij].Set(col); 
362
363 break
364
365 
366 case tPixelFormat::R32G32
367
368 decoded4b = new tColour4b[w*h]; 
369 uint32* udata = (uint32*)src
370 for (int ij = 0; ij < w*h; ij++) 
371
372 uint8 r = udata[ij*2 + 0] >> 24
373 uint8 g = udata[ij*2 + 1] >> 24
374 tColour4b col(r, g, 0u, 255u); 
375 decoded4b[ij].Set(col); 
376
377 break
378
379 
380 case tPixelFormat::R32G32B32
381
382 decoded4b = new tColour4b[w*h]; 
383 uint32* udata = (uint32*)src
384 for (int ij = 0; ij < w*h; ij++) 
385
386 uint8 r = udata[ij*3 + 0] >> 24
387 uint8 g = udata[ij*3 + 1] >> 24
388 uint8 b = udata[ij*3 + 2] >> 24
389 tColour4b col(r, g, b, 255u); 
390 decoded4b[ij].Set(col); 
391
392 break
393
394 
395 case tPixelFormat::R32G32B32A32
396
397 decoded4b = new tColour4b[w*h]; 
398 uint32* udata = (uint32*)src
399 for (int ij = 0; ij < w*h; ij++) 
400
401 uint8 r = udata[ij*4 + 0] >> 24
402 uint8 g = udata[ij*4 + 1] >> 24
403 uint8 b = udata[ij*4 + 2] >> 24
404 uint8 a = udata[ij*4 + 3] >> 24
405 tColour4b col(r, g, b, a); 
406 decoded4b[ij].Set(col); 
407
408 break
409
410 
411 case tPixelFormat::R16f
412
413 // This HDR format has 1 red half-float channel. 
414 decoded4f = new tColour4f[w*h]; 
415 tHalf* hdata = (tHalf*)src
416 for (int ij = 0; ij < w*h; ij++) 
417
418 float r = hdata[ij*1 + 0]; 
419 tColour4f col(r, 0.0f, 0.0f, 1.0f); 
420 decoded4f[ij].Set(col); 
421
422 break
423
424 
425 case tPixelFormat::R16G16f
426
427 // This HDR format has 2 half-float channels. Red and green. 
428 decoded4f = new tColour4f[w*h]; 
429 tHalf* hdata = (tHalf*)src
430 for (int ij = 0; ij < w*h; ij++) 
431
432 float r = hdata[ij*2 + 0]; 
433 float g = hdata[ij*2 + 1]; 
434 tColour4f col(r, g, 0.0f, 1.0f); 
435 decoded4f[ij].Set(col); 
436
437 break
438
439 
440 case tPixelFormat::R16G16B16f
441
442 // This HDR format has 3 half-float channels. RGB. 
443 decoded4f = new tColour4f[w*h]; 
444 tHalf* hdata = (tHalf*)src
445 for (int ij = 0; ij < w*h; ij++) 
446
447 float r = hdata[ij*3 + 0]; 
448 float g = hdata[ij*3 + 1]; 
449 float b = hdata[ij*3 + 2]; 
450 tColour4f col(r, g, b, 1.0f); 
451 decoded4f[ij].Set(col); 
452
453 break
454
455 
456 case tPixelFormat::R16G16B16A16f
457
458 // This HDR format has 4 half-float channels. RGBA. 
459 decoded4f = new tColour4f[w*h]; 
460 tHalf* hdata = (tHalf*)src
461 for (int ij = 0; ij < w*h; ij++) 
462
463 float r = hdata[ij*4 + 0]; 
464 float g = hdata[ij*4 + 1]; 
465 float b = hdata[ij*4 + 2]; 
466 float a = hdata[ij*4 + 3]; 
467 tColour4f col(r, g, b, a); 
468 decoded4f[ij].Set(col); 
469
470 break
471
472 
473 case tPixelFormat::R32f
474
475 // This HDR format has 1 red float channel. 
476 decoded4f = new tColour4f[w*h]; 
477 float* fdata = (float*)src
478 for (int ij = 0; ij < w*h; ij++) 
479
480 float r = fdata[ij*1 + 0]; 
481 tColour4f col(r, 0.0f, 0.0f, 1.0f); 
482 decoded4f[ij].Set(col); 
483
484 break
485
486 
487 case tPixelFormat::R32G32f
488
489 // This HDR format has 2 float channels. Red and green. 
490 decoded4f = new tColour4f[w*h]; 
491 float* fdata = (float*)src
492 for (int ij = 0; ij < w*h; ij++) 
493
494 float r = fdata[ij*2 + 0]; 
495 float g = fdata[ij*2 + 1]; 
496 tColour4f col(r, g, 0.0f, 1.0f); 
497 decoded4f[ij].Set(col); 
498
499 break
500
501 
502 case tPixelFormat::R32G32B32f
503
504 // This HDR format has 3 float channels. RGB. 
505 decoded4f = new tColour4f[w*h]; 
506 float* fdata = (float*)src
507 for (int ij = 0; ij < w*h; ij++) 
508
509 float r = fdata[ij*3 + 0]; 
510 float g = fdata[ij*3 + 1]; 
511 float b = fdata[ij*3 + 2]; 
512 tColour4f col(r, g, b, 1.0f); 
513 decoded4f[ij].Set(col); 
514
515 break
516
517 
518 case tPixelFormat::R32G32B32A32f
519
520 // This HDR format has 4 RGBA floats. 
521 decoded4f = new tColour4f[w*h]; 
522 float* fdata = (float*)src
523 for (int ij = 0; ij < w*h; ij++) 
524
525 float r = fdata[ij*4 + 0]; 
526 float g = fdata[ij*4 + 1]; 
527 float b = fdata[ij*4 + 2]; 
528 float a = fdata[ij*4 + 3]; 
529 tColour4f col(r, g, b, a); 
530 decoded4f[ij].Set(col); 
531
532 break
533
534 
535 case tPixelFormat::R11G11B10uf
536
537 // This HDR format has 3 RGB floats packed into 32-bits. 
538 decoded4f = new tColour4f[w*h]; 
539 uint32* fdata = (uint32*)src
540 for (int ij = 0; ij < w*h; ij++) 
541
542 tPackedF11F11F10 packed(fdata[ij]); 
543 float r, g, b
544 packed.Get(x&: r, y&: g, z&: b); 
545 tColour4f col(r, g, b, 1.0f); 
546 decoded4f[ij].Set(col); 
547
548 break
549
550 
551 case tPixelFormat::B10G11R11uf
552
553 // This HDR format has 3 RGB floats packed into 32-bits. 
554 decoded4f = new tColour4f[w*h]; 
555 uint32* fdata = (uint32*)src
556 for (int ij = 0; ij < w*h; ij++) 
557
558 tPackedF10F11F11 packed(fdata[ij]); 
559 float r, g, b
560 packed.Get(x&: b, y&: g, z&: r); 
561 tColour4f col(r, g, b, 1.0f); 
562 decoded4f[ij].Set(col); 
563
564 break
565
566 
567 case tPixelFormat::R9G9B9E5uf
568
569 // This HDR format has 3 RGB floats packed into 32-bits. 
570 decoded4f = new tColour4f[w*h]; 
571 uint32* fdata = (uint32*)src
572 for (int ij = 0; ij < w*h; ij++) 
573
574 tPackedM9M9M9E5 packed(fdata[ij]); 
575 float r, g, b
576 packed.Get(x&: r, y&: g, z&: b); 
577 tColour4f col(r, g, b, 1.0f); 
578 decoded4f[ij].Set(col); 
579
580 break
581
582 
583 case tPixelFormat::E5B9G9R9uf
584
585 // This HDR format has 3 RGB floats packed into 32-bits. 
586 decoded4f = new tColour4f[w*h]; 
587 uint32* fdata = (uint32*)src
588 for (int ij = 0; ij < w*h; ij++) 
589
590 tPackedE5M9M9M9 packed(fdata[ij]); 
591 float r, g, b
592 packed.Get(x&: b, y&: g, z&: r); 
593 tColour4f col(r, g, b, 1.0f); 
594 decoded4f[ij].Set(col); 
595
596 break
597
598 
599 case tPixelFormat::R8G8B8M8
600
601 // This HDR format has 8-bit RGB components and a shared 8-bit multiplier. 
602 decoded4f = new tColour4f[w*h]; 
603 uint8* udata = (uint8*)src
604 for (int ij = 0; ij < w*h; ij++) 
605
606 float r = float(src[ij*4+0]) / 255.0f
607 float g = float(src[ij*4+1]) / 255.0f
608 float b = float(src[ij*4+2]) / 255.0f
609 float m = float(src[ij*4+3]) / 255.0f
610 r *= m * RGBM_RGBD_MaxRange
611 g *= m * RGBM_RGBD_MaxRange
612 b *= m * RGBM_RGBD_MaxRange
613 tColour4f col(r, g, b, 1.0f); 
614 decoded4f[ij].Set(col); 
615
616 break
617
618 
619 case tPixelFormat::R8G8B8D8
620
621 // This HDR format has 8-bit RGB components and a shared 8-bit divisor. 
622 decoded4f = new tColour4f[w*h]; 
623 uint8* udata = (uint8*)src
624 for (int ij = 0; ij < w*h; ij++) 
625
626 float r = float(src[ij*4+0]) / 255.0f
627 float g = float(src[ij*4+1]) / 255.0f
628 float b = float(src[ij*4+2]) / 255.0f
629 float d = float(src[ij*4+3]) / 255.0f
630 if (d == 0.0f
631
632 r = 0.0f
633 g = 0.0f
634 b = 0.0f
635 d = 1.0f
636
637 r *= (RGBM_RGBD_MaxRange/255.0f) / d
638 g *= (RGBM_RGBD_MaxRange/255.0f) / d
639 b *= (RGBM_RGBD_MaxRange/255.0f) / d
640 tColour4f col(r, g, b, 1.0f); 
641 decoded4f[ij].Set(col); 
642
643 break
644
645 
646 default
647 return DecodeResult::PackedDecodeError
648
649 
650 return DecodeResult::Success
651
652 
653 
654tImage::DecodeResult tImage::DecodePixelData_Block(tPixelFormat fmt, const uint8* src, int srcSize, int w, int h, tColour4b*& decoded4b, tColour4f*& decoded4f
655
656 if (decoded4b || decoded4f
657 return DecodeResult::BuffersNotClear
658 
659 if (!tIsBCFormat(format: fmt)) 
660 return DecodeResult::UnsupportedFormat
661 
662 if ((w <= 0) || (h <= 0) || !src
663 return DecodeResult::InvalidInput
664 
665 // We need extra room because the decompressor (bcdec) does not take an input for 
666 // the width and height, only the pitch (bytes per row). This means a texture that is 5 
667 // high will actually have row 6, 7, 8 written to. 
668 int wfull = 4 * tGetNumBlocks(blockWH: 4, imageWH: w); 
669 int hfull = 4 * tGetNumBlocks(blockWH: 4, imageWH: h); 
670 tColour4b* decodedFull4i = nullptr
671 tColour4f* decodedFull4f = nullptr
672 switch (fmt
673
674 case tPixelFormat::BC1DXT1
675 case tPixelFormat::BC1DXT1A
676
677 decodedFull4i = new tColour4b[wfull*hfull]; 
678 for (int y = 0; y < hfull; y += 4
679 for (int x = 0; x < wfull; x += 4
680
681 uint8* dst = (uint8*)decodedFull4i + (y*wfull + x) * 4
682 
683 // At first didn't understand the pitch (3rd) argument. It's cuz the block needs to be written into 
684 // multiple rows of the destination and we need to know how far to increment to the next row of 4. 
685 bcdec_bc1(compressedBlock: src, decompressedBlock: dst, destinationPitch: wfull * 4); 
686 src += BCDEC_BC1_BLOCK_SIZE
687
688 
689 break
690
691 
692 case tPixelFormat::BC2DXT2DXT3
693
694 decodedFull4i = new tColour4b[wfull*hfull]; 
695 for (int y = 0; y < hfull; y += 4
696 for (int x = 0; x < wfull; x += 4
697
698 uint8* dst = (uint8*)decodedFull4i + (y*wfull + x) * 4
699 bcdec_bc2(compressedBlock: src, decompressedBlock: dst, destinationPitch: wfull * 4); 
700 src += BCDEC_BC2_BLOCK_SIZE
701
702 break
703
704 
705 case tPixelFormat::BC3DXT4DXT5
706
707 decodedFull4i = new tColour4b[wfull*hfull]; 
708 for (int y = 0; y < hfull; y += 4
709 for (int x = 0; x < wfull; x += 4
710
711 uint8* dst = (uint8*)decodedFull4i + (y*wfull + x) * 4
712 bcdec_bc3(compressedBlock: src, decompressedBlock: dst, destinationPitch: wfull * 4); 
713 src += BCDEC_BC3_BLOCK_SIZE
714
715 break
716
717 
718 case tPixelFormat::BC4ATI1U
719
720 // This HDR format decompresses to R uint8s. 
721 uint8* rdata = new uint8[wfull*hfull]; 
722 for (int y = 0; y < hfull; y += 4
723 for (int x = 0; x < wfull; x += 4
724
725 uint8* dst = (rdata + (y*wfull + x) * 1); 
726 bcdec_bc4(compressedBlock: src, decompressedBlock: dst, destinationPitch: wfull * 1); 
727 src += BCDEC_BC4_BLOCK_SIZE
728
729 
730 // Now convert to 32-bit RGBA. 
731 decodedFull4i = new tColour4b[wfull*hfull]; 
732 for (int xy = 0; xy < wfull*hfull; xy++) 
733
734 uint8 v = rdata[xy]; 
735 tColour4b col(v, 0u, 0u, 255u); 
736 decodedFull4i[xy].Set(col); 
737
738 delete[] rdata
739 break
740
741 
742 case tPixelFormat::BC4ATI1S
743
744 // This HDR format decompresses to R uint8s. 
745 uint8* rdata = new uint8[wfull*hfull]; 
746 for (int y = 0; y < hfull; y += 4
747 for (int x = 0; x < wfull; x += 4
748
749 uint8* dst = (rdata + (y*wfull + x) * 1); 
750 bcdec_bc4(compressedBlock: src, decompressedBlock: dst, destinationPitch: wfull * 1); 
751 src += BCDEC_BC4_BLOCK_SIZE
752
753 
754 // Now convert to 32-bit RGBA. 
755 decodedFull4i = new tColour4b[wfull*hfull]; 
756 for (int xy = 0; xy < wfull*hfull; xy++) 
757
758 int vi = *((int8*)&rdata[xy]); 
759 vi += 128
760 uint8 v = uint8(vi); 
761 tColour4b col(v, 0u, 0u, 255u); 
762 decodedFull4i[xy].Set(col); 
763
764 delete[] rdata
765 break
766
767 
768 case tPixelFormat::BC5ATI2U
769
770 // This HDR format decompresses to RG uint8s. 
771 struct RG { uint8 R; uint8 G; }; 
772 RG* rgData = new RG[wfull*hfull]; 
773 
774 for (int y = 0; y < hfull; y += 4
775 for (int x = 0; x < wfull; x += 4
776
777 uint8* dst = (uint8*)rgData + (y*wfull + x) * 2
778 bcdec_bc5(compressedBlock: src, decompressedBlock: dst, destinationPitch: wfull * 2); 
779 src += BCDEC_BC5_BLOCK_SIZE
780
781 
782 // Now convert to 32-bit RGBA with 0,255 for B,A. 
783 decodedFull4i = new tColour4b[wfull*hfull]; 
784 for (int xy = 0; xy < wfull*hfull; xy++) 
785
786 tColour4b col(rgData[xy].R, rgData[xy].G, 0u, 255u); 
787 decodedFull4i[xy].Set(col); 
788
789 delete[] rgData
790 break
791
792 
793 case tPixelFormat::BC5ATI2S
794
795 // This HDR format decompresses to RG uint8s. 
796 struct RG { uint8 R; uint8 G; }; 
797 RG* rgData = new RG[wfull*hfull]; 
798 
799 for (int y = 0; y < hfull; y += 4
800 for (int x = 0; x < wfull; x += 4
801
802 uint8* dst = (uint8*)rgData + (y*wfull + x) * 2
803 bcdec_bc5(compressedBlock: src, decompressedBlock: dst, destinationPitch: wfull * 2); 
804 src += BCDEC_BC5_BLOCK_SIZE
805
806 
807 // Now convert to 32-bit RGBA with 0,255 for B,A. 
808 decodedFull4i = new tColour4b[wfull*hfull]; 
809 for (int xy = 0; xy < wfull*hfull; xy++) 
810
811 int iR = *((int8*)&rgData[xy].R); 
812 int iG = *((int8*)&rgData[xy].G); 
813 iR += 128
814 iG += 128
815 tColour4b col(uint8(iR), uint8(iG), 0u, 255u); 
816 decodedFull4i[xy].Set(col); 
817
818 delete[] rgData
819 break
820
821 
822 case tPixelFormat::BC6U
823 case tPixelFormat::BC6S
824
825 // This HDR format decompresses to RGB floats. 
826 tColour3f* rgbData = new tColour3f[wfull*hfull]; 
827 
828 for (int y = 0; y < hfull; y += 4
829 for (int x = 0; x < wfull; x += 4
830
831 uint8* dst = (uint8*)((float*)rgbData + (y*wfull + x) * 3); 
832 bool signedData = fmt == tPixelFormat::BC6S
833 bcdec_bc6h_float(compressedBlock: src, decompressedBlock: dst, destinationPitch: wfull * 3, isSigned: signedData); 
834 src += BCDEC_BC6H_BLOCK_SIZE
835
836 
837 // Now convert to 4-float (128-bit) RGBA with 1.0f alpha. 
838 decodedFull4f = new tColour4f[wfull*hfull]; 
839 for (int xy = 0; xy < wfull*hfull; xy++) 
840
841 tColour4f col(rgbData[xy], 1.0f); 
842 decodedFull4f[xy].Set(col); 
843
844 delete[] rgbData
845 break
846
847 
848 case tPixelFormat::BC7
849
850 decodedFull4i = new tColour4b[wfull*hfull]; 
851 for (int y = 0; y < hfull; y += 4
852 for (int x = 0; x < wfull; x += 4
853
854 uint8* dst = (uint8*)decodedFull4i + (y*wfull + x) * 4
855 bcdec_bc7(compressedBlock: src, decompressedBlock: dst, destinationPitch: wfull * 4); 
856 src += BCDEC_BC7_BLOCK_SIZE
857
858 break
859
860 
861 case tPixelFormat::ETC1
862 case tPixelFormat::ETC2RGB: // Same decoder. Backwards compatible. 
863
864 decodedFull4i = new tColour4b[wfull*hfull]; 
865 for (int y = 0; y < hfull; y += 4
866 for (int x = 0; x < wfull; x += 4
867
868 uint8* dst = (uint8*)decodedFull4i + (y*wfull + x) * 4
869 etcdec_etc_rgb(compressedBlock: src, decompressedBlock: dst, destinationPitch: wfull * 4); 
870 src += ETCDEC_ETC_RGB_BLOCK_SIZE
871
872 break
873
874 
875 case tPixelFormat::ETC2RGBA
876
877 decodedFull4i = new tColour4b[wfull*hfull]; 
878 for (int y = 0; y < hfull; y += 4
879 for (int x = 0; x < wfull; x += 4
880
881 uint8* dst = (uint8*)decodedFull4i + (y*wfull + x) * 4
882 etcdec_eac_rgba(compressedBlock: src, decompressedBlock: dst, destinationPitch: wfull * 4); 
883 src += ETCDEC_EAC_RGBA_BLOCK_SIZE
884
885 break
886
887 
888 case tPixelFormat::ETC2RGBA1
889
890 decodedFull4i = new tColour4b[wfull*hfull]; 
891 for (int y = 0; y < hfull; y += 4
892 for (int x = 0; x < wfull; x += 4
893
894 uint8* dst = (uint8*)decodedFull4i + (y*wfull + x) * 4
895 etcdec_etc_rgb_a1(compressedBlock: src, decompressedBlock: dst, destinationPitch: wfull * 4); 
896 src += ETCDEC_ETC_RGB_A1_BLOCK_SIZE
897
898 break
899
900 
901 case tPixelFormat::EACR11U
902
903 // This format decompresses to R uint16. 
904 uint16* rdata = new uint16[wfull*hfull]; 
905 
906 for (int y = 0; y < hfull; y += 4
907 for (int x = 0; x < wfull; x += 4
908
909 uint16* dst = (rdata + (y*wfull + x) * 1); 
910 etcdec_eac_r11_u16(compressedBlock: src, decompressedBlock: dst, destinationPitch: wfull * sizeof(uint16)); 
911 src += ETCDEC_EAC_R11_BLOCK_SIZE
912
913 
914 // Now convert to 32-bit RGBA. 
915 decodedFull4i = new tColour4b[wfull*hfull]; 
916 for (int xy = 0; xy < wfull*hfull; xy++) 
917
918 uint8 v = uint8( (255*rdata[xy]) / 65535 ); 
919 tColour4b col(v, 0u, 0u, 255u); 
920 decodedFull4i[xy].Set(col); 
921
922 delete[] rdata
923 break
924
925 
926 case tPixelFormat::EACR11S
927
928 // This format decompresses to R float. 
929 float* rdata = new float[wfull*hfull]; 
930 
931 for (int y = 0; y < hfull; y += 4
932 for (int x = 0; x < wfull; x += 4
933
934 float* dst = (rdata + (y*wfull + x) * 1); 
935 etcdec_eac_r11_float(compressedBlock: src, decompressedBlock: dst, destinationPitch: wfull * sizeof(float), isSigned: 1); 
936 src += ETCDEC_EAC_R11_BLOCK_SIZE
937
938 
939 // Now convert to 32-bit RGBA. 
940 decodedFull4i = new tColour4b[wfull*hfull]; 
941 for (int xy = 0; xy < wfull*hfull; xy++) 
942
943 float vf = tMath::tSaturate(val: (rdata[xy]+1.0f) / 2.0f); 
944 uint8 v = uint8( 255.0f * vf ); 
945 tColour4b col(v, 0u, 0u, 255u); 
946 decodedFull4i[xy].Set(col); 
947
948 delete[] rdata
949 break
950
951 
952 case tPixelFormat::EACRG11U
953
954 struct RG { uint16 R; uint16 G; }; 
955 // This format decompresses to RG uint16s. 
956 RG* rdata = new RG[wfull*hfull]; 
957 
958 for (int y = 0; y < hfull; y += 4
959 for (int x = 0; x < wfull; x += 4
960
961 uint16* dst = (uint16*)rdata + (y*wfull + x) * 2
962 etcdec_eac_rg11_u16(compressedBlock: src, decompressedBlock: dst, destinationPitch: wfull * sizeof(RG)); 
963 src += ETCDEC_EAC_RG11_BLOCK_SIZE
964
965 
966 // Now convert to 32-bit RGBA. 
967 decodedFull4i = new tColour4b[wfull*hfull]; 
968 for (int xy = 0; xy < wfull*hfull; xy++) 
969
970 uint8 r = uint8( (255*rdata[xy].R) / 65535 ); 
971 uint8 g = uint8( (255*rdata[xy].G) / 65535 ); 
972 tColour4b col(r, g, 0u, 255u); 
973 decodedFull4i[xy].Set(col); 
974
975 delete[] rdata
976 break
977
978 
979 case tPixelFormat::EACRG11S
980
981 struct RG { float R; float G; }; 
982 // This format decompresses to RG floats. 
983 RG* rdata = new RG[wfull*hfull]; 
984 
985 for (int y = 0; y < hfull; y += 4
986 for (int x = 0; x < wfull; x += 4
987
988 float* dst = (float*)rdata + (y*wfull + x) * 2
989 etcdec_eac_rg11_float(compressedBlock: src, decompressedBlock: dst, destinationPitch: wfull * sizeof(RG), isSigned: 1); 
990 src += ETCDEC_EAC_RG11_BLOCK_SIZE
991
992 
993 // Now convert to 32-bit RGBA. 
994 decodedFull4i = new tColour4b[wfull*hfull]; 
995 for (int xy = 0; xy < wfull*hfull; xy++) 
996
997 float rf = tMath::tSaturate(val: (rdata[xy].R+1.0f) / 2.0f); 
998 float gf = tMath::tSaturate(val: (rdata[xy].G+1.0f) / 2.0f); 
999 uint8 r = uint8( 255.0f * rf ); 
1000 uint8 g = uint8( 255.0f * gf ); 
1001 tColour4b col(r, g, 0u, 255u); 
1002 decodedFull4i[xy].Set(col); 
1003
1004 delete[] rdata
1005 break
1006
1007 
1008 default
1009 return DecodeResult::BlockDecodeError
1010
1011 
1012 // Decode worked. We are now in RGBA 32-bit or float 128-bit. Width and height are already correct. 
1013 // This isn't the most efficient because we don't have a stride in a tLayer, but correctness first. 
1014 // Basically the decodedFull data may be too big if we needed extra room for w and h to do the decompression. 
1015 // This happens when the image dimensions where not multiples of the block size. We deal with that here. 
1016 // This is only inefficient if the dimensions were not a mult of 4, otherwise we can use the buffer directly. 
1017 tAssert((decodedFull4i || decodedFull4f) && !(decodedFull4i && decodedFull4f)); 
1018 
1019 // At this point the job is to get decoded4b or decoded4f to be valid. First check if sizes match exactly. 
1020 if ((wfull == w) && (hfull == h)) 
1021
1022 decoded4b = decodedFull4i
1023 decoded4f = decodedFull4f
1024
1025 else 
1026
1027 if (decodedFull4i
1028
1029 decoded4b = new tColour4b[w*h]; 
1030 tColour4b* src = decodedFull4i
1031 tColour4b* dst = decoded4b
1032 for (int r = 0; r < h; r++) 
1033
1034 tStd::tMemcpy(dest: dst, src, numBytes: w*sizeof(tColour4b)); 
1035 src += wfull
1036 dst += w
1037
1038 delete[] decodedFull4i
1039
1040 else if (decodedFull4f
1041
1042 decoded4f = new tColour4f[w*h]; 
1043 tColour4f* src = decodedFull4f
1044 tColour4f* dst = decoded4f
1045 for (int r = 0; r < h; r++) 
1046
1047 tStd::tMemcpy(dest: dst, src, numBytes: w*sizeof(tColour4f)); 
1048 src += wfull
1049 dst += w
1050
1051 delete[] decodedFull4f
1052
1053
1054 
1055 return DecodeResult::Success
1056
1057 
1058 
1059tImage::DecodeResult tImage::DecodePixelData_ASTC(tPixelFormat fmt, const uint8* src, int srcSize, int w, int h, tColour4f*& decoded4f, tColourProfile profile
1060
1061 if (decoded4f
1062 return DecodeResult::BuffersNotClear
1063 
1064 if (!tIsASTCFormat(format: fmt)) 
1065 return DecodeResult::UnsupportedFormat
1066 
1067 if ((w <= 0) || (h <= 0) || !src
1068 return DecodeResult::InvalidInput
1069 
1070 int blockW = 0
1071 int blockH = 0
1072 int blockD = 1
1073 
1074 // Convert source colour profile to astc colour profile. 
1075 astcenc_profile profileastc = ASTCENC_PRF_LDR_SRGB
1076 switch (profile
1077
1078 case tColourProfile::Auto: profileastc = ASTCENC_PRF_HDR_RGB_LDR_A;break; // Works for LDR also. 
1079 case tColourProfile::LDRsRGB_LDRlA: profileastc = ASTCENC_PRF_LDR_SRGB; break
1080 case tColourProfile::LDRgRGB_LDRlA: profileastc = ASTCENC_PRF_LDR_SRGB; break; // Best approximation. 
1081 case tColourProfile::LDRlRGBA: profileastc = ASTCENC_PRF_LDR; break
1082 case tColourProfile::HDRlRGB_LDRlA: profileastc = ASTCENC_PRF_HDR_RGB_LDR_A;break
1083 case tColourProfile::HDRlRGBA: profileastc = ASTCENC_PRF_HDR; break
1084
1085 
1086 switch (fmt
1087
1088 case tPixelFormat::ASTC4X4: blockW = 4; blockH = 4; break
1089 case tPixelFormat::ASTC5X4: blockW = 5; blockH = 4; break
1090 case tPixelFormat::ASTC5X5: blockW = 5; blockH = 5; break
1091 case tPixelFormat::ASTC6X5: blockW = 6; blockH = 5; break
1092 case tPixelFormat::ASTC6X6: blockW = 6; blockH = 6; break
1093 case tPixelFormat::ASTC8X5: blockW = 8; blockH = 5; break
1094 case tPixelFormat::ASTC8X6: blockW = 8; blockH = 6; break
1095 case tPixelFormat::ASTC8X8: blockW = 8; blockH = 8; break
1096 case tPixelFormat::ASTC10X5: blockW = 10; blockH = 5; break
1097 case tPixelFormat::ASTC10X6: blockW = 10; blockH = 6; break
1098 case tPixelFormat::ASTC10X8: blockW = 10; blockH = 8; break
1099 case tPixelFormat::ASTC10X10: blockW = 10; blockH = 10; break
1100 case tPixelFormat::ASTC12X10: blockW = 12; blockH = 10; break
1101 case tPixelFormat::ASTC12X12: blockW = 12; blockH = 12; break
1102 default: break
1103
1104 
1105 if (!blockW || !blockH
1106 return DecodeResult::ASTCDecodeError
1107 
1108 float quality = ASTCENC_PRE_MEDIUM; // Only need for compression. 
1109 astcenc_error result = ASTCENC_SUCCESS
1110 astcenc_config config
1111 astcenc_config_init(profile: profileastc, block_x: blockW, block_y: blockH, block_z: blockD, quality, flags: ASTCENC_FLG_DECOMPRESS_ONLY, config: &config); 
1112 
1113 // astcenc_get_error_string(status) can be called for details. 
1114 if (result != ASTCENC_SUCCESS
1115 return DecodeResult::ASTCDecodeError
1116 
1117 astcenc_context* context = nullptr
1118 int numThreads = tMath::tMax(a: tSystem::tGetNumCores(), b: 2); 
1119 result = astcenc_context_alloc(config: &config, thread_count: numThreads, context: &context); 
1120 if (result != ASTCENC_SUCCESS
1121 return DecodeResult::ASTCDecodeError
1122 
1123 decoded4f = new tColour4f[w*h]; 
1124 astcenc_image image
1125 image.dim_x = w
1126 image.dim_y = h
1127 image.dim_z = 1
1128 image.data_type = ASTCENC_TYPE_F32
1129 
1130 tColour4f* slices = decoded4f
1131 image.data = reinterpret_cast<void**>(&slices); 
1132 astcenc_swizzle swizzle { .r: ASTCENC_SWZ_R, .g: ASTCENC_SWZ_G, .b: ASTCENC_SWZ_B, .a: ASTCENC_SWZ_A }; 
1133 
1134 result = astcenc_decompress_image(context, data: src, data_len: srcSize, image_out: &image, swizzle: &swizzle, thread_index: 0); 
1135 if (result != ASTCENC_SUCCESS
1136
1137 astcenc_context_free(context); 
1138 delete[] decoded4f
1139 decoded4f = nullptr
1140 return DecodeResult::ASTCDecodeError
1141
1142 astcenc_context_free(context); 
1143 
1144 return DecodeResult::Success
1145
1146 
1147 
1148tImage::DecodeResult tImage::DecodePixelData_PVR(tPixelFormat fmt, const uint8* src, int srcSize, int w, int h, tColour4b*& decoded4b, tColour4f*& decoded4f
1149
1150 if (decoded4b || decoded4f
1151 return DecodeResult::BuffersNotClear
1152 
1153 if (!tIsPVRFormat(format: fmt)) 
1154 return DecodeResult::UnsupportedFormat
1155 
1156 if ((w <= 0) || (h <= 0) || !src
1157 return DecodeResult::InvalidInput
1158 
1159 // The PVRTDecompress calls expect the decoded destination array to be bug enough to handle w*h tColour4b pixels. 
1160 // The function handles cases where the min width and height are too small, so even a 1x1 image can be handed off. 
1161 switch (fmt
1162
1163 case tPixelFormat::PVRBPP4
1164
1165 decoded4b = new tColour4b[w*h]; 
1166 uint32_t do2bitMode = 0
1167 uint32_t numSrcBytesDecompressed = pvr::PVRTDecompressPVRTC(compressedData: src, do2bitMode, xDim: w, yDim: h, outResultImage: (uint8_t*)decoded4b); 
1168 if (numSrcBytesDecompressed == 0
1169
1170 delete[] decoded4b
1171 decoded4b = nullptr
1172 return DecodeResult::PVRDecodeError
1173
1174 break
1175
1176 
1177 case tPixelFormat::PVRBPP2
1178
1179 decoded4b = new tColour4b[w*h]; 
1180 uint32_t do2bitMode = 1
1181 uint32_t numSrcBytesDecompressed = pvr::PVRTDecompressPVRTC(compressedData: src, do2bitMode, xDim: w, yDim: h, outResultImage: (uint8_t*)decoded4b); 
1182 if (numSrcBytesDecompressed == 0
1183
1184 delete[] decoded4b
1185 decoded4b = nullptr
1186 return DecodeResult::PVRDecodeError
1187
1188 break
1189
1190 
1191 #ifdef PIXEL_FORMAT_INCLUDE_NOT_IMPLEMENTED 
1192 case tPixelFormat::PVR2BPP4: 
1193 case tPixelFormat::PVR2BPP2: 
1194 return DecodeResult::UnsupportedFormat; 
1195 
1196 case tPixelFormat::PVRHDRBPP8: 
1197 case tPixelFormat::PVRHDRBPP6: 
1198 return DecodeResult::UnsupportedFormat; 
1199 
1200 case tPixelFormat::PVR2HDRBPP8: 
1201 case tPixelFormat::PVR2HDRBPP6: 
1202 return DecodeResult::UnsupportedFormat; 
1203 #endif 
1204 
1205 default
1206 return DecodeResult::PVRDecodeError
1207
1208 
1209 return DecodeResult::Success
1210
1211 
1212 
1213uint16 tImage::BC3Block::GetAlphaRow(int row
1214
1215 tAssert(row < 4); 
1216 switch (row
1217
1218 case 1
1219 return (AlphaTable[2] << 4) | (0x0F & (AlphaTable[1] >> 4)); 
1220 
1221 case 0
1222 return ((AlphaTable[1] & 0x0F) << 8) | AlphaTable[0]; 
1223 
1224 case 3
1225 return (AlphaTable[5] << 4) | (0x0F & (AlphaTable[4] >> 4)); 
1226 
1227 case 2
1228 return ((AlphaTable[4] & 0x0F) << 8) | AlphaTable[3]; 
1229
1230 return 0
1231
1232 
1233 
1234void tImage::BC3Block::SetAlphaRow(int row, uint16 val
1235
1236 tAssert(row < 4); 
1237 tAssert(val < 4096); 
1238 switch (row
1239
1240 case 1
1241 AlphaTable[2] = val >> 4
1242 AlphaTable[1] = (AlphaTable[1] & 0x0F) | ((val & 0x000F) << 4); 
1243 break
1244 
1245 case 0
1246 AlphaTable[1] = (AlphaTable[1] & 0xF0) | (val >> 8); 
1247 AlphaTable[0] = val & 0x00FF
1248 break
1249 
1250 case 3
1251 AlphaTable[5] = val >> 4
1252 AlphaTable[4] = (AlphaTable[4] & 0x0F) | ((val & 0x000F) << 4); 
1253 break
1254 
1255 case 2
1256 AlphaTable[4] = (AlphaTable[4] & 0xF0) | (val >> 8); 
1257 AlphaTable[3] = val & 0x00FF
1258 break
1259
1260
1261 
1262 
1263bool tImage::DoBC1BlocksHaveBinaryAlpha(tImage::BC1Block* block, int numBlocks
1264
1265 // The only way to check if the DXT1 format has alpha is by checking each block individually. If the block uses 
1266 // alpha, the min and max colours are ordered in a particular order. 
1267 for (int b = 0; b < numBlocks; b++) 
1268
1269 if (block->Colour0 <= block->Colour1
1270
1271 // It seems that at least the nVidia DXT compressor can generate an opaque DXT1 block with the colours in the order for a transparent one. 
1272 // This forces us to check all the indexes to see if the alpha index (11 in binary) is used -- if not then it's still an opaque block. 
1273 for (int row = 0; row < 4; row++) 
1274
1275 uint8 bits = block->LookupTableRows[row]; 
1276 if 
1277
1278 ((bits & 0x03) == 0x03) || 
1279 ((bits & 0x0C) == 0x0C) || 
1280 ((bits & 0x30) == 0x30) || 
1281 ((bits & 0xC0) == 0xC0
1282
1283
1284 return true
1285
1286
1287
1288 
1289 block++; 
1290
1291 
1292 return false
1293
1294 
1295 
1296bool tImage::CanReverseRowData(tPixelFormat format, int height
1297
1298 if (tIsPackedFormat(format)) 
1299 return CanReverseRowData_Packed(format); 
1300 
1301 if (tIsBCFormat(format)) 
1302 return CanReverseRowData_BC(format, height); 
1303 
1304 return false
1305
1306 
1307 
1308uint8* tImage::CreateReversedRowData(const uint8* pixelData, tPixelFormat pixelDataFormat, int numBlocksW, int numBlocksH
1309
1310 if (tIsPackedFormat(format: pixelDataFormat)) 
1311 return CreateReversedRowData_Packed(pixelData, pixelDataFormat, width: numBlocksW, height: numBlocksH); 
1312 
1313 if (tIsBCFormat(format: pixelDataFormat)) 
1314 return CreateReversedRowData_BC(pixelData, pixelDataFormat, numBlocksW, numBlocksH); 
1315 
1316 return nullptr
1317
1318 
1319 
1320bool tImage::CanReverseRowData_Packed(tPixelFormat format
1321
1322 int bitsPerPixel = tImage::tGetBitsPerPixel(format); 
1323 if ((bitsPerPixel % 8) == 0
1324 return true
1325 
1326 return false
1327
1328 
1329 
1330uint8* tImage::CreateReversedRowData_Packed(const uint8* pixelData, tPixelFormat pixelDataFormat, int width, int height
1331
1332 // We only support pixel formats that contain a whole number of bytes per pixel. 
1333 // That will cover all reasonable RGB and RGBA formats, but not ASTC formats. 
1334 if (!CanReverseRowData_Packed(format: pixelDataFormat)) 
1335 return nullptr
1336 
1337 int bitsPerPixel = tImage::tGetBitsPerPixel(pixelDataFormat); 
1338 int bytesPerPixel = bitsPerPixel/8
1339 int numBytes = width*height*bytesPerPixel
1340 
1341 uint8* reversedPixelData = new uint8[numBytes]; 
1342 uint8* dstData = reversedPixelData
1343 for (int row = height-1; row >= 0; row--) 
1344
1345 for (int col = 0; col < width; col++) 
1346
1347 const uint8* srcData = pixelData + row*bytesPerPixel*width + col*bytesPerPixel
1348 for (int byte = 0; byte < bytesPerPixel; byte++, dstData++, srcData++) 
1349 *dstData = *srcData
1350
1351
1352 return reversedPixelData
1353
1354 
1355 
1356bool tImage::CanReverseRowData_BC(tPixelFormat format, int height
1357
1358 switch (format
1359
1360 case tPixelFormat::BC1DXT1A
1361 case tPixelFormat::BC1DXT1
1362 case tPixelFormat::BC2DXT2DXT3
1363 case tPixelFormat::BC3DXT4DXT5
1364 if ((height % tGetBlockHeight(format)) == 0
1365 return true
1366 break
1367
1368 
1369 return false
1370
1371 
1372 
1373uint8* tImage::CreateReversedRowData_BC(const uint8* pixelData, tPixelFormat pixelDataFormat, int numBlocksW, int numBlocksH
1374
1375 // We do not support all BC formats for this.. 
1376 if (!CanReverseRowData_BC(format: pixelDataFormat, height: numBlocksH*tGetBlockHeight(pixelDataFormat))) 
1377 return nullptr
1378 
1379 int bcBlockSize = tImage::tGetBytesPerBlock(pixelDataFormat); 
1380 int numBlocks = numBlocksW*numBlocksH
1381 int numBytes = numBlocks * bcBlockSize
1382 
1383 uint8* reversedPixelData = new uint8[numBytes]; 
1384 uint8* dstData = reversedPixelData
1385 for (int row = numBlocksH-1; row >= 0; row--) 
1386
1387 for (int col = 0; col < numBlocksW; col++) 
1388
1389 const uint8* srcData = pixelData + row*bcBlockSize*numBlocksW + col*bcBlockSize
1390 for (int byte = 0; byte < bcBlockSize; byte++, dstData++, srcData++) 
1391 *dstData = *srcData
1392
1393
1394 
1395 // Now we flip the inter-block rows by messing with the block's lookup-table. We handle three types of 
1396 // blocks: BC1, BC2, and BC3. BC4/5 probably could be handled, and BC6/7 are too complex. 
1397 switch (pixelDataFormat
1398
1399 case tPixelFormat::BC1DXT1A
1400 case tPixelFormat::BC1DXT1
1401
1402 tImage::BC1Block* block = (tImage::BC1Block*)reversedPixelData
1403 for (int b = 0; b < numBlocks; b++, block++) 
1404
1405 // Reorder each row's colour indexes. 
1406 tStd::tSwap(a&: block->LookupTableRows[0], b&: block->LookupTableRows[3]); 
1407 tStd::tSwap(a&: block->LookupTableRows[1], b&: block->LookupTableRows[2]); 
1408
1409 break
1410
1411 
1412 case tPixelFormat::BC2DXT2DXT3
1413
1414 tImage::BC2Block* block = (tImage::BC2Block*)reversedPixelData
1415 for (int b = 0; b < numBlocks; b++, block++) 
1416
1417 // Reorder the explicit alphas AND the colour indexes. 
1418 tStd::tSwap(a&: block->AlphaTableRows[0], b&: block->AlphaTableRows[3]); 
1419 tStd::tSwap(a&: block->AlphaTableRows[1], b&: block->AlphaTableRows[2]); 
1420 tStd::tSwap(a&: block->ColourBlock.LookupTableRows[0], b&: block->ColourBlock.LookupTableRows[3]); 
1421 tStd::tSwap(a&: block->ColourBlock.LookupTableRows[1], b&: block->ColourBlock.LookupTableRows[2]); 
1422
1423 break
1424
1425 
1426 case tPixelFormat::BC3DXT4DXT5
1427
1428 tImage::BC3Block* block = (tImage::BC3Block*)reversedPixelData
1429 for (int b = 0; b < numBlocks; b++, block++) 
1430
1431 // Reorder the alpha indexes AND the colour indexes. 
1432 uint16 orig0 = block->GetAlphaRow(row: 0); 
1433 block->SetAlphaRow(row: 0, val: block->GetAlphaRow(row: 3)); 
1434 block->SetAlphaRow(row: 3, val: orig0); 
1435 
1436 uint16 orig1 = block->GetAlphaRow(row: 1); 
1437 block->SetAlphaRow(row: 1, val: block->GetAlphaRow(row: 2)); 
1438 block->SetAlphaRow(row: 2, val: orig1); 
1439 
1440 tStd::tSwap(a&: block->ColourBlock.LookupTableRows[0], b&: block->ColourBlock.LookupTableRows[3]); 
1441 tStd::tSwap(a&: block->ColourBlock.LookupTableRows[1], b&: block->ColourBlock.LookupTableRows[2]); 
1442
1443 break
1444
1445 
1446 default
1447 // We should not get here. Should have early returned already. 
1448 tAssert(!"Should be unreachable."); 
1449 delete[] reversedPixelData
1450 return nullptr
1451
1452 
1453 return reversedPixelData
1454
1455