BsPixelUtil.cpp 62 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853185418551856185718581859186018611862186318641865186618671868186918701871187218731874187518761877187818791880188118821883188418851886188718881889189018911892189318941895189618971898189919001901190219031904190519061907
  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. {}, // Deleted format
  364. //-----------------------------------------------------------------------
  365. {}, // Deleted format
  366. //-----------------------------------------------------------------------
  367. {"PF_B8G8R8A8",
  368. /* Bytes per element */
  369. 4,
  370. /* Flags */
  371. PFF_HASALPHA | PFF_NATIVEENDIAN,
  372. /* Component type and count */
  373. PCT_BYTE, 4,
  374. /* rbits, gbits, bbits, abits */
  375. 8, 8, 8, 8,
  376. /* Masks and shifts */
  377. 0x00FF0000, 0x0000FF00, 0x000000FF, 0xFF000000,
  378. 16, 8, 0, 24
  379. },
  380. //-----------------------------------------------------------------------
  381. {"PF_R8G8B8A8",
  382. /* Bytes per element */
  383. 4,
  384. /* Flags */
  385. PFF_HASALPHA | PFF_NATIVEENDIAN,
  386. /* Component type and count */
  387. PCT_BYTE, 4,
  388. /* rbits, gbits, bbits, abits */
  389. 8, 8, 8, 8,
  390. /* Masks and shifts */
  391. 0x000000FF, 0x0000FF00, 0x00FF0000, 0xFF000000,
  392. 0, 8, 16, 24
  393. },
  394. //-----------------------------------------------------------------------
  395. {}, // Deleted format
  396. //-----------------------------------------------------------------------
  397. {}, // Deleted format
  398. //-----------------------------------------------------------------------
  399. {}, // Deleted format
  400. //-----------------------------------------------------------------------
  401. {}, // Deleted format
  402. //-----------------------------------------------------------------------
  403. {"PF_BC1",
  404. /* Bytes per element */
  405. 0,
  406. /* Flags */
  407. PFF_COMPRESSED | PFF_HASALPHA,
  408. /* Component type and count */
  409. PCT_BYTE, 3, // No alpha
  410. /* rbits, gbits, bbits, abits */
  411. 0, 0, 0, 0,
  412. /* Masks and shifts */
  413. 0, 0, 0, 0, 0, 0, 0, 0
  414. },
  415. //-----------------------------------------------------------------------
  416. {"PF_BC1a",
  417. /* Bytes per element */
  418. 0,
  419. /* Flags */
  420. PFF_COMPRESSED,
  421. /* Component type and count */
  422. PCT_BYTE, 3,
  423. /* rbits, gbits, bbits, abits */
  424. 0, 0, 0, 0,
  425. /* Masks and shifts */
  426. 0, 0, 0, 0, 0, 0, 0, 0
  427. },
  428. //-----------------------------------------------------------------------
  429. {"PF_BC2",
  430. /* Bytes per element */
  431. 0,
  432. /* Flags */
  433. PFF_COMPRESSED | PFF_HASALPHA,
  434. /* Component type and count */
  435. PCT_BYTE, 4,
  436. /* rbits, gbits, bbits, abits */
  437. 0, 0, 0, 0,
  438. /* Masks and shifts */
  439. 0, 0, 0, 0, 0, 0, 0, 0
  440. },
  441. //-----------------------------------------------------------------------
  442. {"PF_BC3",
  443. /* Bytes per element */
  444. 0,
  445. /* Flags */
  446. PFF_COMPRESSED | PFF_HASALPHA,
  447. /* Component type and count */
  448. PCT_BYTE, 4,
  449. /* rbits, gbits, bbits, abits */
  450. 0, 0, 0, 0,
  451. /* Masks and shifts */
  452. 0, 0, 0, 0, 0, 0, 0, 0
  453. },
  454. //-----------------------------------------------------------------------
  455. {"PF_BC4",
  456. /* Bytes per element */
  457. 0,
  458. /* Flags */
  459. PFF_COMPRESSED,
  460. /* Component type and count */
  461. PCT_BYTE, 1,
  462. /* rbits, gbits, bbits, abits */
  463. 0, 0, 0, 0,
  464. /* Masks and shifts */
  465. 0, 0, 0, 0, 0, 0, 0, 0
  466. },
  467. //-----------------------------------------------------------------------
  468. {"PF_BC5",
  469. /* Bytes per element */
  470. 0,
  471. /* Flags */
  472. PFF_COMPRESSED,
  473. /* Component type and count */
  474. PCT_BYTE, 2,
  475. /* rbits, gbits, bbits, abits */
  476. 0, 0, 0, 0,
  477. /* Masks and shifts */
  478. 0, 0, 0, 0, 0, 0, 0, 0
  479. },
  480. //-----------------------------------------------------------------------
  481. {"PF_BC6H",
  482. /* Bytes per element */
  483. 0,
  484. /* Flags */
  485. PFF_COMPRESSED,
  486. /* Component type and count */
  487. PCT_FLOAT16, 3,
  488. /* rbits, gbits, bbits, abits */
  489. 0, 0, 0, 0,
  490. /* Masks and shifts */
  491. 0, 0, 0, 0, 0, 0, 0, 0
  492. },
  493. //-----------------------------------------------------------------------
  494. {"PF_BC7",
  495. /* Bytes per element */
  496. 0,
  497. /* Flags */
  498. PFF_COMPRESSED | PFF_HASALPHA,
  499. /* Component type and count */
  500. PCT_BYTE, 4,
  501. /* rbits, gbits, bbits, abits */
  502. 0, 0, 0, 0,
  503. /* Masks and shifts */
  504. 0, 0, 0, 0, 0, 0, 0, 0
  505. },
  506. //-----------------------------------------------------------------------
  507. {"PF_FLOAT16_R",
  508. /* Bytes per element */
  509. 2,
  510. /* Flags */
  511. PFF_FLOAT,
  512. /* Component type and count */
  513. PCT_FLOAT16, 1,
  514. /* rbits, gbits, bbits, abits */
  515. 16, 0, 0, 0,
  516. /* Masks and shifts */
  517. 0, 0, 0, 0, 0, 0, 0, 0
  518. },
  519. //-----------------------------------------------------------------------
  520. {"PF_FLOAT16_RG",
  521. /* Bytes per element */
  522. 4,
  523. /* Flags */
  524. PFF_FLOAT,
  525. /* Component type and count */
  526. PCT_FLOAT16, 2,
  527. /* rbits, gbits, bbits, abits */
  528. 16, 16, 0, 0,
  529. /* Masks and shifts */
  530. 0, 0, 0, 0, 0, 0, 0, 0
  531. },
  532. //-----------------------------------------------------------------------
  533. {"PF_FLOAT16_RGB",
  534. /* Bytes per element */
  535. 6,
  536. /* Flags */
  537. PFF_FLOAT,
  538. /* Component type and count */
  539. PCT_FLOAT16, 3,
  540. /* rbits, gbits, bbits, abits */
  541. 16, 16, 16, 0,
  542. /* Masks and shifts */
  543. 0, 0, 0, 0, 0, 0, 0, 0
  544. },
  545. //-----------------------------------------------------------------------
  546. {"PF_FLOAT16_RGBA",
  547. /* Bytes per element */
  548. 8,
  549. /* Flags */
  550. PFF_FLOAT | PFF_HASALPHA,
  551. /* Component type and count */
  552. PCT_FLOAT16, 4,
  553. /* rbits, gbits, bbits, abits */
  554. 16, 16, 16, 16,
  555. /* Masks and shifts */
  556. 0, 0, 0, 0, 0, 0, 0, 0
  557. },
  558. //-----------------------------------------------------------------------
  559. {"PF_FLOAT32_R",
  560. /* Bytes per element */
  561. 4,
  562. /* Flags */
  563. PFF_FLOAT,
  564. /* Component type and count */
  565. PCT_FLOAT32, 1,
  566. /* rbits, gbits, bbits, abits */
  567. 32, 0, 0, 0,
  568. /* Masks and shifts */
  569. 0, 0, 0, 0, 0, 0, 0, 0
  570. },
  571. //-----------------------------------------------------------------------
  572. {"PF_FLOAT32_RG",
  573. /* Bytes per element */
  574. 8,
  575. /* Flags */
  576. PFF_FLOAT,
  577. /* Component type and count */
  578. PCT_FLOAT32, 2,
  579. /* rbits, gbits, bbits, abits */
  580. 32, 32, 0, 0,
  581. /* Masks and shifts */
  582. 0, 0, 0, 0, 0, 0, 0, 0
  583. },
  584. //-----------------------------------------------------------------------
  585. {"PF_FLOAT32_RGB",
  586. /* Bytes per element */
  587. 12,
  588. /* Flags */
  589. PFF_FLOAT,
  590. /* Component type and count */
  591. PCT_FLOAT32, 3,
  592. /* rbits, gbits, bbits, abits */
  593. 32, 32, 32, 0,
  594. /* Masks and shifts */
  595. 0, 0, 0, 0, 0, 0, 0, 0
  596. },
  597. //-----------------------------------------------------------------------
  598. {"PF_FLOAT32_RGBA",
  599. /* Bytes per element */
  600. 16,
  601. /* Flags */
  602. PFF_FLOAT | PFF_HASALPHA,
  603. /* Component type and count */
  604. PCT_FLOAT32, 4,
  605. /* rbits, gbits, bbits, abits */
  606. 32, 32, 32, 32,
  607. /* Masks and shifts */
  608. 0, 0, 0, 0, 0, 0, 0, 0
  609. },
  610. //-----------------------------------------------------------------------
  611. {"PF_D32_S8X24",
  612. /* Bytes per element */
  613. 8,
  614. /* Flags */
  615. PFF_DEPTH | PFF_FLOAT,
  616. /* Component type and count */
  617. PCT_FLOAT32, 2,
  618. /* rbits, gbits, bbits, abits */
  619. 0, 0, 0, 0,
  620. /* Masks and shifts */
  621. 0, 0, 0, 0, 0, 0, 0, 0
  622. },
  623. //-----------------------------------------------------------------------
  624. {"PF_D24_S8",
  625. /* Bytes per element */
  626. 4,
  627. /* Flags */
  628. PFF_DEPTH | PFF_FLOAT,
  629. /* Component type and count */
  630. PCT_FLOAT32, 1,
  631. /* rbits, gbits, bbits, abits */
  632. 0, 0, 0, 0,
  633. /* Masks and shifts */
  634. 0, 0, 0, 0, 0, 0, 0, 0
  635. },
  636. //-----------------------------------------------------------------------
  637. {"PF_D32",
  638. /* Bytes per element */
  639. 4,
  640. /* Flags */
  641. PFF_DEPTH | PFF_FLOAT,
  642. /* Component type and count */
  643. PCT_FLOAT32, 1,
  644. /* rbits, gbits, bbits, abits */
  645. 0, 0, 0, 0,
  646. /* Masks and shifts */
  647. 0, 0, 0, 0, 0, 0, 0, 0
  648. },
  649. //-----------------------------------------------------------------------
  650. {"PF_D16",
  651. /* Bytes per element */
  652. 2,
  653. /* Flags */
  654. PFF_DEPTH | PFF_FLOAT,
  655. /* Component type and count */
  656. PCT_FLOAT16, 1,
  657. /* rbits, gbits, bbits, abits */
  658. 0, 0, 0, 0,
  659. /* Masks and shifts */
  660. 0, 0, 0, 0, 0, 0, 0, 0
  661. },
  662. //-----------------------------------------------------------------------
  663. { "PF_FLOAT_R11G11B10",
  664. /* Bytes per element */
  665. 4,
  666. /* Flags */
  667. PFF_FLOAT,
  668. /* Component type and count */
  669. PCT_PACKED_R11G11B10, 1,
  670. /* rbits, gbits, bbits, abits */
  671. 11, 11, 10, 0,
  672. /* Masks and shifts */
  673. 0x000007FF, 0x003FF800, 0xFFC00000, 0,
  674. 0, 11, 22, 0
  675. },
  676. //-----------------------------------------------------------------------
  677. { "PF_UNORM_R10G10B10A2",
  678. /* Bytes per element */
  679. 4,
  680. /* Flags */
  681. PFF_FLOAT | PFF_HASALPHA,
  682. /* Component type and count */
  683. PCT_PACKED_R10G10B10A2, 1,
  684. /* rbits, gbits, bbits, abits */
  685. 10, 10, 10, 2,
  686. /* Masks and shifts */
  687. 0x000003FF, 0x000FFC00, 0x3FF00000, 0xC0000000,
  688. 0, 10, 20, 30
  689. },
  690. };
  691. static inline const PixelFormatDescription &getDescriptionFor(const PixelFormat fmt)
  692. {
  693. const int ord = (int)fmt;
  694. assert(ord>=0 && ord<PF_COUNT);
  695. return _pixelFormats[ord];
  696. }
  697. /** Handles compression output from NVTT library for a single image. */
  698. struct NVTTCompressOutputHandler : public nvtt::OutputHandler
  699. {
  700. NVTTCompressOutputHandler(UINT8* buffer, UINT32 sizeBytes)
  701. :buffer(buffer), bufferWritePos(buffer), bufferEnd(buffer + sizeBytes)
  702. { }
  703. virtual void beginImage(int size, int width, int height, int depth, int face, int miplevel) override
  704. { }
  705. virtual bool writeData(const void* data, int size) override
  706. {
  707. assert((bufferWritePos + size) <= bufferEnd);
  708. memcpy(bufferWritePos, data, size);
  709. bufferWritePos += size;
  710. return true;
  711. }
  712. UINT8* buffer;
  713. UINT8* bufferWritePos;
  714. UINT8* bufferEnd;
  715. };
  716. /** Handles output from NVTT library for a mip-map chain. */
  717. struct NVTTMipmapOutputHandler : public nvtt::OutputHandler
  718. {
  719. NVTTMipmapOutputHandler(const Vector<SPtr<PixelData>>& buffers)
  720. :buffers(buffers), bufferWritePos(nullptr), bufferEnd(nullptr)
  721. { }
  722. virtual void beginImage(int size, int width, int height, int depth, int face, int miplevel)
  723. {
  724. assert(miplevel >= 0 && miplevel < (int)buffers.size());
  725. assert(size == buffers[miplevel]->getConsecutiveSize());
  726. activeBuffer = buffers[miplevel];
  727. bufferWritePos = activeBuffer->getData();
  728. bufferEnd = bufferWritePos + activeBuffer->getConsecutiveSize();
  729. }
  730. virtual bool writeData(const void* data, int size)
  731. {
  732. assert((bufferWritePos + size) <= bufferEnd);
  733. memcpy(bufferWritePos, data, size);
  734. bufferWritePos += size;
  735. return true;
  736. }
  737. Vector<SPtr<PixelData>> buffers;
  738. SPtr<PixelData> activeBuffer;
  739. UINT8* bufferWritePos;
  740. UINT8* bufferEnd;
  741. };
  742. nvtt::Format toNVTTFormat(PixelFormat format)
  743. {
  744. switch (format)
  745. {
  746. case PF_BC1:
  747. return nvtt::Format_BC1;
  748. case PF_BC1a:
  749. return nvtt::Format_BC1a;
  750. case PF_BC2:
  751. return nvtt::Format_BC2;
  752. case PF_BC3:
  753. return nvtt::Format_BC3;
  754. case PF_BC4:
  755. return nvtt::Format_BC4;
  756. case PF_BC5:
  757. return nvtt::Format_BC5;
  758. default: // Unsupported format
  759. return nvtt::Format_BC3;
  760. }
  761. }
  762. nvtt::Quality toNVTTQuality(CompressionQuality quality)
  763. {
  764. switch (quality)
  765. {
  766. case CompressionQuality::Fastest:
  767. return nvtt::Quality_Fastest;
  768. case CompressionQuality::Highest:
  769. return nvtt::Quality_Highest;
  770. case CompressionQuality::Normal:
  771. return nvtt::Quality_Normal;
  772. case CompressionQuality::Production:
  773. return nvtt::Quality_Normal;
  774. }
  775. // Unknown quality level
  776. return nvtt::Quality_Normal;
  777. }
  778. nvtt::AlphaMode toNVTTAlphaMode(AlphaMode alphaMode)
  779. {
  780. switch (alphaMode)
  781. {
  782. case AlphaMode::None:
  783. return nvtt::AlphaMode_None;
  784. case AlphaMode::Premultiplied:
  785. return nvtt::AlphaMode_Premultiplied;
  786. case AlphaMode::Transparency:
  787. return nvtt::AlphaMode_Transparency;
  788. }
  789. // Unknown alpha mode
  790. return nvtt::AlphaMode_None;
  791. }
  792. nvtt::WrapMode toNVTTWrapMode(MipMapWrapMode wrapMode)
  793. {
  794. switch (wrapMode)
  795. {
  796. case MipMapWrapMode::Clamp:
  797. return nvtt::WrapMode_Clamp;
  798. case MipMapWrapMode::Mirror:
  799. return nvtt::WrapMode_Mirror;
  800. case MipMapWrapMode::Repeat:
  801. return nvtt::WrapMode_Repeat;
  802. }
  803. // Unknown alpha mode
  804. return nvtt::WrapMode_Mirror;
  805. }
  806. UINT32 PixelUtil::getNumElemBytes(PixelFormat format)
  807. {
  808. return getDescriptionFor(format).elemBytes;
  809. }
  810. UINT32 PixelUtil::getMemorySize(UINT32 width, UINT32 height, UINT32 depth, PixelFormat format)
  811. {
  812. if(isCompressed(format))
  813. {
  814. switch(format)
  815. {
  816. // BC formats work by dividing the image into 4x4 blocks, then encoding each
  817. // 4x4 block with a certain number of bytes.
  818. case PF_BC1:
  819. case PF_BC1a:
  820. case PF_BC4:
  821. return ((width+3)/4)*((height+3)/4)*8 * depth;
  822. case PF_BC2:
  823. case PF_BC3:
  824. case PF_BC5:
  825. case PF_BC6H:
  826. case PF_BC7:
  827. return ((width+3)/4)*((height+3)/4)*16 * depth;
  828. default:
  829. BS_EXCEPT(InvalidParametersException, "Invalid compressed pixel format");
  830. return 0;
  831. }
  832. }
  833. return width*height*depth*getNumElemBytes(format);
  834. }
  835. void PixelUtil::getPitch(UINT32 width, UINT32 height, UINT32 depth, PixelFormat format,
  836. UINT32& rowPitch, UINT32& depthPitch)
  837. {
  838. if (isCompressed(format))
  839. {
  840. switch (format)
  841. {
  842. // BC formats work by dividing the image into 4x4 blocks, then encoding each
  843. // 4x4 block with a certain number of bytes.
  844. case PF_BC1:
  845. case PF_BC1a:
  846. case PF_BC4:
  847. case PF_BC2:
  848. case PF_BC3:
  849. case PF_BC5:
  850. case PF_BC6H:
  851. case PF_BC7:
  852. rowPitch = div(width + 3, 4).quot * 4;
  853. depthPitch = div(height + 3, 4).quot * 4 * rowPitch;
  854. return;
  855. default:
  856. BS_EXCEPT(InvalidParametersException, "Invalid compressed pixel format");
  857. return;
  858. }
  859. }
  860. rowPitch = width;
  861. depthPitch = width * height;
  862. }
  863. void PixelUtil::getSizeForMipLevel(UINT32 width, UINT32 height, UINT32 depth, UINT32 mipLevel,
  864. UINT32& mipWidth, UINT32& mipHeight, UINT32& mipDepth)
  865. {
  866. mipWidth = width;
  867. mipHeight = height;
  868. mipDepth = depth;
  869. for (UINT32 i = 0; i < mipLevel; i++)
  870. {
  871. if (mipWidth != 1) mipWidth /= 2;
  872. if (mipHeight != 1) mipHeight /= 2;
  873. if (mipDepth != 1) mipDepth /= 2;
  874. }
  875. }
  876. UINT32 PixelUtil::getNumElemBits(PixelFormat format)
  877. {
  878. return getDescriptionFor(format).elemBytes * 8;
  879. }
  880. UINT32 PixelUtil::getFlags(PixelFormat format)
  881. {
  882. return getDescriptionFor(format).flags;
  883. }
  884. bool PixelUtil::hasAlpha(PixelFormat format)
  885. {
  886. return (PixelUtil::getFlags(format) & PFF_HASALPHA) > 0;
  887. }
  888. bool PixelUtil::isFloatingPoint(PixelFormat format)
  889. {
  890. return (PixelUtil::getFlags(format) & PFF_FLOAT) > 0;
  891. }
  892. bool PixelUtil::isCompressed(PixelFormat format)
  893. {
  894. return (PixelUtil::getFlags(format) & PFF_COMPRESSED) > 0;
  895. }
  896. bool PixelUtil::isDepth(PixelFormat format)
  897. {
  898. return (PixelUtil::getFlags(format) & PFF_DEPTH) > 0;
  899. }
  900. bool PixelUtil::isNativeEndian(PixelFormat format)
  901. {
  902. return (PixelUtil::getFlags(format) & PFF_NATIVEENDIAN) > 0;
  903. }
  904. bool PixelUtil::isValidExtent(UINT32 width, UINT32 height, UINT32 depth, PixelFormat format)
  905. {
  906. if(isCompressed(format))
  907. {
  908. switch(format)
  909. {
  910. case PF_BC1:
  911. case PF_BC2:
  912. case PF_BC1a:
  913. case PF_BC3:
  914. case PF_BC4:
  915. case PF_BC5:
  916. case PF_BC6H:
  917. case PF_BC7:
  918. return ((width & 3) == 0 && (height & 3) == 0 && depth == 1);
  919. default:
  920. return true;
  921. }
  922. }
  923. else
  924. {
  925. return true;
  926. }
  927. }
  928. void PixelUtil::getBitDepths(PixelFormat format, int rgba[4])
  929. {
  930. const PixelFormatDescription& des = getDescriptionFor(format);
  931. rgba[0] = des.rbits;
  932. rgba[1] = des.gbits;
  933. rgba[2] = des.bbits;
  934. rgba[3] = des.abits;
  935. }
  936. void PixelUtil::getBitMasks(PixelFormat format, UINT32 rgba[4])
  937. {
  938. const PixelFormatDescription& des = getDescriptionFor(format);
  939. rgba[0] = des.rmask;
  940. rgba[1] = des.gmask;
  941. rgba[2] = des.bmask;
  942. rgba[3] = des.amask;
  943. }
  944. void PixelUtil::getBitShifts(PixelFormat format, UINT8 rgba[4])
  945. {
  946. const PixelFormatDescription& des = getDescriptionFor(format);
  947. rgba[0] = des.rshift;
  948. rgba[1] = des.gshift;
  949. rgba[2] = des.bshift;
  950. rgba[3] = des.ashift;
  951. }
  952. String PixelUtil::getFormatName(PixelFormat srcformat)
  953. {
  954. return getDescriptionFor(srcformat).name;
  955. }
  956. bool PixelUtil::isAccessible(PixelFormat srcformat)
  957. {
  958. if (srcformat == PF_UNKNOWN)
  959. return false;
  960. UINT32 flags = getFlags(srcformat);
  961. return !((flags & PFF_COMPRESSED) || (flags & PFF_DEPTH));
  962. }
  963. PixelComponentType PixelUtil::getElementType(PixelFormat format)
  964. {
  965. const PixelFormatDescription& des = getDescriptionFor(format);
  966. return des.componentType;
  967. }
  968. UINT32 PixelUtil::getNumElements(PixelFormat format)
  969. {
  970. const PixelFormatDescription& des = getDescriptionFor(format);
  971. return des.componentCount;
  972. }
  973. UINT32 PixelUtil::getMaxMipmaps(UINT32 width, UINT32 height, UINT32 depth, PixelFormat format)
  974. {
  975. UINT32 count = 0;
  976. if((width > 0) && (height > 0))
  977. {
  978. do {
  979. if(width>1) width = width/2;
  980. if(height>1) height = height/2;
  981. if(depth>1) depth = depth/2;
  982. count ++;
  983. } while(!(width == 1 && height == 1 && depth == 1));
  984. }
  985. return count;
  986. }
  987. void PixelUtil::packColor(const Color& color, PixelFormat format, void* dest)
  988. {
  989. packColor(color.r, color.g, color.b, color.a, format, dest);
  990. }
  991. void PixelUtil::packColor(UINT8 r, UINT8 g, UINT8 b, UINT8 a, PixelFormat format, void* dest)
  992. {
  993. const PixelFormatDescription &des = getDescriptionFor(format);
  994. if(des.flags & PFF_NATIVEENDIAN)
  995. {
  996. // Shortcut for integer formats packing
  997. UINT32 value = ((Bitwise::fixedToFixed(r, 8, des.rbits)<<des.rshift) & des.rmask) |
  998. ((Bitwise::fixedToFixed(g, 8, des.gbits)<<des.gshift) & des.gmask) |
  999. ((Bitwise::fixedToFixed(b, 8, des.bbits)<<des.bshift) & des.bmask) |
  1000. ((Bitwise::fixedToFixed(a, 8, des.abits)<<des.ashift) & des.amask);
  1001. // And write to memory
  1002. Bitwise::intWrite(dest, des.elemBytes, value);
  1003. }
  1004. else
  1005. {
  1006. // Convert to float
  1007. packColor((float)r/255.0f,(float)g/255.0f,(float)b/255.0f,(float)a/255.0f, format, dest);
  1008. }
  1009. }
  1010. void PixelUtil::packColor(float r, float g, float b, float a, const PixelFormat format, void* dest)
  1011. {
  1012. const PixelFormatDescription& des = getDescriptionFor(format);
  1013. if(des.flags & PFF_NATIVEENDIAN)
  1014. {
  1015. // Do the packing
  1016. const unsigned int value = ((Bitwise::floatToFixed(r, des.rbits)<<des.rshift) & des.rmask) |
  1017. ((Bitwise::floatToFixed(g, des.gbits)<<des.gshift) & des.gmask) |
  1018. ((Bitwise::floatToFixed(b, des.bbits)<<des.bshift) & des.bmask) |
  1019. ((Bitwise::floatToFixed(a, des.abits)<<des.ashift) & des.amask);
  1020. // And write to memory
  1021. Bitwise::intWrite(dest, des.elemBytes, value);
  1022. }
  1023. else
  1024. {
  1025. switch(format)
  1026. {
  1027. case PF_FLOAT32_R:
  1028. ((float*)dest)[0] = r;
  1029. break;
  1030. case PF_FLOAT32_RG:
  1031. ((float*)dest)[0] = r;
  1032. ((float*)dest)[1] = g;
  1033. break;
  1034. case PF_FLOAT32_RGB:
  1035. ((float*)dest)[0] = r;
  1036. ((float*)dest)[1] = g;
  1037. ((float*)dest)[2] = b;
  1038. break;
  1039. case PF_FLOAT32_RGBA:
  1040. ((float*)dest)[0] = r;
  1041. ((float*)dest)[1] = g;
  1042. ((float*)dest)[2] = b;
  1043. ((float*)dest)[3] = a;
  1044. break;
  1045. case PF_FLOAT16_R:
  1046. ((UINT16*)dest)[0] = Bitwise::floatToHalf(r);
  1047. break;
  1048. case PF_FLOAT16_RG:
  1049. ((UINT16*)dest)[0] = Bitwise::floatToHalf(r);
  1050. ((UINT16*)dest)[1] = Bitwise::floatToHalf(g);
  1051. break;
  1052. case PF_FLOAT16_RGB:
  1053. ((UINT16*)dest)[0] = Bitwise::floatToHalf(r);
  1054. ((UINT16*)dest)[1] = Bitwise::floatToHalf(g);
  1055. ((UINT16*)dest)[2] = Bitwise::floatToHalf(b);
  1056. break;
  1057. case PF_FLOAT16_RGBA:
  1058. ((UINT16*)dest)[0] = Bitwise::floatToHalf(r);
  1059. ((UINT16*)dest)[1] = Bitwise::floatToHalf(g);
  1060. ((UINT16*)dest)[2] = Bitwise::floatToHalf(b);
  1061. ((UINT16*)dest)[3] = Bitwise::floatToHalf(a);
  1062. break;
  1063. case PF_R8G8:
  1064. ((UINT8*)dest)[0] = (UINT8)Bitwise::floatToFixed(r, 8);
  1065. ((UINT8*)dest)[1] = (UINT8)Bitwise::floatToFixed(g, 8);
  1066. break;
  1067. case PF_R8:
  1068. ((UINT8*)dest)[0] = (UINT8)Bitwise::floatToFixed(r, 8);
  1069. break;
  1070. default:
  1071. LOGERR("Pack to " + getFormatName(format) + " not implemented");
  1072. break;
  1073. }
  1074. }
  1075. }
  1076. void PixelUtil::unpackColor(Color* color, PixelFormat format, const void* src)
  1077. {
  1078. unpackColor(&color->r, &color->g, &color->b, &color->a, format, src);
  1079. }
  1080. void PixelUtil::unpackColor(UINT8* r, UINT8* g, UINT8* b, UINT8* a, PixelFormat format, const void* src)
  1081. {
  1082. const PixelFormatDescription &des = getDescriptionFor(format);
  1083. if(des.flags & PFF_NATIVEENDIAN)
  1084. {
  1085. // Shortcut for integer formats unpacking
  1086. const UINT32 value = Bitwise::intRead(src, des.elemBytes);
  1087. *r = (UINT8)Bitwise::fixedToFixed((value & des.rmask)>>des.rshift, des.rbits, 8);
  1088. *g = (UINT8)Bitwise::fixedToFixed((value & des.gmask)>>des.gshift, des.gbits, 8);
  1089. *b = (UINT8)Bitwise::fixedToFixed((value & des.bmask)>>des.bshift, des.bbits, 8);
  1090. if(des.flags & PFF_HASALPHA)
  1091. {
  1092. *a = (UINT8)Bitwise::fixedToFixed((value & des.amask)>>des.ashift, des.abits, 8);
  1093. }
  1094. else
  1095. {
  1096. *a = 255; // No alpha, default a component to full
  1097. }
  1098. }
  1099. else
  1100. {
  1101. // Do the operation with the more generic floating point
  1102. float rr, gg, bb, aa;
  1103. unpackColor(&rr,&gg,&bb,&aa, format, src);
  1104. *r = (UINT8)Bitwise::floatToFixed(rr, 8);
  1105. *g = (UINT8)Bitwise::floatToFixed(gg, 8);
  1106. *b = (UINT8)Bitwise::floatToFixed(bb, 8);
  1107. *a = (UINT8)Bitwise::floatToFixed(aa, 8);
  1108. }
  1109. }
  1110. void PixelUtil::unpackColor(float* r, float* g, float* b, float* a, PixelFormat format, const void* src)
  1111. {
  1112. const PixelFormatDescription &des = getDescriptionFor(format);
  1113. if(des.flags & PFF_NATIVEENDIAN)
  1114. {
  1115. // Shortcut for integer formats unpacking
  1116. const unsigned int value = Bitwise::intRead(src, des.elemBytes);
  1117. *r = Bitwise::fixedToFloat((value & des.rmask)>>des.rshift, des.rbits);
  1118. *g = Bitwise::fixedToFloat((value & des.gmask)>>des.gshift, des.gbits);
  1119. *b = Bitwise::fixedToFloat((value & des.bmask)>>des.bshift, des.bbits);
  1120. if(des.flags & PFF_HASALPHA)
  1121. {
  1122. *a = Bitwise::fixedToFloat((value & des.amask)>>des.ashift, des.abits);
  1123. }
  1124. else
  1125. {
  1126. *a = 1.0f; // No alpha, default a component to full
  1127. }
  1128. }
  1129. else
  1130. {
  1131. switch(format)
  1132. {
  1133. case PF_FLOAT32_R:
  1134. *r = *g = *b = ((float*)src)[0];
  1135. *a = 1.0f;
  1136. break;
  1137. case PF_FLOAT32_RG:
  1138. *r = ((float*)src)[0];
  1139. *g = *b = ((float*)src)[1];
  1140. *a = 1.0f;
  1141. break;
  1142. case PF_FLOAT32_RGB:
  1143. *r = ((float*)src)[0];
  1144. *g = ((float*)src)[1];
  1145. *b = ((float*)src)[2];
  1146. *a = 1.0f;
  1147. break;
  1148. case PF_FLOAT32_RGBA:
  1149. *r = ((float*)src)[0];
  1150. *g = ((float*)src)[1];
  1151. *b = ((float*)src)[2];
  1152. *a = ((float*)src)[3];
  1153. break;
  1154. case PF_FLOAT16_R:
  1155. *r = *g = *b = Bitwise::halfToFloat(((UINT16*)src)[0]);
  1156. *a = 1.0f;
  1157. break;
  1158. case PF_FLOAT16_RG:
  1159. *r = Bitwise::halfToFloat(((UINT16*)src)[0]);
  1160. *g = *b = Bitwise::halfToFloat(((UINT16*)src)[1]);
  1161. *a = 1.0f;
  1162. break;
  1163. case PF_FLOAT16_RGB:
  1164. *r = Bitwise::halfToFloat(((UINT16*)src)[0]);
  1165. *g = Bitwise::halfToFloat(((UINT16*)src)[1]);
  1166. *b = Bitwise::halfToFloat(((UINT16*)src)[2]);
  1167. *a = 1.0f;
  1168. break;
  1169. case PF_FLOAT16_RGBA:
  1170. *r = Bitwise::halfToFloat(((UINT16*)src)[0]);
  1171. *g = Bitwise::halfToFloat(((UINT16*)src)[1]);
  1172. *b = Bitwise::halfToFloat(((UINT16*)src)[2]);
  1173. *a = Bitwise::halfToFloat(((UINT16*)src)[3]);
  1174. break;
  1175. case PF_R8G8:
  1176. *r = Bitwise::fixedToFloat(((UINT8*)src)[0], 8);
  1177. *g = Bitwise::fixedToFloat(((UINT8*)src)[1], 8);
  1178. *b = 0.0f;
  1179. *a = 1.0f;
  1180. break;
  1181. case PF_R8:
  1182. *r = Bitwise::fixedToFloat(((UINT8*)src)[0], 8);
  1183. *g = 0.0f;
  1184. *b = 0.0f;
  1185. *a = 1.0f;
  1186. break;
  1187. default:
  1188. LOGERR("Unpack from " + getFormatName(format) + " not implemented");
  1189. break;
  1190. }
  1191. }
  1192. }
  1193. void PixelUtil::packDepth(float depth, const PixelFormat format, void* dest)
  1194. {
  1195. if (!isDepth(format))
  1196. {
  1197. LOGERR("Cannot convert depth to " + getFormatName(format) + ": it is not a depth format");
  1198. return;
  1199. }
  1200. LOGERR("Method is not implemented");
  1201. //TODO implement depth packing
  1202. }
  1203. float PixelUtil::unpackDepth(PixelFormat format, void* src)
  1204. {
  1205. const PixelFormatDescription &des = getDescriptionFor(format);
  1206. if (!isDepth(format))
  1207. {
  1208. LOGERR("Cannot unpack from " + getFormatName(format) + ": it is not a depth format");
  1209. return 0;
  1210. }
  1211. UINT32* color = (UINT32 *)src;
  1212. switch (format)
  1213. {
  1214. case PF_D24S8:
  1215. return static_cast<float>(*color & 0x00FFFFFF) / (float)16777216;
  1216. break;
  1217. case PF_D16:
  1218. return static_cast<float>(*color & 0xFFFF) / (float)65536;
  1219. break;
  1220. case PF_D32:
  1221. return static_cast<float>(*color & 0xFFFFFFFF) / (float)4294967296;
  1222. break;
  1223. case PF_D32_S8X24:
  1224. return static_cast<float>(*color & 0xFFFFFFFF) / (float)4294967296;
  1225. break;
  1226. default:
  1227. LOGERR("Cannot unpack from " + getFormatName(format));
  1228. return 0;
  1229. break;
  1230. }
  1231. }
  1232. void PixelUtil::bulkPixelConversion(const PixelData &src, PixelData &dst)
  1233. {
  1234. assert(src.getWidth() == dst.getWidth() &&
  1235. src.getHeight() == dst.getHeight() &&
  1236. src.getDepth() == dst.getDepth());
  1237. // Check for compressed formats, we don't support decompression
  1238. if(PixelUtil::isCompressed(src.getFormat()))
  1239. {
  1240. if(src.getFormat() == dst.getFormat())
  1241. {
  1242. memcpy(dst.getData(), src.getData(), src.getConsecutiveSize());
  1243. return;
  1244. }
  1245. else
  1246. {
  1247. LOGERR("bulkPixelConversion() cannot be used to compress or decompress images");
  1248. return;
  1249. }
  1250. }
  1251. // Check for compression
  1252. if (PixelUtil::isCompressed(dst.getFormat()))
  1253. {
  1254. if (src.getFormat() == dst.getFormat())
  1255. {
  1256. memcpy(dst.getData(), src.getData(), src.getConsecutiveSize());
  1257. return;
  1258. }
  1259. else
  1260. {
  1261. CompressionOptions co;
  1262. co.format = dst.getFormat();
  1263. compress(src, dst, co);
  1264. return;
  1265. }
  1266. }
  1267. // The easy case
  1268. if(src.getFormat() == dst.getFormat())
  1269. {
  1270. // Everything consecutive?
  1271. if(src.isConsecutive() && dst.isConsecutive())
  1272. {
  1273. memcpy(dst.getData(), src.getData(), src.getConsecutiveSize());
  1274. return;
  1275. }
  1276. const UINT32 srcPixelSize = PixelUtil::getNumElemBytes(src.getFormat());
  1277. const UINT32 dstPixelSize = PixelUtil::getNumElemBytes(dst.getFormat());
  1278. UINT8 *srcptr = static_cast<UINT8*>(src.getData())
  1279. + (src.getLeft() + src.getTop() * src.getRowPitch() + src.getFront() * src.getSlicePitch()) * srcPixelSize;
  1280. UINT8 *dstptr = static_cast<UINT8*>(dst.getData())
  1281. + (dst.getLeft() + dst.getTop() * dst.getRowPitch() + dst.getFront() * dst.getSlicePitch()) * dstPixelSize;
  1282. // Calculate pitches+skips in bytes
  1283. const UINT32 srcRowPitchBytes = src.getRowPitch()*srcPixelSize;
  1284. const UINT32 srcSliceSkipBytes = src.getSliceSkip()*srcPixelSize;
  1285. const UINT32 dstRowPitchBytes = dst.getRowPitch()*dstPixelSize;
  1286. const UINT32 dstSliceSkipBytes = dst.getSliceSkip()*dstPixelSize;
  1287. // Otherwise, copy per row
  1288. const UINT32 rowSize = src.getWidth()*srcPixelSize;
  1289. for (UINT32 z = src.getFront(); z < src.getBack(); z++)
  1290. {
  1291. for(UINT32 y = src.getTop(); y < src.getBottom(); y++)
  1292. {
  1293. memcpy(dstptr, srcptr, rowSize);
  1294. srcptr += srcRowPitchBytes;
  1295. dstptr += dstRowPitchBytes;
  1296. }
  1297. srcptr += srcSliceSkipBytes;
  1298. dstptr += dstSliceSkipBytes;
  1299. }
  1300. return;
  1301. }
  1302. const UINT32 srcPixelSize = PixelUtil::getNumElemBytes(src.getFormat());
  1303. const UINT32 dstPixelSize = PixelUtil::getNumElemBytes(dst.getFormat());
  1304. UINT8 *srcptr = static_cast<UINT8*>(src.getData())
  1305. + (src.getLeft() + src.getTop() * src.getRowPitch() + src.getFront() * src.getSlicePitch()) * srcPixelSize;
  1306. UINT8 *dstptr = static_cast<UINT8*>(dst.getData())
  1307. + (dst.getLeft() + dst.getTop() * dst.getRowPitch() + dst.getFront() * dst.getSlicePitch()) * dstPixelSize;
  1308. // Calculate pitches+skips in bytes
  1309. const UINT32 srcRowSkipBytes = src.getRowSkip()*srcPixelSize;
  1310. const UINT32 srcSliceSkipBytes = src.getSliceSkip()*srcPixelSize;
  1311. const UINT32 dstRowSkipBytes = dst.getRowSkip()*dstPixelSize;
  1312. const UINT32 dstSliceSkipBytes = dst.getSliceSkip()*dstPixelSize;
  1313. // The brute force fallback
  1314. float r,g,b,a;
  1315. for (UINT32 z = src.getFront(); z<src.getBack(); z++)
  1316. {
  1317. for (UINT32 y = src.getTop(); y < src.getBottom(); y++)
  1318. {
  1319. for (UINT32 x = src.getLeft(); x<src.getRight(); x++)
  1320. {
  1321. unpackColor(&r, &g, &b, &a, src.getFormat(), srcptr);
  1322. packColor(r, g, b, a, dst.getFormat(), dstptr);
  1323. srcptr += srcPixelSize;
  1324. dstptr += dstPixelSize;
  1325. }
  1326. srcptr += srcRowSkipBytes;
  1327. dstptr += dstRowSkipBytes;
  1328. }
  1329. srcptr += srcSliceSkipBytes;
  1330. dstptr += dstSliceSkipBytes;
  1331. }
  1332. }
  1333. void PixelUtil::scale(const PixelData& src, PixelData& scaled, Filter filter)
  1334. {
  1335. assert(PixelUtil::isAccessible(src.getFormat()));
  1336. assert(PixelUtil::isAccessible(scaled.getFormat()));
  1337. PixelData temp;
  1338. switch (filter)
  1339. {
  1340. default:
  1341. case FILTER_NEAREST:
  1342. if(src.getFormat() == scaled.getFormat())
  1343. {
  1344. // No intermediate buffer needed
  1345. temp = scaled;
  1346. }
  1347. else
  1348. {
  1349. // Allocate temporary buffer of destination size in source format
  1350. temp = PixelData(scaled.getWidth(), scaled.getHeight(), scaled.getDepth(), src.getFormat());
  1351. temp.allocateInternalBuffer();
  1352. }
  1353. // No conversion
  1354. switch (PixelUtil::getNumElemBytes(src.getFormat()))
  1355. {
  1356. case 1: NearestResampler<1>::scale(src, temp); break;
  1357. case 2: NearestResampler<2>::scale(src, temp); break;
  1358. case 3: NearestResampler<3>::scale(src, temp); break;
  1359. case 4: NearestResampler<4>::scale(src, temp); break;
  1360. case 6: NearestResampler<6>::scale(src, temp); break;
  1361. case 8: NearestResampler<8>::scale(src, temp); break;
  1362. case 12: NearestResampler<12>::scale(src, temp); break;
  1363. case 16: NearestResampler<16>::scale(src, temp); break;
  1364. default:
  1365. // Never reached
  1366. assert(false);
  1367. }
  1368. if(temp.getData() != scaled.getData())
  1369. {
  1370. // Blit temp buffer
  1371. PixelUtil::bulkPixelConversion(temp, scaled);
  1372. temp.freeInternalBuffer();
  1373. }
  1374. break;
  1375. case FILTER_LINEAR:
  1376. switch (src.getFormat())
  1377. {
  1378. case PF_R8G8:
  1379. case PF_R8G8B8: case PF_B8G8R8:
  1380. case PF_R8G8B8A8: case PF_B8G8R8A8:
  1381. if(src.getFormat() == scaled.getFormat())
  1382. {
  1383. // No intermediate buffer needed
  1384. temp = scaled;
  1385. }
  1386. else
  1387. {
  1388. // Allocate temp buffer of destination size in source format
  1389. temp = PixelData(scaled.getWidth(), scaled.getHeight(), scaled.getDepth(), src.getFormat());
  1390. temp.allocateInternalBuffer();
  1391. }
  1392. // No conversion
  1393. switch (PixelUtil::getNumElemBytes(src.getFormat()))
  1394. {
  1395. case 1: LinearResampler_Byte<1>::scale(src, temp); break;
  1396. case 2: LinearResampler_Byte<2>::scale(src, temp); break;
  1397. case 3: LinearResampler_Byte<3>::scale(src, temp); break;
  1398. case 4: LinearResampler_Byte<4>::scale(src, temp); break;
  1399. default:
  1400. // Never reached
  1401. assert(false);
  1402. }
  1403. if(temp.getData() != scaled.getData())
  1404. {
  1405. // Blit temp buffer
  1406. PixelUtil::bulkPixelConversion(temp, scaled);
  1407. temp.freeInternalBuffer();
  1408. }
  1409. break;
  1410. case PF_FLOAT32_RGB:
  1411. case PF_FLOAT32_RGBA:
  1412. if (scaled.getFormat() == PF_FLOAT32_RGB || scaled.getFormat() == PF_FLOAT32_RGBA)
  1413. {
  1414. // float32 to float32, avoid unpack/repack overhead
  1415. LinearResampler_Float32::scale(src, scaled);
  1416. break;
  1417. }
  1418. // Else, fall through
  1419. default:
  1420. // Fallback case, slow but works
  1421. LinearResampler::scale(src, scaled);
  1422. }
  1423. break;
  1424. }
  1425. }
  1426. void PixelUtil::copy(const PixelData& src, PixelData& dst, UINT32 offsetX, UINT32 offsetY, UINT32 offsetZ)
  1427. {
  1428. if(src.getFormat() != dst.getFormat())
  1429. {
  1430. LOGERR("Source format is different from destination format for copy(). This operation cannot be used for "
  1431. "a format conversion. Aborting copy.");
  1432. return;
  1433. }
  1434. UINT32 right = offsetX + dst.getWidth();
  1435. UINT32 bottom = offsetY + dst.getHeight();
  1436. UINT32 back = offsetZ + dst.getDepth();
  1437. if(right > src.getWidth() || bottom > src.getHeight() || back > src.getDepth())
  1438. {
  1439. LOGERR("Provided offset or destination size is too large and is referencing pixels that are out of bounds"
  1440. " on the source texture. Aborting copy().");
  1441. return;
  1442. }
  1443. UINT8* srcPtr = (UINT8*)src.getData() + offsetZ * src.getSlicePitch();
  1444. UINT8* dstPtr = (UINT8*)dst.getData();
  1445. UINT32 elemSize = getNumElemBytes(dst.getFormat());
  1446. UINT32 rowSize = dst.getWidth() * elemSize;
  1447. for(UINT32 z = 0; z < dst.getDepth(); z++)
  1448. {
  1449. UINT8* srcRowPtr = srcPtr + offsetY * src.getRowPitch() * elemSize;
  1450. UINT8* dstRowPtr = dstPtr;
  1451. for(UINT32 y = 0; y < dst.getHeight(); y++)
  1452. {
  1453. memcpy(dstRowPtr, srcRowPtr + offsetX * elemSize, rowSize);
  1454. srcRowPtr += src.getRowPitch() * elemSize;
  1455. dstRowPtr += dst.getRowPitch() * elemSize;
  1456. }
  1457. srcPtr += src.getSlicePitch() * elemSize;
  1458. dstPtr += dst.getSlicePitch() * elemSize;
  1459. }
  1460. }
  1461. void PixelUtil::mirror(PixelData& pixelData, MirrorMode mode)
  1462. {
  1463. UINT32 width = pixelData.getWidth();
  1464. UINT32 height = pixelData.getHeight();
  1465. UINT32 depth = pixelData.getDepth();
  1466. UINT32 elemSize = getNumElemBytes(pixelData.getFormat());
  1467. if (mode.isSet(MirrorModeBits::Z))
  1468. {
  1469. UINT32 sliceSize = width * height * elemSize;
  1470. UINT8* sliceTemp = bs_stack_alloc<UINT8>(sliceSize);
  1471. UINT8* dataPtr = pixelData.getData();
  1472. UINT32 halfDepth = depth / 2;
  1473. for (UINT32 z = 0; z < halfDepth; z++)
  1474. {
  1475. UINT32 srcZ = z * sliceSize;
  1476. UINT32 dstZ = (depth - z - 1) * sliceSize;
  1477. memcpy(sliceTemp, &dataPtr[dstZ], sliceSize);
  1478. memcpy(&dataPtr[srcZ], &dataPtr[srcZ], sliceSize);
  1479. memcpy(&dataPtr[dstZ], sliceTemp, sliceSize);
  1480. }
  1481. // Note: If flipping Y or X as well I could do it here without an extra set of memcpys
  1482. bs_stack_free(sliceTemp);
  1483. }
  1484. if(mode.isSet(MirrorModeBits::Y))
  1485. {
  1486. UINT32 rowSize = width * elemSize;
  1487. UINT8* rowTemp = bs_stack_alloc<UINT8>(rowSize);
  1488. UINT8* slicePtr = pixelData.getData();
  1489. for (UINT32 z = 0; z < depth; z++)
  1490. {
  1491. UINT32 halfHeight = height / 2;
  1492. for (UINT32 y = 0; y < halfHeight; y++)
  1493. {
  1494. UINT32 srcY = y * rowSize;
  1495. UINT32 dstY = (height - y - 1) * rowSize;
  1496. memcpy(rowTemp, &slicePtr[dstY], rowSize);
  1497. memcpy(&slicePtr[dstY], &slicePtr[srcY], rowSize);
  1498. memcpy(&slicePtr[srcY], rowTemp, rowSize);
  1499. }
  1500. // Note: If flipping X as well I could do it here without an extra set of memcpys
  1501. slicePtr += pixelData.getSlicePitch() * elemSize;
  1502. }
  1503. bs_stack_free(rowTemp);
  1504. }
  1505. if (mode.isSet(MirrorModeBits::X))
  1506. {
  1507. UINT8* elemTemp = bs_stack_alloc<UINT8>(elemSize);
  1508. UINT8* slicePtr = pixelData.getData();
  1509. for (UINT32 z = 0; z < depth; z++)
  1510. {
  1511. UINT8* rowPtr = slicePtr;
  1512. for (UINT32 y = 0; y < height; y++)
  1513. {
  1514. UINT32 halfWidth = width / 2;
  1515. for (UINT32 x = 0; x < halfWidth; x++)
  1516. {
  1517. UINT32 srcX = x * elemSize;
  1518. UINT32 dstX = (width - x - 1) * elemSize;
  1519. memcpy(elemTemp, &rowPtr[dstX], elemSize);
  1520. memcpy(&rowPtr[dstX], &rowPtr[srcX], elemSize);
  1521. memcpy(&rowPtr[srcX], elemTemp, elemSize);
  1522. }
  1523. rowPtr += pixelData.getRowPitch() * elemSize;
  1524. }
  1525. slicePtr += pixelData.getSlicePitch() * elemSize;
  1526. }
  1527. bs_stack_free(elemTemp);
  1528. }
  1529. }
  1530. void PixelUtil::applyGamma(UINT8* buffer, float gamma, UINT32 size, UINT8 bpp)
  1531. {
  1532. if(gamma == 1.0f)
  1533. return;
  1534. UINT32 stride = bpp >> 3;
  1535. for(size_t i = 0, j = size / stride; i < j; i++, buffer += stride)
  1536. {
  1537. float r = (float)buffer[0];
  1538. float g = (float)buffer[1];
  1539. float b = (float)buffer[2];
  1540. r = r * gamma;
  1541. g = g * gamma;
  1542. b = b * gamma;
  1543. float scale = 1.0f;
  1544. float tmp = 0.0f;
  1545. if(r > 255.0f && (tmp=(255.0f/r)) < scale)
  1546. scale = tmp;
  1547. if(g > 255.0f && (tmp=(255.0f/g)) < scale)
  1548. scale = tmp;
  1549. if(b > 255.0f && (tmp=(255.0f/b)) < scale)
  1550. scale = tmp;
  1551. r *= scale;
  1552. g *= scale;
  1553. b *= scale;
  1554. buffer[0] = (UINT8)r;
  1555. buffer[1] = (UINT8)g;
  1556. buffer[2] = (UINT8)b;
  1557. }
  1558. }
  1559. void PixelUtil::compress(const PixelData& src, PixelData& dst, const CompressionOptions& options)
  1560. {
  1561. if (!isCompressed(options.format))
  1562. {
  1563. LOGERR("Compression failed. Destination format is not a valid compressed format.")
  1564. return;
  1565. }
  1566. // Note: NVTT site has implementations for these two formats for when I decide to add them
  1567. if (options.format == PF_BC6H || options.format == PF_BC7)
  1568. {
  1569. LOGERR("Compression failed. BC6H and BC7 formats are currently not supported.")
  1570. return;
  1571. }
  1572. if (src.getDepth() != 1)
  1573. {
  1574. LOGERR("Compression failed. 3D texture compression not supported.")
  1575. return;
  1576. }
  1577. if (isCompressed(src.getFormat()))
  1578. {
  1579. LOGERR("Compression failed. Source data cannot be compressed.");
  1580. return;
  1581. }
  1582. PixelData bgraData(src.getWidth(), src.getHeight(), 1, PF_R8G8B8A8);
  1583. bgraData.allocateInternalBuffer();
  1584. bulkPixelConversion(src, bgraData);
  1585. nvtt::InputOptions io;
  1586. io.setTextureLayout(nvtt::TextureType_2D, src.getWidth(), src.getHeight());
  1587. io.setMipmapData(bgraData.getData(), src.getWidth(), src.getHeight());
  1588. io.setMipmapGeneration(false);
  1589. io.setAlphaMode(toNVTTAlphaMode(options.alphaMode));
  1590. io.setNormalMap(options.isNormalMap);
  1591. if (options.isSRGB)
  1592. io.setGamma(2.2f, 2.2f);
  1593. else
  1594. io.setGamma(1.0f, 1.0f);
  1595. nvtt::CompressionOptions co;
  1596. co.setFormat(toNVTTFormat(options.format));
  1597. co.setQuality(toNVTTQuality(options.quality));
  1598. NVTTCompressOutputHandler outputHandler(dst.getData(), dst.getConsecutiveSize());
  1599. nvtt::OutputOptions oo;
  1600. oo.setOutputHeader(false);
  1601. oo.setOutputHandler(&outputHandler);
  1602. nvtt::Compressor compressor;
  1603. if (!compressor.process(io, co, oo))
  1604. {
  1605. LOGERR("Compression failed. Internal error.");
  1606. return;
  1607. }
  1608. }
  1609. Vector<SPtr<PixelData>> PixelUtil::genMipmaps(const PixelData& src, const MipMapGenOptions& options)
  1610. {
  1611. Vector<SPtr<PixelData>> outputMipBuffers;
  1612. if (src.getDepth() != 1)
  1613. {
  1614. LOGERR("Mipmap generation failed. 3D texture formats not supported.")
  1615. return outputMipBuffers;
  1616. }
  1617. // Note: Add support for floating point mips, no reason they shouldn't be supported other than
  1618. // nvtt doesn't support them natively
  1619. if (isCompressed(src.getFormat()) || isFloatingPoint(src.getFormat()))
  1620. {
  1621. LOGERR("Mipmap generation failed. Source data cannot be compressed or in floating point format.")
  1622. return outputMipBuffers;
  1623. }
  1624. if (!Bitwise::isPow2(src.getWidth()) || !Bitwise::isPow2(src.getHeight()))
  1625. {
  1626. LOGERR("Mipmap generation failed. Texture width & height must be powers of 2.");
  1627. return outputMipBuffers;
  1628. }
  1629. PixelData rgbaData(src.getWidth(), src.getHeight(), 1, PF_R8G8B8A8);
  1630. rgbaData.allocateInternalBuffer();
  1631. bulkPixelConversion(src, rgbaData);
  1632. nvtt::InputOptions io;
  1633. io.setTextureLayout(nvtt::TextureType_2D, src.getWidth(), src.getHeight());
  1634. io.setMipmapData(rgbaData.getData(), src.getWidth(), src.getHeight());
  1635. io.setMipmapGeneration(true);
  1636. io.setNormalMap(options.isNormalMap);
  1637. io.setNormalizeMipmaps(options.normalizeMipmaps);
  1638. io.setWrapMode(toNVTTWrapMode(options.wrapMode));
  1639. nvtt::CompressionOptions co;
  1640. co.setFormat(nvtt::Format_RGBA);
  1641. UINT32 numMips = getMaxMipmaps(src.getWidth(), src.getHeight(), 1, src.getFormat());
  1642. Vector<SPtr<PixelData>> rgbaMipBuffers;
  1643. // Note: This can be done more effectively without creating so many temp buffers
  1644. // and working with the original formats directly, but it would complicate the code
  1645. // too much at the moment.
  1646. UINT32 curWidth = src.getWidth();
  1647. UINT32 curHeight = src.getHeight();
  1648. for (UINT32 i = 0; i < numMips; i++)
  1649. {
  1650. rgbaMipBuffers.push_back(bs_shared_ptr_new<PixelData>(curWidth, curHeight, 1, PF_R8G8B8A8));
  1651. rgbaMipBuffers.back()->allocateInternalBuffer();
  1652. if (curWidth > 1)
  1653. curWidth = curWidth / 2;
  1654. if (curHeight > 1)
  1655. curHeight = curHeight / 2;
  1656. }
  1657. rgbaMipBuffers.push_back(bs_shared_ptr_new<PixelData>(curWidth, curHeight, 1, PF_R8G8B8A8));
  1658. rgbaMipBuffers.back()->allocateInternalBuffer();
  1659. NVTTMipmapOutputHandler outputHandler(rgbaMipBuffers);
  1660. nvtt::OutputOptions oo;
  1661. oo.setOutputHeader(false);
  1662. oo.setOutputHandler(&outputHandler);
  1663. nvtt::Compressor compressor;
  1664. if (!compressor.process(io, co, oo))
  1665. {
  1666. LOGERR("Mipmap generation failed. Internal error.");
  1667. return outputMipBuffers;
  1668. }
  1669. rgbaData.freeInternalBuffer();
  1670. for (UINT32 i = 0; i < (UINT32)rgbaMipBuffers.size(); i++)
  1671. {
  1672. SPtr<PixelData> argbBuffer = rgbaMipBuffers[i];
  1673. SPtr<PixelData> outputBuffer = bs_shared_ptr_new<PixelData>(argbBuffer->getWidth(), argbBuffer->getHeight(), 1, src.getFormat());
  1674. outputBuffer->allocateInternalBuffer();
  1675. bulkPixelConversion(*argbBuffer, *outputBuffer);
  1676. argbBuffer->freeInternalBuffer();
  1677. outputMipBuffers.push_back(outputBuffer);
  1678. }
  1679. return outputMipBuffers;
  1680. }
  1681. }