pvr.cpp 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713
  1. /******************************************************************************
  2. @File PVRTDecompress.cpp
  3. @Title
  4. @Copyright Copyright (C) 2000 - 2008 by Imagination Technologies Limited.
  5. @Platform ANSI compatible
  6. @Description PVRTC Texture Decompression.
  7. ******************************************************************************/
  8. #include <stdlib.h>
  9. #include <stdio.h>
  10. #include <limits.h>
  11. #include <math.h>
  12. #include <string.h>
  13. #include <assert.h>
  14. #include <cstdint>
  15. #include "base/pvr.h"
  16. #define PVRT_MIN(a,b) (((a) < (b)) ? (a) : (b))
  17. #define PVRT_MAX(a,b) (((a) > (b)) ? (a) : (b))
  18. #define PVRT_CLAMP(x, l, h) (PVRT_MIN((h), PVRT_MAX((x), (l))))
  19. /*****************************************************************************
  20. * defines and consts
  21. *****************************************************************************/
  22. #define PT_INDEX (2) // The Punch-through index
  23. #define BLK_Y_SIZE (4) // always 4 for all 2D block types
  24. #define BLK_X_MAX (8) // Max X dimension for blocks
  25. #define BLK_X_2BPP (8) // dimensions for the two formats
  26. #define BLK_X_4BPP (4)
  27. #define WRAP_COORD(Val, Size) ((Val) & ((Size)-1))
  28. #define POWER_OF_2(X) util_number_is_power_2(X)
  29. /*
  30. Define an expression to either wrap or clamp large or small vals to the
  31. legal coordinate range
  32. */
  33. #define LIMIT_COORD(Val, Size, AssumeImageTiles) \
  34. ((AssumeImageTiles)? WRAP_COORD((Val), (Size)): PVRT_CLAMP((Val), 0, (Size)-1))
  35. /*****************************************************************************
  36. * Useful typedefs
  37. *****************************************************************************/
  38. typedef uint32_t U32;
  39. typedef uint8_t U8;
  40. /***********************************************************
  41. DECOMPRESSION ROUTINES
  42. ************************************************************/
  43. /*!***********************************************************************
  44. @Struct AMTC_BLOCK_STRUCT
  45. @Brief
  46. *************************************************************************/
  47. typedef struct
  48. {
  49. // Uses 64 bits pre block
  50. U32 PackedData[2];
  51. }AMTC_BLOCK_STRUCT;
  52. static void PVRDecompress(AMTC_BLOCK_STRUCT *pCompressedData,
  53. const bool Do2bitMode,
  54. const int XDim,
  55. const int YDim,
  56. const int AssumeImageTiles,
  57. unsigned char* pResultImage);
  58. /*!***********************************************************************
  59. @Function PVRTDecompressPVRTC
  60. @Input pCompressedData The PVRTC texture data to decompress
  61. @Input Do2bitMode Signifies whether the data is PVRTC2 or PVRTC4
  62. @Input XDim X dimension of the texture
  63. @Input YDim Y dimension of the texture
  64. @Modified pResultImage The decompressed texture data
  65. @Description Decompresses PVRTC to RGBA 8888
  66. *************************************************************************/
  67. int PVRTDecompressPVRTC(const void * const pCompressedData,const int XDim,const int YDim, void *pDestData,const bool Do2bitMode)
  68. {
  69. PVRDecompress((AMTC_BLOCK_STRUCT*)pCompressedData,Do2bitMode,XDim,YDim,1,(unsigned char*)pDestData);
  70. return XDim*YDim/2;
  71. }
  72. /*!***********************************************************************
  73. @Function util_number_is_power_2
  74. @Input input A number
  75. @Returns TRUE if the number is an integer power of two, else FALSE.
  76. @Description Check that a number is an integer power of two, i.e.
  77. 1, 2, 4, 8, ... etc.
  78. Returns FALSE for zero.
  79. *************************************************************************/
  80. int util_number_is_power_2( unsigned input )
  81. {
  82. unsigned minus1;
  83. if( !input ) return 0;
  84. minus1 = input - 1;
  85. return ( (input | minus1) == (input ^ minus1) ) ? 1 : 0;
  86. }
  87. /*!***********************************************************************
  88. @Function Unpack5554Colour
  89. @Input pBlock
  90. @Input ABColours
  91. @Description Given a block, extract the colour information and convert
  92. to 5554 formats
  93. *************************************************************************/
  94. static void Unpack5554Colour(const AMTC_BLOCK_STRUCT *pBlock,
  95. int ABColours[2][4])
  96. {
  97. U32 RawBits[2];
  98. int i;
  99. // Extract A and B
  100. RawBits[0] = pBlock->PackedData[1] & (0xFFFE); // 15 bits (shifted up by one)
  101. RawBits[1] = pBlock->PackedData[1] >> 16; // 16 bits
  102. // step through both colours
  103. for(i = 0; i < 2; i++)
  104. {
  105. // If completely opaque
  106. if(RawBits[i] & (1<<15))
  107. {
  108. // Extract R and G (both 5 bit)
  109. ABColours[i][0] = (RawBits[i] >> 10) & 0x1F;
  110. ABColours[i][1] = (RawBits[i] >> 5) & 0x1F;
  111. /*
  112. The precision of Blue depends on A or B. If A then we need to
  113. replicate the top bit to get 5 bits in total
  114. */
  115. ABColours[i][2] = RawBits[i] & 0x1F;
  116. if(i==0)
  117. {
  118. ABColours[0][2] |= ABColours[0][2] >> 4;
  119. }
  120. // set 4bit alpha fully on...
  121. ABColours[i][3] = 0xF;
  122. }
  123. else // Else if colour has variable translucency
  124. {
  125. /*
  126. Extract R and G (both 4 bit).
  127. (Leave a space on the end for the replication of bits
  128. */
  129. ABColours[i][0] = (RawBits[i] >> (8-1)) & 0x1E;
  130. ABColours[i][1] = (RawBits[i] >> (4-1)) & 0x1E;
  131. // replicate bits to truly expand to 5 bits
  132. ABColours[i][0] |= ABColours[i][0] >> 4;
  133. ABColours[i][1] |= ABColours[i][1] >> 4;
  134. // grab the 3(+padding) or 4 bits of blue and add an extra padding bit
  135. ABColours[i][2] = (RawBits[i] & 0xF) << 1;
  136. /*
  137. expand from 3 to 5 bits if this is from colour A, or 4 to 5 bits if from
  138. colour B
  139. */
  140. if(i==0)
  141. {
  142. ABColours[0][2] |= ABColours[0][2] >> 3;
  143. }
  144. else
  145. {
  146. ABColours[0][2] |= ABColours[0][2] >> 4;
  147. }
  148. // Set the alpha bits to be 3 + a zero on the end
  149. ABColours[i][3] = (RawBits[i] >> 11) & 0xE;
  150. }
  151. }
  152. }
  153. /*!***********************************************************************
  154. @Function UnpackModulations
  155. @Input pBlock
  156. @Input Do2bitMode
  157. @Input ModulationVals
  158. @Input ModulationModes
  159. @Input StartX
  160. @Input StartY
  161. @Description Given the block and the texture type and it's relative
  162. position in the 2x2 group of blocks, extract the bit
  163. patterns for the fully defined pixels.
  164. *************************************************************************/
  165. static void UnpackModulations(const AMTC_BLOCK_STRUCT *pBlock,
  166. const int Do2bitMode,
  167. int ModulationVals[8][16],
  168. int ModulationModes[8][16],
  169. int StartX,
  170. int StartY)
  171. {
  172. int BlockModMode;
  173. U32 ModulationBits;
  174. int x, y;
  175. BlockModMode= pBlock->PackedData[1] & 1;
  176. ModulationBits = pBlock->PackedData[0];
  177. // if it's in an interpolated mode
  178. if(Do2bitMode && BlockModMode)
  179. {
  180. /*
  181. run through all the pixels in the block. Note we can now treat all the
  182. "stored" values as if they have 2bits (even when they didn't!)
  183. */
  184. for(y = 0; y < BLK_Y_SIZE; y++)
  185. {
  186. for(x = 0; x < BLK_X_2BPP; x++)
  187. {
  188. ModulationModes[y+StartY][x+StartX] = BlockModMode;
  189. // if this is a stored value...
  190. if(((x^y)&1) == 0)
  191. {
  192. ModulationVals[y+StartY][x+StartX] = ModulationBits & 3;
  193. ModulationBits >>= 2;
  194. }
  195. }
  196. }
  197. }
  198. else if(Do2bitMode) // else if direct encoded 2bit mode - i.e. 1 mode bit per pixel
  199. {
  200. for(y = 0; y < BLK_Y_SIZE; y++)
  201. {
  202. for(x = 0; x < BLK_X_2BPP; x++)
  203. {
  204. ModulationModes[y+StartY][x+StartX] = BlockModMode;
  205. // double the bits so 0=> 00, and 1=>11
  206. if(ModulationBits & 1)
  207. {
  208. ModulationVals[y+StartY][x+StartX] = 0x3;
  209. }
  210. else
  211. {
  212. ModulationVals[y+StartY][x+StartX] = 0x0;
  213. }
  214. ModulationBits >>= 1;
  215. }
  216. }
  217. }
  218. else // else its the 4bpp mode so each value has 2 bits
  219. {
  220. for(y = 0; y < BLK_Y_SIZE; y++)
  221. {
  222. for(x = 0; x < BLK_X_4BPP; x++)
  223. {
  224. ModulationModes[y+StartY][x+StartX] = BlockModMode;
  225. ModulationVals[y+StartY][x+StartX] = ModulationBits & 3;
  226. ModulationBits >>= 2;
  227. }
  228. }
  229. }
  230. // make sure nothing is left over
  231. assert(ModulationBits==0);
  232. }
  233. /*!***********************************************************************
  234. @Function InterpolateColours
  235. @Input ColourP
  236. @Input ColourQ
  237. @Input ColourR
  238. @Input ColourS
  239. @Input Do2bitMode
  240. @Input x
  241. @Input y
  242. @Modified Result
  243. @Description This performs a HW bit accurate interpolation of either the
  244. A or B colours for a particular pixel.
  245. NOTE: It is assumed that the source colours are in ARGB 5554
  246. format - This means that some "preparation" of the values will
  247. be necessary.
  248. *************************************************************************/
  249. static void InterpolateColours(const int ColourP[4],
  250. const int ColourQ[4],
  251. const int ColourR[4],
  252. const int ColourS[4],
  253. const int Do2bitMode,
  254. const int x,
  255. const int y,
  256. int Result[4])
  257. {
  258. int u, v, uscale;
  259. int k;
  260. int tmp1, tmp2;
  261. int P[4], Q[4], R[4], S[4];
  262. // Copy the colours
  263. for(k = 0; k < 4; k++)
  264. {
  265. P[k] = ColourP[k];
  266. Q[k] = ColourQ[k];
  267. R[k] = ColourR[k];
  268. S[k] = ColourS[k];
  269. }
  270. // put the x and y values into the right range
  271. v = (y & 0x3) | ((~y & 0x2) << 1);
  272. if(Do2bitMode)
  273. u = (x & 0x7) | ((~x & 0x4) << 1);
  274. else
  275. u = (x & 0x3) | ((~x & 0x2) << 1);
  276. // get the u and v scale amounts
  277. v = v - BLK_Y_SIZE/2;
  278. if(Do2bitMode)
  279. {
  280. u = u - BLK_X_2BPP/2;
  281. uscale = 8;
  282. }
  283. else
  284. {
  285. u = u - BLK_X_4BPP/2;
  286. uscale = 4;
  287. }
  288. for(k = 0; k < 4; k++)
  289. {
  290. tmp1 = P[k] * uscale + u * (Q[k] - P[k]);
  291. tmp2 = R[k] * uscale + u * (S[k] - R[k]);
  292. tmp1 = tmp1 * 4 + v * (tmp2 - tmp1);
  293. Result[k] = tmp1;
  294. }
  295. // Lop off the appropriate number of bits to get us to 8 bit precision
  296. if(Do2bitMode)
  297. {
  298. // do RGB
  299. for(k = 0; k < 3; k++)
  300. {
  301. Result[k] >>= 2;
  302. }
  303. Result[3] >>= 1;
  304. }
  305. else
  306. {
  307. // do RGB (A is ok)
  308. for(k = 0; k < 3; k++)
  309. {
  310. Result[k] >>= 1;
  311. }
  312. }
  313. // sanity check
  314. for(k = 0; k < 4; k++)
  315. {
  316. assert(Result[k] < 256);
  317. }
  318. /*
  319. Convert from 5554 to 8888
  320. do RGB 5.3 => 8
  321. */
  322. for(k = 0; k < 3; k++)
  323. {
  324. Result[k] += Result[k] >> 5;
  325. }
  326. Result[3] += Result[3] >> 4;
  327. // 2nd sanity check
  328. for(k = 0; k < 4; k++)
  329. {
  330. assert(Result[k] < 256);
  331. }
  332. }
  333. /*!***********************************************************************
  334. @Function GetModulationValue
  335. @Input x
  336. @Input y
  337. @Input Do2bitMode
  338. @Input ModulationVals
  339. @Input ModulationModes
  340. @Input Mod
  341. @Input DoPT
  342. @Description Get the modulation value as a numerator of a fraction of 8ths
  343. *************************************************************************/
  344. static void GetModulationValue(int x,
  345. int y,
  346. const int Do2bitMode,
  347. const int ModulationVals[8][16],
  348. const int ModulationModes[8][16],
  349. int *Mod,
  350. int *DoPT)
  351. {
  352. static const int RepVals0[4] = {0, 3, 5, 8};
  353. static const int RepVals1[4] = {0, 4, 4, 8};
  354. int ModVal;
  355. // Map X and Y into the local 2x2 block
  356. y = (y & 0x3) | ((~y & 0x2) << 1);
  357. if(Do2bitMode)
  358. x = (x & 0x7) | ((~x & 0x4) << 1);
  359. else
  360. x = (x & 0x3) | ((~x & 0x2) << 1);
  361. // assume no PT for now
  362. *DoPT = 0;
  363. // extract the modulation value. If a simple encoding
  364. if(ModulationModes[y][x]==0)
  365. {
  366. ModVal = RepVals0[ModulationVals[y][x]];
  367. }
  368. else if(Do2bitMode)
  369. {
  370. // if this is a stored value
  371. if(((x^y)&1)==0)
  372. ModVal = RepVals0[ModulationVals[y][x]];
  373. else if(ModulationModes[y][x] == 1) // else average from the neighbours if H&V interpolation..
  374. {
  375. ModVal = (RepVals0[ModulationVals[y-1][x]] +
  376. RepVals0[ModulationVals[y+1][x]] +
  377. RepVals0[ModulationVals[y][x-1]] +
  378. RepVals0[ModulationVals[y][x+1]] + 2) / 4;
  379. }
  380. else if(ModulationModes[y][x] == 2) // else if H-Only
  381. {
  382. ModVal = (RepVals0[ModulationVals[y][x-1]] +
  383. RepVals0[ModulationVals[y][x+1]] + 1) / 2;
  384. }
  385. else // else it's V-Only
  386. {
  387. ModVal = (RepVals0[ModulationVals[y-1][x]] +
  388. RepVals0[ModulationVals[y+1][x]] + 1) / 2;
  389. }
  390. }
  391. else // else it's 4BPP and PT encoding
  392. {
  393. ModVal = RepVals1[ModulationVals[y][x]];
  394. *DoPT = ModulationVals[y][x] == PT_INDEX;
  395. }
  396. *Mod =ModVal;
  397. }
  398. /*!***********************************************************************
  399. @Function TwiddleUV
  400. @Input YSize Y dimension of the texture in pixels
  401. @Input XSize X dimension of the texture in pixels
  402. @Input YPos Pixel Y position
  403. @Input XPos Pixel X position
  404. @Returns The twiddled offset of the pixel
  405. @Description Given the Block (or pixel) coordinates and the dimension of
  406. the texture in blocks (or pixels) this returns the twiddled
  407. offset of the block (or pixel) from the start of the map.
  408. NOTE the dimensions of the texture must be a power of 2
  409. *************************************************************************/
  410. static int DisableTwiddlingRoutine = 0;
  411. static U32 TwiddleUV(U32 YSize, U32 XSize, U32 YPos, U32 XPos)
  412. {
  413. U32 Twiddled;
  414. U32 MinDimension;
  415. U32 MaxValue;
  416. U32 SrcBitPos;
  417. U32 DstBitPos;
  418. int ShiftCount;
  419. assert(YPos < YSize);
  420. assert(XPos < XSize);
  421. assert(POWER_OF_2(YSize));
  422. assert(POWER_OF_2(XSize));
  423. if(YSize < XSize)
  424. {
  425. MinDimension = YSize;
  426. MaxValue = XPos;
  427. }
  428. else
  429. {
  430. MinDimension = XSize;
  431. MaxValue = YPos;
  432. }
  433. // Nasty hack to disable twiddling
  434. if(DisableTwiddlingRoutine)
  435. return (YPos* XSize + XPos);
  436. // Step through all the bits in the "minimum" dimension
  437. SrcBitPos = 1;
  438. DstBitPos = 1;
  439. Twiddled = 0;
  440. ShiftCount = 0;
  441. while(SrcBitPos < MinDimension)
  442. {
  443. if(YPos & SrcBitPos)
  444. {
  445. Twiddled |= DstBitPos;
  446. }
  447. if(XPos & SrcBitPos)
  448. {
  449. Twiddled |= (DstBitPos << 1);
  450. }
  451. SrcBitPos <<= 1;
  452. DstBitPos <<= 2;
  453. ShiftCount += 1;
  454. }
  455. // prepend any unused bits
  456. MaxValue >>= ShiftCount;
  457. Twiddled |= (MaxValue << (2*ShiftCount));
  458. return Twiddled;
  459. }
  460. /*!***********************************************************************
  461. @Function Decompress
  462. @Input pCompressedData The PVRTC texture data to decompress
  463. @Input Do2BitMode Signifies whether the data is PVRTC2 or PVRTC4
  464. @Input XDim X dimension of the texture
  465. @Input YDim Y dimension of the texture
  466. @Input AssumeImageTiles Assume the texture data tiles
  467. @Modified pResultImage The decompressed texture data
  468. @Description Decompresses PVRTC to RGBA 8888
  469. *************************************************************************/
  470. static void PVRDecompress(AMTC_BLOCK_STRUCT *pCompressedData,
  471. const bool Do2bitMode,
  472. const int XDim,
  473. const int YDim,
  474. const int AssumeImageTiles,
  475. unsigned char* pResultImage)
  476. {
  477. int x, y;
  478. int i, j;
  479. int BlkX, BlkY;
  480. int BlkXp1, BlkYp1;
  481. int XBlockSize;
  482. int BlkXDim, BlkYDim;
  483. int StartX, StartY;
  484. int ModulationVals[8][16];
  485. int ModulationModes[8][16];
  486. int Mod, DoPT;
  487. unsigned int uPosition;
  488. // local neighbourhood of blocks
  489. AMTC_BLOCK_STRUCT *pBlocks[2][2];
  490. AMTC_BLOCK_STRUCT *pPrevious[2][2] = {{NULL, NULL}, {NULL, NULL}};
  491. // Low precision colours extracted from the blocks
  492. struct
  493. {
  494. int Reps[2][4];
  495. }Colours5554[2][2];
  496. // Interpolated A and B colours for the pixel
  497. int ASig[4], BSig[4];
  498. int Result[4];
  499. if(Do2bitMode)
  500. XBlockSize = BLK_X_2BPP;
  501. else
  502. XBlockSize = BLK_X_4BPP;
  503. // For MBX don't allow the sizes to get too small
  504. BlkXDim = PVRT_MAX(2, XDim / XBlockSize);
  505. BlkYDim = PVRT_MAX(2, YDim / BLK_Y_SIZE);
  506. /*
  507. Step through the pixels of the image decompressing each one in turn
  508. Note that this is a hideously inefficient way to do this!
  509. */
  510. for(y = 0; y < YDim; y++)
  511. {
  512. for(x = 0; x < XDim; x++)
  513. {
  514. // map this pixel to the top left neighbourhood of blocks
  515. BlkX = (x - XBlockSize/2);
  516. BlkY = (y - BLK_Y_SIZE/2);
  517. BlkX = LIMIT_COORD(BlkX, XDim, AssumeImageTiles);
  518. BlkY = LIMIT_COORD(BlkY, YDim, AssumeImageTiles);
  519. BlkX /= XBlockSize;
  520. BlkY /= BLK_Y_SIZE;
  521. // compute the positions of the other 3 blocks
  522. BlkXp1 = LIMIT_COORD(BlkX+1, BlkXDim, AssumeImageTiles);
  523. BlkYp1 = LIMIT_COORD(BlkY+1, BlkYDim, AssumeImageTiles);
  524. // Map to block memory locations
  525. pBlocks[0][0] = pCompressedData +TwiddleUV(BlkYDim, BlkXDim, BlkY, BlkX);
  526. pBlocks[0][1] = pCompressedData +TwiddleUV(BlkYDim, BlkXDim, BlkY, BlkXp1);
  527. pBlocks[1][0] = pCompressedData +TwiddleUV(BlkYDim, BlkXDim, BlkYp1, BlkX);
  528. pBlocks[1][1] = pCompressedData +TwiddleUV(BlkYDim, BlkXDim, BlkYp1, BlkXp1);
  529. /*
  530. extract the colours and the modulation information IF the previous values
  531. have changed.
  532. */
  533. if(memcmp(pPrevious, pBlocks, 4*sizeof(void*)) != 0)
  534. {
  535. StartY = 0;
  536. for(i = 0; i < 2; i++)
  537. {
  538. StartX = 0;
  539. for(j = 0; j < 2; j++)
  540. {
  541. Unpack5554Colour(pBlocks[i][j], Colours5554[i][j].Reps);
  542. UnpackModulations(pBlocks[i][j],
  543. Do2bitMode,
  544. ModulationVals,
  545. ModulationModes,
  546. StartX, StartY);
  547. StartX += XBlockSize;
  548. }
  549. StartY += BLK_Y_SIZE;
  550. }
  551. // make a copy of the new pointers
  552. memcpy(pPrevious, pBlocks, 4*sizeof(void*));
  553. }
  554. // decompress the pixel. First compute the interpolated A and B signals
  555. InterpolateColours(Colours5554[0][0].Reps[0],
  556. Colours5554[0][1].Reps[0],
  557. Colours5554[1][0].Reps[0],
  558. Colours5554[1][1].Reps[0],
  559. Do2bitMode, x, y,
  560. ASig);
  561. InterpolateColours(Colours5554[0][0].Reps[1],
  562. Colours5554[0][1].Reps[1],
  563. Colours5554[1][0].Reps[1],
  564. Colours5554[1][1].Reps[1],
  565. Do2bitMode, x, y,
  566. BSig);
  567. GetModulationValue(x,y, Do2bitMode, (const int (*)[16])ModulationVals, (const int (*)[16])ModulationModes,
  568. &Mod, &DoPT);
  569. // compute the modulated colour
  570. for(i = 0; i < 4; i++)
  571. {
  572. Result[i] = ASig[i] * 8 + Mod * (BSig[i] - ASig[i]);
  573. Result[i] >>= 3;
  574. }
  575. if(DoPT)
  576. Result[3] = 0;
  577. // Store the result in the output image
  578. uPosition = (x+y*XDim)<<2;
  579. pResultImage[uPosition+0] = (U8)Result[0];
  580. pResultImage[uPosition+1] = (U8)Result[1];
  581. pResultImage[uPosition+2] = (U8)Result[2];
  582. pResultImage[uPosition+3] = (U8)Result[3];
  583. }
  584. }
  585. }
  586. /*****************************************************************************
  587. End of file (pvr.cpp)
  588. *****************************************************************************/