• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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