BsPixelUtil.cpp 59 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828
  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 BansheeEngine
  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. }
  903. }
  904. else
  905. {
  906. return width*height*depth*getNumElemBytes(format);
  907. }
  908. return 0;
  909. }
  910. void PixelUtil::getSizeForMipLevel(UINT32 width, UINT32 height, UINT32 depth, UINT32 mipLevel,
  911. UINT32& mipWidth, UINT32& mipHeight, UINT32& mipDepth)
  912. {
  913. mipWidth = width;
  914. mipHeight = height;
  915. mipDepth = depth;
  916. for (UINT32 i = 0; i < mipLevel; i++)
  917. {
  918. if (mipWidth != 1) mipWidth /= 2;
  919. if (mipHeight != 1) mipHeight /= 2;
  920. if (mipDepth != 1) mipDepth /= 2;
  921. }
  922. }
  923. UINT32 PixelUtil::getNumElemBits(PixelFormat format)
  924. {
  925. return getDescriptionFor(format).elemBytes * 8;
  926. }
  927. UINT32 PixelUtil::getFlags(PixelFormat format)
  928. {
  929. return getDescriptionFor(format).flags;
  930. }
  931. bool PixelUtil::hasAlpha(PixelFormat format)
  932. {
  933. return (PixelUtil::getFlags(format) & PFF_HASALPHA) > 0;
  934. }
  935. bool PixelUtil::isFloatingPoint(PixelFormat format)
  936. {
  937. return (PixelUtil::getFlags(format) & PFF_FLOAT) > 0;
  938. }
  939. bool PixelUtil::isCompressed(PixelFormat format)
  940. {
  941. return (PixelUtil::getFlags(format) & PFF_COMPRESSED) > 0;
  942. }
  943. bool PixelUtil::isDepth(PixelFormat format)
  944. {
  945. return (PixelUtil::getFlags(format) & PFF_DEPTH) > 0;
  946. }
  947. bool PixelUtil::isNativeEndian(PixelFormat format)
  948. {
  949. return (PixelUtil::getFlags(format) & PFF_NATIVEENDIAN) > 0;
  950. }
  951. bool PixelUtil::isValidExtent(UINT32 width, UINT32 height, UINT32 depth, PixelFormat format)
  952. {
  953. if(isCompressed(format))
  954. {
  955. switch(format)
  956. {
  957. case PF_BC1:
  958. case PF_BC2:
  959. case PF_BC1a:
  960. case PF_BC3:
  961. case PF_BC4:
  962. case PF_BC5:
  963. case PF_BC6H:
  964. case PF_BC7:
  965. return ((width & 3) == 0 && (height & 3) == 0 && depth == 1);
  966. default:
  967. return true;
  968. }
  969. }
  970. else
  971. {
  972. return true;
  973. }
  974. }
  975. void PixelUtil::getBitDepths(PixelFormat format, int rgba[4])
  976. {
  977. const PixelFormatDescription& des = getDescriptionFor(format);
  978. rgba[0] = des.rbits;
  979. rgba[1] = des.gbits;
  980. rgba[2] = des.bbits;
  981. rgba[3] = des.abits;
  982. }
  983. void PixelUtil::getBitMasks(PixelFormat format, UINT32 rgba[4])
  984. {
  985. const PixelFormatDescription& des = getDescriptionFor(format);
  986. rgba[0] = des.rmask;
  987. rgba[1] = des.gmask;
  988. rgba[2] = des.bmask;
  989. rgba[3] = des.amask;
  990. }
  991. void PixelUtil::getBitShifts(PixelFormat format, UINT8 rgba[4])
  992. {
  993. const PixelFormatDescription& des = getDescriptionFor(format);
  994. rgba[0] = des.rshift;
  995. rgba[1] = des.gshift;
  996. rgba[2] = des.bshift;
  997. rgba[3] = des.ashift;
  998. }
  999. String PixelUtil::getFormatName(PixelFormat srcformat)
  1000. {
  1001. return getDescriptionFor(srcformat).name;
  1002. }
  1003. bool PixelUtil::isAccessible(PixelFormat srcformat)
  1004. {
  1005. if (srcformat == PF_UNKNOWN)
  1006. return false;
  1007. UINT32 flags = getFlags(srcformat);
  1008. return !((flags & PFF_COMPRESSED) || (flags & PFF_DEPTH));
  1009. }
  1010. PixelComponentType PixelUtil::getElementType(PixelFormat format)
  1011. {
  1012. const PixelFormatDescription& des = getDescriptionFor(format);
  1013. return des.componentType;
  1014. }
  1015. UINT32 PixelUtil::getNumElements(PixelFormat format)
  1016. {
  1017. const PixelFormatDescription& des = getDescriptionFor(format);
  1018. return des.componentCount;
  1019. }
  1020. UINT32 PixelUtil::getMaxMipmaps(UINT32 width, UINT32 height, UINT32 depth, PixelFormat format)
  1021. {
  1022. UINT32 count = 0;
  1023. if((width > 0) && (height > 0))
  1024. {
  1025. do {
  1026. if(width>1) width = width/2;
  1027. if(height>1) height = height/2;
  1028. if(depth>1) depth = depth/2;
  1029. count ++;
  1030. } while(!(width == 1 && height == 1 && depth == 1));
  1031. }
  1032. return count;
  1033. }
  1034. void PixelUtil::packColor(const Color& color, PixelFormat format, void* dest)
  1035. {
  1036. packColor(color.r, color.g, color.b, color.a, format, dest);
  1037. }
  1038. void PixelUtil::packColor(UINT8 r, UINT8 g, UINT8 b, UINT8 a, PixelFormat format, void* dest)
  1039. {
  1040. const PixelFormatDescription &des = getDescriptionFor(format);
  1041. if(des.flags & PFF_NATIVEENDIAN)
  1042. {
  1043. // Shortcut for integer formats packing
  1044. UINT32 value = ((Bitwise::fixedToFixed(r, 8, des.rbits)<<des.rshift) & des.rmask) |
  1045. ((Bitwise::fixedToFixed(g, 8, des.gbits)<<des.gshift) & des.gmask) |
  1046. ((Bitwise::fixedToFixed(b, 8, des.bbits)<<des.bshift) & des.bmask) |
  1047. ((Bitwise::fixedToFixed(a, 8, des.abits)<<des.ashift) & des.amask);
  1048. // And write to memory
  1049. Bitwise::intWrite(dest, des.elemBytes, value);
  1050. }
  1051. else
  1052. {
  1053. // Convert to float
  1054. packColor((float)r/255.0f,(float)g/255.0f,(float)b/255.0f,(float)a/255.0f, format, dest);
  1055. }
  1056. }
  1057. void PixelUtil::packColor(float r, float g, float b, float a, const PixelFormat format, void* dest)
  1058. {
  1059. const PixelFormatDescription& des = getDescriptionFor(format);
  1060. if(des.flags & PFF_NATIVEENDIAN)
  1061. {
  1062. // Do the packing
  1063. const unsigned int value = ((Bitwise::floatToFixed(r, des.rbits)<<des.rshift) & des.rmask) |
  1064. ((Bitwise::floatToFixed(g, des.gbits)<<des.gshift) & des.gmask) |
  1065. ((Bitwise::floatToFixed(b, des.bbits)<<des.bshift) & des.bmask) |
  1066. ((Bitwise::floatToFixed(a, des.abits)<<des.ashift) & des.amask);
  1067. // And write to memory
  1068. Bitwise::intWrite(dest, des.elemBytes, value);
  1069. }
  1070. else
  1071. {
  1072. switch(format)
  1073. {
  1074. case PF_FLOAT32_R:
  1075. ((float*)dest)[0] = r;
  1076. break;
  1077. case PF_FLOAT32_RG:
  1078. ((float*)dest)[0] = r;
  1079. ((float*)dest)[1] = g;
  1080. break;
  1081. case PF_FLOAT32_RGB:
  1082. ((float*)dest)[0] = r;
  1083. ((float*)dest)[1] = g;
  1084. ((float*)dest)[2] = b;
  1085. break;
  1086. case PF_FLOAT32_RGBA:
  1087. ((float*)dest)[0] = r;
  1088. ((float*)dest)[1] = g;
  1089. ((float*)dest)[2] = b;
  1090. ((float*)dest)[3] = a;
  1091. break;
  1092. case PF_FLOAT16_R:
  1093. ((UINT16*)dest)[0] = Bitwise::floatToHalf(r);
  1094. break;
  1095. case PF_FLOAT16_RG:
  1096. ((UINT16*)dest)[0] = Bitwise::floatToHalf(r);
  1097. ((UINT16*)dest)[1] = Bitwise::floatToHalf(g);
  1098. break;
  1099. case PF_FLOAT16_RGB:
  1100. ((UINT16*)dest)[0] = Bitwise::floatToHalf(r);
  1101. ((UINT16*)dest)[1] = Bitwise::floatToHalf(g);
  1102. ((UINT16*)dest)[2] = Bitwise::floatToHalf(b);
  1103. break;
  1104. case PF_FLOAT16_RGBA:
  1105. ((UINT16*)dest)[0] = Bitwise::floatToHalf(r);
  1106. ((UINT16*)dest)[1] = Bitwise::floatToHalf(g);
  1107. ((UINT16*)dest)[2] = Bitwise::floatToHalf(b);
  1108. ((UINT16*)dest)[3] = Bitwise::floatToHalf(a);
  1109. break;
  1110. case PF_R8G8:
  1111. ((UINT8*)dest)[0] = (UINT8)Bitwise::floatToFixed(r, 8);
  1112. ((UINT8*)dest)[1] = (UINT8)Bitwise::floatToFixed(g, 8);
  1113. break;
  1114. case PF_R8:
  1115. ((UINT8*)dest)[0] = (UINT8)Bitwise::floatToFixed(r, 8);
  1116. break;
  1117. default:
  1118. LOGERR("Pack to " + getFormatName(format) + " not implemented");
  1119. break;
  1120. }
  1121. }
  1122. }
  1123. void PixelUtil::unpackColor(Color* color, PixelFormat format, const void* src)
  1124. {
  1125. unpackColor(&color->r, &color->g, &color->b, &color->a, format, src);
  1126. }
  1127. void PixelUtil::unpackColor(UINT8* r, UINT8* g, UINT8* b, UINT8* a, PixelFormat format, const void* src)
  1128. {
  1129. const PixelFormatDescription &des = getDescriptionFor(format);
  1130. if(des.flags & PFF_NATIVEENDIAN)
  1131. {
  1132. // Shortcut for integer formats unpacking
  1133. const UINT32 value = Bitwise::intRead(src, des.elemBytes);
  1134. *r = (UINT8)Bitwise::fixedToFixed((value & des.rmask)>>des.rshift, des.rbits, 8);
  1135. *g = (UINT8)Bitwise::fixedToFixed((value & des.gmask)>>des.gshift, des.gbits, 8);
  1136. *b = (UINT8)Bitwise::fixedToFixed((value & des.bmask)>>des.bshift, des.bbits, 8);
  1137. if(des.flags & PFF_HASALPHA)
  1138. {
  1139. *a = (UINT8)Bitwise::fixedToFixed((value & des.amask)>>des.ashift, des.abits, 8);
  1140. }
  1141. else
  1142. {
  1143. *a = 255; // No alpha, default a component to full
  1144. }
  1145. }
  1146. else
  1147. {
  1148. // Do the operation with the more generic floating point
  1149. float rr, gg, bb, aa;
  1150. unpackColor(&rr,&gg,&bb,&aa, format, src);
  1151. *r = (UINT8)Bitwise::floatToFixed(rr, 8);
  1152. *g = (UINT8)Bitwise::floatToFixed(gg, 8);
  1153. *b = (UINT8)Bitwise::floatToFixed(bb, 8);
  1154. *a = (UINT8)Bitwise::floatToFixed(aa, 8);
  1155. }
  1156. }
  1157. void PixelUtil::unpackColor(float* r, float* g, float* b, float* a, PixelFormat format, const void* src)
  1158. {
  1159. const PixelFormatDescription &des = getDescriptionFor(format);
  1160. if(des.flags & PFF_NATIVEENDIAN)
  1161. {
  1162. // Shortcut for integer formats unpacking
  1163. const unsigned int value = Bitwise::intRead(src, des.elemBytes);
  1164. *r = Bitwise::fixedToFloat((value & des.rmask)>>des.rshift, des.rbits);
  1165. *g = Bitwise::fixedToFloat((value & des.gmask)>>des.gshift, des.gbits);
  1166. *b = Bitwise::fixedToFloat((value & des.bmask)>>des.bshift, des.bbits);
  1167. if(des.flags & PFF_HASALPHA)
  1168. {
  1169. *a = Bitwise::fixedToFloat((value & des.amask)>>des.ashift, des.abits);
  1170. }
  1171. else
  1172. {
  1173. *a = 1.0f; // No alpha, default a component to full
  1174. }
  1175. }
  1176. else
  1177. {
  1178. switch(format)
  1179. {
  1180. case PF_FLOAT32_R:
  1181. *r = *g = *b = ((float*)src)[0];
  1182. *a = 1.0f;
  1183. break;
  1184. case PF_FLOAT32_RG:
  1185. *r = ((float*)src)[0];
  1186. *g = *b = ((float*)src)[1];
  1187. *a = 1.0f;
  1188. break;
  1189. case PF_FLOAT32_RGB:
  1190. *r = ((float*)src)[0];
  1191. *g = ((float*)src)[1];
  1192. *b = ((float*)src)[2];
  1193. *a = 1.0f;
  1194. break;
  1195. case PF_FLOAT32_RGBA:
  1196. *r = ((float*)src)[0];
  1197. *g = ((float*)src)[1];
  1198. *b = ((float*)src)[2];
  1199. *a = ((float*)src)[3];
  1200. break;
  1201. case PF_FLOAT16_R:
  1202. *r = *g = *b = Bitwise::halfToFloat(((UINT16*)src)[0]);
  1203. *a = 1.0f;
  1204. break;
  1205. case PF_FLOAT16_RG:
  1206. *r = Bitwise::halfToFloat(((UINT16*)src)[0]);
  1207. *g = *b = Bitwise::halfToFloat(((UINT16*)src)[1]);
  1208. *a = 1.0f;
  1209. break;
  1210. case PF_FLOAT16_RGB:
  1211. *r = Bitwise::halfToFloat(((UINT16*)src)[0]);
  1212. *g = Bitwise::halfToFloat(((UINT16*)src)[1]);
  1213. *b = Bitwise::halfToFloat(((UINT16*)src)[2]);
  1214. *a = 1.0f;
  1215. break;
  1216. case PF_FLOAT16_RGBA:
  1217. *r = Bitwise::halfToFloat(((UINT16*)src)[0]);
  1218. *g = Bitwise::halfToFloat(((UINT16*)src)[1]);
  1219. *b = Bitwise::halfToFloat(((UINT16*)src)[2]);
  1220. *a = Bitwise::halfToFloat(((UINT16*)src)[3]);
  1221. break;
  1222. case PF_R8G8:
  1223. *r = Bitwise::fixedToFloat(((UINT8*)src)[0], 8);
  1224. *g = Bitwise::fixedToFloat(((UINT8*)src)[1], 8);
  1225. *b = 0.0f;
  1226. *a = 1.0f;
  1227. break;
  1228. case PF_R8:
  1229. *r = Bitwise::fixedToFloat(((UINT8*)src)[0], 8);
  1230. *g = 0.0f;
  1231. *b = 0.0f;
  1232. *a = 1.0f;
  1233. break;
  1234. default:
  1235. LOGERR("Unpack from " + getFormatName(format) + " not implemented");
  1236. break;
  1237. }
  1238. }
  1239. }
  1240. void PixelUtil::packDepth(float depth, const PixelFormat format, void* dest)
  1241. {
  1242. if (!isDepth(format))
  1243. {
  1244. LOGERR("Cannot convert depth to " + getFormatName(format) + ": it is not a depth format");
  1245. return;
  1246. }
  1247. }
  1248. void PixelUtil::unpackDepth(float& depth, PixelFormat format, void* src)
  1249. {
  1250. const PixelFormatDescription &des = getDescriptionFor(format);
  1251. if (!isDepth(format))
  1252. {
  1253. LOGERR("Cannot unpack from " + getFormatName(format) + ": it is not a depth format");
  1254. return;
  1255. }
  1256. //TODO fancy checks
  1257. UINT32* color = (UINT32 *)src;
  1258. float d = static_cast<float>(*color & 0x00FFFFFF);
  1259. depth = d / (float)16777216;
  1260. }
  1261. void PixelUtil::bulkPixelConversion(const PixelData &src, PixelData &dst)
  1262. {
  1263. assert(src.getWidth() == dst.getWidth() &&
  1264. src.getHeight() == dst.getHeight() &&
  1265. src.getDepth() == dst.getDepth());
  1266. // Check for compressed formats, we don't support decompression
  1267. if(PixelUtil::isCompressed(src.getFormat()))
  1268. {
  1269. if(src.getFormat() == dst.getFormat())
  1270. {
  1271. memcpy(dst.getData(), src.getData(), src.getConsecutiveSize());
  1272. return;
  1273. }
  1274. else
  1275. {
  1276. LOGERR("bulkPixelConversion() cannot be used to compress or decompress images");
  1277. return;
  1278. }
  1279. }
  1280. // Check for compression
  1281. if (PixelUtil::isCompressed(dst.getFormat()))
  1282. {
  1283. if (src.getFormat() == dst.getFormat())
  1284. {
  1285. memcpy(dst.getData(), src.getData(), src.getConsecutiveSize());
  1286. return;
  1287. }
  1288. else
  1289. {
  1290. CompressionOptions co;
  1291. co.format = dst.getFormat();
  1292. compress(src, dst, co);
  1293. return;
  1294. }
  1295. }
  1296. // The easy case
  1297. if(src.getFormat() == dst.getFormat())
  1298. {
  1299. // Everything consecutive?
  1300. if(src.isConsecutive() && dst.isConsecutive())
  1301. {
  1302. memcpy(dst.getData(), src.getData(), src.getConsecutiveSize());
  1303. return;
  1304. }
  1305. const UINT32 srcPixelSize = PixelUtil::getNumElemBytes(src.getFormat());
  1306. const UINT32 dstPixelSize = PixelUtil::getNumElemBytes(dst.getFormat());
  1307. UINT8 *srcptr = static_cast<UINT8*>(src.getData())
  1308. + (src.getLeft() + src.getTop() * src.getRowPitch() + src.getFront() * src.getSlicePitch()) * srcPixelSize;
  1309. UINT8 *dstptr = static_cast<UINT8*>(dst.getData())
  1310. + (dst.getLeft() + dst.getTop() * dst.getRowPitch() + dst.getFront() * dst.getSlicePitch()) * dstPixelSize;
  1311. // Calculate pitches+skips in bytes
  1312. const UINT32 srcRowPitchBytes = src.getRowPitch()*srcPixelSize;
  1313. const UINT32 srcSliceSkipBytes = src.getSliceSkip()*srcPixelSize;
  1314. const UINT32 dstRowPitchBytes = dst.getRowPitch()*dstPixelSize;
  1315. const UINT32 dstSliceSkipBytes = dst.getSliceSkip()*dstPixelSize;
  1316. // Otherwise, copy per row
  1317. const UINT32 rowSize = src.getWidth()*srcPixelSize;
  1318. for (UINT32 z = src.getFront(); z < src.getBack(); z++)
  1319. {
  1320. for(UINT32 y = src.getTop(); y < src.getBottom(); y++)
  1321. {
  1322. memcpy(dstptr, srcptr, rowSize);
  1323. srcptr += srcRowPitchBytes;
  1324. dstptr += dstRowPitchBytes;
  1325. }
  1326. srcptr += srcSliceSkipBytes;
  1327. dstptr += dstSliceSkipBytes;
  1328. }
  1329. return;
  1330. }
  1331. // Converting to PF_X8R8G8B8 is exactly the same as converting to
  1332. // PF_A8R8G8B8. (same with PF_X8B8G8R8 and PF_A8B8G8R8)
  1333. if(dst.getFormat() == PF_X8R8G8B8 || dst.getFormat() == PF_X8B8G8R8)
  1334. {
  1335. // Do the same conversion, with PF_A8R8G8B8, which has a lot of
  1336. // optimized conversions
  1337. PixelFormat tempFormat = dst.getFormat() == PF_X8R8G8B8?PF_A8R8G8B8:PF_A8B8G8R8;
  1338. PixelData tempdst(dst.getWidth(), dst.getHeight(), dst.getDepth(), tempFormat);
  1339. bulkPixelConversion(src, tempdst);
  1340. return;
  1341. }
  1342. // Converting from PF_X8R8G8B8 is exactly the same as converting from
  1343. // PF_A8R8G8B8, given that the destination format does not have alpha.
  1344. if((src.getFormat() == PF_X8R8G8B8 || src.getFormat() == PF_X8B8G8R8) && !hasAlpha(dst.getFormat()))
  1345. {
  1346. // Do the same conversion, with PF_A8R8G8B8, which has a lot of
  1347. // optimized conversions
  1348. PixelFormat tempFormat = src.getFormat()==PF_X8R8G8B8?PF_A8R8G8B8:PF_A8B8G8R8;
  1349. PixelData tempsrc(src.getWidth(), src.getHeight(), src.getDepth(), tempFormat);
  1350. tempsrc.setExternalBuffer(src.getData());
  1351. bulkPixelConversion(tempsrc, dst);
  1352. return;
  1353. }
  1354. const UINT32 srcPixelSize = PixelUtil::getNumElemBytes(src.getFormat());
  1355. const UINT32 dstPixelSize = PixelUtil::getNumElemBytes(dst.getFormat());
  1356. UINT8 *srcptr = static_cast<UINT8*>(src.getData())
  1357. + (src.getLeft() + src.getTop() * src.getRowPitch() + src.getFront() * src.getSlicePitch()) * srcPixelSize;
  1358. UINT8 *dstptr = static_cast<UINT8*>(dst.getData())
  1359. + (dst.getLeft() + dst.getTop() * dst.getRowPitch() + dst.getFront() * dst.getSlicePitch()) * dstPixelSize;
  1360. // Calculate pitches+skips in bytes
  1361. const UINT32 srcRowSkipBytes = src.getRowSkip()*srcPixelSize;
  1362. const UINT32 srcSliceSkipBytes = src.getSliceSkip()*srcPixelSize;
  1363. const UINT32 dstRowSkipBytes = dst.getRowSkip()*dstPixelSize;
  1364. const UINT32 dstSliceSkipBytes = dst.getSliceSkip()*dstPixelSize;
  1365. // The brute force fallback
  1366. float r,g,b,a;
  1367. for (UINT32 z = src.getFront(); z<src.getBack(); z++)
  1368. {
  1369. for (UINT32 y = src.getTop(); y < src.getBottom(); y++)
  1370. {
  1371. for (UINT32 x = src.getLeft(); x<src.getRight(); x++)
  1372. {
  1373. unpackColor(&r, &g, &b, &a, src.getFormat(), srcptr);
  1374. packColor(r, g, b, a, dst.getFormat(), dstptr);
  1375. srcptr += srcPixelSize;
  1376. dstptr += dstPixelSize;
  1377. }
  1378. srcptr += srcRowSkipBytes;
  1379. dstptr += dstRowSkipBytes;
  1380. }
  1381. srcptr += srcSliceSkipBytes;
  1382. dstptr += dstSliceSkipBytes;
  1383. }
  1384. }
  1385. void PixelUtil::scale(const PixelData& src, PixelData& scaled, Filter filter)
  1386. {
  1387. assert(PixelUtil::isAccessible(src.getFormat()));
  1388. assert(PixelUtil::isAccessible(scaled.getFormat()));
  1389. PixelData temp;
  1390. switch (filter)
  1391. {
  1392. default:
  1393. case FILTER_NEAREST:
  1394. if(src.getFormat() == scaled.getFormat())
  1395. {
  1396. // No intermediate buffer needed
  1397. temp = scaled;
  1398. }
  1399. else
  1400. {
  1401. // Allocate temporary buffer of destination size in source format
  1402. temp = PixelData(scaled.getWidth(), scaled.getHeight(), scaled.getDepth(), src.getFormat());
  1403. temp.allocateInternalBuffer();
  1404. }
  1405. // No conversion
  1406. switch (PixelUtil::getNumElemBytes(src.getFormat()))
  1407. {
  1408. case 1: NearestResampler<1>::scale(src, temp); break;
  1409. case 2: NearestResampler<2>::scale(src, temp); break;
  1410. case 3: NearestResampler<3>::scale(src, temp); break;
  1411. case 4: NearestResampler<4>::scale(src, temp); break;
  1412. case 6: NearestResampler<6>::scale(src, temp); break;
  1413. case 8: NearestResampler<8>::scale(src, temp); break;
  1414. case 12: NearestResampler<12>::scale(src, temp); break;
  1415. case 16: NearestResampler<16>::scale(src, temp); break;
  1416. default:
  1417. // Never reached
  1418. assert(false);
  1419. }
  1420. if(temp.getData() != scaled.getData())
  1421. {
  1422. // Blit temp buffer
  1423. PixelUtil::bulkPixelConversion(temp, scaled);
  1424. temp.freeInternalBuffer();
  1425. }
  1426. break;
  1427. case FILTER_LINEAR:
  1428. switch (src.getFormat())
  1429. {
  1430. case PF_R8G8:
  1431. case PF_R8G8B8: case PF_B8G8R8:
  1432. case PF_R8G8B8A8: case PF_B8G8R8A8:
  1433. case PF_A8B8G8R8: case PF_A8R8G8B8:
  1434. case PF_X8B8G8R8: case PF_X8R8G8B8:
  1435. if(src.getFormat() == scaled.getFormat())
  1436. {
  1437. // No intermediate buffer needed
  1438. temp = scaled;
  1439. }
  1440. else
  1441. {
  1442. // Allocate temp buffer of destination size in source format
  1443. temp = PixelData(scaled.getWidth(), scaled.getHeight(), scaled.getDepth(), src.getFormat());
  1444. temp.allocateInternalBuffer();
  1445. }
  1446. // No conversion
  1447. switch (PixelUtil::getNumElemBytes(src.getFormat()))
  1448. {
  1449. case 1: LinearResampler_Byte<1>::scale(src, temp); break;
  1450. case 2: LinearResampler_Byte<2>::scale(src, temp); break;
  1451. case 3: LinearResampler_Byte<3>::scale(src, temp); break;
  1452. case 4: LinearResampler_Byte<4>::scale(src, temp); break;
  1453. default:
  1454. // Never reached
  1455. assert(false);
  1456. }
  1457. if(temp.getData() != scaled.getData())
  1458. {
  1459. // Blit temp buffer
  1460. PixelUtil::bulkPixelConversion(temp, scaled);
  1461. temp.freeInternalBuffer();
  1462. }
  1463. break;
  1464. case PF_FLOAT32_RGB:
  1465. case PF_FLOAT32_RGBA:
  1466. if (scaled.getFormat() == PF_FLOAT32_RGB || scaled.getFormat() == PF_FLOAT32_RGBA)
  1467. {
  1468. // float32 to float32, avoid unpack/repack overhead
  1469. LinearResampler_Float32::scale(src, scaled);
  1470. break;
  1471. }
  1472. // Else, fall through
  1473. default:
  1474. // Fallback case, slow but works
  1475. LinearResampler::scale(src, scaled);
  1476. }
  1477. break;
  1478. }
  1479. }
  1480. void PixelUtil::applyGamma(UINT8* buffer, float gamma, UINT32 size, UINT8 bpp)
  1481. {
  1482. if(gamma == 1.0f)
  1483. return;
  1484. UINT32 stride = bpp >> 3;
  1485. for(size_t i = 0, j = size / stride; i < j; i++, buffer += stride)
  1486. {
  1487. float r = (float)buffer[0];
  1488. float g = (float)buffer[1];
  1489. float b = (float)buffer[2];
  1490. r = r * gamma;
  1491. g = g * gamma;
  1492. b = b * gamma;
  1493. float scale = 1.0f;
  1494. float tmp = 0.0f;
  1495. if(r > 255.0f && (tmp=(255.0f/r)) < scale)
  1496. scale = tmp;
  1497. if(g > 255.0f && (tmp=(255.0f/g)) < scale)
  1498. scale = tmp;
  1499. if(b > 255.0f && (tmp=(255.0f/b)) < scale)
  1500. scale = tmp;
  1501. r *= scale;
  1502. g *= scale;
  1503. b *= scale;
  1504. buffer[0] = (UINT8)r;
  1505. buffer[1] = (UINT8)g;
  1506. buffer[2] = (UINT8)b;
  1507. }
  1508. }
  1509. void PixelUtil::compress(const PixelData& src, PixelData& dst, const CompressionOptions& options)
  1510. {
  1511. if (!isCompressed(options.format))
  1512. {
  1513. LOGERR("Compression failed. Destination format is not a valid compressed format.")
  1514. return;
  1515. }
  1516. // Note: NVTT site has implementations for these two formats for when I decide to add them
  1517. if (options.format == PF_BC6H || options.format == PF_BC7)
  1518. {
  1519. LOGERR("Compression failed. BC6H and BC7 formats are currently not supported.")
  1520. return;
  1521. }
  1522. if (src.getDepth() != 1)
  1523. {
  1524. LOGERR("Compression failed. 3D texture compression not supported.")
  1525. return;
  1526. }
  1527. if (isCompressed(src.getFormat()))
  1528. {
  1529. LOGERR("Compression failed. Source data cannot be compressed.");
  1530. return;
  1531. }
  1532. PixelData bgraData(src.getWidth(), src.getHeight(), 1, PF_B8G8R8A8);
  1533. bgraData.allocateInternalBuffer();
  1534. bulkPixelConversion(src, bgraData);
  1535. nvtt::InputOptions io;
  1536. io.setTextureLayout(nvtt::TextureType_2D, src.getWidth(), src.getHeight());
  1537. io.setMipmapData(bgraData.getData(), src.getWidth(), src.getHeight());
  1538. io.setMipmapGeneration(false);
  1539. io.setAlphaMode(toNVTTAlphaMode(options.alphaMode));
  1540. io.setNormalMap(options.isNormalMap);
  1541. if (options.isSRGB)
  1542. io.setGamma(2.2f, 2.2f);
  1543. else
  1544. io.setGamma(1.0f, 1.0f);
  1545. nvtt::CompressionOptions co;
  1546. co.setFormat(toNVTTFormat(options.format));
  1547. co.setQuality(toNVTTQuality(options.quality));
  1548. NVTTCompressOutputHandler outputHandler(dst.getData(), dst.getConsecutiveSize());
  1549. nvtt::OutputOptions oo;
  1550. oo.setOutputHeader(false);
  1551. oo.setOutputHandler(&outputHandler);
  1552. nvtt::Compressor compressor;
  1553. if (!compressor.process(io, co, oo))
  1554. {
  1555. LOGERR("Compression failed. Internal error.");
  1556. return;
  1557. }
  1558. }
  1559. Vector<SPtr<PixelData>> PixelUtil::genMipmaps(const PixelData& src, const MipMapGenOptions& options)
  1560. {
  1561. Vector<SPtr<PixelData>> outputMipBuffers;
  1562. if (src.getDepth() != 1)
  1563. {
  1564. LOGERR("Mipmap generation failed. 3D texture formats not supported.")
  1565. return outputMipBuffers;
  1566. }
  1567. // Note: Add support for floating point mips, no reason they shouldn't be supported other than
  1568. // nvtt doesn't support them natively
  1569. if (isCompressed(src.getFormat()) || isFloatingPoint(src.getFormat()))
  1570. {
  1571. LOGERR("Mipmap generation failed. Source data cannot be compressed or in floating point format.")
  1572. return outputMipBuffers;
  1573. }
  1574. if (!Math::isPow2(src.getWidth()) || !Math::isPow2(src.getHeight()))
  1575. {
  1576. LOGERR("Mipmap generation failed. Texture width & height must be powers of 2.");
  1577. return outputMipBuffers;
  1578. }
  1579. PixelData argbData(src.getWidth(), src.getHeight(), 1, PF_A8R8G8B8);
  1580. argbData.allocateInternalBuffer();
  1581. bulkPixelConversion(src, argbData);
  1582. nvtt::InputOptions io;
  1583. io.setTextureLayout(nvtt::TextureType_2D, src.getWidth(), src.getHeight());
  1584. io.setMipmapData(argbData.getData(), src.getWidth(), src.getHeight());
  1585. io.setMipmapGeneration(true);
  1586. io.setNormalMap(options.isNormalMap);
  1587. io.setNormalizeMipmaps(options.normalizeMipmaps);
  1588. io.setWrapMode(toNVTTWrapMode(options.wrapMode));
  1589. nvtt::CompressionOptions co;
  1590. co.setFormat(nvtt::Format_RGBA);
  1591. UINT32 numMips = getMaxMipmaps(src.getWidth(), src.getHeight(), 1, src.getFormat());
  1592. Vector<SPtr<PixelData>> argbMipBuffers;
  1593. // Note: This can be done more effectively without creating so many temp buffers
  1594. // and working with the original formats directly, but it would complicate the code
  1595. // too much at the moment.
  1596. UINT32 curWidth = src.getWidth();
  1597. UINT32 curHeight = src.getHeight();
  1598. for (UINT32 i = 0; i < numMips; i++)
  1599. {
  1600. argbMipBuffers.push_back(bs_shared_ptr_new<PixelData>(curWidth, curHeight, 1, PF_A8R8G8B8));
  1601. argbMipBuffers.back()->allocateInternalBuffer();
  1602. if (curWidth > 1)
  1603. curWidth = curWidth / 2;
  1604. if (curHeight > 1)
  1605. curHeight = curHeight / 2;
  1606. }
  1607. argbMipBuffers.push_back(bs_shared_ptr_new<PixelData>(curWidth, curHeight, 1, PF_A8R8G8B8));
  1608. argbMipBuffers.back()->allocateInternalBuffer();
  1609. NVTTMipmapOutputHandler outputHandler(argbMipBuffers);
  1610. nvtt::OutputOptions oo;
  1611. oo.setOutputHeader(false);
  1612. oo.setOutputHandler(&outputHandler);
  1613. nvtt::Compressor compressor;
  1614. if (!compressor.process(io, co, oo))
  1615. {
  1616. LOGERR("Mipmap generation failed. Internal error.");
  1617. return outputMipBuffers;
  1618. }
  1619. argbData.freeInternalBuffer();
  1620. for (UINT32 i = 0; i < (UINT32)argbMipBuffers.size(); i++)
  1621. {
  1622. SPtr<PixelData> argbBuffer = argbMipBuffers[i];
  1623. SPtr<PixelData> outputBuffer = bs_shared_ptr_new<PixelData>(argbBuffer->getWidth(), argbBuffer->getHeight(), 1, src.getFormat());
  1624. outputBuffer->allocateInternalBuffer();
  1625. bulkPixelConversion(*argbBuffer, *outputBuffer);
  1626. argbBuffer->freeInternalBuffer();
  1627. outputMipBuffers.push_back(outputBuffer);
  1628. }
  1629. return outputMipBuffers;
  1630. }
  1631. }