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