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 *****************************************************************************/
35struct Pixel32
36{
37	PVRTuint8 red,green,blue,alpha;
38};
39
40struct Pixel128S
41{
42	PVRTint32 red,green,blue,alpha;
43};
44
45struct PVRTCWord
46{
47	PVRTuint32 u32ModulationData;
48	PVRTuint32 u32ColourData;
49};
50
51struct 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*************************************************************************/
62static 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*************************************************************************/
92static 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*************************************************************************/
123static 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*************************************************************************/
227static 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*************************************************************************/
367static 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*************************************************************************/
422static 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*************************************************************************/
495static 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*************************************************************************/
509static 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*************************************************************************/
533static 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*************************************************************************/
590static 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*************************************************************************/
627static 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*************************************************************************/
707int 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/*****************************************************************************
752Macros
753*****************************************************************************/
754#define _CLAMP_(X,Xmin,Xmax) (  (X)<(Xmax) ?  (  (X)<(Xmin)?(Xmin):(X)  )  : (Xmax)    )
755
756/*****************************************************************************
757Constants
758******************************************************************************/
759unsigned int ETC_FLIP =  0x01000000;
760unsigned int ETC_DIFF = 0x02000000;
761const 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*************************************************************************/
782static 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*************************************************************************/
809static 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*************************************************************************/
915int 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