Home | History | Annotate | Download | only in Tools
      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 *************************************************************************/
     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 *************************************************************************/
     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 *************************************************************************/
    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 *************************************************************************/
    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 *************************************************************************/
    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 *************************************************************************/
    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 *************************************************************************/
    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 *************************************************************************/
    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 *************************************************************************/
    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 *************************************************************************/
    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 *************************************************************************/
    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 *************************************************************************/
    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 *************************************************************************/
    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 *************************************************************************/
    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 *************************************************************************/
    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