123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713 |
- /******************************************************************************
-
- @File PVRTDecompress.cpp
-
- @Title
-
- @Copyright Copyright (C) 2000 - 2008 by Imagination Technologies Limited.
-
- @Platform ANSI compatible
-
- @Description PVRTC Texture Decompression.
-
- ******************************************************************************/
- #include <stdlib.h>
- #include <stdio.h>
- #include <limits.h>
- #include <math.h>
- #include <string.h>
- #include <assert.h>
- #include <cstdint>
- #include "base/pvr.h"
- #define PVRT_MIN(a,b) (((a) < (b)) ? (a) : (b))
- #define PVRT_MAX(a,b) (((a) > (b)) ? (a) : (b))
- #define PVRT_CLAMP(x, l, h) (PVRT_MIN((h), PVRT_MAX((x), (l))))
- /*****************************************************************************
- * defines and consts
- *****************************************************************************/
- #define PT_INDEX (2) // The Punch-through index
- #define BLK_Y_SIZE (4) // always 4 for all 2D block types
- #define BLK_X_MAX (8) // Max X dimension for blocks
- #define BLK_X_2BPP (8) // dimensions for the two formats
- #define BLK_X_4BPP (4)
- #define WRAP_COORD(Val, Size) ((Val) & ((Size)-1))
- #define POWER_OF_2(X) util_number_is_power_2(X)
- /*
- Define an expression to either wrap or clamp large or small vals to the
- legal coordinate range
- */
- #define LIMIT_COORD(Val, Size, AssumeImageTiles) \
- ((AssumeImageTiles)? WRAP_COORD((Val), (Size)): PVRT_CLAMP((Val), 0, (Size)-1))
- /*****************************************************************************
- * Useful typedefs
- *****************************************************************************/
- typedef uint32_t U32;
- typedef uint8_t U8;
- /***********************************************************
- DECOMPRESSION ROUTINES
- ************************************************************/
- /*!***********************************************************************
- @Struct AMTC_BLOCK_STRUCT
- @Brief
- *************************************************************************/
- typedef struct
- {
- // Uses 64 bits pre block
- U32 PackedData[2];
- }AMTC_BLOCK_STRUCT;
- static void PVRDecompress(AMTC_BLOCK_STRUCT *pCompressedData,
- const bool Do2bitMode,
- const int XDim,
- const int YDim,
- const int AssumeImageTiles,
- unsigned char* pResultImage);
- /*!***********************************************************************
- @Function PVRTDecompressPVRTC
- @Input pCompressedData The PVRTC texture data to decompress
- @Input Do2bitMode Signifies whether the data is PVRTC2 or PVRTC4
- @Input XDim X dimension of the texture
- @Input YDim Y dimension of the texture
- @Modified pResultImage The decompressed texture data
- @Description Decompresses PVRTC to RGBA 8888
- *************************************************************************/
- int PVRTDecompressPVRTC(const void * const pCompressedData,const int XDim,const int YDim, void *pDestData,const bool Do2bitMode)
- {
- PVRDecompress((AMTC_BLOCK_STRUCT*)pCompressedData,Do2bitMode,XDim,YDim,1,(unsigned char*)pDestData);
-
- return XDim*YDim/2;
- }
- /*!***********************************************************************
- @Function util_number_is_power_2
- @Input input A number
- @Returns TRUE if the number is an integer power of two, else FALSE.
- @Description Check that a number is an integer power of two, i.e.
- 1, 2, 4, 8, ... etc.
- Returns FALSE for zero.
- *************************************************************************/
- int util_number_is_power_2( unsigned input )
- {
- unsigned minus1;
-
- if( !input ) return 0;
-
- minus1 = input - 1;
- return ( (input | minus1) == (input ^ minus1) ) ? 1 : 0;
- }
- /*!***********************************************************************
- @Function Unpack5554Colour
- @Input pBlock
- @Input ABColours
- @Description Given a block, extract the colour information and convert
- to 5554 formats
- *************************************************************************/
- static void Unpack5554Colour(const AMTC_BLOCK_STRUCT *pBlock,
- int ABColours[2][4])
- {
- U32 RawBits[2];
-
- int i;
-
- // Extract A and B
- RawBits[0] = pBlock->PackedData[1] & (0xFFFE); // 15 bits (shifted up by one)
- RawBits[1] = pBlock->PackedData[1] >> 16; // 16 bits
-
- // step through both colours
- for(i = 0; i < 2; i++)
- {
- // If completely opaque
- if(RawBits[i] & (1<<15))
- {
- // Extract R and G (both 5 bit)
- ABColours[i][0] = (RawBits[i] >> 10) & 0x1F;
- ABColours[i][1] = (RawBits[i] >> 5) & 0x1F;
-
- /*
- The precision of Blue depends on A or B. If A then we need to
- replicate the top bit to get 5 bits in total
- */
- ABColours[i][2] = RawBits[i] & 0x1F;
- if(i==0)
- {
- ABColours[0][2] |= ABColours[0][2] >> 4;
- }
-
- // set 4bit alpha fully on...
- ABColours[i][3] = 0xF;
- }
- else // Else if colour has variable translucency
- {
- /*
- Extract R and G (both 4 bit).
- (Leave a space on the end for the replication of bits
- */
- ABColours[i][0] = (RawBits[i] >> (8-1)) & 0x1E;
- ABColours[i][1] = (RawBits[i] >> (4-1)) & 0x1E;
-
- // replicate bits to truly expand to 5 bits
- ABColours[i][0] |= ABColours[i][0] >> 4;
- ABColours[i][1] |= ABColours[i][1] >> 4;
-
- // grab the 3(+padding) or 4 bits of blue and add an extra padding bit
- ABColours[i][2] = (RawBits[i] & 0xF) << 1;
-
- /*
- expand from 3 to 5 bits if this is from colour A, or 4 to 5 bits if from
- colour B
- */
- if(i==0)
- {
- ABColours[0][2] |= ABColours[0][2] >> 3;
- }
- else
- {
- ABColours[0][2] |= ABColours[0][2] >> 4;
- }
-
- // Set the alpha bits to be 3 + a zero on the end
- ABColours[i][3] = (RawBits[i] >> 11) & 0xE;
- }
- }
- }
- /*!***********************************************************************
- @Function UnpackModulations
- @Input pBlock
- @Input Do2bitMode
- @Input ModulationVals
- @Input ModulationModes
- @Input StartX
- @Input StartY
- @Description Given the block and the texture type and it's relative
- position in the 2x2 group of blocks, extract the bit
- patterns for the fully defined pixels.
- *************************************************************************/
- static void UnpackModulations(const AMTC_BLOCK_STRUCT *pBlock,
- const int Do2bitMode,
- int ModulationVals[8][16],
- int ModulationModes[8][16],
- int StartX,
- int StartY)
- {
- int BlockModMode;
- U32 ModulationBits;
-
- int x, y;
-
- BlockModMode= pBlock->PackedData[1] & 1;
- ModulationBits = pBlock->PackedData[0];
-
- // if it's in an interpolated mode
- if(Do2bitMode && BlockModMode)
- {
- /*
- run through all the pixels in the block. Note we can now treat all the
- "stored" values as if they have 2bits (even when they didn't!)
- */
- for(y = 0; y < BLK_Y_SIZE; y++)
- {
- for(x = 0; x < BLK_X_2BPP; x++)
- {
- ModulationModes[y+StartY][x+StartX] = BlockModMode;
-
- // if this is a stored value...
- if(((x^y)&1) == 0)
- {
- ModulationVals[y+StartY][x+StartX] = ModulationBits & 3;
- ModulationBits >>= 2;
- }
- }
- }
- }
- else if(Do2bitMode) // else if direct encoded 2bit mode - i.e. 1 mode bit per pixel
- {
- for(y = 0; y < BLK_Y_SIZE; y++)
- {
- for(x = 0; x < BLK_X_2BPP; x++)
- {
- ModulationModes[y+StartY][x+StartX] = BlockModMode;
-
- // double the bits so 0=> 00, and 1=>11
- if(ModulationBits & 1)
- {
- ModulationVals[y+StartY][x+StartX] = 0x3;
- }
- else
- {
- ModulationVals[y+StartY][x+StartX] = 0x0;
- }
- ModulationBits >>= 1;
- }
- }
- }
- else // else its the 4bpp mode so each value has 2 bits
- {
- for(y = 0; y < BLK_Y_SIZE; y++)
- {
- for(x = 0; x < BLK_X_4BPP; x++)
- {
- ModulationModes[y+StartY][x+StartX] = BlockModMode;
-
- ModulationVals[y+StartY][x+StartX] = ModulationBits & 3;
- ModulationBits >>= 2;
- }
- }
- }
-
- // make sure nothing is left over
- assert(ModulationBits==0);
- }
- /*!***********************************************************************
- @Function InterpolateColours
- @Input ColourP
- @Input ColourQ
- @Input ColourR
- @Input ColourS
- @Input Do2bitMode
- @Input x
- @Input y
- @Modified Result
- @Description This performs a HW bit accurate interpolation of either the
- A or B colours for a particular pixel.
-
- NOTE: It is assumed that the source colours are in ARGB 5554
- format - This means that some "preparation" of the values will
- be necessary.
- *************************************************************************/
- static void InterpolateColours(const int ColourP[4],
- const int ColourQ[4],
- const int ColourR[4],
- const int ColourS[4],
- const int Do2bitMode,
- const int x,
- const int y,
- int Result[4])
- {
- int u, v, uscale;
- int k;
-
- int tmp1, tmp2;
-
- int P[4], Q[4], R[4], S[4];
-
- // Copy the colours
- for(k = 0; k < 4; k++)
- {
- P[k] = ColourP[k];
- Q[k] = ColourQ[k];
- R[k] = ColourR[k];
- S[k] = ColourS[k];
- }
-
- // put the x and y values into the right range
- v = (y & 0x3) | ((~y & 0x2) << 1);
-
- if(Do2bitMode)
- u = (x & 0x7) | ((~x & 0x4) << 1);
- else
- u = (x & 0x3) | ((~x & 0x2) << 1);
-
- // get the u and v scale amounts
- v = v - BLK_Y_SIZE/2;
-
- if(Do2bitMode)
- {
- u = u - BLK_X_2BPP/2;
- uscale = 8;
- }
- else
- {
- u = u - BLK_X_4BPP/2;
- uscale = 4;
- }
-
- for(k = 0; k < 4; k++)
- {
- tmp1 = P[k] * uscale + u * (Q[k] - P[k]);
- tmp2 = R[k] * uscale + u * (S[k] - R[k]);
-
- tmp1 = tmp1 * 4 + v * (tmp2 - tmp1);
-
- Result[k] = tmp1;
- }
-
- // Lop off the appropriate number of bits to get us to 8 bit precision
- if(Do2bitMode)
- {
- // do RGB
- for(k = 0; k < 3; k++)
- {
- Result[k] >>= 2;
- }
-
- Result[3] >>= 1;
- }
- else
- {
- // do RGB (A is ok)
- for(k = 0; k < 3; k++)
- {
- Result[k] >>= 1;
- }
- }
-
- // sanity check
- for(k = 0; k < 4; k++)
- {
- assert(Result[k] < 256);
- }
-
-
- /*
- Convert from 5554 to 8888
-
- do RGB 5.3 => 8
- */
- for(k = 0; k < 3; k++)
- {
- Result[k] += Result[k] >> 5;
- }
-
- Result[3] += Result[3] >> 4;
-
- // 2nd sanity check
- for(k = 0; k < 4; k++)
- {
- assert(Result[k] < 256);
- }
-
- }
- /*!***********************************************************************
- @Function GetModulationValue
- @Input x
- @Input y
- @Input Do2bitMode
- @Input ModulationVals
- @Input ModulationModes
- @Input Mod
- @Input DoPT
- @Description Get the modulation value as a numerator of a fraction of 8ths
- *************************************************************************/
- static void GetModulationValue(int x,
- int y,
- const int Do2bitMode,
- const int ModulationVals[8][16],
- const int ModulationModes[8][16],
- int *Mod,
- int *DoPT)
- {
- static const int RepVals0[4] = {0, 3, 5, 8};
- static const int RepVals1[4] = {0, 4, 4, 8};
-
- int ModVal;
-
- // Map X and Y into the local 2x2 block
- y = (y & 0x3) | ((~y & 0x2) << 1);
-
- if(Do2bitMode)
- x = (x & 0x7) | ((~x & 0x4) << 1);
- else
- x = (x & 0x3) | ((~x & 0x2) << 1);
-
- // assume no PT for now
- *DoPT = 0;
-
- // extract the modulation value. If a simple encoding
- if(ModulationModes[y][x]==0)
- {
- ModVal = RepVals0[ModulationVals[y][x]];
- }
- else if(Do2bitMode)
- {
- // if this is a stored value
- if(((x^y)&1)==0)
- ModVal = RepVals0[ModulationVals[y][x]];
- else if(ModulationModes[y][x] == 1) // else average from the neighbours if H&V interpolation..
- {
- ModVal = (RepVals0[ModulationVals[y-1][x]] +
- RepVals0[ModulationVals[y+1][x]] +
- RepVals0[ModulationVals[y][x-1]] +
- RepVals0[ModulationVals[y][x+1]] + 2) / 4;
- }
- else if(ModulationModes[y][x] == 2) // else if H-Only
- {
- ModVal = (RepVals0[ModulationVals[y][x-1]] +
- RepVals0[ModulationVals[y][x+1]] + 1) / 2;
- }
- else // else it's V-Only
- {
- ModVal = (RepVals0[ModulationVals[y-1][x]] +
- RepVals0[ModulationVals[y+1][x]] + 1) / 2;
- }
- }
- else // else it's 4BPP and PT encoding
- {
- ModVal = RepVals1[ModulationVals[y][x]];
-
- *DoPT = ModulationVals[y][x] == PT_INDEX;
- }
-
- *Mod =ModVal;
- }
- /*!***********************************************************************
- @Function TwiddleUV
- @Input YSize Y dimension of the texture in pixels
- @Input XSize X dimension of the texture in pixels
- @Input YPos Pixel Y position
- @Input XPos Pixel X position
- @Returns The twiddled offset of the pixel
- @Description Given the Block (or pixel) coordinates and the dimension of
- the texture in blocks (or pixels) this returns the twiddled
- offset of the block (or pixel) from the start of the map.
-
- NOTE the dimensions of the texture must be a power of 2
- *************************************************************************/
- static int DisableTwiddlingRoutine = 0;
- static U32 TwiddleUV(U32 YSize, U32 XSize, U32 YPos, U32 XPos)
- {
- U32 Twiddled;
-
- U32 MinDimension;
- U32 MaxValue;
-
- U32 SrcBitPos;
- U32 DstBitPos;
-
- int ShiftCount;
-
- assert(YPos < YSize);
- assert(XPos < XSize);
-
- assert(POWER_OF_2(YSize));
- assert(POWER_OF_2(XSize));
-
- if(YSize < XSize)
- {
- MinDimension = YSize;
- MaxValue = XPos;
- }
- else
- {
- MinDimension = XSize;
- MaxValue = YPos;
- }
-
- // Nasty hack to disable twiddling
- if(DisableTwiddlingRoutine)
- return (YPos* XSize + XPos);
-
- // Step through all the bits in the "minimum" dimension
- SrcBitPos = 1;
- DstBitPos = 1;
- Twiddled = 0;
- ShiftCount = 0;
-
- while(SrcBitPos < MinDimension)
- {
- if(YPos & SrcBitPos)
- {
- Twiddled |= DstBitPos;
- }
-
- if(XPos & SrcBitPos)
- {
- Twiddled |= (DstBitPos << 1);
- }
-
-
- SrcBitPos <<= 1;
- DstBitPos <<= 2;
- ShiftCount += 1;
-
- }
-
- // prepend any unused bits
- MaxValue >>= ShiftCount;
-
- Twiddled |= (MaxValue << (2*ShiftCount));
-
- return Twiddled;
- }
- /*!***********************************************************************
- @Function Decompress
- @Input pCompressedData The PVRTC texture data to decompress
- @Input Do2BitMode Signifies whether the data is PVRTC2 or PVRTC4
- @Input XDim X dimension of the texture
- @Input YDim Y dimension of the texture
- @Input AssumeImageTiles Assume the texture data tiles
- @Modified pResultImage The decompressed texture data
- @Description Decompresses PVRTC to RGBA 8888
- *************************************************************************/
- static void PVRDecompress(AMTC_BLOCK_STRUCT *pCompressedData,
- const bool Do2bitMode,
- const int XDim,
- const int YDim,
- const int AssumeImageTiles,
- unsigned char* pResultImage)
- {
- int x, y;
- int i, j;
-
- int BlkX, BlkY;
- int BlkXp1, BlkYp1;
- int XBlockSize;
- int BlkXDim, BlkYDim;
-
- int StartX, StartY;
-
- int ModulationVals[8][16];
- int ModulationModes[8][16];
-
- int Mod, DoPT;
-
- unsigned int uPosition;
-
- // local neighbourhood of blocks
- AMTC_BLOCK_STRUCT *pBlocks[2][2];
-
- AMTC_BLOCK_STRUCT *pPrevious[2][2] = {{NULL, NULL}, {NULL, NULL}};
-
- // Low precision colours extracted from the blocks
- struct
- {
- int Reps[2][4];
- }Colours5554[2][2];
-
- // Interpolated A and B colours for the pixel
- int ASig[4], BSig[4];
-
- int Result[4];
-
- if(Do2bitMode)
- XBlockSize = BLK_X_2BPP;
- else
- XBlockSize = BLK_X_4BPP;
-
- // For MBX don't allow the sizes to get too small
- BlkXDim = PVRT_MAX(2, XDim / XBlockSize);
- BlkYDim = PVRT_MAX(2, YDim / BLK_Y_SIZE);
-
- /*
- Step through the pixels of the image decompressing each one in turn
-
- Note that this is a hideously inefficient way to do this!
- */
- for(y = 0; y < YDim; y++)
- {
- for(x = 0; x < XDim; x++)
- {
- // map this pixel to the top left neighbourhood of blocks
- BlkX = (x - XBlockSize/2);
- BlkY = (y - BLK_Y_SIZE/2);
-
- BlkX = LIMIT_COORD(BlkX, XDim, AssumeImageTiles);
- BlkY = LIMIT_COORD(BlkY, YDim, AssumeImageTiles);
-
-
- BlkX /= XBlockSize;
- BlkY /= BLK_Y_SIZE;
-
- // compute the positions of the other 3 blocks
- BlkXp1 = LIMIT_COORD(BlkX+1, BlkXDim, AssumeImageTiles);
- BlkYp1 = LIMIT_COORD(BlkY+1, BlkYDim, AssumeImageTiles);
-
- // Map to block memory locations
- pBlocks[0][0] = pCompressedData +TwiddleUV(BlkYDim, BlkXDim, BlkY, BlkX);
- pBlocks[0][1] = pCompressedData +TwiddleUV(BlkYDim, BlkXDim, BlkY, BlkXp1);
- pBlocks[1][0] = pCompressedData +TwiddleUV(BlkYDim, BlkXDim, BlkYp1, BlkX);
- pBlocks[1][1] = pCompressedData +TwiddleUV(BlkYDim, BlkXDim, BlkYp1, BlkXp1);
-
-
- /*
- extract the colours and the modulation information IF the previous values
- have changed.
- */
- if(memcmp(pPrevious, pBlocks, 4*sizeof(void*)) != 0)
- {
- StartY = 0;
- for(i = 0; i < 2; i++)
- {
- StartX = 0;
- for(j = 0; j < 2; j++)
- {
- Unpack5554Colour(pBlocks[i][j], Colours5554[i][j].Reps);
-
- UnpackModulations(pBlocks[i][j],
- Do2bitMode,
- ModulationVals,
- ModulationModes,
- StartX, StartY);
-
- StartX += XBlockSize;
- }
-
- StartY += BLK_Y_SIZE;
- }
-
- // make a copy of the new pointers
- memcpy(pPrevious, pBlocks, 4*sizeof(void*));
- }
-
- // decompress the pixel. First compute the interpolated A and B signals
- InterpolateColours(Colours5554[0][0].Reps[0],
- Colours5554[0][1].Reps[0],
- Colours5554[1][0].Reps[0],
- Colours5554[1][1].Reps[0],
- Do2bitMode, x, y,
- ASig);
-
- InterpolateColours(Colours5554[0][0].Reps[1],
- Colours5554[0][1].Reps[1],
- Colours5554[1][0].Reps[1],
- Colours5554[1][1].Reps[1],
- Do2bitMode, x, y,
- BSig);
-
- GetModulationValue(x,y, Do2bitMode, (const int (*)[16])ModulationVals, (const int (*)[16])ModulationModes,
- &Mod, &DoPT);
-
- // compute the modulated colour
- for(i = 0; i < 4; i++)
- {
- Result[i] = ASig[i] * 8 + Mod * (BSig[i] - ASig[i]);
- Result[i] >>= 3;
- }
-
- if(DoPT)
- Result[3] = 0;
-
- // Store the result in the output image
- uPosition = (x+y*XDim)<<2;
- pResultImage[uPosition+0] = (U8)Result[0];
- pResultImage[uPosition+1] = (U8)Result[1];
- pResultImage[uPosition+2] = (U8)Result[2];
- pResultImage[uPosition+3] = (U8)Result[3];
- }
- }
- }
- /*****************************************************************************
- End of file (pvr.cpp)
- *****************************************************************************/
|