BsPixelUtil.cpp 61 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853185418551856185718581859186018611862186318641865186618671868186918701871187218731874
  1. //********************************** Banshee Engine (www.banshee3d.com) **************************************************//
  2. //**************** Copyright (c) 2016 Marko Pintera ([email protected]). All rights reserved. **********************//
  3. #include "BsPixelUtil.h"
  4. #include "BsBitwise.h"
  5. #include "BsColor.h"
  6. #include "BsMath.h"
  7. #include "BsException.h"
  8. #include <nvtt.h>
  9. namespace bs
  10. {
  11. /**
  12. * Performs pixel data resampling using the point filter (nearest neighbor). Does not perform format conversions.
  13. *
  14. * @tparam elementSize Size of a single pixel in bytes.
  15. */
  16. template<UINT32 elementSize> struct NearestResampler
  17. {
  18. static void scale(const PixelData& source, const PixelData& dest)
  19. {
  20. UINT8* sourceData = source.getData();
  21. UINT8* destPtr = dest.getData();
  22. // Get steps for traversing source data in 16/48 fixed point format
  23. UINT64 stepX = ((UINT64)source.getWidth() << 48) / dest.getWidth();
  24. UINT64 stepY = ((UINT64)source.getHeight() << 48) / dest.getHeight();
  25. UINT64 stepZ = ((UINT64)source.getDepth() << 48) / dest.getDepth();
  26. UINT64 curZ = (stepZ >> 1) - 1; // Offset half a pixel to start at pixel center
  27. for (UINT32 z = dest.getFront(); z < dest.getBack(); z++, curZ += stepZ)
  28. {
  29. UINT32 offsetZ = (UINT32)(curZ >> 48) * source.getSlicePitch();
  30. UINT64 curY = (stepY >> 1) - 1; // Offset half a pixel to start at pixel center
  31. for (UINT32 y = dest.getTop(); y < dest.getBottom(); y++, curY += stepY)
  32. {
  33. UINT32 offsetY = (UINT32)(curY >> 48) * source.getRowPitch();
  34. UINT64 curX = (stepX >> 1) - 1; // Offset half a pixel to start at pixel center
  35. for (UINT32 x = dest.getLeft(); x < dest.getRight(); x++, curX += stepX)
  36. {
  37. UINT32 offsetX = (UINT32)(curX >> 48);
  38. UINT32 offsetBytes = elementSize*(offsetX + offsetY + offsetZ);
  39. UINT8* curSourcePtr = sourceData + offsetBytes;
  40. memcpy(destPtr, curSourcePtr, elementSize);
  41. destPtr += elementSize;
  42. }
  43. destPtr += elementSize*dest.getRowSkip();
  44. }
  45. destPtr += elementSize*dest.getSliceSkip();
  46. }
  47. }
  48. };
  49. /** Performs pixel data resampling using the box filter (linear). Performs format conversions. */
  50. struct LinearResampler
  51. {
  52. static void scale(const PixelData& source, const PixelData& dest)
  53. {
  54. UINT32 sourceElemSize = PixelUtil::getNumElemBytes(source.getFormat());
  55. UINT32 destElemSize = PixelUtil::getNumElemBytes(dest.getFormat());
  56. UINT8* sourceData = source.getData();
  57. UINT8* destPtr = dest.getData();
  58. // Get steps for traversing source data in 16/48 fixed point precision format
  59. UINT64 stepX = ((UINT64)source.getWidth() << 48) / dest.getWidth();
  60. UINT64 stepY = ((UINT64)source.getHeight() << 48) / dest.getHeight();
  61. UINT64 stepZ = ((UINT64)source.getDepth() << 48) / dest.getDepth();
  62. // Contains 16/16 fixed point precision format. Most significant
  63. // 16 bits will contain the coordinate in the source image, and the
  64. // least significant 16 bits will contain the fractional part of the coordinate
  65. // that will be used for determining the blend amount.
  66. UINT32 temp = 0;
  67. UINT64 curZ = (stepZ >> 1) - 1; // Offset half a pixel to start at pixel center
  68. for (UINT32 z = dest.getFront(); z < dest.getBack(); z++, curZ += stepZ)
  69. {
  70. temp = UINT32(curZ >> 32);
  71. temp = (temp > 0x8000)? temp - 0x8000 : 0;
  72. UINT32 sampleCoordZ1 = temp >> 16;
  73. UINT32 sampleCoordZ2 = std::min(sampleCoordZ1 + 1, (UINT32)source.getDepth() - 1);
  74. float sampleWeightZ = (temp & 0xFFFF) / 65536.0f;
  75. UINT64 curY = (stepY >> 1) - 1; // Offset half a pixel to start at pixel center
  76. for (UINT32 y = dest.getTop(); y < dest.getBottom(); y++, curY += stepY)
  77. {
  78. temp = (UINT32)(curY >> 32);
  79. temp = (temp > 0x8000)? temp - 0x8000 : 0;
  80. UINT32 sampleCoordY1 = temp >> 16;
  81. UINT32 sampleCoordY2 = std::min(sampleCoordY1 + 1, (UINT32)source.getHeight() - 1);
  82. float sampleWeightY = (temp & 0xFFFF) / 65536.0f;
  83. UINT64 curX = (stepX >> 1) - 1; // Offset half a pixel to start at pixel center
  84. for (UINT32 x = dest.getLeft(); x < dest.getRight(); x++, curX += stepX)
  85. {
  86. temp = (UINT32)(curX >> 32);
  87. temp = (temp > 0x8000)? temp - 0x8000 : 0;
  88. UINT32 sampleCoordX1 = temp >> 16;
  89. UINT32 sampleCoordX2 = std::min(sampleCoordX1 + 1, (UINT32)source.getWidth() - 1);
  90. float sampleWeightX = (temp & 0xFFFF) / 65536.0f;
  91. Color x1y1z1, x2y1z1, x1y2z1, x2y2z1;
  92. Color x1y1z2, x2y1z2, x1y2z2, x2y2z2;
  93. #define GETSOURCEDATA(x, y, z) sourceData + sourceElemSize*((x)+(y)*source.getRowPitch() + (z)*source.getSlicePitch())
  94. PixelUtil::unpackColor(&x1y1z1, source.getFormat(), GETSOURCEDATA(sampleCoordX1, sampleCoordY1, sampleCoordZ1));
  95. PixelUtil::unpackColor(&x2y1z1, source.getFormat(), GETSOURCEDATA(sampleCoordX2, sampleCoordY1, sampleCoordZ1));
  96. PixelUtil::unpackColor(&x1y2z1, source.getFormat(), GETSOURCEDATA(sampleCoordX1, sampleCoordY2, sampleCoordZ1));
  97. PixelUtil::unpackColor(&x2y2z1, source.getFormat(), GETSOURCEDATA(sampleCoordX2, sampleCoordY2, sampleCoordZ1));
  98. PixelUtil::unpackColor(&x1y1z2, source.getFormat(), GETSOURCEDATA(sampleCoordX1, sampleCoordY1, sampleCoordZ2));
  99. PixelUtil::unpackColor(&x2y1z2, source.getFormat(), GETSOURCEDATA(sampleCoordX2, sampleCoordY1, sampleCoordZ2));
  100. PixelUtil::unpackColor(&x1y2z2, source.getFormat(), GETSOURCEDATA(sampleCoordX1, sampleCoordY2, sampleCoordZ2));
  101. PixelUtil::unpackColor(&x2y2z2, source.getFormat(), GETSOURCEDATA(sampleCoordX2, sampleCoordY2, sampleCoordZ2));
  102. #undef GETSOURCEDATA
  103. Color accum =
  104. x1y1z1 * ((1.0f - sampleWeightX)*(1.0f - sampleWeightY)*(1.0f - sampleWeightZ)) +
  105. x2y1z1 * ( sampleWeightX *(1.0f - sampleWeightY)*(1.0f - sampleWeightZ)) +
  106. x1y2z1 * ((1.0f - sampleWeightX)* sampleWeightY *(1.0f - sampleWeightZ)) +
  107. x2y2z1 * ( sampleWeightX * sampleWeightY *(1.0f - sampleWeightZ)) +
  108. x1y1z2 * ((1.0f - sampleWeightX)*(1.0f - sampleWeightY)* sampleWeightZ ) +
  109. x2y1z2 * ( sampleWeightX *(1.0f - sampleWeightY)* sampleWeightZ ) +
  110. x1y2z2 * ((1.0f - sampleWeightX)* sampleWeightY * sampleWeightZ ) +
  111. x2y2z2 * ( sampleWeightX * sampleWeightY * sampleWeightZ );
  112. PixelUtil::packColor(accum, dest.getFormat(), destPtr);
  113. destPtr += destElemSize;
  114. }
  115. destPtr += destElemSize * dest.getRowSkip();
  116. }
  117. destPtr += destElemSize * dest.getSliceSkip();
  118. }
  119. }
  120. };
  121. /**
  122. * Performs pixel data resampling using the box filter (linear). Only handles float RGB or RGBA pixel data (32 bits per
  123. * channel).
  124. */
  125. struct LinearResampler_Float32
  126. {
  127. static void scale(const PixelData& source, const PixelData& dest)
  128. {
  129. UINT32 numSourceChannels = PixelUtil::getNumElemBytes(source.getFormat()) / sizeof(float);
  130. UINT32 numDestChannels = PixelUtil::getNumElemBytes(dest.getFormat()) / sizeof(float);
  131. float* sourceData = (float*)source.getData();
  132. float* destPtr = (float*)dest.getData();
  133. // Get steps for traversing source data in 16/48 fixed point precision format
  134. UINT64 stepX = ((UINT64)source.getWidth() << 48) / dest.getWidth();
  135. UINT64 stepY = ((UINT64)source.getHeight() << 48) / dest.getHeight();
  136. UINT64 stepZ = ((UINT64)source.getDepth() << 48) / dest.getDepth();
  137. // Contains 16/16 fixed point precision format. Most significant
  138. // 16 bits will contain the coordinate in the source image, and the
  139. // least significant 16 bits will contain the fractional part of the coordinate
  140. // that will be used for determining the blend amount.
  141. UINT32 temp = 0;
  142. UINT64 curZ = (stepZ >> 1) - 1; // Offset half a pixel to start at pixel center
  143. for (UINT32 z = dest.getFront(); z < dest.getBack(); z++, curZ += stepZ)
  144. {
  145. temp = (UINT32)(curZ >> 32);
  146. temp = (temp > 0x8000)? temp - 0x8000 : 0;
  147. UINT32 sampleCoordZ1 = temp >> 16;
  148. UINT32 sampleCoordZ2 = std::min(sampleCoordZ1 + 1, (UINT32)source.getDepth() - 1);
  149. float sampleWeightZ = (temp & 0xFFFF) / 65536.0f;
  150. UINT64 curY = (stepY >> 1) - 1; // Offset half a pixel to start at pixel center
  151. for (UINT32 y = dest.getTop(); y < dest.getBottom(); y++, curY += stepY)
  152. {
  153. temp = (UINT32)(curY >> 32);
  154. temp = (temp > 0x8000)? temp - 0x8000 : 0;
  155. UINT32 sampleCoordY1 = temp >> 16;
  156. UINT32 sampleCoordY2 = std::min(sampleCoordY1 + 1, (UINT32)source.getHeight() - 1);
  157. float sampleWeightY = (temp & 0xFFFF) / 65536.0f;
  158. UINT64 curX = (stepX >> 1) - 1; // Offset half a pixel to start at pixel center
  159. for (UINT32 x = dest.getLeft(); x < dest.getRight(); x++, curX += stepX)
  160. {
  161. temp = (UINT32)(curX >> 32);
  162. temp = (temp > 0x8000)? temp - 0x8000 : 0;
  163. UINT32 sampleCoordX1 = temp >> 16;
  164. UINT32 sampleCoordX2 = std::min(sampleCoordX1 + 1, (UINT32)source.getWidth() - 1);
  165. float sampleWeightX = (temp & 0xFFFF) / 65536.0f;
  166. // process R,G,B,A simultaneously for cache coherence?
  167. float accum[4] = { 0.0f, 0.0f, 0.0f, 0.0f };
  168. #define ACCUM3(x,y,z,factor) \
  169. { float f = factor; \
  170. UINT32 offset = (x + y*source.getRowPitch() + z*source.getSlicePitch())*numSourceChannels; \
  171. accum[0] += sourceData[offset + 0] * f; accum[1] += sourceData[offset + 1] * f; \
  172. accum[2] += sourceData[offset + 2] * f; }
  173. #define ACCUM4(x,y,z,factor) \
  174. { float f = factor; \
  175. UINT32 offset = (x + y*source.getRowPitch() + z*source.getSlicePitch())*numSourceChannels; \
  176. accum[0] += sourceData[offset + 0] * f; accum[1] += sourceData[offset + 1] * f; \
  177. accum[2] += sourceData[offset + 2] * f; accum[3] += sourceData[offset + 3] * f; }
  178. if (numSourceChannels == 3 || numDestChannels == 3)
  179. {
  180. // RGB
  181. ACCUM3(sampleCoordX1, sampleCoordY1, sampleCoordZ1, (1.0f - sampleWeightX) * (1.0f - sampleWeightY) * (1.0f - sampleWeightZ));
  182. ACCUM3(sampleCoordX2, sampleCoordY1, sampleCoordZ1, sampleWeightX * (1.0f - sampleWeightY) * (1.0f - sampleWeightZ));
  183. ACCUM3(sampleCoordX1, sampleCoordY2, sampleCoordZ1, (1.0f - sampleWeightX) * sampleWeightY * (1.0f - sampleWeightZ));
  184. ACCUM3(sampleCoordX2, sampleCoordY2, sampleCoordZ1, sampleWeightX * sampleWeightY * (1.0f - sampleWeightZ));
  185. ACCUM3(sampleCoordX1, sampleCoordY1, sampleCoordZ2, (1.0f - sampleWeightX) * (1.0f - sampleWeightY) * sampleWeightZ);
  186. ACCUM3(sampleCoordX2, sampleCoordY1, sampleCoordZ2, sampleWeightX * (1.0f - sampleWeightY) * sampleWeightZ);
  187. ACCUM3(sampleCoordX1, sampleCoordY2, sampleCoordZ2, (1.0f - sampleWeightX) * sampleWeightY * sampleWeightZ);
  188. ACCUM3(sampleCoordX2, sampleCoordY2, sampleCoordZ2, sampleWeightX * sampleWeightY * sampleWeightZ);
  189. accum[3] = 1.0f;
  190. }
  191. else
  192. {
  193. // RGBA
  194. ACCUM4(sampleCoordX1, sampleCoordY1, sampleCoordZ1, (1.0f - sampleWeightX) * (1.0f - sampleWeightY) * (1.0f - sampleWeightZ));
  195. ACCUM4(sampleCoordX2, sampleCoordY1, sampleCoordZ1, sampleWeightX * (1.0f - sampleWeightY) * (1.0f - sampleWeightZ));
  196. ACCUM4(sampleCoordX1, sampleCoordY2, sampleCoordZ1, (1.0f - sampleWeightX) * sampleWeightY * (1.0f - sampleWeightZ));
  197. ACCUM4(sampleCoordX2, sampleCoordY2, sampleCoordZ1, sampleWeightX * sampleWeightY * (1.0f - sampleWeightZ));
  198. ACCUM4(sampleCoordX1, sampleCoordY1, sampleCoordZ2, (1.0f - sampleWeightX) * (1.0f - sampleWeightY) * sampleWeightZ);
  199. ACCUM4(sampleCoordX2, sampleCoordY1, sampleCoordZ2, sampleWeightX * (1.0f - sampleWeightY) * sampleWeightZ);
  200. ACCUM4(sampleCoordX1, sampleCoordY2, sampleCoordZ2, (1.0f - sampleWeightX) * sampleWeightY * sampleWeightZ);
  201. ACCUM4(sampleCoordX2, sampleCoordY2, sampleCoordZ2, sampleWeightX * sampleWeightY * sampleWeightZ);
  202. }
  203. memcpy(destPtr, accum, sizeof(float)*numDestChannels);
  204. #undef ACCUM3
  205. #undef ACCUM4
  206. destPtr += numDestChannels;
  207. }
  208. destPtr += numDestChannels*dest.getRowSkip();
  209. }
  210. destPtr += numDestChannels*dest.getSliceSkip();
  211. }
  212. }
  213. };
  214. // byte linear resampler, does not do any format conversions.
  215. // only handles pixel formats that use 1 byte per color channel.
  216. // 2D only; punts 3D pixelboxes to default LinearResampler (slow).
  217. // templated on bytes-per-pixel to allow compiler optimizations, such
  218. // as unrolling loops and replacing multiplies with bitshifts
  219. /**
  220. * Performs pixel data resampling using the box filter (linear). Only handles pixel formats with one byte per channel.
  221. * Does not perform format conversion.
  222. *
  223. * @tparam channels Number of channels in the pixel format.
  224. */
  225. template<UINT32 channels> struct LinearResampler_Byte
  226. {
  227. static void scale(const PixelData& source, const PixelData& dest)
  228. {
  229. // Only optimized for 2D
  230. if (source.getDepth() > 1 || dest.getDepth() > 1)
  231. {
  232. LinearResampler::scale(source, dest);
  233. return;
  234. }
  235. UINT8* sourceData = (UINT8*)source.getData();
  236. UINT8* destPtr = (UINT8*)dest.getData();
  237. // Get steps for traversing source data in 16/48 fixed point precision format
  238. UINT64 stepX = ((UINT64)source.getWidth() << 48) / dest.getWidth();
  239. UINT64 stepY = ((UINT64)source.getHeight() << 48) / dest.getHeight();
  240. // Contains 16/16 fixed point precision format. Most significant
  241. // 16 bits will contain the coordinate in the source image, and the
  242. // least significant 16 bits will contain the fractional part of the coordinate
  243. // that will be used for determining the blend amount.
  244. UINT32 temp;
  245. UINT64 curY = (stepY >> 1) - 1; // Offset half a pixel to start at pixel center
  246. for (UINT32 y = dest.getTop(); y < dest.getBottom(); y++, curY += stepY)
  247. {
  248. temp = (UINT32)(curY >> 36);
  249. temp = (temp > 0x800)? temp - 0x800: 0;
  250. UINT32 sampleWeightY = temp & 0xFFF;
  251. UINT32 sampleCoordY1 = temp >> 12;
  252. UINT32 sampleCoordY2 = std::min(sampleCoordY1 + 1, (UINT32)source.getBottom() - source.getTop() - 1);
  253. UINT32 sampleY1Offset = sampleCoordY1 * source.getRowPitch();
  254. UINT32 sampleY2Offset = sampleCoordY2 * source.getRowPitch();
  255. UINT64 curX = (stepX >> 1) - 1; // Offset half a pixel to start at pixel center
  256. for (UINT32 x = dest.getLeft(); x < dest.getRight(); x++, curX += stepX)
  257. {
  258. temp = (UINT32)(curX >> 36);
  259. temp = (temp > 0x800)? temp - 0x800 : 0;
  260. UINT32 sampleWeightX = temp & 0xFFF;
  261. UINT32 sampleCoordX1 = temp >> 12;
  262. UINT32 sampleCoordX2 = std::min(sampleCoordX1 + 1, (UINT32)source.getRight() - source.getLeft() - 1);
  263. UINT32 sxfsyf = sampleWeightX*sampleWeightY;
  264. for (UINT32 k = 0; k < channels; k++)
  265. {
  266. UINT32 accum =
  267. sourceData[(sampleCoordX1 + sampleY1Offset)*channels+k]*(0x1000000-(sampleWeightX<<12)-(sampleWeightY<<12)+sxfsyf) +
  268. sourceData[(sampleCoordX2 + sampleY1Offset)*channels+k]*((sampleWeightX<<12)-sxfsyf) +
  269. sourceData[(sampleCoordX1 + sampleY2Offset)*channels+k]*((sampleWeightY<<12)-sxfsyf) +
  270. sourceData[(sampleCoordX2 + sampleY2Offset)*channels+k]*sxfsyf;
  271. // Round up to byte size
  272. *destPtr = (UINT8)((accum + 0x800000) >> 24);
  273. destPtr++;
  274. }
  275. }
  276. destPtr += channels*dest.getRowSkip();
  277. }
  278. }
  279. };
  280. /** Data describing a pixel format. */
  281. struct PixelFormatDescription
  282. {
  283. const char* name; /**< Name of the format. */
  284. UINT8 elemBytes; /**< Number of bytes one element (color value) uses. */
  285. UINT32 flags; /**< PixelFormatFlags set by the pixel format. */
  286. PixelComponentType componentType; /**< Data type of a single element of the format. */
  287. UINT8 componentCount; /**< Number of elements in the format. */
  288. UINT8 rbits, gbits, bbits, abits; /**< Number of bits per element in the format. */
  289. UINT32 rmask, gmask, bmask, amask; /**< Masks used by packers/unpackers. */
  290. UINT8 rshift, gshift, bshift, ashift; /**< Shifts used by packers/unpackers. */
  291. };
  292. /** A list of all available pixel formats. */
  293. PixelFormatDescription _pixelFormats[PF_COUNT] = {
  294. {"PF_UNKNOWN",
  295. /* Bytes per element */
  296. 0,
  297. /* Flags */
  298. 0,
  299. /* Component type and count */
  300. PCT_BYTE, 0,
  301. /* rbits, gbits, bbits, abits */
  302. 0, 0, 0, 0,
  303. /* Masks and shifts */
  304. 0, 0, 0, 0, 0, 0, 0, 0
  305. },
  306. //-----------------------------------------------------------------------
  307. {"PF_R8",
  308. /* Bytes per element */
  309. 1,
  310. /* Flags */
  311. 0,
  312. /* Component type and count */
  313. PCT_BYTE, 1,
  314. /* rbits, gbits, bbits, abits */
  315. 8, 0, 0, 0,
  316. /* Masks and shifts */
  317. 0x000000FF, 0, 0, 0,
  318. 0, 0, 0, 0
  319. },
  320. //-----------------------------------------------------------------------
  321. {"PF_R8G8",
  322. /* Bytes per element */
  323. 2,
  324. /* Flags */
  325. 0,
  326. /* Component type and count */
  327. PCT_BYTE, 2,
  328. /* rbits, gbits, bbits, abits */
  329. 8, 8, 0, 0,
  330. /* Masks and shifts */
  331. 0x000000FF, 0x0000FF00, 0, 0,
  332. 0, 8, 0, 0
  333. },
  334. //-----------------------------------------------------------------------
  335. {"PF_R8G8B8",
  336. /* Bytes per element */
  337. 3, // 24 bit integer -- special
  338. /* Flags */
  339. PFF_NATIVEENDIAN,
  340. /* Component type and count */
  341. PCT_BYTE, 3,
  342. /* rbits, gbits, bbits, abits */
  343. 8, 8, 8, 0,
  344. /* Masks and shifts */
  345. 0x000000FF, 0x0000FF00, 0x00FF0000, 0,
  346. 0, 8, 16, 0
  347. },
  348. //-----------------------------------------------------------------------
  349. {"PF_B8G8R8",
  350. /* Bytes per element */
  351. 3, // 24 bit integer -- special
  352. /* Flags */
  353. PFF_NATIVEENDIAN,
  354. /* Component type and count */
  355. PCT_BYTE, 3,
  356. /* rbits, gbits, bbits, abits */
  357. 8, 8, 8, 0,
  358. /* Masks and shifts */
  359. 0x00FF0000, 0x0000FF00, 0x000000FF, 0,
  360. 16, 8, 0, 0
  361. },
  362. //-----------------------------------------------------------------------
  363. {"PF_A8R8G8B8",
  364. /* Bytes per element */
  365. 4,
  366. /* Flags */
  367. PFF_HASALPHA | PFF_NATIVEENDIAN,
  368. /* Component type and count */
  369. PCT_BYTE, 4,
  370. /* rbits, gbits, bbits, abits */
  371. 8, 8, 8, 8,
  372. /* Masks and shifts */
  373. 0x0000FF00, 0x00FF0000, 0xFF000000, 0x000000FF,
  374. 8, 16, 24, 0
  375. },
  376. //-----------------------------------------------------------------------
  377. {"PF_A8B8G8R8",
  378. /* Bytes per element */
  379. 4,
  380. /* Flags */
  381. PFF_HASALPHA | PFF_NATIVEENDIAN,
  382. /* Component type and count */
  383. PCT_BYTE, 4,
  384. /* rbits, gbits, bbits, abits */
  385. 8, 8, 8, 8,
  386. /* Masks and shifts */
  387. 0xFF000000, 0x00FF0000, 0x0000FF00, 0x000000FF,
  388. 24, 16, 8, 0,
  389. },
  390. //-----------------------------------------------------------------------
  391. {"PF_B8G8R8A8",
  392. /* Bytes per element */
  393. 4,
  394. /* Flags */
  395. PFF_HASALPHA | PFF_NATIVEENDIAN,
  396. /* Component type and count */
  397. PCT_BYTE, 4,
  398. /* rbits, gbits, bbits, abits */
  399. 8, 8, 8, 8,
  400. /* Masks and shifts */
  401. 0x00FF0000, 0x0000FF00, 0x000000FF, 0xFF000000,
  402. 16, 8, 0, 24
  403. },
  404. //-----------------------------------------------------------------------
  405. {"PF_R8G8B8A8",
  406. /* Bytes per element */
  407. 4,
  408. /* Flags */
  409. PFF_HASALPHA | PFF_NATIVEENDIAN,
  410. /* Component type and count */
  411. PCT_BYTE, 4,
  412. /* rbits, gbits, bbits, abits */
  413. 8, 8, 8, 8,
  414. /* Masks and shifts */
  415. 0x000000FF, 0x0000FF00, 0x00FF0000, 0xFF000000,
  416. 0, 8, 16, 24
  417. },
  418. //-----------------------------------------------------------------------
  419. {"PF_X8R8G8B8",
  420. /* Bytes per element */
  421. 4,
  422. /* Flags */
  423. PFF_NATIVEENDIAN,
  424. /* Component type and count */
  425. PCT_BYTE, 3,
  426. /* rbits, gbits, bbits, abits */
  427. 8, 8, 8, 0,
  428. /* Masks and shifts */
  429. 0x0000FF00, 0x00FF0000, 0xFF000000, 0x000000FF,
  430. 8, 16, 24, 0
  431. },
  432. //-----------------------------------------------------------------------
  433. {"PF_X8B8G8R8",
  434. /* Bytes per element */
  435. 4,
  436. /* Flags */
  437. PFF_NATIVEENDIAN,
  438. /* Component type and count */
  439. PCT_BYTE, 3,
  440. /* rbits, gbits, bbits, abits */
  441. 8, 8, 8, 0,
  442. /* Masks and shifts */
  443. 0xFF000000, 0x00FF0000, 0x0000FF00, 0x000000FF,
  444. 24, 16, 8, 0
  445. },
  446. //-----------------------------------------------------------------------
  447. {"PF_R8G8B8X8",
  448. /* Bytes per element */
  449. 4,
  450. /* Flags */
  451. PFF_HASALPHA | PFF_NATIVEENDIAN,
  452. /* Component type and count */
  453. PCT_BYTE, 3,
  454. /* rbits, gbits, bbits, abits */
  455. 8, 8, 8, 0,
  456. /* Masks and shifts */
  457. 0x000000FF, 0x0000FF00, 0x00FF0000, 0xFF000000,
  458. 0, 8, 16, 0
  459. },
  460. //-----------------------------------------------------------------------
  461. {"PF_B8G8R8X8",
  462. /* Bytes per element */
  463. 4,
  464. /* Flags */
  465. PFF_HASALPHA | PFF_NATIVEENDIAN,
  466. /* Component type and count */
  467. PCT_BYTE, 3,
  468. /* rbits, gbits, bbits, abits */
  469. 8, 8, 8, 0,
  470. /* Masks and shifts */
  471. 0x00FF0000, 0x0000FF00, 0x000000FF, 0xFF000000,
  472. 16, 8, 0, 0
  473. },
  474. //-----------------------------------------------------------------------
  475. {"PF_BC1",
  476. /* Bytes per element */
  477. 0,
  478. /* Flags */
  479. PFF_COMPRESSED | PFF_HASALPHA,
  480. /* Component type and count */
  481. PCT_BYTE, 3, // No alpha
  482. /* rbits, gbits, bbits, abits */
  483. 0, 0, 0, 0,
  484. /* Masks and shifts */
  485. 0, 0, 0, 0, 0, 0, 0, 0
  486. },
  487. //-----------------------------------------------------------------------
  488. {"PF_BC1a",
  489. /* Bytes per element */
  490. 0,
  491. /* Flags */
  492. PFF_COMPRESSED,
  493. /* Component type and count */
  494. PCT_BYTE, 3,
  495. /* rbits, gbits, bbits, abits */
  496. 0, 0, 0, 0,
  497. /* Masks and shifts */
  498. 0, 0, 0, 0, 0, 0, 0, 0
  499. },
  500. //-----------------------------------------------------------------------
  501. {"PF_BC2",
  502. /* Bytes per element */
  503. 0,
  504. /* Flags */
  505. PFF_COMPRESSED | PFF_HASALPHA,
  506. /* Component type and count */
  507. PCT_BYTE, 4,
  508. /* rbits, gbits, bbits, abits */
  509. 0, 0, 0, 0,
  510. /* Masks and shifts */
  511. 0, 0, 0, 0, 0, 0, 0, 0
  512. },
  513. //-----------------------------------------------------------------------
  514. {"PF_BC3",
  515. /* Bytes per element */
  516. 0,
  517. /* Flags */
  518. PFF_COMPRESSED | PFF_HASALPHA,
  519. /* Component type and count */
  520. PCT_BYTE, 4,
  521. /* rbits, gbits, bbits, abits */
  522. 0, 0, 0, 0,
  523. /* Masks and shifts */
  524. 0, 0, 0, 0, 0, 0, 0, 0
  525. },
  526. //-----------------------------------------------------------------------
  527. {"PF_BC4",
  528. /* Bytes per element */
  529. 0,
  530. /* Flags */
  531. PFF_COMPRESSED,
  532. /* Component type and count */
  533. PCT_BYTE, 1,
  534. /* rbits, gbits, bbits, abits */
  535. 0, 0, 0, 0,
  536. /* Masks and shifts */
  537. 0, 0, 0, 0, 0, 0, 0, 0
  538. },
  539. //-----------------------------------------------------------------------
  540. {"PF_BC5",
  541. /* Bytes per element */
  542. 0,
  543. /* Flags */
  544. PFF_COMPRESSED,
  545. /* Component type and count */
  546. PCT_BYTE, 2,
  547. /* rbits, gbits, bbits, abits */
  548. 0, 0, 0, 0,
  549. /* Masks and shifts */
  550. 0, 0, 0, 0, 0, 0, 0, 0
  551. },
  552. //-----------------------------------------------------------------------
  553. {"PF_BC6H",
  554. /* Bytes per element */
  555. 0,
  556. /* Flags */
  557. PFF_COMPRESSED,
  558. /* Component type and count */
  559. PCT_FLOAT16, 3,
  560. /* rbits, gbits, bbits, abits */
  561. 0, 0, 0, 0,
  562. /* Masks and shifts */
  563. 0, 0, 0, 0, 0, 0, 0, 0
  564. },
  565. //-----------------------------------------------------------------------
  566. {"PF_BC7",
  567. /* Bytes per element */
  568. 0,
  569. /* Flags */
  570. PFF_COMPRESSED | PFF_HASALPHA,
  571. /* Component type and count */
  572. PCT_BYTE, 4,
  573. /* rbits, gbits, bbits, abits */
  574. 0, 0, 0, 0,
  575. /* Masks and shifts */
  576. 0, 0, 0, 0, 0, 0, 0, 0
  577. },
  578. //-----------------------------------------------------------------------
  579. {"PF_FLOAT16_R",
  580. /* Bytes per element */
  581. 2,
  582. /* Flags */
  583. PFF_FLOAT,
  584. /* Component type and count */
  585. PCT_FLOAT16, 1,
  586. /* rbits, gbits, bbits, abits */
  587. 16, 0, 0, 0,
  588. /* Masks and shifts */
  589. 0, 0, 0, 0, 0, 0, 0, 0
  590. },
  591. //-----------------------------------------------------------------------
  592. {"PF_FLOAT16_RG",
  593. /* Bytes per element */
  594. 4,
  595. /* Flags */
  596. PFF_FLOAT,
  597. /* Component type and count */
  598. PCT_FLOAT16, 2,
  599. /* rbits, gbits, bbits, abits */
  600. 16, 16, 0, 0,
  601. /* Masks and shifts */
  602. 0, 0, 0, 0, 0, 0, 0, 0
  603. },
  604. //-----------------------------------------------------------------------
  605. {"PF_FLOAT16_RGB",
  606. /* Bytes per element */
  607. 6,
  608. /* Flags */
  609. PFF_FLOAT,
  610. /* Component type and count */
  611. PCT_FLOAT16, 3,
  612. /* rbits, gbits, bbits, abits */
  613. 16, 16, 16, 0,
  614. /* Masks and shifts */
  615. 0, 0, 0, 0, 0, 0, 0, 0
  616. },
  617. //-----------------------------------------------------------------------
  618. {"PF_FLOAT16_RGBA",
  619. /* Bytes per element */
  620. 8,
  621. /* Flags */
  622. PFF_FLOAT | PFF_HASALPHA,
  623. /* Component type and count */
  624. PCT_FLOAT16, 4,
  625. /* rbits, gbits, bbits, abits */
  626. 16, 16, 16, 16,
  627. /* Masks and shifts */
  628. 0, 0, 0, 0, 0, 0, 0, 0
  629. },
  630. //-----------------------------------------------------------------------
  631. {"PF_FLOAT32_R",
  632. /* Bytes per element */
  633. 4,
  634. /* Flags */
  635. PFF_FLOAT,
  636. /* Component type and count */
  637. PCT_FLOAT32, 1,
  638. /* rbits, gbits, bbits, abits */
  639. 32, 0, 0, 0,
  640. /* Masks and shifts */
  641. 0, 0, 0, 0, 0, 0, 0, 0
  642. },
  643. //-----------------------------------------------------------------------
  644. {"PF_FLOAT32_RG",
  645. /* Bytes per element */
  646. 8,
  647. /* Flags */
  648. PFF_FLOAT,
  649. /* Component type and count */
  650. PCT_FLOAT32, 2,
  651. /* rbits, gbits, bbits, abits */
  652. 32, 32, 0, 0,
  653. /* Masks and shifts */
  654. 0, 0, 0, 0, 0, 0, 0, 0
  655. },
  656. //-----------------------------------------------------------------------
  657. {"PF_FLOAT32_RGB",
  658. /* Bytes per element */
  659. 12,
  660. /* Flags */
  661. PFF_FLOAT,
  662. /* Component type and count */
  663. PCT_FLOAT32, 3,
  664. /* rbits, gbits, bbits, abits */
  665. 32, 32, 32, 0,
  666. /* Masks and shifts */
  667. 0, 0, 0, 0, 0, 0, 0, 0
  668. },
  669. //-----------------------------------------------------------------------
  670. {"PF_FLOAT32_RGBA",
  671. /* Bytes per element */
  672. 16,
  673. /* Flags */
  674. PFF_FLOAT | PFF_HASALPHA,
  675. /* Component type and count */
  676. PCT_FLOAT32, 4,
  677. /* rbits, gbits, bbits, abits */
  678. 32, 32, 32, 32,
  679. /* Masks and shifts */
  680. 0, 0, 0, 0, 0, 0, 0, 0
  681. },
  682. //-----------------------------------------------------------------------
  683. {"PF_D32_S8X24",
  684. /* Bytes per element */
  685. 8,
  686. /* Flags */
  687. PFF_DEPTH | PFF_FLOAT,
  688. /* Component type and count */
  689. PCT_FLOAT32, 2,
  690. /* rbits, gbits, bbits, abits */
  691. 0, 0, 0, 0,
  692. /* Masks and shifts */
  693. 0, 0, 0, 0, 0, 0, 0, 0
  694. },
  695. //-----------------------------------------------------------------------
  696. {"PF_D24_S8",
  697. /* Bytes per element */
  698. 4,
  699. /* Flags */
  700. PFF_DEPTH | PFF_FLOAT,
  701. /* Component type and count */
  702. PCT_FLOAT32, 1,
  703. /* rbits, gbits, bbits, abits */
  704. 0, 0, 0, 0,
  705. /* Masks and shifts */
  706. 0, 0, 0, 0, 0, 0, 0, 0
  707. },
  708. //-----------------------------------------------------------------------
  709. {"PF_D32",
  710. /* Bytes per element */
  711. 4,
  712. /* Flags */
  713. PFF_DEPTH | PFF_FLOAT,
  714. /* Component type and count */
  715. PCT_FLOAT32, 1,
  716. /* rbits, gbits, bbits, abits */
  717. 0, 0, 0, 0,
  718. /* Masks and shifts */
  719. 0, 0, 0, 0, 0, 0, 0, 0
  720. },
  721. //-----------------------------------------------------------------------
  722. {"PF_D16",
  723. /* Bytes per element */
  724. 2,
  725. /* Flags */
  726. PFF_DEPTH | PFF_FLOAT,
  727. /* Component type and count */
  728. PCT_FLOAT16, 1,
  729. /* rbits, gbits, bbits, abits */
  730. 0, 0, 0, 0,
  731. /* Masks and shifts */
  732. 0, 0, 0, 0, 0, 0, 0, 0
  733. },
  734. //-----------------------------------------------------------------------
  735. { "PF_FLOAT_R11G11B10",
  736. /* Bytes per element */
  737. 4,
  738. /* Flags */
  739. PFF_FLOAT,
  740. /* Component type and count */
  741. PCT_PACKED_R11G11B10, 1,
  742. /* rbits, gbits, bbits, abits */
  743. 11, 11, 10, 0,
  744. /* Masks and shifts */
  745. 0x000007FF, 0x003FF800, 0xFFC00000, 0,
  746. 0, 11, 22, 0
  747. },
  748. //-----------------------------------------------------------------------
  749. { "PF_UNORM_R10G10B10A2",
  750. /* Bytes per element */
  751. 4,
  752. /* Flags */
  753. PFF_FLOAT | PFF_HASALPHA,
  754. /* Component type and count */
  755. PCT_PACKED_R10G10B10A2, 1,
  756. /* rbits, gbits, bbits, abits */
  757. 10, 10, 10, 2,
  758. /* Masks and shifts */
  759. 0x000003FF, 0x000FFC00, 0x3FF00000, 0xC0000000,
  760. 0, 10, 20, 30
  761. },
  762. };
  763. static inline const PixelFormatDescription &getDescriptionFor(const PixelFormat fmt)
  764. {
  765. const int ord = (int)fmt;
  766. assert(ord>=0 && ord<PF_COUNT);
  767. return _pixelFormats[ord];
  768. }
  769. /** Handles compression output from NVTT library for a single image. */
  770. struct NVTTCompressOutputHandler : public nvtt::OutputHandler
  771. {
  772. NVTTCompressOutputHandler(UINT8* buffer, UINT32 sizeBytes)
  773. :buffer(buffer), bufferWritePos(buffer), bufferEnd(buffer + sizeBytes)
  774. { }
  775. virtual void beginImage(int size, int width, int height, int depth, int face, int miplevel) override
  776. { }
  777. virtual bool writeData(const void* data, int size) override
  778. {
  779. assert((bufferWritePos + size) <= bufferEnd);
  780. memcpy(bufferWritePos, data, size);
  781. bufferWritePos += size;
  782. return true;
  783. }
  784. UINT8* buffer;
  785. UINT8* bufferWritePos;
  786. UINT8* bufferEnd;
  787. };
  788. /** Handles output from NVTT library for a mip-map chain. */
  789. struct NVTTMipmapOutputHandler : public nvtt::OutputHandler
  790. {
  791. NVTTMipmapOutputHandler(const Vector<SPtr<PixelData>>& buffers)
  792. :buffers(buffers), bufferWritePos(nullptr), bufferEnd(nullptr)
  793. { }
  794. virtual void beginImage(int size, int width, int height, int depth, int face, int miplevel)
  795. {
  796. assert(miplevel >= 0 && miplevel < (int)buffers.size());
  797. assert(size == buffers[miplevel]->getConsecutiveSize());
  798. activeBuffer = buffers[miplevel];
  799. bufferWritePos = activeBuffer->getData();
  800. bufferEnd = bufferWritePos + activeBuffer->getConsecutiveSize();
  801. }
  802. virtual bool writeData(const void* data, int size)
  803. {
  804. assert((bufferWritePos + size) <= bufferEnd);
  805. memcpy(bufferWritePos, data, size);
  806. bufferWritePos += size;
  807. return true;
  808. }
  809. Vector<SPtr<PixelData>> buffers;
  810. SPtr<PixelData> activeBuffer;
  811. UINT8* bufferWritePos;
  812. UINT8* bufferEnd;
  813. };
  814. nvtt::Format toNVTTFormat(PixelFormat format)
  815. {
  816. switch (format)
  817. {
  818. case PF_BC1:
  819. return nvtt::Format_BC1;
  820. case PF_BC1a:
  821. return nvtt::Format_BC1a;
  822. case PF_BC2:
  823. return nvtt::Format_BC2;
  824. case PF_BC3:
  825. return nvtt::Format_BC3;
  826. case PF_BC4:
  827. return nvtt::Format_BC4;
  828. case PF_BC5:
  829. return nvtt::Format_BC5;
  830. default: // Unsupported format
  831. return nvtt::Format_BC3;
  832. }
  833. }
  834. nvtt::Quality toNVTTQuality(CompressionQuality quality)
  835. {
  836. switch (quality)
  837. {
  838. case CompressionQuality::Fastest:
  839. return nvtt::Quality_Fastest;
  840. case CompressionQuality::Highest:
  841. return nvtt::Quality_Highest;
  842. case CompressionQuality::Normal:
  843. return nvtt::Quality_Normal;
  844. case CompressionQuality::Production:
  845. return nvtt::Quality_Normal;
  846. }
  847. // Unknown quality level
  848. return nvtt::Quality_Normal;
  849. }
  850. nvtt::AlphaMode toNVTTAlphaMode(AlphaMode alphaMode)
  851. {
  852. switch (alphaMode)
  853. {
  854. case AlphaMode::None:
  855. return nvtt::AlphaMode_None;
  856. case AlphaMode::Premultiplied:
  857. return nvtt::AlphaMode_Premultiplied;
  858. case AlphaMode::Transparency:
  859. return nvtt::AlphaMode_Transparency;
  860. }
  861. // Unknown alpha mode
  862. return nvtt::AlphaMode_None;
  863. }
  864. nvtt::WrapMode toNVTTWrapMode(MipMapWrapMode wrapMode)
  865. {
  866. switch (wrapMode)
  867. {
  868. case MipMapWrapMode::Clamp:
  869. return nvtt::WrapMode_Clamp;
  870. case MipMapWrapMode::Mirror:
  871. return nvtt::WrapMode_Mirror;
  872. case MipMapWrapMode::Repeat:
  873. return nvtt::WrapMode_Repeat;
  874. }
  875. // Unknown alpha mode
  876. return nvtt::WrapMode_Mirror;
  877. }
  878. UINT32 PixelUtil::getNumElemBytes(PixelFormat format)
  879. {
  880. return getDescriptionFor(format).elemBytes;
  881. }
  882. UINT32 PixelUtil::getMemorySize(UINT32 width, UINT32 height, UINT32 depth, PixelFormat format)
  883. {
  884. if(isCompressed(format))
  885. {
  886. switch(format)
  887. {
  888. // BC formats work by dividing the image into 4x4 blocks, then encoding each
  889. // 4x4 block with a certain number of bytes.
  890. case PF_BC1:
  891. case PF_BC1a:
  892. case PF_BC4:
  893. return ((width+3)/4)*((height+3)/4)*8 * depth;
  894. case PF_BC2:
  895. case PF_BC3:
  896. case PF_BC5:
  897. case PF_BC6H:
  898. case PF_BC7:
  899. return ((width+3)/4)*((height+3)/4)*16 * depth;
  900. default:
  901. BS_EXCEPT(InvalidParametersException, "Invalid compressed pixel format");
  902. return 0;
  903. }
  904. }
  905. return width*height*depth*getNumElemBytes(format);
  906. }
  907. void PixelUtil::getPitch(UINT32 width, UINT32 height, UINT32 depth, PixelFormat format,
  908. UINT32& rowPitch, UINT32& depthPitch)
  909. {
  910. if (isCompressed(format))
  911. {
  912. switch (format)
  913. {
  914. // BC formats work by dividing the image into 4x4 blocks, then encoding each
  915. // 4x4 block with a certain number of bytes.
  916. case PF_BC1:
  917. case PF_BC1a:
  918. case PF_BC4:
  919. case PF_BC2:
  920. case PF_BC3:
  921. case PF_BC5:
  922. case PF_BC6H:
  923. case PF_BC7:
  924. rowPitch = div(width + 3, 4).quot * 4;
  925. depthPitch = div(height + 3, 4).quot * 4 * rowPitch;
  926. return;
  927. default:
  928. BS_EXCEPT(InvalidParametersException, "Invalid compressed pixel format");
  929. return;
  930. }
  931. }
  932. rowPitch = width;
  933. depthPitch = width * height;
  934. }
  935. void PixelUtil::getSizeForMipLevel(UINT32 width, UINT32 height, UINT32 depth, UINT32 mipLevel,
  936. UINT32& mipWidth, UINT32& mipHeight, UINT32& mipDepth)
  937. {
  938. mipWidth = width;
  939. mipHeight = height;
  940. mipDepth = depth;
  941. for (UINT32 i = 0; i < mipLevel; i++)
  942. {
  943. if (mipWidth != 1) mipWidth /= 2;
  944. if (mipHeight != 1) mipHeight /= 2;
  945. if (mipDepth != 1) mipDepth /= 2;
  946. }
  947. }
  948. UINT32 PixelUtil::getNumElemBits(PixelFormat format)
  949. {
  950. return getDescriptionFor(format).elemBytes * 8;
  951. }
  952. UINT32 PixelUtil::getFlags(PixelFormat format)
  953. {
  954. return getDescriptionFor(format).flags;
  955. }
  956. bool PixelUtil::hasAlpha(PixelFormat format)
  957. {
  958. return (PixelUtil::getFlags(format) & PFF_HASALPHA) > 0;
  959. }
  960. bool PixelUtil::isFloatingPoint(PixelFormat format)
  961. {
  962. return (PixelUtil::getFlags(format) & PFF_FLOAT) > 0;
  963. }
  964. bool PixelUtil::isCompressed(PixelFormat format)
  965. {
  966. return (PixelUtil::getFlags(format) & PFF_COMPRESSED) > 0;
  967. }
  968. bool PixelUtil::isDepth(PixelFormat format)
  969. {
  970. return (PixelUtil::getFlags(format) & PFF_DEPTH) > 0;
  971. }
  972. bool PixelUtil::isNativeEndian(PixelFormat format)
  973. {
  974. return (PixelUtil::getFlags(format) & PFF_NATIVEENDIAN) > 0;
  975. }
  976. bool PixelUtil::isValidExtent(UINT32 width, UINT32 height, UINT32 depth, PixelFormat format)
  977. {
  978. if(isCompressed(format))
  979. {
  980. switch(format)
  981. {
  982. case PF_BC1:
  983. case PF_BC2:
  984. case PF_BC1a:
  985. case PF_BC3:
  986. case PF_BC4:
  987. case PF_BC5:
  988. case PF_BC6H:
  989. case PF_BC7:
  990. return ((width & 3) == 0 && (height & 3) == 0 && depth == 1);
  991. default:
  992. return true;
  993. }
  994. }
  995. else
  996. {
  997. return true;
  998. }
  999. }
  1000. void PixelUtil::getBitDepths(PixelFormat format, int rgba[4])
  1001. {
  1002. const PixelFormatDescription& des = getDescriptionFor(format);
  1003. rgba[0] = des.rbits;
  1004. rgba[1] = des.gbits;
  1005. rgba[2] = des.bbits;
  1006. rgba[3] = des.abits;
  1007. }
  1008. void PixelUtil::getBitMasks(PixelFormat format, UINT32 rgba[4])
  1009. {
  1010. const PixelFormatDescription& des = getDescriptionFor(format);
  1011. rgba[0] = des.rmask;
  1012. rgba[1] = des.gmask;
  1013. rgba[2] = des.bmask;
  1014. rgba[3] = des.amask;
  1015. }
  1016. void PixelUtil::getBitShifts(PixelFormat format, UINT8 rgba[4])
  1017. {
  1018. const PixelFormatDescription& des = getDescriptionFor(format);
  1019. rgba[0] = des.rshift;
  1020. rgba[1] = des.gshift;
  1021. rgba[2] = des.bshift;
  1022. rgba[3] = des.ashift;
  1023. }
  1024. String PixelUtil::getFormatName(PixelFormat srcformat)
  1025. {
  1026. return getDescriptionFor(srcformat).name;
  1027. }
  1028. bool PixelUtil::isAccessible(PixelFormat srcformat)
  1029. {
  1030. if (srcformat == PF_UNKNOWN)
  1031. return false;
  1032. UINT32 flags = getFlags(srcformat);
  1033. return !((flags & PFF_COMPRESSED) || (flags & PFF_DEPTH));
  1034. }
  1035. PixelComponentType PixelUtil::getElementType(PixelFormat format)
  1036. {
  1037. const PixelFormatDescription& des = getDescriptionFor(format);
  1038. return des.componentType;
  1039. }
  1040. UINT32 PixelUtil::getNumElements(PixelFormat format)
  1041. {
  1042. const PixelFormatDescription& des = getDescriptionFor(format);
  1043. return des.componentCount;
  1044. }
  1045. UINT32 PixelUtil::getMaxMipmaps(UINT32 width, UINT32 height, UINT32 depth, PixelFormat format)
  1046. {
  1047. UINT32 count = 0;
  1048. if((width > 0) && (height > 0))
  1049. {
  1050. do {
  1051. if(width>1) width = width/2;
  1052. if(height>1) height = height/2;
  1053. if(depth>1) depth = depth/2;
  1054. count ++;
  1055. } while(!(width == 1 && height == 1 && depth == 1));
  1056. }
  1057. return count;
  1058. }
  1059. void PixelUtil::packColor(const Color& color, PixelFormat format, void* dest)
  1060. {
  1061. packColor(color.r, color.g, color.b, color.a, format, dest);
  1062. }
  1063. void PixelUtil::packColor(UINT8 r, UINT8 g, UINT8 b, UINT8 a, PixelFormat format, void* dest)
  1064. {
  1065. const PixelFormatDescription &des = getDescriptionFor(format);
  1066. if(des.flags & PFF_NATIVEENDIAN)
  1067. {
  1068. // Shortcut for integer formats packing
  1069. UINT32 value = ((Bitwise::fixedToFixed(r, 8, des.rbits)<<des.rshift) & des.rmask) |
  1070. ((Bitwise::fixedToFixed(g, 8, des.gbits)<<des.gshift) & des.gmask) |
  1071. ((Bitwise::fixedToFixed(b, 8, des.bbits)<<des.bshift) & des.bmask) |
  1072. ((Bitwise::fixedToFixed(a, 8, des.abits)<<des.ashift) & des.amask);
  1073. // And write to memory
  1074. Bitwise::intWrite(dest, des.elemBytes, value);
  1075. }
  1076. else
  1077. {
  1078. // Convert to float
  1079. packColor((float)r/255.0f,(float)g/255.0f,(float)b/255.0f,(float)a/255.0f, format, dest);
  1080. }
  1081. }
  1082. void PixelUtil::packColor(float r, float g, float b, float a, const PixelFormat format, void* dest)
  1083. {
  1084. const PixelFormatDescription& des = getDescriptionFor(format);
  1085. if(des.flags & PFF_NATIVEENDIAN)
  1086. {
  1087. // Do the packing
  1088. const unsigned int value = ((Bitwise::floatToFixed(r, des.rbits)<<des.rshift) & des.rmask) |
  1089. ((Bitwise::floatToFixed(g, des.gbits)<<des.gshift) & des.gmask) |
  1090. ((Bitwise::floatToFixed(b, des.bbits)<<des.bshift) & des.bmask) |
  1091. ((Bitwise::floatToFixed(a, des.abits)<<des.ashift) & des.amask);
  1092. // And write to memory
  1093. Bitwise::intWrite(dest, des.elemBytes, value);
  1094. }
  1095. else
  1096. {
  1097. switch(format)
  1098. {
  1099. case PF_FLOAT32_R:
  1100. ((float*)dest)[0] = r;
  1101. break;
  1102. case PF_FLOAT32_RG:
  1103. ((float*)dest)[0] = r;
  1104. ((float*)dest)[1] = g;
  1105. break;
  1106. case PF_FLOAT32_RGB:
  1107. ((float*)dest)[0] = r;
  1108. ((float*)dest)[1] = g;
  1109. ((float*)dest)[2] = b;
  1110. break;
  1111. case PF_FLOAT32_RGBA:
  1112. ((float*)dest)[0] = r;
  1113. ((float*)dest)[1] = g;
  1114. ((float*)dest)[2] = b;
  1115. ((float*)dest)[3] = a;
  1116. break;
  1117. case PF_FLOAT16_R:
  1118. ((UINT16*)dest)[0] = Bitwise::floatToHalf(r);
  1119. break;
  1120. case PF_FLOAT16_RG:
  1121. ((UINT16*)dest)[0] = Bitwise::floatToHalf(r);
  1122. ((UINT16*)dest)[1] = Bitwise::floatToHalf(g);
  1123. break;
  1124. case PF_FLOAT16_RGB:
  1125. ((UINT16*)dest)[0] = Bitwise::floatToHalf(r);
  1126. ((UINT16*)dest)[1] = Bitwise::floatToHalf(g);
  1127. ((UINT16*)dest)[2] = Bitwise::floatToHalf(b);
  1128. break;
  1129. case PF_FLOAT16_RGBA:
  1130. ((UINT16*)dest)[0] = Bitwise::floatToHalf(r);
  1131. ((UINT16*)dest)[1] = Bitwise::floatToHalf(g);
  1132. ((UINT16*)dest)[2] = Bitwise::floatToHalf(b);
  1133. ((UINT16*)dest)[3] = Bitwise::floatToHalf(a);
  1134. break;
  1135. case PF_R8G8:
  1136. ((UINT8*)dest)[0] = (UINT8)Bitwise::floatToFixed(r, 8);
  1137. ((UINT8*)dest)[1] = (UINT8)Bitwise::floatToFixed(g, 8);
  1138. break;
  1139. case PF_R8:
  1140. ((UINT8*)dest)[0] = (UINT8)Bitwise::floatToFixed(r, 8);
  1141. break;
  1142. default:
  1143. LOGERR("Pack to " + getFormatName(format) + " not implemented");
  1144. break;
  1145. }
  1146. }
  1147. }
  1148. void PixelUtil::unpackColor(Color* color, PixelFormat format, const void* src)
  1149. {
  1150. unpackColor(&color->r, &color->g, &color->b, &color->a, format, src);
  1151. }
  1152. void PixelUtil::unpackColor(UINT8* r, UINT8* g, UINT8* b, UINT8* a, PixelFormat format, const void* src)
  1153. {
  1154. const PixelFormatDescription &des = getDescriptionFor(format);
  1155. if(des.flags & PFF_NATIVEENDIAN)
  1156. {
  1157. // Shortcut for integer formats unpacking
  1158. const UINT32 value = Bitwise::intRead(src, des.elemBytes);
  1159. *r = (UINT8)Bitwise::fixedToFixed((value & des.rmask)>>des.rshift, des.rbits, 8);
  1160. *g = (UINT8)Bitwise::fixedToFixed((value & des.gmask)>>des.gshift, des.gbits, 8);
  1161. *b = (UINT8)Bitwise::fixedToFixed((value & des.bmask)>>des.bshift, des.bbits, 8);
  1162. if(des.flags & PFF_HASALPHA)
  1163. {
  1164. *a = (UINT8)Bitwise::fixedToFixed((value & des.amask)>>des.ashift, des.abits, 8);
  1165. }
  1166. else
  1167. {
  1168. *a = 255; // No alpha, default a component to full
  1169. }
  1170. }
  1171. else
  1172. {
  1173. // Do the operation with the more generic floating point
  1174. float rr, gg, bb, aa;
  1175. unpackColor(&rr,&gg,&bb,&aa, format, src);
  1176. *r = (UINT8)Bitwise::floatToFixed(rr, 8);
  1177. *g = (UINT8)Bitwise::floatToFixed(gg, 8);
  1178. *b = (UINT8)Bitwise::floatToFixed(bb, 8);
  1179. *a = (UINT8)Bitwise::floatToFixed(aa, 8);
  1180. }
  1181. }
  1182. void PixelUtil::unpackColor(float* r, float* g, float* b, float* a, PixelFormat format, const void* src)
  1183. {
  1184. const PixelFormatDescription &des = getDescriptionFor(format);
  1185. if(des.flags & PFF_NATIVEENDIAN)
  1186. {
  1187. // Shortcut for integer formats unpacking
  1188. const unsigned int value = Bitwise::intRead(src, des.elemBytes);
  1189. *r = Bitwise::fixedToFloat((value & des.rmask)>>des.rshift, des.rbits);
  1190. *g = Bitwise::fixedToFloat((value & des.gmask)>>des.gshift, des.gbits);
  1191. *b = Bitwise::fixedToFloat((value & des.bmask)>>des.bshift, des.bbits);
  1192. if(des.flags & PFF_HASALPHA)
  1193. {
  1194. *a = Bitwise::fixedToFloat((value & des.amask)>>des.ashift, des.abits);
  1195. }
  1196. else
  1197. {
  1198. *a = 1.0f; // No alpha, default a component to full
  1199. }
  1200. }
  1201. else
  1202. {
  1203. switch(format)
  1204. {
  1205. case PF_FLOAT32_R:
  1206. *r = *g = *b = ((float*)src)[0];
  1207. *a = 1.0f;
  1208. break;
  1209. case PF_FLOAT32_RG:
  1210. *r = ((float*)src)[0];
  1211. *g = *b = ((float*)src)[1];
  1212. *a = 1.0f;
  1213. break;
  1214. case PF_FLOAT32_RGB:
  1215. *r = ((float*)src)[0];
  1216. *g = ((float*)src)[1];
  1217. *b = ((float*)src)[2];
  1218. *a = 1.0f;
  1219. break;
  1220. case PF_FLOAT32_RGBA:
  1221. *r = ((float*)src)[0];
  1222. *g = ((float*)src)[1];
  1223. *b = ((float*)src)[2];
  1224. *a = ((float*)src)[3];
  1225. break;
  1226. case PF_FLOAT16_R:
  1227. *r = *g = *b = Bitwise::halfToFloat(((UINT16*)src)[0]);
  1228. *a = 1.0f;
  1229. break;
  1230. case PF_FLOAT16_RG:
  1231. *r = Bitwise::halfToFloat(((UINT16*)src)[0]);
  1232. *g = *b = Bitwise::halfToFloat(((UINT16*)src)[1]);
  1233. *a = 1.0f;
  1234. break;
  1235. case PF_FLOAT16_RGB:
  1236. *r = Bitwise::halfToFloat(((UINT16*)src)[0]);
  1237. *g = Bitwise::halfToFloat(((UINT16*)src)[1]);
  1238. *b = Bitwise::halfToFloat(((UINT16*)src)[2]);
  1239. *a = 1.0f;
  1240. break;
  1241. case PF_FLOAT16_RGBA:
  1242. *r = Bitwise::halfToFloat(((UINT16*)src)[0]);
  1243. *g = Bitwise::halfToFloat(((UINT16*)src)[1]);
  1244. *b = Bitwise::halfToFloat(((UINT16*)src)[2]);
  1245. *a = Bitwise::halfToFloat(((UINT16*)src)[3]);
  1246. break;
  1247. case PF_R8G8:
  1248. *r = Bitwise::fixedToFloat(((UINT8*)src)[0], 8);
  1249. *g = Bitwise::fixedToFloat(((UINT8*)src)[1], 8);
  1250. *b = 0.0f;
  1251. *a = 1.0f;
  1252. break;
  1253. case PF_R8:
  1254. *r = Bitwise::fixedToFloat(((UINT8*)src)[0], 8);
  1255. *g = 0.0f;
  1256. *b = 0.0f;
  1257. *a = 1.0f;
  1258. break;
  1259. default:
  1260. LOGERR("Unpack from " + getFormatName(format) + " not implemented");
  1261. break;
  1262. }
  1263. }
  1264. }
  1265. void PixelUtil::packDepth(float depth, const PixelFormat format, void* dest)
  1266. {
  1267. if (!isDepth(format))
  1268. {
  1269. LOGERR("Cannot convert depth to " + getFormatName(format) + ": it is not a depth format");
  1270. return;
  1271. }
  1272. LOGERR("Method is not implemented");
  1273. //TODO implement depth packing
  1274. }
  1275. float PixelUtil::unpackDepth(PixelFormat format, void* src)
  1276. {
  1277. const PixelFormatDescription &des = getDescriptionFor(format);
  1278. if (!isDepth(format))
  1279. {
  1280. LOGERR("Cannot unpack from " + getFormatName(format) + ": it is not a depth format");
  1281. return 0;
  1282. }
  1283. UINT32* color = (UINT32 *)src;
  1284. switch (format)
  1285. {
  1286. case PF_D24S8:
  1287. return static_cast<float>(*color & 0x00FFFFFF) / (float)16777216;
  1288. break;
  1289. case PF_D16:
  1290. return static_cast<float>(*color & 0xFFFF) / (float)65536;
  1291. break;
  1292. case PF_D32:
  1293. return static_cast<float>(*color & 0xFFFFFFFF) / (float)4294967296;
  1294. break;
  1295. case PF_D32_S8X24:
  1296. return static_cast<float>(*color & 0xFFFFFFFF) / (float)4294967296;
  1297. break;
  1298. default:
  1299. LOGERR("Cannot unpack from " + getFormatName(format));
  1300. return 0;
  1301. break;
  1302. }
  1303. }
  1304. void PixelUtil::bulkPixelConversion(const PixelData &src, PixelData &dst)
  1305. {
  1306. assert(src.getWidth() == dst.getWidth() &&
  1307. src.getHeight() == dst.getHeight() &&
  1308. src.getDepth() == dst.getDepth());
  1309. // Check for compressed formats, we don't support decompression
  1310. if(PixelUtil::isCompressed(src.getFormat()))
  1311. {
  1312. if(src.getFormat() == dst.getFormat())
  1313. {
  1314. memcpy(dst.getData(), src.getData(), src.getConsecutiveSize());
  1315. return;
  1316. }
  1317. else
  1318. {
  1319. LOGERR("bulkPixelConversion() cannot be used to compress or decompress images");
  1320. return;
  1321. }
  1322. }
  1323. // Check for compression
  1324. if (PixelUtil::isCompressed(dst.getFormat()))
  1325. {
  1326. if (src.getFormat() == dst.getFormat())
  1327. {
  1328. memcpy(dst.getData(), src.getData(), src.getConsecutiveSize());
  1329. return;
  1330. }
  1331. else
  1332. {
  1333. CompressionOptions co;
  1334. co.format = dst.getFormat();
  1335. compress(src, dst, co);
  1336. return;
  1337. }
  1338. }
  1339. // The easy case
  1340. if(src.getFormat() == dst.getFormat())
  1341. {
  1342. // Everything consecutive?
  1343. if(src.isConsecutive() && dst.isConsecutive())
  1344. {
  1345. memcpy(dst.getData(), src.getData(), src.getConsecutiveSize());
  1346. return;
  1347. }
  1348. const UINT32 srcPixelSize = PixelUtil::getNumElemBytes(src.getFormat());
  1349. const UINT32 dstPixelSize = PixelUtil::getNumElemBytes(dst.getFormat());
  1350. UINT8 *srcptr = static_cast<UINT8*>(src.getData())
  1351. + (src.getLeft() + src.getTop() * src.getRowPitch() + src.getFront() * src.getSlicePitch()) * srcPixelSize;
  1352. UINT8 *dstptr = static_cast<UINT8*>(dst.getData())
  1353. + (dst.getLeft() + dst.getTop() * dst.getRowPitch() + dst.getFront() * dst.getSlicePitch()) * dstPixelSize;
  1354. // Calculate pitches+skips in bytes
  1355. const UINT32 srcRowPitchBytes = src.getRowPitch()*srcPixelSize;
  1356. const UINT32 srcSliceSkipBytes = src.getSliceSkip()*srcPixelSize;
  1357. const UINT32 dstRowPitchBytes = dst.getRowPitch()*dstPixelSize;
  1358. const UINT32 dstSliceSkipBytes = dst.getSliceSkip()*dstPixelSize;
  1359. // Otherwise, copy per row
  1360. const UINT32 rowSize = src.getWidth()*srcPixelSize;
  1361. for (UINT32 z = src.getFront(); z < src.getBack(); z++)
  1362. {
  1363. for(UINT32 y = src.getTop(); y < src.getBottom(); y++)
  1364. {
  1365. memcpy(dstptr, srcptr, rowSize);
  1366. srcptr += srcRowPitchBytes;
  1367. dstptr += dstRowPitchBytes;
  1368. }
  1369. srcptr += srcSliceSkipBytes;
  1370. dstptr += dstSliceSkipBytes;
  1371. }
  1372. return;
  1373. }
  1374. // Converting to PF_X8R8G8B8 is exactly the same as converting to
  1375. // PF_A8R8G8B8. (same with PF_X8B8G8R8 and PF_A8B8G8R8)
  1376. if(dst.getFormat() == PF_X8R8G8B8 || dst.getFormat() == PF_X8B8G8R8)
  1377. {
  1378. // Do the same conversion, with PF_A8R8G8B8, which has a lot of
  1379. // optimized conversions
  1380. PixelFormat tempFormat = dst.getFormat() == PF_X8R8G8B8?PF_A8R8G8B8:PF_A8B8G8R8;
  1381. PixelData tempdst(dst.getWidth(), dst.getHeight(), dst.getDepth(), tempFormat);
  1382. bulkPixelConversion(src, tempdst);
  1383. return;
  1384. }
  1385. // Converting from PF_X8R8G8B8 is exactly the same as converting from
  1386. // PF_A8R8G8B8, given that the destination format does not have alpha.
  1387. if((src.getFormat() == PF_X8R8G8B8 || src.getFormat() == PF_X8B8G8R8) && !hasAlpha(dst.getFormat()))
  1388. {
  1389. // Do the same conversion, with PF_A8R8G8B8, which has a lot of
  1390. // optimized conversions
  1391. PixelFormat tempFormat = src.getFormat()==PF_X8R8G8B8?PF_A8R8G8B8:PF_A8B8G8R8;
  1392. PixelData tempsrc(src.getWidth(), src.getHeight(), src.getDepth(), tempFormat);
  1393. tempsrc.setExternalBuffer(src.getData());
  1394. bulkPixelConversion(tempsrc, dst);
  1395. return;
  1396. }
  1397. const UINT32 srcPixelSize = PixelUtil::getNumElemBytes(src.getFormat());
  1398. const UINT32 dstPixelSize = PixelUtil::getNumElemBytes(dst.getFormat());
  1399. UINT8 *srcptr = static_cast<UINT8*>(src.getData())
  1400. + (src.getLeft() + src.getTop() * src.getRowPitch() + src.getFront() * src.getSlicePitch()) * srcPixelSize;
  1401. UINT8 *dstptr = static_cast<UINT8*>(dst.getData())
  1402. + (dst.getLeft() + dst.getTop() * dst.getRowPitch() + dst.getFront() * dst.getSlicePitch()) * dstPixelSize;
  1403. // Calculate pitches+skips in bytes
  1404. const UINT32 srcRowSkipBytes = src.getRowSkip()*srcPixelSize;
  1405. const UINT32 srcSliceSkipBytes = src.getSliceSkip()*srcPixelSize;
  1406. const UINT32 dstRowSkipBytes = dst.getRowSkip()*dstPixelSize;
  1407. const UINT32 dstSliceSkipBytes = dst.getSliceSkip()*dstPixelSize;
  1408. // The brute force fallback
  1409. float r,g,b,a;
  1410. for (UINT32 z = src.getFront(); z<src.getBack(); z++)
  1411. {
  1412. for (UINT32 y = src.getTop(); y < src.getBottom(); y++)
  1413. {
  1414. for (UINT32 x = src.getLeft(); x<src.getRight(); x++)
  1415. {
  1416. unpackColor(&r, &g, &b, &a, src.getFormat(), srcptr);
  1417. packColor(r, g, b, a, dst.getFormat(), dstptr);
  1418. srcptr += srcPixelSize;
  1419. dstptr += dstPixelSize;
  1420. }
  1421. srcptr += srcRowSkipBytes;
  1422. dstptr += dstRowSkipBytes;
  1423. }
  1424. srcptr += srcSliceSkipBytes;
  1425. dstptr += dstSliceSkipBytes;
  1426. }
  1427. }
  1428. void PixelUtil::scale(const PixelData& src, PixelData& scaled, Filter filter)
  1429. {
  1430. assert(PixelUtil::isAccessible(src.getFormat()));
  1431. assert(PixelUtil::isAccessible(scaled.getFormat()));
  1432. PixelData temp;
  1433. switch (filter)
  1434. {
  1435. default:
  1436. case FILTER_NEAREST:
  1437. if(src.getFormat() == scaled.getFormat())
  1438. {
  1439. // No intermediate buffer needed
  1440. temp = scaled;
  1441. }
  1442. else
  1443. {
  1444. // Allocate temporary buffer of destination size in source format
  1445. temp = PixelData(scaled.getWidth(), scaled.getHeight(), scaled.getDepth(), src.getFormat());
  1446. temp.allocateInternalBuffer();
  1447. }
  1448. // No conversion
  1449. switch (PixelUtil::getNumElemBytes(src.getFormat()))
  1450. {
  1451. case 1: NearestResampler<1>::scale(src, temp); break;
  1452. case 2: NearestResampler<2>::scale(src, temp); break;
  1453. case 3: NearestResampler<3>::scale(src, temp); break;
  1454. case 4: NearestResampler<4>::scale(src, temp); break;
  1455. case 6: NearestResampler<6>::scale(src, temp); break;
  1456. case 8: NearestResampler<8>::scale(src, temp); break;
  1457. case 12: NearestResampler<12>::scale(src, temp); break;
  1458. case 16: NearestResampler<16>::scale(src, temp); break;
  1459. default:
  1460. // Never reached
  1461. assert(false);
  1462. }
  1463. if(temp.getData() != scaled.getData())
  1464. {
  1465. // Blit temp buffer
  1466. PixelUtil::bulkPixelConversion(temp, scaled);
  1467. temp.freeInternalBuffer();
  1468. }
  1469. break;
  1470. case FILTER_LINEAR:
  1471. switch (src.getFormat())
  1472. {
  1473. case PF_R8G8:
  1474. case PF_R8G8B8: case PF_B8G8R8:
  1475. case PF_R8G8B8A8: case PF_B8G8R8A8:
  1476. case PF_A8B8G8R8: case PF_A8R8G8B8:
  1477. case PF_X8B8G8R8: case PF_X8R8G8B8:
  1478. if(src.getFormat() == scaled.getFormat())
  1479. {
  1480. // No intermediate buffer needed
  1481. temp = scaled;
  1482. }
  1483. else
  1484. {
  1485. // Allocate temp buffer of destination size in source format
  1486. temp = PixelData(scaled.getWidth(), scaled.getHeight(), scaled.getDepth(), src.getFormat());
  1487. temp.allocateInternalBuffer();
  1488. }
  1489. // No conversion
  1490. switch (PixelUtil::getNumElemBytes(src.getFormat()))
  1491. {
  1492. case 1: LinearResampler_Byte<1>::scale(src, temp); break;
  1493. case 2: LinearResampler_Byte<2>::scale(src, temp); break;
  1494. case 3: LinearResampler_Byte<3>::scale(src, temp); break;
  1495. case 4: LinearResampler_Byte<4>::scale(src, temp); break;
  1496. default:
  1497. // Never reached
  1498. assert(false);
  1499. }
  1500. if(temp.getData() != scaled.getData())
  1501. {
  1502. // Blit temp buffer
  1503. PixelUtil::bulkPixelConversion(temp, scaled);
  1504. temp.freeInternalBuffer();
  1505. }
  1506. break;
  1507. case PF_FLOAT32_RGB:
  1508. case PF_FLOAT32_RGBA:
  1509. if (scaled.getFormat() == PF_FLOAT32_RGB || scaled.getFormat() == PF_FLOAT32_RGBA)
  1510. {
  1511. // float32 to float32, avoid unpack/repack overhead
  1512. LinearResampler_Float32::scale(src, scaled);
  1513. break;
  1514. }
  1515. // Else, fall through
  1516. default:
  1517. // Fallback case, slow but works
  1518. LinearResampler::scale(src, scaled);
  1519. }
  1520. break;
  1521. }
  1522. }
  1523. void PixelUtil::applyGamma(UINT8* buffer, float gamma, UINT32 size, UINT8 bpp)
  1524. {
  1525. if(gamma == 1.0f)
  1526. return;
  1527. UINT32 stride = bpp >> 3;
  1528. for(size_t i = 0, j = size / stride; i < j; i++, buffer += stride)
  1529. {
  1530. float r = (float)buffer[0];
  1531. float g = (float)buffer[1];
  1532. float b = (float)buffer[2];
  1533. r = r * gamma;
  1534. g = g * gamma;
  1535. b = b * gamma;
  1536. float scale = 1.0f;
  1537. float tmp = 0.0f;
  1538. if(r > 255.0f && (tmp=(255.0f/r)) < scale)
  1539. scale = tmp;
  1540. if(g > 255.0f && (tmp=(255.0f/g)) < scale)
  1541. scale = tmp;
  1542. if(b > 255.0f && (tmp=(255.0f/b)) < scale)
  1543. scale = tmp;
  1544. r *= scale;
  1545. g *= scale;
  1546. b *= scale;
  1547. buffer[0] = (UINT8)r;
  1548. buffer[1] = (UINT8)g;
  1549. buffer[2] = (UINT8)b;
  1550. }
  1551. }
  1552. void PixelUtil::compress(const PixelData& src, PixelData& dst, const CompressionOptions& options)
  1553. {
  1554. if (!isCompressed(options.format))
  1555. {
  1556. LOGERR("Compression failed. Destination format is not a valid compressed format.")
  1557. return;
  1558. }
  1559. // Note: NVTT site has implementations for these two formats for when I decide to add them
  1560. if (options.format == PF_BC6H || options.format == PF_BC7)
  1561. {
  1562. LOGERR("Compression failed. BC6H and BC7 formats are currently not supported.")
  1563. return;
  1564. }
  1565. if (src.getDepth() != 1)
  1566. {
  1567. LOGERR("Compression failed. 3D texture compression not supported.")
  1568. return;
  1569. }
  1570. if (isCompressed(src.getFormat()))
  1571. {
  1572. LOGERR("Compression failed. Source data cannot be compressed.");
  1573. return;
  1574. }
  1575. PixelData bgraData(src.getWidth(), src.getHeight(), 1, PF_B8G8R8A8);
  1576. bgraData.allocateInternalBuffer();
  1577. bulkPixelConversion(src, bgraData);
  1578. nvtt::InputOptions io;
  1579. io.setTextureLayout(nvtt::TextureType_2D, src.getWidth(), src.getHeight());
  1580. io.setMipmapData(bgraData.getData(), src.getWidth(), src.getHeight());
  1581. io.setMipmapGeneration(false);
  1582. io.setAlphaMode(toNVTTAlphaMode(options.alphaMode));
  1583. io.setNormalMap(options.isNormalMap);
  1584. if (options.isSRGB)
  1585. io.setGamma(2.2f, 2.2f);
  1586. else
  1587. io.setGamma(1.0f, 1.0f);
  1588. nvtt::CompressionOptions co;
  1589. co.setFormat(toNVTTFormat(options.format));
  1590. co.setQuality(toNVTTQuality(options.quality));
  1591. NVTTCompressOutputHandler outputHandler(dst.getData(), dst.getConsecutiveSize());
  1592. nvtt::OutputOptions oo;
  1593. oo.setOutputHeader(false);
  1594. oo.setOutputHandler(&outputHandler);
  1595. nvtt::Compressor compressor;
  1596. if (!compressor.process(io, co, oo))
  1597. {
  1598. LOGERR("Compression failed. Internal error.");
  1599. return;
  1600. }
  1601. }
  1602. Vector<SPtr<PixelData>> PixelUtil::genMipmaps(const PixelData& src, const MipMapGenOptions& options)
  1603. {
  1604. Vector<SPtr<PixelData>> outputMipBuffers;
  1605. if (src.getDepth() != 1)
  1606. {
  1607. LOGERR("Mipmap generation failed. 3D texture formats not supported.")
  1608. return outputMipBuffers;
  1609. }
  1610. // Note: Add support for floating point mips, no reason they shouldn't be supported other than
  1611. // nvtt doesn't support them natively
  1612. if (isCompressed(src.getFormat()) || isFloatingPoint(src.getFormat()))
  1613. {
  1614. LOGERR("Mipmap generation failed. Source data cannot be compressed or in floating point format.")
  1615. return outputMipBuffers;
  1616. }
  1617. if (!Math::isPow2(src.getWidth()) || !Math::isPow2(src.getHeight()))
  1618. {
  1619. LOGERR("Mipmap generation failed. Texture width & height must be powers of 2.");
  1620. return outputMipBuffers;
  1621. }
  1622. PixelData argbData(src.getWidth(), src.getHeight(), 1, PF_A8R8G8B8);
  1623. argbData.allocateInternalBuffer();
  1624. bulkPixelConversion(src, argbData);
  1625. nvtt::InputOptions io;
  1626. io.setTextureLayout(nvtt::TextureType_2D, src.getWidth(), src.getHeight());
  1627. io.setMipmapData(argbData.getData(), src.getWidth(), src.getHeight());
  1628. io.setMipmapGeneration(true);
  1629. io.setNormalMap(options.isNormalMap);
  1630. io.setNormalizeMipmaps(options.normalizeMipmaps);
  1631. io.setWrapMode(toNVTTWrapMode(options.wrapMode));
  1632. nvtt::CompressionOptions co;
  1633. co.setFormat(nvtt::Format_RGBA);
  1634. UINT32 numMips = getMaxMipmaps(src.getWidth(), src.getHeight(), 1, src.getFormat());
  1635. Vector<SPtr<PixelData>> argbMipBuffers;
  1636. // Note: This can be done more effectively without creating so many temp buffers
  1637. // and working with the original formats directly, but it would complicate the code
  1638. // too much at the moment.
  1639. UINT32 curWidth = src.getWidth();
  1640. UINT32 curHeight = src.getHeight();
  1641. for (UINT32 i = 0; i < numMips; i++)
  1642. {
  1643. argbMipBuffers.push_back(bs_shared_ptr_new<PixelData>(curWidth, curHeight, 1, PF_A8R8G8B8));
  1644. argbMipBuffers.back()->allocateInternalBuffer();
  1645. if (curWidth > 1)
  1646. curWidth = curWidth / 2;
  1647. if (curHeight > 1)
  1648. curHeight = curHeight / 2;
  1649. }
  1650. argbMipBuffers.push_back(bs_shared_ptr_new<PixelData>(curWidth, curHeight, 1, PF_A8R8G8B8));
  1651. argbMipBuffers.back()->allocateInternalBuffer();
  1652. NVTTMipmapOutputHandler outputHandler(argbMipBuffers);
  1653. nvtt::OutputOptions oo;
  1654. oo.setOutputHeader(false);
  1655. oo.setOutputHandler(&outputHandler);
  1656. nvtt::Compressor compressor;
  1657. if (!compressor.process(io, co, oo))
  1658. {
  1659. LOGERR("Mipmap generation failed. Internal error.");
  1660. return outputMipBuffers;
  1661. }
  1662. argbData.freeInternalBuffer();
  1663. for (UINT32 i = 0; i < (UINT32)argbMipBuffers.size(); i++)
  1664. {
  1665. SPtr<PixelData> argbBuffer = argbMipBuffers[i];
  1666. SPtr<PixelData> outputBuffer = bs_shared_ptr_new<PixelData>(argbBuffer->getWidth(), argbBuffer->getHeight(), 1, src.getFormat());
  1667. outputBuffer->allocateInternalBuffer();
  1668. bulkPixelConversion(*argbBuffer, *outputBuffer);
  1669. argbBuffer->freeInternalBuffer();
  1670. outputMipBuffers.push_back(outputBuffer);
  1671. }
  1672. return outputMipBuffers;
  1673. }
  1674. }