PVRTC.cpp 25 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706
  1. /******************************************************************************/
  2. #include "stdafx.h"
  3. /******************************************************************************/
  4. namespace EE{
  5. namespace PVRTC{
  6. /***********************************************************/
  7. typedef U8 PVRTuint8;
  8. typedef I32 PVRTint32;
  9. typedef U32 PVRTuint32;
  10. /***********************************************************
  11. DECOMPRESSION ROUTINES
  12. ************************************************************/
  13. /*****************************************************************************
  14. * Useful structs
  15. *****************************************************************************/
  16. struct Pixel32
  17. {
  18. PVRTuint8 red,green,blue,alpha;
  19. };
  20. struct Pixel128S
  21. {
  22. PVRTint32 red,green,blue,alpha;
  23. };
  24. struct PVRTCWord
  25. {
  26. PVRTuint32 u32ModulationData;
  27. PVRTuint32 u32ColourData;
  28. };
  29. struct PVRTCWordIndices
  30. {
  31. int P[2], Q[2], R[2], S[2];
  32. };
  33. /********************************************************************************/
  34. /*!***********************************************************************
  35. @Function getColourA
  36. @Input u32ColourData Colour information from a PVRTCWord.
  37. @Return Returns the first colour in a PVRTCWord's colour data.
  38. @Description Decodes the first colour in a PVRTCWord's colour data.
  39. *************************************************************************/
  40. static Pixel32 getColourA(PVRTuint32 u32ColourData)
  41. {
  42. Pixel32 colour;
  43. // Opaque Colour Mode - RGB 554
  44. if ((u32ColourData & 0x8000) != 0)
  45. {
  46. colour.red = (PVRTuint8)((u32ColourData & 0x7c00) >> 10); // 5->5 bits
  47. colour.green = (PVRTuint8)((u32ColourData & 0x3e0) >> 5); // 5->5 bits
  48. colour.blue = (PVRTuint8)(u32ColourData & 0x1e) | ((u32ColourData & 0x1e) >> 4); // 4->5 bits
  49. colour.alpha = (PVRTuint8)0xf;// 0->4 bits
  50. }
  51. // Transparent Colour Mode - ARGB 3443
  52. else
  53. {
  54. colour.red = (PVRTuint8)((u32ColourData & 0xf00) >> 7) | ((u32ColourData & 0xf00) >> 11); // 4->5 bits
  55. colour.green = (PVRTuint8)((u32ColourData & 0xf0) >> 3) | ((u32ColourData & 0xf0) >> 7); // 4->5 bits
  56. colour.blue = (PVRTuint8)((u32ColourData & 0xe) << 1) | ((u32ColourData & 0xe) >> 2); // 3->5 bits
  57. colour.alpha = (PVRTuint8)((u32ColourData & 0x7000) >> 11);// 3->4 bits - note 0 at right
  58. }
  59. return colour;
  60. }
  61. /*!***********************************************************************
  62. @Function getColourB
  63. @Input u32ColourData Colour information from a PVRTCWord.
  64. @Return Returns the second colour in a PVRTCWord's colour data.
  65. @Description Decodes the second colour in a PVRTCWord's colour data.
  66. *************************************************************************/
  67. static Pixel32 getColourB(PVRTuint32 u32ColourData)
  68. {
  69. Pixel32 colour;
  70. // Opaque Colour Mode - RGB 555
  71. if (u32ColourData & 0x80000000)
  72. {
  73. colour.red = (PVRTuint8)((u32ColourData & 0x7c000000) >> 26); // 5->5 bits
  74. colour.green = (PVRTuint8)((u32ColourData & 0x3e00000) >> 21); // 5->5 bits
  75. colour.blue = (PVRTuint8)((u32ColourData & 0x1f0000) >> 16); // 5->5 bits
  76. colour.alpha = (PVRTuint8)0xf;// 0 bits
  77. }
  78. // Transparent Colour Mode - ARGB 3444
  79. else
  80. {
  81. colour.red = (PVRTuint8)(((u32ColourData & 0xf000000) >> 23) | ((u32ColourData & 0xf000000) >> 27)); // 4->5 bits
  82. colour.green = (PVRTuint8)(((u32ColourData & 0xf00000) >> 19) | ((u32ColourData & 0xf00000) >> 23)); // 4->5 bits
  83. colour.blue = (PVRTuint8)(((u32ColourData & 0xf0000) >> 15) | ((u32ColourData & 0xf0000) >> 19)); // 4->5 bits
  84. colour.alpha = (PVRTuint8)((u32ColourData & 0x70000000) >> 27);// 3->4 bits - note 0 at right
  85. }
  86. return colour;
  87. }
  88. /*!***********************************************************************
  89. @Function interpolateColours
  90. @Input P,Q,R,S Low bit-rate colour values for each PVRTCWord.
  91. @Modified pPixel Output array for upscaled colour values.
  92. @Input ui8Bpp Number of bpp.
  93. @Description Bilinear upscale from 2x2 pixels to 4x4/8x4 pixels (depending on PVRTC bpp mode).
  94. *************************************************************************/
  95. static void interpolateColours(Pixel32 P, Pixel32 Q, Pixel32 R, Pixel32 S,
  96. Pixel128S *pPixel, PVRTuint8 ui8Bpp)
  97. {
  98. PVRTuint32 ui32WordWidth=4;
  99. PVRTuint32 ui32WordHeight=4;
  100. if (ui8Bpp==2)
  101. ui32WordWidth=8;
  102. //Convert to int 32.
  103. Pixel128S hP = {(PVRTint32)P.red,(PVRTint32)P.green,(PVRTint32)P.blue,(PVRTint32)P.alpha};
  104. Pixel128S hQ = {(PVRTint32)Q.red,(PVRTint32)Q.green,(PVRTint32)Q.blue,(PVRTint32)Q.alpha};
  105. Pixel128S hR = {(PVRTint32)R.red,(PVRTint32)R.green,(PVRTint32)R.blue,(PVRTint32)R.alpha};
  106. Pixel128S hS = {(PVRTint32)S.red,(PVRTint32)S.green,(PVRTint32)S.blue,(PVRTint32)S.alpha};
  107. //Get vectors.
  108. Pixel128S QminusP = {hQ.red - hP.red, hQ.green - hP.green, hQ.blue - hP.blue, hQ.alpha - hP.alpha};
  109. Pixel128S SminusR = {hS.red - hR.red, hS.green - hR.green, hS.blue - hR.blue, hS.alpha - hR.alpha};
  110. //Multiply colours.
  111. hP.red *= ui32WordWidth;
  112. hP.green *= ui32WordWidth;
  113. hP.blue *= ui32WordWidth;
  114. hP.alpha *= ui32WordWidth;
  115. hR.red *= ui32WordWidth;
  116. hR.green *= ui32WordWidth;
  117. hR.blue *= ui32WordWidth;
  118. hR.alpha *= ui32WordWidth;
  119. if (ui8Bpp==2)
  120. {
  121. //Loop through pixels to achieve results.
  122. for (unsigned int x=0; x < ui32WordWidth; x++)
  123. {
  124. Pixel128S Result={4*hP.red, 4*hP.green, 4*hP.blue, 4*hP.alpha};
  125. Pixel128S dY = {hR.red - hP.red, hR.green - hP.green, hR.blue - hP.blue, hR.alpha - hP.alpha};
  126. for (unsigned int y=0; y < ui32WordHeight; y++)
  127. {
  128. pPixel[y*ui32WordWidth+x].red = (PVRTint32)((Result.red >> 7) + (Result.red >> 2));
  129. pPixel[y*ui32WordWidth+x].green = (PVRTint32)((Result.green >> 7) + (Result.green >> 2));
  130. pPixel[y*ui32WordWidth+x].blue = (PVRTint32)((Result.blue >> 7) + (Result.blue >> 2));
  131. pPixel[y*ui32WordWidth+x].alpha = (PVRTint32)((Result.alpha >> 5) + (Result.alpha >> 1));
  132. Result.red += dY.red;
  133. Result.green += dY.green;
  134. Result.blue += dY.blue;
  135. Result.alpha += dY.alpha;
  136. }
  137. hP.red += QminusP.red;
  138. hP.green += QminusP.green;
  139. hP.blue += QminusP.blue;
  140. hP.alpha += QminusP.alpha;
  141. hR.red += SminusR.red;
  142. hR.green += SminusR.green;
  143. hR.blue += SminusR.blue;
  144. hR.alpha += SminusR.alpha;
  145. }
  146. }
  147. else
  148. {
  149. //Loop through pixels to achieve results.
  150. for (unsigned int y=0; y < ui32WordHeight; y++)
  151. {
  152. Pixel128S Result={4*hP.red, 4*hP.green, 4*hP.blue, 4*hP.alpha};
  153. Pixel128S dY = {hR.red - hP.red, hR.green - hP.green, hR.blue - hP.blue, hR.alpha - hP.alpha};
  154. for (unsigned int x=0; x < ui32WordWidth; x++)
  155. {
  156. pPixel[y*ui32WordWidth+x].red = (PVRTint32)((Result.red >> 6) + (Result.red >> 1));
  157. pPixel[y*ui32WordWidth+x].green = (PVRTint32)((Result.green >> 6) + (Result.green >> 1));
  158. pPixel[y*ui32WordWidth+x].blue = (PVRTint32)((Result.blue >> 6) + (Result.blue >> 1));
  159. pPixel[y*ui32WordWidth+x].alpha = (PVRTint32)((Result.alpha >> 4) + (Result.alpha));
  160. Result.red += dY.red;
  161. Result.green += dY.green;
  162. Result.blue += dY.blue;
  163. Result.alpha += dY.alpha;
  164. }
  165. hP.red += QminusP.red;
  166. hP.green += QminusP.green;
  167. hP.blue += QminusP.blue;
  168. hP.alpha += QminusP.alpha;
  169. hR.red += SminusR.red;
  170. hR.green += SminusR.green;
  171. hR.blue += SminusR.blue;
  172. hR.alpha += SminusR.alpha;
  173. }
  174. }
  175. }
  176. /*!***********************************************************************
  177. @Function unpackModulations
  178. @Input word PVRTCWord to be decompressed
  179. @Input offsetX X position within the PVRTCWord
  180. @Input offsetY Y position within the PVRTCWord
  181. @Modified i32ModulationValues The array of modulation values.
  182. @Modified i32ModulationModes The array of modulation modes.
  183. @Input ui8Bpp Number of bpp.
  184. @Description Reads out and decodes the modulation values within the a given PVRTCWord
  185. *************************************************************************/
  186. static void unpackModulations(const PVRTCWord& word, int offsetX, int offsetY, PVRTint32 i32ModulationValues[16][8], PVRTint32 i32ModulationModes[16][8], PVRTuint8 ui8Bpp)
  187. {
  188. PVRTuint32 WordModMode = word.u32ColourData & 0x1;
  189. PVRTuint32 ModulationBits = word.u32ModulationData;
  190. // Unpack differently depending on 2bpp or 4bpp modes.
  191. if (ui8Bpp==2)
  192. {
  193. if(WordModMode)
  194. {
  195. // determine which of the three modes are in use:
  196. // If this is the either the H-only or V-only interpolation mode...
  197. if(ModulationBits & 0x1)
  198. {
  199. // look at the "LSB" for the "centre" (V=2,H=4) texel. Its LSB is now
  200. // actually used to indicate whether it's the H-only mode or the V-only...
  201. // The centre texel data is the at (y==2, x==4) and so its LSB is at bit 20.
  202. if(ModulationBits & (0x1 << 20))
  203. {
  204. // This is the V-only mode
  205. WordModMode = 3;
  206. }
  207. else
  208. {
  209. // This is the H-only mode
  210. WordModMode = 2;
  211. }
  212. // Create an extra bit for the centre pixel so that it looks like
  213. // we have 2 actual bits for this texel. It makes later coding much easier.
  214. if(ModulationBits & (0x1 << 21))
  215. {
  216. // set it to produce code for 1.0
  217. ModulationBits |= (0x1 << 20);
  218. }
  219. else
  220. {
  221. // clear it to produce 0.0 code
  222. ModulationBits &= ~(0x1 << 20);
  223. }
  224. }// end if H-Only or V-Only interpolation mode was chosen
  225. if(ModulationBits & 0x2)
  226. {
  227. ModulationBits |= 0x1; /*set it*/
  228. }
  229. else
  230. {
  231. ModulationBits &= ~0x1; /*clear it*/
  232. }
  233. // run through all the pixels in the block. Note we can now treat all the
  234. // "stored" values as if they have 2bits (even when they didn't!)
  235. for(int y = 0; y < 4; y++)
  236. {
  237. for(int x = 0; x < 8; x++)
  238. {
  239. i32ModulationModes[x+offsetX][y+offsetY] = WordModMode;
  240. // if this is a stored value...
  241. if(((x^y)&1) == 0)
  242. {
  243. i32ModulationValues[x+offsetX][y+offsetY] = ModulationBits & 3;
  244. ModulationBits >>= 2;
  245. }
  246. }
  247. } // end for y
  248. }
  249. // else if direct encoded 2bit mode - i.e. 1 mode bit per pixel
  250. else
  251. {
  252. for(int y = 0; y < 4; y++)
  253. {
  254. for(int x = 0; x < 8; x++)
  255. {
  256. i32ModulationModes[x+offsetX][y+offsetY] = WordModMode;
  257. /*
  258. // double the bits so 0=> 00, and 1=>11
  259. */
  260. if(ModulationBits & 1)
  261. {
  262. i32ModulationValues[x+offsetX][y+offsetY] = 0x3;
  263. }
  264. else
  265. {
  266. i32ModulationValues[x+offsetX][y+offsetY] = 0x0;
  267. }
  268. ModulationBits >>= 1;
  269. }
  270. }// end for y
  271. }
  272. }
  273. else
  274. {
  275. //Much simpler than the 2bpp decompression, only two modes, so the n/8 values are set directly.
  276. // run through all the pixels in the word.
  277. if (WordModMode)
  278. {
  279. for(int y = 0; y < 4; y++)
  280. {
  281. for(int x = 0; x < 4; x++)
  282. {
  283. i32ModulationValues[y+offsetY][x+offsetX] = ModulationBits & 3;
  284. //if (i32ModulationValues==0) {}; don't need to check 0, 0 = 0/8.
  285. if (i32ModulationValues[y+offsetY][x+offsetX]==1) { i32ModulationValues[y+offsetY][x+offsetX]=4;}
  286. else if (i32ModulationValues[y+offsetY][x+offsetX]==2) { i32ModulationValues[y+offsetY][x+offsetX]=14;} //+10 tells the decompressor to punch through alpha.
  287. else if (i32ModulationValues[y+offsetY][x+offsetX]==3) { i32ModulationValues[y+offsetY][x+offsetX]=8;}
  288. ModulationBits >>= 2;
  289. } // end for x
  290. } // end for y
  291. }
  292. else
  293. {
  294. for(int y = 0; y < 4; y++)
  295. {
  296. for(int x = 0; x < 4; x++)
  297. {
  298. i32ModulationValues[y+offsetY][x+offsetX] = ModulationBits & 3;
  299. i32ModulationValues[y+offsetY][x+offsetX]*=3;
  300. if (i32ModulationValues[y+offsetY][x+offsetX]>3) i32ModulationValues[y+offsetY][x+offsetX]-=1;
  301. ModulationBits >>= 2;
  302. } // end for x
  303. } // end for y
  304. }
  305. }
  306. }
  307. /*!***********************************************************************
  308. @Function getModulationValues
  309. @Input i32ModulationValues The array of modulation values.
  310. @Input i32ModulationModes The array of modulation modes.
  311. @Input xPos The x Position within the current word.
  312. @Input yPos The y Position within the current word.
  313. @Input ui8Bpp Number of bpp.
  314. @Return Returns the modulation value.
  315. @Description Gets the effective modulation values for a given pixel.
  316. *************************************************************************/
  317. static PVRTint32 getModulationValues(PVRTint32 i32ModulationValues[16][8],PVRTint32 i32ModulationModes[16][8],PVRTuint32 xPos,PVRTuint32 yPos,PVRTuint8 ui8Bpp)
  318. {
  319. if (ui8Bpp==2)
  320. {
  321. const int RepVals0[4] = {0, 3, 5, 8};
  322. // extract the modulation value. If a simple encoding
  323. if(i32ModulationModes[xPos][yPos]==0)
  324. {
  325. return RepVals0[i32ModulationValues[xPos][yPos]];
  326. }
  327. else
  328. {
  329. // if this is a stored value
  330. if(((xPos^yPos)&1)==0)
  331. {
  332. return RepVals0[i32ModulationValues[xPos][yPos]];
  333. }
  334. // else average from the neighbours
  335. // if H&V interpolation...
  336. else if(i32ModulationModes[xPos][yPos] == 1)
  337. {
  338. return (RepVals0[i32ModulationValues[xPos][yPos-1]] +
  339. RepVals0[i32ModulationValues[xPos][yPos+1]] +
  340. RepVals0[i32ModulationValues[xPos-1][yPos]] +
  341. RepVals0[i32ModulationValues[xPos+1][yPos]] + 2) / 4;
  342. }
  343. // else if H-Only
  344. else if(i32ModulationModes[xPos][yPos] == 2)
  345. {
  346. return (RepVals0[i32ModulationValues[xPos-1][yPos]] +
  347. RepVals0[i32ModulationValues[xPos+1][yPos]] + 1) / 2;
  348. }
  349. // else it's V-Only
  350. else
  351. {
  352. return (RepVals0[i32ModulationValues[xPos][yPos-1]] +
  353. RepVals0[i32ModulationValues[xPos][yPos+1]] + 1) / 2;
  354. }
  355. }
  356. }
  357. else if (ui8Bpp==4)
  358. return i32ModulationValues[xPos][yPos];
  359. return 0;
  360. }
  361. /*!***********************************************************************
  362. @Function pvrtcGetDecompressedPixels
  363. @Input P,Q,R,S PVRTWords in current decompression area.
  364. @Modified pColourData Output pixels.
  365. @Input ui8Bpp Number of bpp.
  366. @Description Gets decompressed pixels for a given decompression area.
  367. *************************************************************************/
  368. static void pvrtcGetDecompressedPixels(const PVRTCWord& P, const PVRTCWord& Q,
  369. const PVRTCWord& R, const PVRTCWord& S,
  370. Pixel32 *pColourData,
  371. PVRTuint8 ui8Bpp)
  372. {
  373. //4bpp only needs 8*8 values, but 2bpp needs 16*8, so rather than wasting processor time we just statically allocate 16*8.
  374. PVRTint32 i32ModulationValues[16][8];
  375. //Only 2bpp needs this.
  376. PVRTint32 i32ModulationModes[16][8];
  377. //4bpp only needs 16 values, but 2bpp needs 32, so rather than wasting processor time we just statically allocate 32.
  378. Pixel128S upscaledColourA[32];
  379. Pixel128S upscaledColourB[32];
  380. PVRTuint32 ui32WordWidth=4;
  381. PVRTuint32 ui32WordHeight=4;
  382. if (ui8Bpp==2)
  383. ui32WordWidth=8;
  384. //Get the modulations from each word.
  385. unpackModulations(P, 0, 0, i32ModulationValues, i32ModulationModes, ui8Bpp);
  386. unpackModulations(Q, ui32WordWidth, 0, i32ModulationValues, i32ModulationModes, ui8Bpp);
  387. unpackModulations(R, 0, ui32WordHeight, i32ModulationValues, i32ModulationModes, ui8Bpp);
  388. unpackModulations(S, ui32WordWidth, ui32WordHeight, i32ModulationValues, i32ModulationModes, ui8Bpp);
  389. // Bilinear upscale image data from 2x2 -> 4x4
  390. interpolateColours(getColourA(P.u32ColourData), getColourA(Q.u32ColourData),
  391. getColourA(R.u32ColourData), getColourA(S.u32ColourData),
  392. upscaledColourA, ui8Bpp);
  393. interpolateColours(getColourB(P.u32ColourData), getColourB(Q.u32ColourData),
  394. getColourB(R.u32ColourData), getColourB(S.u32ColourData),
  395. upscaledColourB, ui8Bpp);
  396. for (unsigned int y=0; y < ui32WordHeight; y++)
  397. {
  398. for (unsigned int x=0; x < ui32WordWidth; x++)
  399. {
  400. PVRTint32 mod = getModulationValues(i32ModulationValues,i32ModulationModes,x+ui32WordWidth/2,y+ui32WordHeight/2,ui8Bpp);
  401. bool punchthroughAlpha=false;
  402. if (mod>10) {punchthroughAlpha=true; mod-=10;}
  403. Pixel128S result;
  404. result.red = (upscaledColourA[y*ui32WordWidth+x].red * (8-mod) + upscaledColourB[y*ui32WordWidth+x].red * mod) / 8;
  405. result.green = (upscaledColourA[y*ui32WordWidth+x].green * (8-mod) + upscaledColourB[y*ui32WordWidth+x].green * mod) / 8;
  406. result.blue = (upscaledColourA[y*ui32WordWidth+x].blue * (8-mod) + upscaledColourB[y*ui32WordWidth+x].blue * mod) / 8;
  407. if (punchthroughAlpha) result.alpha = 0;
  408. else result.alpha = (upscaledColourA[y*ui32WordWidth+x].alpha * (8-mod) + upscaledColourB[y*ui32WordWidth+x].alpha * mod) / 8;
  409. //Convert the 32bit precision result to 8 bit per channel colour.
  410. if (ui8Bpp==2)
  411. {
  412. pColourData[y*ui32WordWidth+x].red = (PVRTuint8)result.red;
  413. pColourData[y*ui32WordWidth+x].green = (PVRTuint8)result.green;
  414. pColourData[y*ui32WordWidth+x].blue = (PVRTuint8)result.blue;
  415. pColourData[y*ui32WordWidth+x].alpha = (PVRTuint8)result.alpha;
  416. }
  417. else if (ui8Bpp==4)
  418. {
  419. pColourData[y+x*ui32WordHeight].red = (PVRTuint8)result.red;
  420. pColourData[y+x*ui32WordHeight].green = (PVRTuint8)result.green;
  421. pColourData[y+x*ui32WordHeight].blue = (PVRTuint8)result.blue;
  422. pColourData[y+x*ui32WordHeight].alpha = (PVRTuint8)result.alpha;
  423. }
  424. }
  425. }
  426. }
  427. /*!***********************************************************************
  428. @Function wrapWordIndex
  429. @Input numWords Total number of PVRTCWords in the current surface.
  430. @Input word Original index for a PVRTCWord.
  431. @Return unsigned int Wrapped PVRTCWord index.
  432. @Description Maps decompressed data to the correct location in the output buffer.
  433. *************************************************************************/
  434. static unsigned int wrapWordIndex(unsigned int numWords, int word)
  435. {
  436. return ((word + numWords) % numWords);
  437. }
  438. #if DEBUG
  439. /*!***********************************************************************
  440. @Function isPowerOf2
  441. @Input input Value to be checked
  442. @Returns true if the number is an integer power of two, else false.
  443. @Description Check that a number is an integer power of two, i.e.
  444. 1, 2, 4, 8, ... etc.
  445. Returns false for zero.
  446. *************************************************************************/
  447. static bool isPowerOf2( unsigned int input )
  448. {
  449. unsigned int minus1;
  450. if( !input ) return 0;
  451. minus1 = input - 1;
  452. return ( (input | minus1) == (input ^ minus1) );
  453. }
  454. #endif
  455. /*!***********************************************************************
  456. @Function TwiddleUV
  457. @Input YSize Y dimension of the texture in pixels
  458. @Input XSize X dimension of the texture in pixels
  459. @Input YPos Pixel Y position
  460. @Input XPos Pixel X position
  461. @Returns The twiddled offset of the pixel
  462. @Description Given the Word (or pixel) coordinates and the dimension of
  463. the texture in words (or pixels) this returns the twiddled
  464. offset of the word (or pixel) from the start of the map.
  465. NOTE: the dimensions of the texture must be a power of 2
  466. *************************************************************************/
  467. static PVRTuint32 TwiddleUV(PVRTuint32 XSize, PVRTuint32 YSize, PVRTuint32 XPos, PVRTuint32 YPos)
  468. {
  469. //Initially assume X is the larger size.
  470. PVRTuint32 MinDimension=XSize;
  471. PVRTuint32 MaxValue=YPos;
  472. PVRTuint32 Twiddled=0;
  473. PVRTuint32 SrcBitPos=1;
  474. PVRTuint32 DstBitPos=1;
  475. int ShiftCount=0;
  476. //Check the sizes are valid.
  477. DEBUG_ASSERT(YPos < YSize, "TwiddleUV");
  478. DEBUG_ASSERT(XPos < XSize, "TwiddleUV");
  479. DEBUG_ASSERT(isPowerOf2(YSize), "TwiddleUV");
  480. DEBUG_ASSERT(isPowerOf2(XSize), "TwiddleUV");
  481. //If Y is the larger dimension - switch the min/max values.
  482. if(YSize < XSize)
  483. {
  484. MinDimension = YSize;
  485. MaxValue = XPos;
  486. }
  487. // Step through all the bits in the "minimum" dimension
  488. while(SrcBitPos < MinDimension)
  489. {
  490. if(YPos & SrcBitPos)
  491. {
  492. Twiddled |= DstBitPos;
  493. }
  494. if(XPos & SrcBitPos)
  495. {
  496. Twiddled |= (DstBitPos << 1);
  497. }
  498. SrcBitPos <<= 1;
  499. DstBitPos <<= 2;
  500. ShiftCount += 1;
  501. }
  502. // Prepend any unused bits
  503. MaxValue >>= ShiftCount;
  504. Twiddled |= (MaxValue << (2*ShiftCount));
  505. return Twiddled;
  506. }
  507. /*!***********************************************************************
  508. @Function mapDecompressedData
  509. @Modified pOutput The PVRTC texture data to decompress
  510. @Input width Width of the texture surface.
  511. @Input pWord A pointer to the decompressed PVRTCWord in pixel form.
  512. @Input &words Indices for the PVRTCword.
  513. @Input ui8Bpp number of bits per pixel
  514. @Description Maps decompressed data to the correct location in the output buffer.
  515. *************************************************************************/
  516. static void mapDecompressedData(Pixel32* pOutput, int width,
  517. const Pixel32 *pWord,
  518. const PVRTCWordIndices &words,
  519. const PVRTuint8 ui8Bpp)
  520. {
  521. PVRTuint32 ui32WordWidth=4;
  522. PVRTuint32 ui32WordHeight=4;
  523. if (ui8Bpp==2)
  524. ui32WordWidth=8;
  525. for (unsigned int y=0; y < ui32WordHeight/2; y++)
  526. {
  527. for (unsigned int x=0; x < ui32WordWidth/2; x++)
  528. {
  529. pOutput[(((words.P[1] * ui32WordHeight) + y + ui32WordHeight/2)
  530. * width + words.P[0] *ui32WordWidth + x + ui32WordWidth/2)] = pWord[y*ui32WordWidth+x]; // map P
  531. pOutput[(((words.Q[1] * ui32WordHeight) + y + ui32WordHeight/2)
  532. * width + words.Q[0] *ui32WordWidth + x)] = pWord[y*ui32WordWidth+x+ui32WordWidth/2]; // map Q
  533. pOutput[(((words.R[1] * ui32WordHeight) + y)
  534. * width + words.R[0] *ui32WordWidth + x + ui32WordWidth/2)] = pWord[(y+ui32WordHeight/2)*ui32WordWidth+x]; // map R
  535. pOutput[(((words.S[1] * ui32WordHeight) + y)
  536. * width + words.S[0] *ui32WordWidth + x)] = pWord[(y+ui32WordHeight/2)*ui32WordWidth+x+ui32WordWidth/2]; // map S
  537. }
  538. }
  539. }
  540. /*!***********************************************************************
  541. @Function pvrtcDecompress
  542. @Input pCompressedData The PVRTC texture data to decompress
  543. @Modified pDecompressedData The output buffer to decompress into.
  544. @Input ui32Width X dimension of the texture
  545. @Input ui32Height Y dimension of the texture
  546. @Input ui8Bpp number of bits per pixel
  547. @Description Internally decompresses PVRTC to RGBA 8888
  548. *************************************************************************/
  549. static int pvrtcDecompress( PVRTuint8 *pCompressedData,
  550. Pixel32 *pDecompressedData,
  551. PVRTuint32 ui32Width,
  552. PVRTuint32 ui32Height,
  553. PVRTuint8 ui8Bpp)
  554. {
  555. PVRTuint32 ui32WordWidth=4;
  556. PVRTuint32 ui32WordHeight=4;
  557. if (ui8Bpp==2)
  558. ui32WordWidth=8;
  559. PVRTuint32 *pWordMembers = (PVRTuint32 *)pCompressedData;
  560. Pixel32 *pOutData = pDecompressedData;
  561. // Calculate number of words
  562. int i32NumXWords = (int)(ui32Width / ui32WordWidth);
  563. int i32NumYWords = (int)(ui32Height / ui32WordHeight);
  564. // Structs used for decompression
  565. PVRTCWordIndices indices;
  566. Pixel32 *pPixels;
  567. pPixels = (Pixel32*)malloc(ui32WordWidth*ui32WordHeight*sizeof(Pixel32));
  568. // For each row of words
  569. for(int wordY=-1; wordY < i32NumYWords-1; wordY++)
  570. {
  571. // for each column of words
  572. for(int wordX=-1; wordX < i32NumXWords-1; wordX++)
  573. {
  574. indices.P[0] = wrapWordIndex(i32NumXWords, wordX);
  575. indices.P[1] = wrapWordIndex(i32NumYWords, wordY);
  576. indices.Q[0] = wrapWordIndex(i32NumXWords, wordX + 1);
  577. indices.Q[1] = wrapWordIndex(i32NumYWords, wordY);
  578. indices.R[0] = wrapWordIndex(i32NumXWords, wordX);
  579. indices.R[1] = wrapWordIndex(i32NumYWords, wordY + 1);
  580. indices.S[0] = wrapWordIndex(i32NumXWords, wordX + 1);
  581. indices.S[1] = wrapWordIndex(i32NumYWords, wordY + 1);
  582. //Work out the offsets into the twiddle structs, multiply by two as there are two members per word.
  583. PVRTuint32 WordOffsets[4] =
  584. {
  585. TwiddleUV(i32NumXWords,i32NumYWords,indices.P[0], indices.P[1])*2,
  586. TwiddleUV(i32NumXWords,i32NumYWords,indices.Q[0], indices.Q[1])*2,
  587. TwiddleUV(i32NumXWords,i32NumYWords,indices.R[0], indices.R[1])*2,
  588. TwiddleUV(i32NumXWords,i32NumYWords,indices.S[0], indices.S[1])*2,
  589. };
  590. //Access individual elements to fill out PVRTCWord
  591. PVRTCWord P,Q,R,S;
  592. P.u32ColourData = pWordMembers[WordOffsets[0]+1];
  593. P.u32ModulationData = pWordMembers[WordOffsets[0]];
  594. Q.u32ColourData = pWordMembers[WordOffsets[1]+1];
  595. Q.u32ModulationData = pWordMembers[WordOffsets[1]];
  596. R.u32ColourData = pWordMembers[WordOffsets[2]+1];
  597. R.u32ModulationData = pWordMembers[WordOffsets[2]];
  598. S.u32ColourData = pWordMembers[WordOffsets[3]+1];
  599. S.u32ModulationData = pWordMembers[WordOffsets[3]];
  600. // assemble 4 words into struct to get decompressed pixels from
  601. pvrtcGetDecompressedPixels(P,Q,R,S,pPixels,ui8Bpp);
  602. mapDecompressedData(pOutData, ui32Width, pPixels, indices, ui8Bpp);
  603. } // for each word
  604. } // for each row of words
  605. free(pPixels);
  606. //Return the data size
  607. return ui32Width * ui32Height / (PVRTuint32)(ui32WordWidth/2);
  608. }
  609. /******************************************************************************/
  610. } // namespace PVRTC
  611. /******************************************************************************/
  612. static Int PVRTCQuality=3; // default=High (used only for PVRTC1_2)
  613. Bool (*CompressPVRTC)(C Image &src, Image &dest, Int quality);
  614. /******************************************************************************/
  615. Int GetPVRTCQuality( ) {return PVRTCQuality ;} // used only for PVRTC1_2
  616. void SetPVRTCQuality(Int quality) { PVRTCQuality=Mid(quality, 0, 4);} // used only for PVRTC1_2
  617. /******************************************************************************/
  618. Bool DecompressPVRTC(C Image &src, Image &dest)
  619. {
  620. Bool ok=false;
  621. if((src.hwType()==IMAGE_PVRTC1_2 || src.hwType()==IMAGE_PVRTC1_4) && dest.createTry(src.hwW(), src.hwH(), src.d(), IMAGE_R8G8B8A8, IMAGE_SOFT, 1)) // use hwX and hwY because decompressor assumes that source and dest have equal sizes, R8G8B8A8 because 'pvrtcDecompress' operates on that format
  622. {
  623. if(src.lockRead())
  624. {
  625. using namespace PVRTC;
  626. ok=true;
  627. REPD(z, dest.d())pvrtcDecompress((PVRTuint8*)(src.data() + z*src.pitch2()), (Pixel32*)(dest.data() + z*dest.pitch2()), dest.w(), dest.h(), (src.hwType()==IMAGE_PVRTC1_2) ? 2 : 4);
  628. src.unlock();
  629. }
  630. dest.fastCrop(src.w(), src.h(), src.d());
  631. }
  632. return ok;
  633. }
  634. /******************************************************************************/
  635. }
  636. /******************************************************************************/