1 /******************************************************************************
2
3 @File PVRTDecompress.cpp
4
5 @Title PVRTDecompress
6
7 @Version
8
9 @Copyright Copyright (c) Imagination Technologies Limited.
10
11 @Platform ANSI compatible
12
13 @Description PVRTC Texture Decompression.
14
15 ******************************************************************************/
16
17 /*****************************************************************************
18 * INCLUDES
19 *****************************************************************************/
20 #include <stdlib.h>
21 #include <stdio.h>
22 #include <limits.h>
23 #include <math.h>
24 #include <string.h>
25 #include "PVRTDecompress.h"
26 #include "PVRTTexture.h"
27 #include "PVRTGlobal.h"
28
29 /***********************************************************
30 DECOMPRESSION ROUTINES
31 ************************************************************/
32 /*****************************************************************************
33 * Useful structs
34 *****************************************************************************/
35 struct Pixel32
36 {
37 PVRTuint8 red,green,blue,alpha;
38 };
39
40 struct Pixel128S
41 {
42 PVRTint32 red,green,blue,alpha;
43 };
44
45 struct PVRTCWord
46 {
47 PVRTuint32 u32ModulationData;
48 PVRTuint32 u32ColourData;
49 };
50
51 struct PVRTCWordIndices
52 {
53 int P[2], Q[2], R[2], S[2];
54 };
55 /********************************************************************************/
56 /*!***********************************************************************
57 @Function getColourA
58 @Input u32ColourData Colour information from a PVRTCWord.
59 @Return Returns the first colour in a PVRTCWord's colour data.
60 @Description Decodes the first colour in a PVRTCWord's colour data.
61 *************************************************************************/
getColourA(PVRTuint32 u32ColourData)62 static Pixel32 getColourA(PVRTuint32 u32ColourData)
63 {
64 Pixel32 colour;
65
66 // Opaque Colour Mode - RGB 554
67 if ((u32ColourData & 0x8000) != 0)
68 {
69 colour.red = (PVRTuint8)((u32ColourData & 0x7c00) >> 10); // 5->5 bits
70 colour.green = (PVRTuint8)((u32ColourData & 0x3e0) >> 5); // 5->5 bits
71 colour.blue = (PVRTuint8)(u32ColourData & 0x1e) | ((u32ColourData & 0x1e) >> 4); // 4->5 bits
72 colour.alpha = (PVRTuint8)0xf;// 0->4 bits
73 }
74 // Transparent Colour Mode - ARGB 3443
75 else
76 {
77 colour.red = (PVRTuint8)((u32ColourData & 0xf00) >> 7) | ((u32ColourData & 0xf00) >> 11); // 4->5 bits
78 colour.green = (PVRTuint8)((u32ColourData & 0xf0) >> 3) | ((u32ColourData & 0xf0) >> 7); // 4->5 bits
79 colour.blue = (PVRTuint8)((u32ColourData & 0xe) << 1) | ((u32ColourData & 0xe) >> 2); // 3->5 bits
80 colour.alpha = (PVRTuint8)((u32ColourData & 0x7000) >> 11);// 3->4 bits - note 0 at right
81 }
82
83 return colour;
84 }
85
86 /*!***********************************************************************
87 @Function getColourB
88 @Input u32ColourData Colour information from a PVRTCWord.
89 @Return Returns the second colour in a PVRTCWord's colour data.
90 @Description Decodes the second colour in a PVRTCWord's colour data.
91 *************************************************************************/
getColourB(PVRTuint32 u32ColourData)92 static Pixel32 getColourB(PVRTuint32 u32ColourData)
93 {
94 Pixel32 colour;
95
96 // Opaque Colour Mode - RGB 555
97 if (u32ColourData & 0x80000000)
98 {
99 colour.red = (PVRTuint8)((u32ColourData & 0x7c000000) >> 26); // 5->5 bits
100 colour.green = (PVRTuint8)((u32ColourData & 0x3e00000) >> 21); // 5->5 bits
101 colour.blue = (PVRTuint8)((u32ColourData & 0x1f0000) >> 16); // 5->5 bits
102 colour.alpha = (PVRTuint8)0xf;// 0 bits
103 }
104 // Transparent Colour Mode - ARGB 3444
105 else
106 {
107 colour.red = (PVRTuint8)(((u32ColourData & 0xf000000) >> 23) | ((u32ColourData & 0xf000000) >> 27)); // 4->5 bits
108 colour.green = (PVRTuint8)(((u32ColourData & 0xf00000) >> 19) | ((u32ColourData & 0xf00000) >> 23)); // 4->5 bits
109 colour.blue = (PVRTuint8)(((u32ColourData & 0xf0000) >> 15) | ((u32ColourData & 0xf0000) >> 19)); // 4->5 bits
110 colour.alpha = (PVRTuint8)((u32ColourData & 0x70000000) >> 27);// 3->4 bits - note 0 at right
111 }
112
113 return colour;
114 }
115
116 /*!***********************************************************************
117 @Function interpolateColours
118 @Input P,Q,R,S Low bit-rate colour values for each PVRTCWord.
119 @Modified pPixel Output array for upscaled colour values.
120 @Input ui8Bpp Number of bpp.
121 @Description Bilinear upscale from 2x2 pixels to 4x4/8x4 pixels (depending on PVRTC bpp mode).
122 *************************************************************************/
interpolateColours(Pixel32 P,Pixel32 Q,Pixel32 R,Pixel32 S,Pixel128S * pPixel,PVRTuint8 ui8Bpp)123 static void interpolateColours(Pixel32 P, Pixel32 Q, Pixel32 R, Pixel32 S,
124 Pixel128S *pPixel, PVRTuint8 ui8Bpp)
125 {
126 PVRTuint32 ui32WordWidth=4;
127 PVRTuint32 ui32WordHeight=4;
128 if (ui8Bpp==2)
129 ui32WordWidth=8;
130
131 //Convert to int 32.
132 Pixel128S hP = {(PVRTint32)P.red,(PVRTint32)P.green,(PVRTint32)P.blue,(PVRTint32)P.alpha};
133 Pixel128S hQ = {(PVRTint32)Q.red,(PVRTint32)Q.green,(PVRTint32)Q.blue,(PVRTint32)Q.alpha};
134 Pixel128S hR = {(PVRTint32)R.red,(PVRTint32)R.green,(PVRTint32)R.blue,(PVRTint32)R.alpha};
135 Pixel128S hS = {(PVRTint32)S.red,(PVRTint32)S.green,(PVRTint32)S.blue,(PVRTint32)S.alpha};
136
137 //Get vectors.
138 Pixel128S QminusP = {hQ.red - hP.red, hQ.green - hP.green, hQ.blue - hP.blue, hQ.alpha - hP.alpha};
139 Pixel128S SminusR = {hS.red - hR.red, hS.green - hR.green, hS.blue - hR.blue, hS.alpha - hR.alpha};
140
141 //Multiply colours.
142 hP.red *= ui32WordWidth;
143 hP.green *= ui32WordWidth;
144 hP.blue *= ui32WordWidth;
145 hP.alpha *= ui32WordWidth;
146 hR.red *= ui32WordWidth;
147 hR.green *= ui32WordWidth;
148 hR.blue *= ui32WordWidth;
149 hR.alpha *= ui32WordWidth;
150
151 if (ui8Bpp==2)
152 {
153 //Loop through pixels to achieve results.
154 for (unsigned int x=0; x < ui32WordWidth; x++)
155 {
156 Pixel128S Result={4*hP.red, 4*hP.green, 4*hP.blue, 4*hP.alpha};
157 Pixel128S dY = {hR.red - hP.red, hR.green - hP.green, hR.blue - hP.blue, hR.alpha - hP.alpha};
158
159 for (unsigned int y=0; y < ui32WordHeight; y++)
160 {
161 pPixel[y*ui32WordWidth+x].red = (PVRTint32)((Result.red >> 7) + (Result.red >> 2));
162 pPixel[y*ui32WordWidth+x].green = (PVRTint32)((Result.green >> 7) + (Result.green >> 2));
163 pPixel[y*ui32WordWidth+x].blue = (PVRTint32)((Result.blue >> 7) + (Result.blue >> 2));
164 pPixel[y*ui32WordWidth+x].alpha = (PVRTint32)((Result.alpha >> 5) + (Result.alpha >> 1));
165
166 Result.red += dY.red;
167 Result.green += dY.green;
168 Result.blue += dY.blue;
169 Result.alpha += dY.alpha;
170 }
171
172 hP.red += QminusP.red;
173 hP.green += QminusP.green;
174 hP.blue += QminusP.blue;
175 hP.alpha += QminusP.alpha;
176
177 hR.red += SminusR.red;
178 hR.green += SminusR.green;
179 hR.blue += SminusR.blue;
180 hR.alpha += SminusR.alpha;
181 }
182 }
183 else
184 {
185 //Loop through pixels to achieve results.
186 for (unsigned int y=0; y < ui32WordHeight; y++)
187 {
188 Pixel128S Result={4*hP.red, 4*hP.green, 4*hP.blue, 4*hP.alpha};
189 Pixel128S dY = {hR.red - hP.red, hR.green - hP.green, hR.blue - hP.blue, hR.alpha - hP.alpha};
190
191 for (unsigned int x=0; x < ui32WordWidth; x++)
192 {
193 pPixel[y*ui32WordWidth+x].red = (PVRTint32)((Result.red >> 6) + (Result.red >> 1));
194 pPixel[y*ui32WordWidth+x].green = (PVRTint32)((Result.green >> 6) + (Result.green >> 1));
195 pPixel[y*ui32WordWidth+x].blue = (PVRTint32)((Result.blue >> 6) + (Result.blue >> 1));
196 pPixel[y*ui32WordWidth+x].alpha = (PVRTint32)((Result.alpha >> 4) + (Result.alpha));
197
198 Result.red += dY.red;
199 Result.green += dY.green;
200 Result.blue += dY.blue;
201 Result.alpha += dY.alpha;
202 }
203
204 hP.red += QminusP.red;
205 hP.green += QminusP.green;
206 hP.blue += QminusP.blue;
207 hP.alpha += QminusP.alpha;
208
209 hR.red += SminusR.red;
210 hR.green += SminusR.green;
211 hR.blue += SminusR.blue;
212 hR.alpha += SminusR.alpha;
213 }
214 }
215 }
216
217 /*!***********************************************************************
218 @Function unpackModulations
219 @Input word PVRTCWord to be decompressed
220 @Input offsetX X position within the PVRTCWord
221 @Input offsetY Y position within the PVRTCWord
222 @Modified i32ModulationValues The array of modulation values.
223 @Modified i32ModulationModes The array of modulation modes.
224 @Input ui8Bpp Number of bpp.
225 @Description Reads out and decodes the modulation values within the a given PVRTCWord
226 *************************************************************************/
unpackModulations(const PVRTCWord & word,int offsetX,int offsetY,PVRTint32 i32ModulationValues[16][8],PVRTint32 i32ModulationModes[16][8],PVRTuint8 ui8Bpp)227 static void unpackModulations(const PVRTCWord& word, int offsetX, int offsetY, PVRTint32 i32ModulationValues[16][8], PVRTint32 i32ModulationModes[16][8], PVRTuint8 ui8Bpp)
228 {
229 PVRTuint32 WordModMode = word.u32ColourData & 0x1;
230 PVRTuint32 ModulationBits = word.u32ModulationData;
231
232 // Unpack differently depending on 2bpp or 4bpp modes.
233 if (ui8Bpp==2)
234 {
235 if(WordModMode)
236 {
237 // determine which of the three modes are in use:
238
239 // If this is the either the H-only or V-only interpolation mode...
240 if(ModulationBits & 0x1)
241 {
242 // look at the "LSB" for the "centre" (V=2,H=4) texel. Its LSB is now
243 // actually used to indicate whether it's the H-only mode or the V-only...
244
245 // The centre texel data is the at (y==2, x==4) and so its LSB is at bit 20.
246 if(ModulationBits & (0x1 << 20))
247 {
248 // This is the V-only mode
249 WordModMode = 3;
250 }
251 else
252 {
253 // This is the H-only mode
254 WordModMode = 2;
255 }
256
257 // Create an extra bit for the centre pixel so that it looks like
258 // we have 2 actual bits for this texel. It makes later coding much easier.
259 if(ModulationBits & (0x1 << 21))
260 {
261 // set it to produce code for 1.0
262 ModulationBits |= (0x1 << 20);
263 }
264 else
265 {
266 // clear it to produce 0.0 code
267 ModulationBits &= ~(0x1 << 20);
268 }
269 }// end if H-Only or V-Only interpolation mode was chosen
270
271 if(ModulationBits & 0x2)
272 {
273 ModulationBits |= 0x1; /*set it*/
274 }
275 else
276 {
277 ModulationBits &= ~0x1; /*clear it*/
278 }
279
280 // run through all the pixels in the block. Note we can now treat all the
281 // "stored" values as if they have 2bits (even when they didn't!)
282 for(int y = 0; y < 4; y++)
283 {
284 for(int x = 0; x < 8; x++)
285 {
286 i32ModulationModes[x+offsetX][y+offsetY] = WordModMode;
287
288 // if this is a stored value...
289 if(((x^y)&1) == 0)
290 {
291 i32ModulationValues[x+offsetX][y+offsetY] = ModulationBits & 3;
292 ModulationBits >>= 2;
293 }
294 }
295 } // end for y
296 }
297 // else if direct encoded 2bit mode - i.e. 1 mode bit per pixel
298 else
299 {
300 for(int y = 0; y < 4; y++)
301 {
302 for(int x = 0; x < 8; x++)
303 {
304 i32ModulationModes[x+offsetX][y+offsetY] = WordModMode;
305
306 /*
307 // double the bits so 0=> 00, and 1=>11
308 */
309 if(ModulationBits & 1)
310 {
311 i32ModulationValues[x+offsetX][y+offsetY] = 0x3;
312 }
313 else
314 {
315 i32ModulationValues[x+offsetX][y+offsetY] = 0x0;
316 }
317 ModulationBits >>= 1;
318 }
319 }// end for y
320 }
321 }
322 else
323 {
324 //Much simpler than the 2bpp decompression, only two modes, so the n/8 values are set directly.
325 // run through all the pixels in the word.
326 if (WordModMode)
327 {
328 for(int y = 0; y < 4; y++)
329 {
330 for(int x = 0; x < 4; x++)
331 {
332 i32ModulationValues[y+offsetY][x+offsetX] = ModulationBits & 3;
333 //if (i32ModulationValues==0) {}; don't need to check 0, 0 = 0/8.
334 if (i32ModulationValues[y+offsetY][x+offsetX]==1) { i32ModulationValues[y+offsetY][x+offsetX]=4;}
335 else if (i32ModulationValues[y+offsetY][x+offsetX]==2) { i32ModulationValues[y+offsetY][x+offsetX]=14;} //+10 tells the decompressor to punch through alpha.
336 else if (i32ModulationValues[y+offsetY][x+offsetX]==3) { i32ModulationValues[y+offsetY][x+offsetX]=8;}
337 ModulationBits >>= 2;
338 } // end for x
339 } // end for y
340 }
341 else
342 {
343 for(int y = 0; y < 4; y++)
344 {
345 for(int x = 0; x < 4; x++)
346 {
347 i32ModulationValues[y+offsetY][x+offsetX] = ModulationBits & 3;
348 i32ModulationValues[y+offsetY][x+offsetX]*=3;
349 if (i32ModulationValues[y+offsetY][x+offsetX]>3) i32ModulationValues[y+offsetY][x+offsetX]-=1;
350 ModulationBits >>= 2;
351 } // end for x
352 } // end for y
353 }
354 }
355 }
356
357 /*!***********************************************************************
358 @Function getModulationValues
359 @Input i32ModulationValues The array of modulation values.
360 @Input i32ModulationModes The array of modulation modes.
361 @Input xPos The x Position within the current word.
362 @Input yPos The y Position within the current word.
363 @Input ui8Bpp Number of bpp.
364 @Return Returns the modulation value.
365 @Description Gets the effective modulation values for a given pixel.
366 *************************************************************************/
getModulationValues(PVRTint32 i32ModulationValues[16][8],PVRTint32 i32ModulationModes[16][8],PVRTuint32 xPos,PVRTuint32 yPos,PVRTuint8 ui8Bpp)367 static PVRTint32 getModulationValues(PVRTint32 i32ModulationValues[16][8],PVRTint32 i32ModulationModes[16][8],PVRTuint32 xPos,PVRTuint32 yPos,PVRTuint8 ui8Bpp)
368 {
369 if (ui8Bpp==2)
370 {
371 const int RepVals0[4] = {0, 3, 5, 8};
372
373 // extract the modulation value. If a simple encoding
374 if(i32ModulationModes[xPos][yPos]==0)
375 {
376 return RepVals0[i32ModulationValues[xPos][yPos]];
377 }
378 else
379 {
380 // if this is a stored value
381 if(((xPos^yPos)&1)==0)
382 {
383 return RepVals0[i32ModulationValues[xPos][yPos]];
384 }
385
386 // else average from the neighbours
387 // if H&V interpolation...
388 else if(i32ModulationModes[xPos][yPos] == 1)
389 {
390 return (RepVals0[i32ModulationValues[xPos][yPos-1]] +
391 RepVals0[i32ModulationValues[xPos][yPos+1]] +
392 RepVals0[i32ModulationValues[xPos-1][yPos]] +
393 RepVals0[i32ModulationValues[xPos+1][yPos]] + 2) / 4;
394 }
395 // else if H-Only
396 else if(i32ModulationModes[xPos][yPos] == 2)
397 {
398 return (RepVals0[i32ModulationValues[xPos-1][yPos]] +
399 RepVals0[i32ModulationValues[xPos+1][yPos]] + 1) / 2;
400 }
401 // else it's V-Only
402 else
403 {
404 return (RepVals0[i32ModulationValues[xPos][yPos-1]] +
405 RepVals0[i32ModulationValues[xPos][yPos+1]] + 1) / 2;
406 }
407 }
408 }
409 else if (ui8Bpp==4)
410 return i32ModulationValues[xPos][yPos];
411
412 return 0;
413 }
414
415 /*!***********************************************************************
416 @Function pvrtcGetDecompressedPixels
417 @Input P,Q,R,S PVRTWords in current decompression area.
418 @Modified pColourData Output pixels.
419 @Input ui8Bpp Number of bpp.
420 @Description Gets decompressed pixels for a given decompression area.
421 *************************************************************************/
pvrtcGetDecompressedPixels(const PVRTCWord & P,const PVRTCWord & Q,const PVRTCWord & R,const PVRTCWord & S,Pixel32 * pColourData,PVRTuint8 ui8Bpp)422 static void pvrtcGetDecompressedPixels(const PVRTCWord& P, const PVRTCWord& Q,
423 const PVRTCWord& R, const PVRTCWord& S,
424 Pixel32 *pColourData,
425 PVRTuint8 ui8Bpp)
426 {
427 //4bpp only needs 8*8 values, but 2bpp needs 16*8, so rather than wasting processor time we just statically allocate 16*8.
428 PVRTint32 i32ModulationValues[16][8];
429 //Only 2bpp needs this.
430 PVRTint32 i32ModulationModes[16][8];
431 //4bpp only needs 16 values, but 2bpp needs 32, so rather than wasting processor time we just statically allocate 32.
432 Pixel128S upscaledColourA[32];
433 Pixel128S upscaledColourB[32];
434
435 PVRTuint32 ui32WordWidth=4;
436 PVRTuint32 ui32WordHeight=4;
437 if (ui8Bpp==2)
438 ui32WordWidth=8;
439
440 //Get the modulations from each word.
441 unpackModulations(P, 0, 0, i32ModulationValues, i32ModulationModes, ui8Bpp);
442 unpackModulations(Q, ui32WordWidth, 0, i32ModulationValues, i32ModulationModes, ui8Bpp);
443 unpackModulations(R, 0, ui32WordHeight, i32ModulationValues, i32ModulationModes, ui8Bpp);
444 unpackModulations(S, ui32WordWidth, ui32WordHeight, i32ModulationValues, i32ModulationModes, ui8Bpp);
445
446 // Bilinear upscale image data from 2x2 -> 4x4
447 interpolateColours(getColourA(P.u32ColourData), getColourA(Q.u32ColourData),
448 getColourA(R.u32ColourData), getColourA(S.u32ColourData),
449 upscaledColourA, ui8Bpp);
450 interpolateColours(getColourB(P.u32ColourData), getColourB(Q.u32ColourData),
451 getColourB(R.u32ColourData), getColourB(S.u32ColourData),
452 upscaledColourB, ui8Bpp);
453
454 for (unsigned int y=0; y < ui32WordHeight; y++)
455 {
456 for (unsigned int x=0; x < ui32WordWidth; x++)
457 {
458 PVRTint32 mod = getModulationValues(i32ModulationValues,i32ModulationModes,x+ui32WordWidth/2,y+ui32WordHeight/2,ui8Bpp);
459 bool punchthroughAlpha=false;
460 if (mod>10) {punchthroughAlpha=true; mod-=10;}
461
462 Pixel128S result;
463 result.red = (upscaledColourA[y*ui32WordWidth+x].red * (8-mod) + upscaledColourB[y*ui32WordWidth+x].red * mod) / 8;
464 result.green = (upscaledColourA[y*ui32WordWidth+x].green * (8-mod) + upscaledColourB[y*ui32WordWidth+x].green * mod) / 8;
465 result.blue = (upscaledColourA[y*ui32WordWidth+x].blue * (8-mod) + upscaledColourB[y*ui32WordWidth+x].blue * mod) / 8;
466 if (punchthroughAlpha) result.alpha = 0;
467 else result.alpha = (upscaledColourA[y*ui32WordWidth+x].alpha * (8-mod) + upscaledColourB[y*ui32WordWidth+x].alpha * mod) / 8;
468
469 //Convert the 32bit precision result to 8 bit per channel colour.
470 if (ui8Bpp==2)
471 {
472 pColourData[y*ui32WordWidth+x].red = (PVRTuint8)result.red;
473 pColourData[y*ui32WordWidth+x].green = (PVRTuint8)result.green;
474 pColourData[y*ui32WordWidth+x].blue = (PVRTuint8)result.blue;
475 pColourData[y*ui32WordWidth+x].alpha = (PVRTuint8)result.alpha;
476 }
477 else if (ui8Bpp==4)
478 {
479 pColourData[y+x*ui32WordHeight].red = (PVRTuint8)result.red;
480 pColourData[y+x*ui32WordHeight].green = (PVRTuint8)result.green;
481 pColourData[y+x*ui32WordHeight].blue = (PVRTuint8)result.blue;
482 pColourData[y+x*ui32WordHeight].alpha = (PVRTuint8)result.alpha;
483 }
484 }
485 }
486 }
487
488 /*!***********************************************************************
489 @Function wrapWordIndex
490 @Input numWords Total number of PVRTCWords in the current surface.
491 @Input word Original index for a PVRTCWord.
492 @Return unsigned int Wrapped PVRTCWord index.
493 @Description Maps decompressed data to the correct location in the output buffer.
494 *************************************************************************/
wrapWordIndex(unsigned int numWords,int word)495 static unsigned int wrapWordIndex(unsigned int numWords, int word)
496 {
497 return ((word + numWords) % numWords);
498 }
499
500 #if defined(_DEBUG)
501 /*!***********************************************************************
502 @Function isPowerOf2
503 @Input input Value to be checked
504 @Returns true if the number is an integer power of two, else false.
505 @Description Check that a number is an integer power of two, i.e.
506 1, 2, 4, 8, ... etc.
507 Returns false for zero.
508 *************************************************************************/
isPowerOf2(unsigned int input)509 static bool isPowerOf2( unsigned int input )
510 {
511 unsigned int minus1;
512
513 if( !input ) return 0;
514
515 minus1 = input - 1;
516 return ( (input | minus1) == (input ^ minus1) );
517 }
518 #endif
519
520 /*!***********************************************************************
521 @Function TwiddleUV
522 @Input YSize Y dimension of the texture in pixels
523 @Input XSize X dimension of the texture in pixels
524 @Input YPos Pixel Y position
525 @Input XPos Pixel X position
526 @Returns The twiddled offset of the pixel
527 @Description Given the Word (or pixel) coordinates and the dimension of
528 the texture in words (or pixels) this returns the twiddled
529 offset of the word (or pixel) from the start of the map.
530
531 NOTE: the dimensions of the texture must be a power of 2
532 *************************************************************************/
TwiddleUV(PVRTuint32 XSize,PVRTuint32 YSize,PVRTuint32 XPos,PVRTuint32 YPos)533 static PVRTuint32 TwiddleUV(PVRTuint32 XSize, PVRTuint32 YSize, PVRTuint32 XPos, PVRTuint32 YPos)
534 {
535 //Initially assume X is the larger size.
536 PVRTuint32 MinDimension=XSize;
537 PVRTuint32 MaxValue=YPos;
538 PVRTuint32 Twiddled=0;
539 PVRTuint32 SrcBitPos=1;
540 PVRTuint32 DstBitPos=1;
541 int ShiftCount=0;
542
543 //Check the sizes are valid.
544 _ASSERT(YPos < YSize);
545 _ASSERT(XPos < XSize);
546 _ASSERT(isPowerOf2(YSize));
547 _ASSERT(isPowerOf2(XSize));
548
549 //If Y is the larger dimension - switch the min/max values.
550 if(YSize < XSize)
551 {
552 MinDimension = YSize;
553 MaxValue = XPos;
554 }
555
556 // Step through all the bits in the "minimum" dimension
557 while(SrcBitPos < MinDimension)
558 {
559 if(YPos & SrcBitPos)
560 {
561 Twiddled |= DstBitPos;
562 }
563
564 if(XPos & SrcBitPos)
565 {
566 Twiddled |= (DstBitPos << 1);
567 }
568
569 SrcBitPos <<= 1;
570 DstBitPos <<= 2;
571 ShiftCount += 1;
572 }
573
574 // Prepend any unused bits
575 MaxValue >>= ShiftCount;
576 Twiddled |= (MaxValue << (2*ShiftCount));
577
578 return Twiddled;
579 }
580
581 /*!***********************************************************************
582 @Function mapDecompressedData
583 @Modified pOutput The PVRTC texture data to decompress
584 @Input width Width of the texture surface.
585 @Input pWord A pointer to the decompressed PVRTCWord in pixel form.
586 @Input &words Indices for the PVRTCword.
587 @Input ui8Bpp number of bits per pixel
588 @Description Maps decompressed data to the correct location in the output buffer.
589 *************************************************************************/
mapDecompressedData(Pixel32 * pOutput,int width,const Pixel32 * pWord,const PVRTCWordIndices & words,const PVRTuint8 ui8Bpp)590 static void mapDecompressedData(Pixel32* pOutput, int width,
591 const Pixel32 *pWord,
592 const PVRTCWordIndices &words,
593 const PVRTuint8 ui8Bpp)
594 {
595 PVRTuint32 ui32WordWidth=4;
596 PVRTuint32 ui32WordHeight=4;
597 if (ui8Bpp==2)
598 ui32WordWidth=8;
599
600 for (unsigned int y=0; y < ui32WordHeight/2; y++)
601 {
602 for (unsigned int x=0; x < ui32WordWidth/2; x++)
603 {
604 pOutput[(((words.P[1] * ui32WordHeight) + y + ui32WordHeight/2)
605 * width + words.P[0] *ui32WordWidth + x + ui32WordWidth/2)] = pWord[y*ui32WordWidth+x]; // map P
606
607 pOutput[(((words.Q[1] * ui32WordHeight) + y + ui32WordHeight/2)
608 * width + words.Q[0] *ui32WordWidth + x)] = pWord[y*ui32WordWidth+x+ui32WordWidth/2]; // map Q
609
610 pOutput[(((words.R[1] * ui32WordHeight) + y)
611 * width + words.R[0] *ui32WordWidth + x + ui32WordWidth/2)] = pWord[(y+ui32WordHeight/2)*ui32WordWidth+x]; // map R
612
613 pOutput[(((words.S[1] * ui32WordHeight) + y)
614 * width + words.S[0] *ui32WordWidth + x)] = pWord[(y+ui32WordHeight/2)*ui32WordWidth+x+ui32WordWidth/2]; // map S
615 }
616 }
617 }
618 /*!***********************************************************************
619 @Function pvrtcDecompress
620 @Input pCompressedData The PVRTC texture data to decompress
621 @Modified pDecompressedData The output buffer to decompress into.
622 @Input ui32Width X dimension of the texture
623 @Input ui32Height Y dimension of the texture
624 @Input ui8Bpp number of bits per pixel
625 @Description Internally decompresses PVRTC to RGBA 8888
626 *************************************************************************/
pvrtcDecompress(PVRTuint8 * pCompressedData,Pixel32 * pDecompressedData,PVRTuint32 ui32Width,PVRTuint32 ui32Height,PVRTuint8 ui8Bpp)627 static int pvrtcDecompress( PVRTuint8 *pCompressedData,
628 Pixel32 *pDecompressedData,
629 PVRTuint32 ui32Width,
630 PVRTuint32 ui32Height,
631 PVRTuint8 ui8Bpp)
632 {
633 PVRTuint32 ui32WordWidth=4;
634 PVRTuint32 ui32WordHeight=4;
635 if (ui8Bpp==2)
636 ui32WordWidth=8;
637
638 PVRTuint32 *pWordMembers = (PVRTuint32 *)pCompressedData;
639 Pixel32 *pOutData = pDecompressedData;
640
641 // Calculate number of words
642 int i32NumXWords = (int)(ui32Width / ui32WordWidth);
643 int i32NumYWords = (int)(ui32Height / ui32WordHeight);
644
645 // Structs used for decompression
646 PVRTCWordIndices indices;
647 Pixel32 *pPixels;
648 pPixels = (Pixel32*)malloc(ui32WordWidth*ui32WordHeight*sizeof(Pixel32));
649
650 // For each row of words
651 for(int wordY=-1; wordY < i32NumYWords-1; wordY++)
652 {
653 // for each column of words
654 for(int wordX=-1; wordX < i32NumXWords-1; wordX++)
655 {
656 indices.P[0] = wrapWordIndex(i32NumXWords, wordX);
657 indices.P[1] = wrapWordIndex(i32NumYWords, wordY);
658 indices.Q[0] = wrapWordIndex(i32NumXWords, wordX + 1);
659 indices.Q[1] = wrapWordIndex(i32NumYWords, wordY);
660 indices.R[0] = wrapWordIndex(i32NumXWords, wordX);
661 indices.R[1] = wrapWordIndex(i32NumYWords, wordY + 1);
662 indices.S[0] = wrapWordIndex(i32NumXWords, wordX + 1);
663 indices.S[1] = wrapWordIndex(i32NumYWords, wordY + 1);
664
665 //Work out the offsets into the twiddle structs, multiply by two as there are two members per word.
666 PVRTuint32 WordOffsets[4] =
667 {
668 TwiddleUV(i32NumXWords,i32NumYWords,indices.P[0], indices.P[1])*2,
669 TwiddleUV(i32NumXWords,i32NumYWords,indices.Q[0], indices.Q[1])*2,
670 TwiddleUV(i32NumXWords,i32NumYWords,indices.R[0], indices.R[1])*2,
671 TwiddleUV(i32NumXWords,i32NumYWords,indices.S[0], indices.S[1])*2,
672 };
673
674 //Access individual elements to fill out PVRTCWord
675 PVRTCWord P,Q,R,S;
676 P.u32ColourData = pWordMembers[WordOffsets[0]+1];
677 P.u32ModulationData = pWordMembers[WordOffsets[0]];
678 Q.u32ColourData = pWordMembers[WordOffsets[1]+1];
679 Q.u32ModulationData = pWordMembers[WordOffsets[1]];
680 R.u32ColourData = pWordMembers[WordOffsets[2]+1];
681 R.u32ModulationData = pWordMembers[WordOffsets[2]];
682 S.u32ColourData = pWordMembers[WordOffsets[3]+1];
683 S.u32ModulationData = pWordMembers[WordOffsets[3]];
684
685 // assemble 4 words into struct to get decompressed pixels from
686 pvrtcGetDecompressedPixels(P,Q,R,S,pPixels,ui8Bpp);
687 mapDecompressedData(pOutData, ui32Width, pPixels, indices, ui8Bpp);
688
689 } // for each word
690 } // for each row of words
691
692 free(pPixels);
693 //Return the data size
694 return ui32Width * ui32Height / (PVRTuint32)(ui32WordWidth/2);
695 }
696
697 /*!***********************************************************************
698 @Function PVRTDecompressPVRTC
699 @Input pCompressedData The PVRTC texture data to decompress
700 @Input Do2bitMode Signifies whether the data is PVRTC2 or PVRTC4
701 @Input XDim X dimension of the texture
702 @Input YDim Y dimension of the texture
703 @Modified pResultImage The decompressed texture data
704 @Return Returns the amount of data that was decompressed.
705 @Description Decompresses PVRTC to RGBA 8888
706 *************************************************************************/
PVRTDecompressPVRTC(const void * pCompressedData,const int Do2bitMode,const int XDim,const int YDim,unsigned char * pResultImage)707 int PVRTDecompressPVRTC(const void *pCompressedData,
708 const int Do2bitMode,
709 const int XDim,
710 const int YDim,
711 unsigned char* pResultImage)
712 {
713 //Cast the output buffer to a Pixel32 pointer.
714 Pixel32* pDecompressedData = (Pixel32*)pResultImage;
715
716 //Check the X and Y values are at least the minimum size.
717 int XTrueDim = PVRT_MAX(XDim,((Do2bitMode==1)?16:8));
718 int YTrueDim = PVRT_MAX(YDim,8);
719
720 //If the dimensions aren't correct, we need to create a new buffer instead of just using the provided one, as the buffer will overrun otherwise.
721 if(XTrueDim!=XDim || YTrueDim!=YDim)
722 {
723 pDecompressedData=(Pixel32*)malloc(XTrueDim*YTrueDim*sizeof(Pixel32));
724 }
725
726 //Decompress the surface.
727 int retval = pvrtcDecompress((PVRTuint8*)pCompressedData,pDecompressedData,XTrueDim,YTrueDim,(Do2bitMode==1?2:4));
728
729 //If the dimensions were too small, then copy the new buffer back into the output buffer.
730 if(XTrueDim!=XDim || YTrueDim!=YDim)
731 {
732 //Loop through all the required pixels.
733 for (int x=0; x<XDim; ++x)
734 {
735 for (int y=0; y<YDim; ++y)
736 {
737 ((Pixel32*)pResultImage)[x+y*XDim]=pDecompressedData[x+y*XTrueDim];
738 }
739 }
740
741 //Free the temporary buffer.
742 free(pDecompressedData);
743 }
744 return retval;
745 }
746
747 /****************************
748 ** ETC Compression
749 ****************************/
750
751 /*****************************************************************************
752 Macros
753 *****************************************************************************/
754 #define _CLAMP_(X,Xmin,Xmax) ( (X)<(Xmax) ? ( (X)<(Xmin)?(Xmin):(X) ) : (Xmax) )
755
756 /*****************************************************************************
757 Constants
758 ******************************************************************************/
759 unsigned int ETC_FLIP = 0x01000000;
760 unsigned int ETC_DIFF = 0x02000000;
761 const int mod[8][4]={{2, 8,-2,-8},
762 {5, 17, -5, -17},
763 {9, 29, -9, -29},
764 {13, 42, -13, -42},
765 {18, 60, -18, -60},
766 {24, 80, -24, -80},
767 {33, 106, -33, -106},
768 {47, 183, -47, -183}};
769
770 /*!***********************************************************************
771 @Function modifyPixel
772 @Input red Red value of pixel
773 @Input green Green value of pixel
774 @Input blue Blue value of pixel
775 @Input x Pixel x position in block
776 @Input y Pixel y position in block
777 @Input modBlock Values for the current block
778 @Input modTable Modulation values
779 @Returns Returns actual pixel colour
780 @Description Used by ETCTextureDecompress
781 *************************************************************************/
modifyPixel(int red,int green,int blue,int x,int y,unsigned int modBlock,int modTable)782 static unsigned int modifyPixel(int red, int green, int blue, int x, int y, unsigned int modBlock, int modTable)
783 {
784 int index = x*4+y, pixelMod;
785 unsigned int mostSig = modBlock<<1;
786
787 if (index<8)
788 pixelMod = mod[modTable][((modBlock>>(index+24))&0x1)+((mostSig>>(index+8))&0x2)];
789 else
790 pixelMod = mod[modTable][((modBlock>>(index+8))&0x1)+((mostSig>>(index-8))&0x2)];
791
792 red = _CLAMP_(red+pixelMod,0,255);
793 green = _CLAMP_(green+pixelMod,0,255);
794 blue = _CLAMP_(blue+pixelMod,0,255);
795
796 return ((red<<16) + (green<<8) + blue)|0xff000000;
797 }
798
799 /*!***********************************************************************
800 @Function ETCTextureDecompress
801 @Input pSrcData The ETC texture data to decompress
802 @Input x X dimension of the texture
803 @Input y Y dimension of the texture
804 @Modified pDestData The decompressed texture data
805 @Input nMode The format of the data
806 @Returns The number of bytes of ETC data decompressed
807 @Description Decompresses ETC to RGBA 8888
808 *************************************************************************/
ETCTextureDecompress(const void * const pSrcData,const int & x,const int & y,const void * pDestData,const int &)809 static int ETCTextureDecompress(const void * const pSrcData, const int &x, const int &y, const void *pDestData,const int &/*nMode*/)
810 {
811 unsigned int blockTop, blockBot, *input = (unsigned int*)pSrcData, *output;
812 unsigned char red1, green1, blue1, red2, green2, blue2;
813 bool bFlip, bDiff;
814 int modtable1,modtable2;
815
816 for(int i=0;i<y;i+=4)
817 {
818 for(int m=0;m<x;m+=4)
819 {
820 blockTop = *(input++);
821 blockBot = *(input++);
822
823 output = (unsigned int*)pDestData + i*x +m;
824
825 // check flipbit
826 bFlip = (blockTop & ETC_FLIP) != 0;
827 bDiff = (blockTop & ETC_DIFF) != 0;
828
829 if(bDiff)
830 { // differential mode 5 colour bits + 3 difference bits
831 // get base colour for subblock 1
832 blue1 = (unsigned char)((blockTop&0xf80000)>>16);
833 green1 = (unsigned char)((blockTop&0xf800)>>8);
834 red1 = (unsigned char)(blockTop&0xf8);
835
836 // get differential colour for subblock 2
837 signed char blues = (signed char)(blue1>>3) + ((signed char) ((blockTop & 0x70000) >> 11)>>5);
838 signed char greens = (signed char)(green1>>3) + ((signed char)((blockTop & 0x700) >>3)>>5);
839 signed char reds = (signed char)(red1>>3) + ((signed char)((blockTop & 0x7)<<5)>>5);
840
841 blue2 = (unsigned char)blues;
842 green2 = (unsigned char)greens;
843 red2 = (unsigned char)reds;
844
845 red1 = red1 +(red1>>5); // copy bits to lower sig
846 green1 = green1 + (green1>>5); // copy bits to lower sig
847 blue1 = blue1 + (blue1>>5); // copy bits to lower sig
848
849 red2 = (red2<<3) +(red2>>2); // copy bits to lower sig
850 green2 = (green2<<3) + (green2>>2); // copy bits to lower sig
851 blue2 = (blue2<<3) + (blue2>>2); // copy bits to lower sig
852 }
853 else
854 { // individual mode 4 + 4 colour bits
855 // get base colour for subblock 1
856 blue1 = (unsigned char)((blockTop&0xf00000)>>16);
857 blue1 = blue1 +(blue1>>4); // copy bits to lower sig
858 green1 = (unsigned char)((blockTop&0xf000)>>8);
859 green1 = green1 + (green1>>4); // copy bits to lower sig
860 red1 = (unsigned char)(blockTop&0xf0);
861 red1 = red1 + (red1>>4); // copy bits to lower sig
862
863 // get base colour for subblock 2
864 blue2 = (unsigned char)((blockTop&0xf0000)>>12);
865 blue2 = blue2 +(blue2>>4); // copy bits to lower sig
866 green2 = (unsigned char)((blockTop&0xf00)>>4);
867 green2 = green2 + (green2>>4); // copy bits to lower sig
868 red2 = (unsigned char)((blockTop&0xf)<<4);
869 red2 = red2 + (red2>>4); // copy bits to lower sig
870 }
871 // get the modtables for each subblock
872 modtable1 = (blockTop>>29)&0x7;
873 modtable2 = (blockTop>>26)&0x7;
874
875 if(!bFlip)
876 { // 2 2x4 blocks side by side
877
878 for(int j=0;j<4;j++) // vertical
879 {
880 for(int k=0;k<2;k++) // horizontal
881 {
882 *(output+j*x+k) = modifyPixel(red1,green1,blue1,k,j,blockBot,modtable1);
883 *(output+j*x+k+2) = modifyPixel(red2,green2,blue2,k+2,j,blockBot,modtable2);
884 }
885 }
886
887 }
888 else
889 { // 2 4x2 blocks on top of each other
890 for(int j=0;j<2;j++)
891 {
892 for(int k=0;k<4;k++)
893 {
894 *(output+j*x+k) = modifyPixel(red1,green1,blue1,k,j,blockBot,modtable1);
895 *(output+(j+2)*x+k) = modifyPixel(red2,green2,blue2,k,j+2,blockBot,modtable2);
896 }
897 }
898 }
899 }
900 }
901
902 return x*y/2;
903 }
904
905 /*!***********************************************************************
906 @Function PVRTDecompressETC
907 @Input pSrcData The ETC texture data to decompress
908 @Input x X dimension of the texture
909 @Input y Y dimension of the texture
910 @Modified pDestData The decompressed texture data
911 @Input nMode The format of the data
912 @Returns The number of bytes of ETC data decompressed
913 @Description Decompresses ETC to RGBA 8888
914 *************************************************************************/
PVRTDecompressETC(const void * const pSrcData,const unsigned int & x,const unsigned int & y,void * pDestData,const int & nMode)915 int PVRTDecompressETC(const void * const pSrcData,
916 const unsigned int &x,
917 const unsigned int &y,
918 void *pDestData,
919 const int &nMode)
920 {
921 int i32read;
922
923 if(x<ETC_MIN_TEXWIDTH || y<ETC_MIN_TEXHEIGHT)
924 { // decompress into a buffer big enough to take the minimum size
925 char* pTempBuffer = (char*)malloc(PVRT_MAX(x,ETC_MIN_TEXWIDTH)*PVRT_MAX(y,ETC_MIN_TEXHEIGHT)*4);
926 i32read = ETCTextureDecompress(pSrcData,PVRT_MAX(x,ETC_MIN_TEXWIDTH),PVRT_MAX(y,ETC_MIN_TEXHEIGHT),pTempBuffer,nMode);
927
928 for(unsigned int i=0;i<y;i++)
929 { // copy from larger temp buffer to output data
930 memcpy((char*)(pDestData)+i*x*4,pTempBuffer+PVRT_MAX(x,ETC_MIN_TEXWIDTH)*4*i,x*4);
931 }
932
933 if(pTempBuffer) free(pTempBuffer);
934 }
935 else // decompress larger MIP levels straight into the output data
936 i32read = ETCTextureDecompress(pSrcData,x,y,pDestData,nMode);
937
938 // swap r and b channels
939 unsigned char* pSwap = (unsigned char*)pDestData, swap;
940
941 for(unsigned int i=0;i<y;i++)
942 for(unsigned int j=0;j<x;j++)
943 {
944 swap = pSwap[0];
945 pSwap[0] = pSwap[2];
946 pSwap[2] = swap;
947 pSwap+=4;
948 }
949
950 return i32read;
951 }
952
953 /*****************************************************************************
954 End of file (PVRTDecompress.cpp)
955 *****************************************************************************/
956
957