CmPixelUtil.cpp 54 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505
  1. #include "CmPixelUtil.h"
  2. #include "CmBitwise.h"
  3. #include "CmColor.h"
  4. #include "CmException.h"
  5. namespace BansheeEngine {
  6. //-----------------------------------------------------------------------
  7. /**
  8. * Resamplers
  9. */
  10. // variable name hints:
  11. // sx_48 = 16/48-bit fixed-point x-position in source
  12. // stepx = difference between adjacent sx_48 values
  13. // sx1 = lower-bound integer x-position in source
  14. // sx2 = upper-bound integer x-position in source
  15. // sxf = fractional weight beween sx1 and sx2
  16. // x,y,z = location of output pixel in destination
  17. // nearest-neighbor resampler, does not convert formats.
  18. // templated on bytes-per-pixel to allow compiler optimizations, such
  19. // as simplifying memcpy() and replacing multiplies with bitshifts
  20. template<unsigned int elemsize> struct NearestResampler {
  21. static void scale(const PixelData& src, const PixelData& dst) {
  22. // assert(src.format == dst.format);
  23. // srcdata stays at beginning, pdst is a moving pointer
  24. UINT8* srcdata = (UINT8*)src.getData();
  25. UINT8* pdst = (UINT8*)dst.getData();
  26. // sx_48,sy_48,sz_48 represent current position in source
  27. // using 16/48-bit fixed precision, incremented by steps
  28. UINT64 stepx = ((UINT64)src.getWidth() << 48) / dst.getWidth();
  29. UINT64 stepy = ((UINT64)src.getHeight() << 48) / dst.getHeight();
  30. UINT64 stepz = ((UINT64)src.getDepth() << 48) / dst.getDepth();
  31. // note: ((stepz>>1) - 1) is an extra half-step increment to adjust
  32. // for the center of the destination pixel, not the top-left corner
  33. UINT64 sz_48 = (stepz >> 1) - 1;
  34. for (size_t z = dst.getFront(); z < dst.getBack(); z++, sz_48 += stepz) {
  35. size_t srczoff = (size_t)(sz_48 >> 48) * src.getSlicePitch();
  36. UINT64 sy_48 = (stepy >> 1) - 1;
  37. for (size_t y = dst.getTop(); y < dst.getBottom(); y++, sy_48 += stepy) {
  38. size_t srcyoff = (size_t)(sy_48 >> 48) * src.getRowPitch();
  39. UINT64 sx_48 = (stepx >> 1) - 1;
  40. for (size_t x = dst.getLeft(); x < dst.getRight(); x++, sx_48 += stepx) {
  41. UINT8* psrc = srcdata +
  42. elemsize*((size_t)(sx_48 >> 48) + srcyoff + srczoff);
  43. memcpy(pdst, psrc, elemsize);
  44. pdst += elemsize;
  45. }
  46. pdst += elemsize*dst.getRowSkip();
  47. }
  48. pdst += elemsize*dst.getSliceSkip();
  49. }
  50. }
  51. };
  52. // default floating-point linear resampler, does format conversion
  53. struct LinearResampler {
  54. static void scale(const PixelData& src, const PixelData& dst) {
  55. size_t srcelemsize = PixelUtil::getNumElemBytes(src.getFormat());
  56. size_t dstelemsize = PixelUtil::getNumElemBytes(dst.getFormat());
  57. // srcdata stays at beginning, pdst is a moving pointer
  58. UINT8* srcdata = (UINT8*)src.getData();
  59. UINT8* pdst = (UINT8*)dst.getData();
  60. // sx_48,sy_48,sz_48 represent current position in source
  61. // using 16/48-bit fixed precision, incremented by steps
  62. UINT64 stepx = ((UINT64)src.getWidth() << 48) / dst.getWidth();
  63. UINT64 stepy = ((UINT64)src.getHeight() << 48) / dst.getHeight();
  64. UINT64 stepz = ((UINT64)src.getDepth() << 48) / dst.getDepth();
  65. // temp is 16/16 bit fixed precision, used to adjust a source
  66. // coordinate (x, y, or z) backwards by half a pixel so that the
  67. // integer bits represent the first sample (eg, sx1) and the
  68. // fractional bits are the blend weight of the second sample
  69. unsigned int temp;
  70. // note: ((stepz>>1) - 1) is an extra half-step increment to adjust
  71. // for the center of the destination pixel, not the top-left corner
  72. UINT64 sz_48 = (stepz >> 1) - 1;
  73. for (size_t z = dst.getFront(); z < dst.getBack(); z++, sz_48+=stepz) {
  74. temp = static_cast<unsigned int>(sz_48 >> 32);
  75. temp = (temp > 0x8000)? temp - 0x8000 : 0;
  76. size_t sz1 = temp >> 16; // src z, sample #1
  77. size_t sz2 = std::min(sz1+1,(size_t)src.getDepth()-1);// src z, sample #2
  78. float szf = (temp & 0xFFFF) / 65536.f; // weight of sample #2
  79. UINT64 sy_48 = (stepy >> 1) - 1;
  80. for (size_t y = dst.getTop(); y < dst.getBottom(); y++, sy_48+=stepy) {
  81. temp = static_cast<unsigned int>(sy_48 >> 32);
  82. temp = (temp > 0x8000)? temp - 0x8000 : 0;
  83. size_t sy1 = temp >> 16; // src y #1
  84. size_t sy2 = std::min(sy1+1,(size_t)src.getHeight()-1);// src y #2
  85. float syf = (temp & 0xFFFF) / 65536.f; // weight of #2
  86. UINT64 sx_48 = (stepx >> 1) - 1;
  87. for (size_t x = dst.getLeft(); x < dst.getRight(); x++, sx_48+=stepx) {
  88. temp = static_cast<unsigned int>(sx_48 >> 32);
  89. temp = (temp > 0x8000)? temp - 0x8000 : 0;
  90. size_t sx1 = temp >> 16; // src x #1
  91. size_t sx2 = std::min(sx1+1,(size_t)src.getWidth()-1);// src x #2
  92. float sxf = (temp & 0xFFFF) / 65536.f; // weight of #2
  93. Color x1y1z1, x2y1z1, x1y2z1, x2y2z1;
  94. Color x1y1z2, x2y1z2, x1y2z2, x2y2z2;
  95. #define UNPACK(dst,x,y,z) PixelUtil::unpackColour(&dst, src.getFormat(), \
  96. srcdata + srcelemsize*((x)+(y)*src.getRowPitch()+(z)*src.getSlicePitch()))
  97. UNPACK(x1y1z1,sx1,sy1,sz1); UNPACK(x2y1z1,sx2,sy1,sz1);
  98. UNPACK(x1y2z1,sx1,sy2,sz1); UNPACK(x2y2z1,sx2,sy2,sz1);
  99. UNPACK(x1y1z2,sx1,sy1,sz2); UNPACK(x2y1z2,sx2,sy1,sz2);
  100. UNPACK(x1y2z2,sx1,sy2,sz2); UNPACK(x2y2z2,sx2,sy2,sz2);
  101. #undef UNPACK
  102. Color accum =
  103. x1y1z1 * ((1.0f - sxf)*(1.0f - syf)*(1.0f - szf)) +
  104. x2y1z1 * ( sxf *(1.0f - syf)*(1.0f - szf)) +
  105. x1y2z1 * ((1.0f - sxf)* syf *(1.0f - szf)) +
  106. x2y2z1 * ( sxf * syf *(1.0f - szf)) +
  107. x1y1z2 * ((1.0f - sxf)*(1.0f - syf)* szf ) +
  108. x2y1z2 * ( sxf *(1.0f - syf)* szf ) +
  109. x1y2z2 * ((1.0f - sxf)* syf * szf ) +
  110. x2y2z2 * ( sxf * syf * szf );
  111. PixelUtil::packColour(accum, dst.getFormat(), pdst);
  112. pdst += dstelemsize;
  113. }
  114. pdst += dstelemsize*dst.getRowSkip();
  115. }
  116. pdst += dstelemsize*dst.getSliceSkip();
  117. }
  118. }
  119. };
  120. // float32 linear resampler, converts FLOAT32_RGB/FLOAT32_RGBA only.
  121. // avoids overhead of pixel unpack/repack function calls
  122. struct LinearResampler_Float32 {
  123. static void scale(const PixelData& src, const PixelData& dst) {
  124. size_t srcchannels = PixelUtil::getNumElemBytes(src.getFormat()) / sizeof(float);
  125. size_t dstchannels = PixelUtil::getNumElemBytes(dst.getFormat()) / sizeof(float);
  126. // assert(srcchannels == 3 || srcchannels == 4);
  127. // assert(dstchannels == 3 || dstchannels == 4);
  128. // srcdata stays at beginning, pdst is a moving pointer
  129. float* srcdata = (float*)src.getData();
  130. float* pdst = (float*)dst.getData();
  131. // sx_48,sy_48,sz_48 represent current position in source
  132. // using 16/48-bit fixed precision, incremented by steps
  133. UINT64 stepx = ((UINT64)src.getWidth() << 48) / dst.getWidth();
  134. UINT64 stepy = ((UINT64)src.getHeight() << 48) / dst.getHeight();
  135. UINT64 stepz = ((UINT64)src.getDepth() << 48) / dst.getDepth();
  136. // temp is 16/16 bit fixed precision, used to adjust a source
  137. // coordinate (x, y, or z) backwards by half a pixel so that the
  138. // integer bits represent the first sample (eg, sx1) and the
  139. // fractional bits are the blend weight of the second sample
  140. unsigned int temp;
  141. // note: ((stepz>>1) - 1) is an extra half-step increment to adjust
  142. // for the center of the destination pixel, not the top-left corner
  143. UINT64 sz_48 = (stepz >> 1) - 1;
  144. for (size_t z = dst.getFront(); z < dst.getBack(); z++, sz_48+=stepz) {
  145. temp = static_cast<unsigned int>(sz_48 >> 32);
  146. temp = (temp > 0x8000)? temp - 0x8000 : 0;
  147. size_t sz1 = temp >> 16; // src z, sample #1
  148. size_t sz2 = std::min(sz1+1,(size_t)src.getDepth()-1);// src z, sample #2
  149. float szf = (temp & 0xFFFF) / 65536.f; // weight of sample #2
  150. UINT64 sy_48 = (stepy >> 1) - 1;
  151. for (size_t y = dst.getTop(); y < dst.getBottom(); y++, sy_48+=stepy) {
  152. temp = static_cast<unsigned int>(sy_48 >> 32);
  153. temp = (temp > 0x8000)? temp - 0x8000 : 0;
  154. size_t sy1 = temp >> 16; // src y #1
  155. size_t sy2 = std::min(sy1+1,(size_t)src.getHeight()-1);// src y #2
  156. float syf = (temp & 0xFFFF) / 65536.f; // weight of #2
  157. UINT64 sx_48 = (stepx >> 1) - 1;
  158. for (size_t x = dst.getLeft(); x < dst.getRight(); x++, sx_48+=stepx) {
  159. temp = static_cast<unsigned int>(sx_48 >> 32);
  160. temp = (temp > 0x8000)? temp - 0x8000 : 0;
  161. size_t sx1 = temp >> 16; // src x #1
  162. size_t sx2 = std::min(sx1+1,(size_t)src.getWidth()-1);// src x #2
  163. float sxf = (temp & 0xFFFF) / 65536.f; // weight of #2
  164. // process R,G,B,A simultaneously for cache coherence?
  165. float accum[4] = { 0.0f, 0.0f, 0.0f, 0.0f };
  166. #define ACCUM3(x,y,z,factor) \
  167. { float f = factor; \
  168. size_t off = (x+y*src.getRowPitch()+z*src.getSlicePitch())*srcchannels; \
  169. accum[0]+=srcdata[off+0]*f; accum[1]+=srcdata[off+1]*f; \
  170. accum[2]+=srcdata[off+2]*f; }
  171. #define ACCUM4(x,y,z,factor) \
  172. { float f = factor; \
  173. size_t off = (x+y*src.getRowPitch()+z*src.getSlicePitch())*srcchannels; \
  174. accum[0]+=srcdata[off+0]*f; accum[1]+=srcdata[off+1]*f; \
  175. accum[2]+=srcdata[off+2]*f; accum[3]+=srcdata[off+3]*f; }
  176. if (srcchannels == 3 || dstchannels == 3) {
  177. // RGB, no alpha
  178. ACCUM3(sx1,sy1,sz1,(1.0f-sxf)*(1.0f-syf)*(1.0f-szf));
  179. ACCUM3(sx2,sy1,sz1, sxf *(1.0f-syf)*(1.0f-szf));
  180. ACCUM3(sx1,sy2,sz1,(1.0f-sxf)* syf *(1.0f-szf));
  181. ACCUM3(sx2,sy2,sz1, sxf * syf *(1.0f-szf));
  182. ACCUM3(sx1,sy1,sz2,(1.0f-sxf)*(1.0f-syf)* szf );
  183. ACCUM3(sx2,sy1,sz2, sxf *(1.0f-syf)* szf );
  184. ACCUM3(sx1,sy2,sz2,(1.0f-sxf)* syf * szf );
  185. ACCUM3(sx2,sy2,sz2, sxf * syf * szf );
  186. accum[3] = 1.0f;
  187. } else {
  188. // RGBA
  189. ACCUM4(sx1,sy1,sz1,(1.0f-sxf)*(1.0f-syf)*(1.0f-szf));
  190. ACCUM4(sx2,sy1,sz1, sxf *(1.0f-syf)*(1.0f-szf));
  191. ACCUM4(sx1,sy2,sz1,(1.0f-sxf)* syf *(1.0f-szf));
  192. ACCUM4(sx2,sy2,sz1, sxf * syf *(1.0f-szf));
  193. ACCUM4(sx1,sy1,sz2,(1.0f-sxf)*(1.0f-syf)* szf );
  194. ACCUM4(sx2,sy1,sz2, sxf *(1.0f-syf)* szf );
  195. ACCUM4(sx1,sy2,sz2,(1.0f-sxf)* syf * szf );
  196. ACCUM4(sx2,sy2,sz2, sxf * syf * szf );
  197. }
  198. memcpy(pdst, accum, sizeof(float)*dstchannels);
  199. #undef ACCUM3
  200. #undef ACCUM4
  201. pdst += dstchannels;
  202. }
  203. pdst += dstchannels*dst.getRowSkip();
  204. }
  205. pdst += dstchannels*dst.getSliceSkip();
  206. }
  207. }
  208. };
  209. // byte linear resampler, does not do any format conversions.
  210. // only handles pixel formats that use 1 byte per color channel.
  211. // 2D only; punts 3D pixelboxes to default LinearResampler (slow).
  212. // templated on bytes-per-pixel to allow compiler optimizations, such
  213. // as unrolling loops and replacing multiplies with bitshifts
  214. template<unsigned int channels> struct LinearResampler_Byte {
  215. static void scale(const PixelData& src, const PixelData& dst) {
  216. // assert(src.format == dst.format);
  217. // only optimized for 2D
  218. if (src.getDepth() > 1 || dst.getDepth() > 1) {
  219. LinearResampler::scale(src, dst);
  220. return;
  221. }
  222. // srcdata stays at beginning of slice, pdst is a moving pointer
  223. UINT8* srcdata = (UINT8*)src.getData();
  224. UINT8* pdst = (UINT8*)dst.getData();
  225. // sx_48,sy_48 represent current position in source
  226. // using 16/48-bit fixed precision, incremented by steps
  227. UINT64 stepx = ((UINT64)src.getWidth() << 48) / dst.getWidth();
  228. UINT64 stepy = ((UINT64)src.getHeight() << 48) / dst.getHeight();
  229. // bottom 28 bits of temp are 16/12 bit fixed precision, used to
  230. // adjust a source coordinate backwards by half a pixel so that the
  231. // integer bits represent the first sample (eg, sx1) and the
  232. // fractional bits are the blend weight of the second sample
  233. unsigned int temp;
  234. UINT64 sy_48 = (stepy >> 1) - 1;
  235. for (size_t y = dst.getTop(); y < dst.getBottom(); y++, sy_48+=stepy) {
  236. temp = static_cast<unsigned int>(sy_48 >> 36);
  237. temp = (temp > 0x800)? temp - 0x800: 0;
  238. unsigned int syf = temp & 0xFFF;
  239. size_t sy1 = temp >> 12;
  240. size_t sy2 = std::min(sy1+1, (size_t)src.getBottom()-src.getTop()-1);
  241. size_t syoff1 = sy1 * src.getRowPitch();
  242. size_t syoff2 = sy2 * src.getRowPitch();
  243. UINT64 sx_48 = (stepx >> 1) - 1;
  244. for (size_t x = dst.getLeft(); x < dst.getRight(); x++, sx_48+=stepx) {
  245. temp = static_cast<unsigned int>(sx_48 >> 36);
  246. temp = (temp > 0x800)? temp - 0x800 : 0;
  247. unsigned int sxf = temp & 0xFFF;
  248. size_t sx1 = temp >> 12;
  249. size_t sx2 = std::min(sx1+1, (size_t)src.getRight()-src.getLeft()-1);
  250. unsigned int sxfsyf = sxf*syf;
  251. for (unsigned int k = 0; k < channels; k++) {
  252. unsigned int accum =
  253. srcdata[(sx1 + syoff1)*channels+k]*(0x1000000-(sxf<<12)-(syf<<12)+sxfsyf) +
  254. srcdata[(sx2 + syoff1)*channels+k]*((sxf<<12)-sxfsyf) +
  255. srcdata[(sx1 + syoff2)*channels+k]*((syf<<12)-sxfsyf) +
  256. srcdata[(sx2 + syoff2)*channels+k]*sxfsyf;
  257. // accum is computed using 8/24-bit fixed-point math
  258. // (maximum is 0xFF000000; rounding will not cause overflow)
  259. *pdst++ = static_cast<UINT8>((accum + 0x800000) >> 24);
  260. }
  261. }
  262. pdst += channels*dst.getRowSkip();
  263. }
  264. }
  265. };
  266. //-----------------------------------------------------------------------
  267. /**
  268. * A record that describes a pixel format in detail.
  269. */
  270. struct PixelFormatDescription {
  271. /* Name of the format, as in the enum */
  272. const char *name;
  273. /* Number of bytes one element (colour value) takes. */
  274. unsigned char elemBytes;
  275. /* Pixel format flags, see enum PixelFormatFlags for the bit field
  276. * definitions
  277. */
  278. UINT32 flags;
  279. /** Component type
  280. */
  281. PixelComponentType componentType;
  282. /** Component count
  283. */
  284. unsigned char componentCount;
  285. /* Number of bits for red(or luminance), green, blue, alpha
  286. */
  287. unsigned char rbits,gbits,bbits,abits; /*, ibits, dbits, ... */
  288. /* Masks and shifts as used by packers/unpackers */
  289. UINT32 rmask, gmask, bmask, amask;
  290. unsigned char rshift, gshift, bshift, ashift;
  291. };
  292. //-----------------------------------------------------------------------
  293. /** Pixel format database */
  294. PixelFormatDescription _pixelFormats[PF_COUNT] = {
  295. //-----------------------------------------------------------------------
  296. {"PF_UNKNOWN",
  297. /* Bytes per element */
  298. 0,
  299. /* Flags */
  300. 0,
  301. /* Component type and count */
  302. PCT_BYTE, 0,
  303. /* rbits, gbits, bbits, abits */
  304. 0, 0, 0, 0,
  305. /* Masks and shifts */
  306. 0, 0, 0, 0, 0, 0, 0, 0
  307. },
  308. //-----------------------------------------------------------------------
  309. {"PF_R8",
  310. /* Bytes per element */
  311. 1,
  312. /* Flags */
  313. 0,
  314. /* Component type and count */
  315. PCT_BYTE, 1,
  316. /* rbits, gbits, bbits, abits */
  317. 8, 0, 0, 0,
  318. /* Masks and shifts */
  319. 0x000000FF, 0, 0, 0,
  320. 0, 0, 0, 0
  321. },
  322. //-----------------------------------------------------------------------
  323. {"PF_R8G8",
  324. /* Bytes per element */
  325. 2,
  326. /* Flags */
  327. 0,
  328. /* Component type and count */
  329. PCT_BYTE, 2,
  330. /* rbits, gbits, bbits, abits */
  331. 8, 8, 0, 0,
  332. /* Masks and shifts */
  333. 0x000000FF, 0x0000FF00, 0, 0,
  334. 0, 8, 0, 0
  335. },
  336. //-----------------------------------------------------------------------
  337. {"PF_R8G8B8",
  338. /* Bytes per element */
  339. 3, // 24 bit integer -- special
  340. /* Flags */
  341. PFF_NATIVEENDIAN,
  342. /* Component type and count */
  343. PCT_BYTE, 3,
  344. /* rbits, gbits, bbits, abits */
  345. 8, 8, 8, 0,
  346. /* Masks and shifts */
  347. 0x000000FF, 0x0000FF00, 0x00FF0000, 0,
  348. 0, 8, 16, 0
  349. },
  350. //-----------------------------------------------------------------------
  351. {"PF_B8G8R8",
  352. /* Bytes per element */
  353. 3, // 24 bit integer -- special
  354. /* Flags */
  355. PFF_NATIVEENDIAN,
  356. /* Component type and count */
  357. PCT_BYTE, 3,
  358. /* rbits, gbits, bbits, abits */
  359. 8, 8, 8, 0,
  360. /* Masks and shifts */
  361. 0x00FF0000, 0x0000FF00, 0x000000FF, 0,
  362. 16, 8, 0, 0
  363. },
  364. //-----------------------------------------------------------------------
  365. {"PF_A8R8G8B8",
  366. /* Bytes per element */
  367. 4,
  368. /* Flags */
  369. PFF_HASALPHA | PFF_NATIVEENDIAN,
  370. /* Component type and count */
  371. PCT_BYTE, 4,
  372. /* rbits, gbits, bbits, abits */
  373. 8, 8, 8, 8,
  374. /* Masks and shifts */
  375. 0x0000FF00, 0x00FF0000, 0xFF000000, 0x000000FF,
  376. 8, 16, 24, 0
  377. },
  378. //-----------------------------------------------------------------------
  379. {"PF_A8B8G8R8",
  380. /* Bytes per element */
  381. 4,
  382. /* Flags */
  383. PFF_HASALPHA | PFF_NATIVEENDIAN,
  384. /* Component type and count */
  385. PCT_BYTE, 4,
  386. /* rbits, gbits, bbits, abits */
  387. 8, 8, 8, 8,
  388. /* Masks and shifts */
  389. 0xFF000000, 0x00FF0000, 0x0000FF00, 0x000000FF,
  390. 24, 16, 8, 0,
  391. },
  392. //-----------------------------------------------------------------------
  393. {"PF_B8G8R8A8",
  394. /* Bytes per element */
  395. 4,
  396. /* Flags */
  397. PFF_HASALPHA | PFF_NATIVEENDIAN,
  398. /* Component type and count */
  399. PCT_BYTE, 4,
  400. /* rbits, gbits, bbits, abits */
  401. 8, 8, 8, 8,
  402. /* Masks and shifts */
  403. 0x00FF0000, 0x0000FF00, 0x000000FF, 0xFF000000,
  404. 16, 8, 0, 24
  405. },
  406. //-----------------------------------------------------------------------
  407. {"PF_R8G8B8A8",
  408. /* Bytes per element */
  409. 4,
  410. /* Flags */
  411. PFF_HASALPHA | PFF_NATIVEENDIAN,
  412. /* Component type and count */
  413. PCT_BYTE, 4,
  414. /* rbits, gbits, bbits, abits */
  415. 8, 8, 8, 8,
  416. /* Masks and shifts */
  417. 0x000000FF, 0x0000FF00, 0x00FF0000, 0xFF000000,
  418. 0, 8, 16, 24
  419. },
  420. //-----------------------------------------------------------------------
  421. {"PF_X8R8G8B8",
  422. /* Bytes per element */
  423. 4,
  424. /* Flags */
  425. PFF_NATIVEENDIAN,
  426. /* Component type and count */
  427. PCT_BYTE, 3,
  428. /* rbits, gbits, bbits, abits */
  429. 8, 8, 8, 0,
  430. /* Masks and shifts */
  431. 0x0000FF00, 0x00FF0000, 0xFF000000, 0x000000FF,
  432. 8, 16, 24, 0
  433. },
  434. //-----------------------------------------------------------------------
  435. {"PF_X8B8G8R8",
  436. /* Bytes per element */
  437. 4,
  438. /* Flags */
  439. PFF_NATIVEENDIAN,
  440. /* Component type and count */
  441. PCT_BYTE, 3,
  442. /* rbits, gbits, bbits, abits */
  443. 8, 8, 8, 0,
  444. /* Masks and shifts */
  445. 0xFF000000, 0x00FF0000, 0x0000FF00, 0x000000FF,
  446. 24, 16, 8, 0
  447. },
  448. //-----------------------------------------------------------------------
  449. {"PF_R8G8B8X8",
  450. /* Bytes per element */
  451. 4,
  452. /* Flags */
  453. PFF_HASALPHA | PFF_NATIVEENDIAN,
  454. /* Component type and count */
  455. PCT_BYTE, 3,
  456. /* rbits, gbits, bbits, abits */
  457. 8, 8, 8, 0,
  458. /* Masks and shifts */
  459. 0x000000FF, 0x0000FF00, 0x00FF0000, 0xFF000000,
  460. 0, 8, 16, 0
  461. },
  462. //-----------------------------------------------------------------------
  463. {"PF_B8G8R8X8",
  464. /* Bytes per element */
  465. 4,
  466. /* Flags */
  467. PFF_HASALPHA | PFF_NATIVEENDIAN,
  468. /* Component type and count */
  469. PCT_BYTE, 3,
  470. /* rbits, gbits, bbits, abits */
  471. 8, 8, 8, 0,
  472. /* Masks and shifts */
  473. 0x00FF0000, 0x0000FF00, 0x000000FF, 0xFF000000,
  474. 16, 8, 0, 0
  475. },
  476. //-----------------------------------------------------------------------
  477. {"PF_DXT1",
  478. /* Bytes per element */
  479. 0,
  480. /* Flags */
  481. PFF_COMPRESSED | PFF_HASALPHA,
  482. /* Component type and count */
  483. PCT_BYTE, 3, // No alpha
  484. /* rbits, gbits, bbits, abits */
  485. 0, 0, 0, 0,
  486. /* Masks and shifts */
  487. 0, 0, 0, 0, 0, 0, 0, 0
  488. },
  489. //-----------------------------------------------------------------------
  490. {"PF_DXT2",
  491. /* Bytes per element */
  492. 0,
  493. /* Flags */
  494. PFF_COMPRESSED | PFF_HASALPHA,
  495. /* Component type and count */
  496. PCT_BYTE, 4,
  497. /* rbits, gbits, bbits, abits */
  498. 0, 0, 0, 0,
  499. /* Masks and shifts */
  500. 0, 0, 0, 0, 0, 0, 0, 0
  501. },
  502. //-----------------------------------------------------------------------
  503. {"PF_DXT3",
  504. /* Bytes per element */
  505. 0,
  506. /* Flags */
  507. PFF_COMPRESSED | PFF_HASALPHA,
  508. /* Component type and count */
  509. PCT_BYTE, 4,
  510. /* rbits, gbits, bbits, abits */
  511. 0, 0, 0, 0,
  512. /* Masks and shifts */
  513. 0, 0, 0, 0, 0, 0, 0, 0
  514. },
  515. //-----------------------------------------------------------------------
  516. {"PF_DXT4",
  517. /* Bytes per element */
  518. 0,
  519. /* Flags */
  520. PFF_COMPRESSED | PFF_HASALPHA,
  521. /* Component type and count */
  522. PCT_BYTE, 4,
  523. /* rbits, gbits, bbits, abits */
  524. 0, 0, 0, 0,
  525. /* Masks and shifts */
  526. 0, 0, 0, 0, 0, 0, 0, 0
  527. },
  528. //-----------------------------------------------------------------------
  529. {"PF_DXT5",
  530. /* Bytes per element */
  531. 0,
  532. /* Flags */
  533. PFF_COMPRESSED | PFF_HASALPHA,
  534. /* Component type and count */
  535. PCT_BYTE, 4,
  536. /* rbits, gbits, bbits, abits */
  537. 0, 0, 0, 0,
  538. /* Masks and shifts */
  539. 0, 0, 0, 0, 0, 0, 0, 0
  540. },
  541. //-----------------------------------------------------------------------
  542. {"PF_FLOAT16_R",
  543. /* Bytes per element */
  544. 2,
  545. /* Flags */
  546. PFF_FLOAT,
  547. /* Component type and count */
  548. PCT_FLOAT16, 1,
  549. /* rbits, gbits, bbits, abits */
  550. 16, 0, 0, 0,
  551. /* Masks and shifts */
  552. 0, 0, 0, 0, 0, 0, 0, 0
  553. },
  554. //-----------------------------------------------------------------------
  555. {"PF_FLOAT16_RG",
  556. /* Bytes per element */
  557. 4,
  558. /* Flags */
  559. PFF_FLOAT,
  560. /* Component type and count */
  561. PCT_FLOAT16, 2,
  562. /* rbits, gbits, bbits, abits */
  563. 16, 16, 0, 0,
  564. /* Masks and shifts */
  565. 0, 0, 0, 0, 0, 0, 0, 0
  566. },
  567. //-----------------------------------------------------------------------
  568. {"PF_FLOAT16_RGB",
  569. /* Bytes per element */
  570. 6,
  571. /* Flags */
  572. PFF_FLOAT,
  573. /* Component type and count */
  574. PCT_FLOAT16, 3,
  575. /* rbits, gbits, bbits, abits */
  576. 16, 16, 16, 0,
  577. /* Masks and shifts */
  578. 0, 0, 0, 0, 0, 0, 0, 0
  579. },
  580. //-----------------------------------------------------------------------
  581. {"PF_FLOAT16_RGBA",
  582. /* Bytes per element */
  583. 8,
  584. /* Flags */
  585. PFF_FLOAT | PFF_HASALPHA,
  586. /* Component type and count */
  587. PCT_FLOAT16, 4,
  588. /* rbits, gbits, bbits, abits */
  589. 16, 16, 16, 16,
  590. /* Masks and shifts */
  591. 0, 0, 0, 0, 0, 0, 0, 0
  592. },
  593. //-----------------------------------------------------------------------
  594. {"PF_FLOAT32_R",
  595. /* Bytes per element */
  596. 4,
  597. /* Flags */
  598. PFF_FLOAT,
  599. /* Component type and count */
  600. PCT_FLOAT32, 1,
  601. /* rbits, gbits, bbits, abits */
  602. 32, 0, 0, 0,
  603. /* Masks and shifts */
  604. 0, 0, 0, 0, 0, 0, 0, 0
  605. },
  606. //-----------------------------------------------------------------------
  607. {"PF_FLOAT32_RG",
  608. /* Bytes per element */
  609. 8,
  610. /* Flags */
  611. PFF_FLOAT,
  612. /* Component type and count */
  613. PCT_FLOAT32, 2,
  614. /* rbits, gbits, bbits, abits */
  615. 32, 32, 0, 0,
  616. /* Masks and shifts */
  617. 0, 0, 0, 0, 0, 0, 0, 0
  618. },
  619. //-----------------------------------------------------------------------
  620. {"PF_FLOAT32_RGB",
  621. /* Bytes per element */
  622. 12,
  623. /* Flags */
  624. PFF_FLOAT,
  625. /* Component type and count */
  626. PCT_FLOAT32, 3,
  627. /* rbits, gbits, bbits, abits */
  628. 32, 32, 32, 0,
  629. /* Masks and shifts */
  630. 0, 0, 0, 0, 0, 0, 0, 0
  631. },
  632. //-----------------------------------------------------------------------
  633. {"PF_FLOAT32_RGBA",
  634. /* Bytes per element */
  635. 16,
  636. /* Flags */
  637. PFF_FLOAT | PFF_HASALPHA,
  638. /* Component type and count */
  639. PCT_FLOAT32, 4,
  640. /* rbits, gbits, bbits, abits */
  641. 32, 32, 32, 32,
  642. /* Masks and shifts */
  643. 0, 0, 0, 0, 0, 0, 0, 0
  644. },
  645. //-----------------------------------------------------------------------
  646. {"PF_D32_S8X24",
  647. /* Bytes per element */
  648. 4,
  649. /* Flags */
  650. PFF_DEPTH | PFF_FLOAT,
  651. /* Component type and count */
  652. PCT_FLOAT32, 1,
  653. /* rbits, gbits, bbits, abits */
  654. 0, 0, 0, 0,
  655. /* Masks and shifts */
  656. 0, 0, 0, 0, 0, 0, 0, 0
  657. },
  658. //-----------------------------------------------------------------------
  659. {"PF_D24_S8",
  660. /* Bytes per element */
  661. 8,
  662. /* Flags */
  663. PFF_DEPTH | PFF_FLOAT,
  664. /* Component type and count */
  665. PCT_FLOAT32, 2,
  666. /* rbits, gbits, bbits, abits */
  667. 0, 0, 0, 0,
  668. /* Masks and shifts */
  669. 0, 0, 0, 0, 0, 0, 0, 0
  670. },
  671. //-----------------------------------------------------------------------
  672. {"PF_D32",
  673. /* Bytes per element */
  674. 4,
  675. /* Flags */
  676. PFF_DEPTH | PFF_FLOAT,
  677. /* Component type and count */
  678. PCT_FLOAT32, 1,
  679. /* rbits, gbits, bbits, abits */
  680. 0, 0, 0, 0,
  681. /* Masks and shifts */
  682. 0, 0, 0, 0, 0, 0, 0, 0
  683. },
  684. //-----------------------------------------------------------------------
  685. {"PF_D16",
  686. /* Bytes per element */
  687. 2,
  688. /* Flags */
  689. PFF_DEPTH | PFF_FLOAT,
  690. /* Component type and count */
  691. PCT_FLOAT16, 1,
  692. /* rbits, gbits, bbits, abits */
  693. 0, 0, 0, 0,
  694. /* Masks and shifts */
  695. 0, 0, 0, 0, 0, 0, 0, 0
  696. },
  697. };
  698. //-----------------------------------------------------------------------
  699. UINT32 PixelData::getConsecutiveSize() const
  700. {
  701. return PixelUtil::getMemorySize(getWidth(), getHeight(), getDepth(), mFormat);
  702. }
  703. PixelData PixelData::getSubVolume(const PixelVolume &def) const
  704. {
  705. if(PixelUtil::isCompressed(mFormat))
  706. {
  707. if(def.left == getLeft() && def.top == getTop() && def.front == getFront() &&
  708. def.right == getRight() && def.bottom == getBottom() && def.back == getBack())
  709. {
  710. // Entire buffer is being queried
  711. return *this;
  712. }
  713. CM_EXCEPT(InvalidParametersException, "Cannot return subvolume of compressed PixelBuffer");
  714. }
  715. if(!mExtents.contains(def))
  716. {
  717. CM_EXCEPT(InvalidParametersException, "Bounds out of range");
  718. }
  719. const size_t elemSize = PixelUtil::getNumElemBytes(mFormat);
  720. // Calculate new data origin
  721. // Notice how we do not propagate left/top/front from the incoming box, since
  722. // the returned pointer is already offset
  723. PixelData rval(def.getWidth(), def.getHeight(), def.getDepth(), mFormat);
  724. rval.setExternalBuffer(((UINT8*)getData()) + ((def.left-getLeft())*elemSize)
  725. + ((def.top-getTop())*mRowPitch*elemSize)
  726. + ((def.front-getFront())*mSlicePitch*elemSize));
  727. rval.mRowPitch = mRowPitch;
  728. rval.mSlicePitch = mSlicePitch;
  729. rval.mFormat = mFormat;
  730. return rval;
  731. }
  732. //-----------------------------------------------------------------------
  733. /**
  734. * Directly get the description record for provided pixel format. For debug builds,
  735. * this checks the bounds of fmt with an assertion.
  736. */
  737. static inline const PixelFormatDescription &getDescriptionFor(const PixelFormat fmt)
  738. {
  739. const int ord = (int)fmt;
  740. assert(ord>=0 && ord<PF_COUNT);
  741. return _pixelFormats[ord];
  742. }
  743. //-----------------------------------------------------------------------
  744. UINT32 PixelUtil::getNumElemBytes( PixelFormat format )
  745. {
  746. return getDescriptionFor(format).elemBytes;
  747. }
  748. //-----------------------------------------------------------------------
  749. UINT32 PixelUtil::getMemorySize(UINT32 width, UINT32 height, UINT32 depth, PixelFormat format)
  750. {
  751. if(isCompressed(format))
  752. {
  753. switch(format)
  754. {
  755. // DXT formats work by dividing the image into 4x4 blocks, then encoding each
  756. // 4x4 block with a certain number of bytes.
  757. case PF_DXT1:
  758. return ((width+3)/4)*((height+3)/4)*8 * depth;
  759. case PF_DXT2:
  760. case PF_DXT3:
  761. case PF_DXT4:
  762. case PF_DXT5:
  763. return ((width+3)/4)*((height+3)/4)*16 * depth;
  764. default:
  765. CM_EXCEPT(InvalidParametersException, "Invalid compressed pixel format");
  766. }
  767. }
  768. else
  769. {
  770. return width*height*depth*getNumElemBytes(format);
  771. }
  772. }
  773. //-----------------------------------------------------------------------
  774. UINT32 PixelUtil::getNumElemBits( PixelFormat format )
  775. {
  776. return getDescriptionFor(format).elemBytes * 8;
  777. }
  778. //-----------------------------------------------------------------------
  779. unsigned int PixelUtil::getFlags( PixelFormat format )
  780. {
  781. return getDescriptionFor(format).flags;
  782. }
  783. //-----------------------------------------------------------------------
  784. bool PixelUtil::hasAlpha(PixelFormat format)
  785. {
  786. return (PixelUtil::getFlags(format) & PFF_HASALPHA) > 0;
  787. }
  788. //-----------------------------------------------------------------------
  789. bool PixelUtil::isFloatingPoint(PixelFormat format)
  790. {
  791. return (PixelUtil::getFlags(format) & PFF_FLOAT) > 0;
  792. }
  793. //-----------------------------------------------------------------------
  794. bool PixelUtil::isCompressed(PixelFormat format)
  795. {
  796. return (PixelUtil::getFlags(format) & PFF_COMPRESSED) > 0;
  797. }
  798. //-----------------------------------------------------------------------
  799. bool PixelUtil::isDepth(PixelFormat format)
  800. {
  801. return (PixelUtil::getFlags(format) & PFF_DEPTH) > 0;
  802. }
  803. //-----------------------------------------------------------------------
  804. bool PixelUtil::isNativeEndian(PixelFormat format)
  805. {
  806. return (PixelUtil::getFlags(format) & PFF_NATIVEENDIAN) > 0;
  807. }
  808. //-----------------------------------------------------------------------
  809. bool PixelUtil::isValidExtent(size_t width, size_t height, size_t depth, PixelFormat format)
  810. {
  811. if(isCompressed(format))
  812. {
  813. switch(format)
  814. {
  815. case PF_DXT1:
  816. case PF_DXT2:
  817. case PF_DXT3:
  818. case PF_DXT4:
  819. case PF_DXT5:
  820. return ((width&3)==0 && (height&3)==0 && depth==1);
  821. default:
  822. return true;
  823. }
  824. }
  825. else
  826. {
  827. return true;
  828. }
  829. }
  830. //-----------------------------------------------------------------------
  831. void PixelUtil::getBitDepths(PixelFormat format, int rgba[4])
  832. {
  833. const PixelFormatDescription &des = getDescriptionFor(format);
  834. rgba[0] = des.rbits;
  835. rgba[1] = des.gbits;
  836. rgba[2] = des.bbits;
  837. rgba[3] = des.abits;
  838. }
  839. //-----------------------------------------------------------------------
  840. void PixelUtil::getBitMasks(PixelFormat format, UINT32 rgba[4])
  841. {
  842. const PixelFormatDescription &des = getDescriptionFor(format);
  843. rgba[0] = des.rmask;
  844. rgba[1] = des.gmask;
  845. rgba[2] = des.bmask;
  846. rgba[3] = des.amask;
  847. }
  848. //---------------------------------------------------------------------
  849. void PixelUtil::getBitShifts(PixelFormat format, unsigned char rgba[4])
  850. {
  851. const PixelFormatDescription &des = getDescriptionFor(format);
  852. rgba[0] = des.rshift;
  853. rgba[1] = des.gshift;
  854. rgba[2] = des.bshift;
  855. rgba[3] = des.ashift;
  856. }
  857. //-----------------------------------------------------------------------
  858. String PixelUtil::getFormatName(PixelFormat srcformat)
  859. {
  860. return getDescriptionFor(srcformat).name;
  861. }
  862. //-----------------------------------------------------------------------
  863. bool PixelUtil::isAccessible(PixelFormat srcformat)
  864. {
  865. if (srcformat == PF_UNKNOWN)
  866. return false;
  867. unsigned int flags = getFlags(srcformat);
  868. return !((flags & PFF_COMPRESSED) || (flags & PFF_DEPTH));
  869. }
  870. //-----------------------------------------------------------------------
  871. PixelComponentType PixelUtil::getComponentType(PixelFormat fmt)
  872. {
  873. const PixelFormatDescription &des = getDescriptionFor(fmt);
  874. return des.componentType;
  875. }
  876. //-----------------------------------------------------------------------
  877. UINT32 PixelUtil::getComponentCount(PixelFormat fmt)
  878. {
  879. const PixelFormatDescription &des = getDescriptionFor(fmt);
  880. return des.componentCount;
  881. }
  882. //-----------------------------------------------------------------------
  883. PixelFormat PixelUtil::getFormatFromName(const String& name, bool accessibleOnly, bool caseSensitive)
  884. {
  885. String tmp = name;
  886. if (!caseSensitive)
  887. {
  888. // We are stored upper-case format names.
  889. StringUtil::toUpperCase(tmp);
  890. }
  891. for (int i = 0; i < PF_COUNT; ++i)
  892. {
  893. PixelFormat pf = static_cast<PixelFormat>(i);
  894. if (!accessibleOnly || isAccessible(pf))
  895. {
  896. if (tmp == getFormatName(pf))
  897. return pf;
  898. }
  899. }
  900. return PF_UNKNOWN;
  901. }
  902. //-----------------------------------------------------------------------
  903. String PixelUtil::getBNFExpressionOfPixelFormats(bool accessibleOnly)
  904. {
  905. // Collect format names sorted by length, it's required by BNF compiler
  906. // that similar tokens need longer ones comes first.
  907. typedef MultiMap<String::size_type, String> FormatNameMap;
  908. FormatNameMap formatNames;
  909. for (size_t i = 0; i < PF_COUNT; ++i)
  910. {
  911. PixelFormat pf = static_cast<PixelFormat>(i);
  912. if (!accessibleOnly || isAccessible(pf))
  913. {
  914. String formatName = getFormatName(pf);
  915. formatNames.insert(std::make_pair(formatName.length(), formatName));
  916. }
  917. }
  918. // Populate the BNF expression in reverse order
  919. String result;
  920. // Note: Stupid M$ VC7.1 can't dealing operator!= with FormatNameMap::const_reverse_iterator.
  921. for (FormatNameMap::reverse_iterator j = formatNames.rbegin(); j != formatNames.rend(); ++j)
  922. {
  923. if (!result.empty())
  924. result += " | ";
  925. result += "'" + j->second + "'";
  926. }
  927. return result;
  928. }
  929. UINT32 PixelUtil::getMaxMipmaps(UINT32 width, UINT32 height, UINT32 depth, PixelFormat format)
  930. {
  931. UINT32 count = 0;
  932. if((width > 0) && (height > 0))
  933. {
  934. do {
  935. if(width>1) width = width/2;
  936. if(height>1) height = height/2;
  937. if(depth>1) depth = depth/2;
  938. /*
  939. NOT needed, compressed formats will have mipmaps up to 1x1
  940. if(PixelUtil::isValidExtent(width, height, depth, format))
  941. count ++;
  942. else
  943. break;
  944. */
  945. count ++;
  946. } while(!(width == 1 && height == 1 && depth == 1));
  947. }
  948. return count;
  949. }
  950. //-----------------------------------------------------------------------
  951. /*************************************************************************
  952. * Pixel packing/unpacking utilities
  953. */
  954. void PixelUtil::packColour(const Color &colour, const PixelFormat pf, void* dest)
  955. {
  956. packColour(colour.r, colour.g, colour.b, colour.a, pf, dest);
  957. }
  958. //-----------------------------------------------------------------------
  959. void PixelUtil::packColour(const UINT8 r, const UINT8 g, const UINT8 b, const UINT8 a, const PixelFormat pf, void* dest)
  960. {
  961. const PixelFormatDescription &des = getDescriptionFor(pf);
  962. if(des.flags & PFF_NATIVEENDIAN) {
  963. // Shortcut for integer formats packing
  964. unsigned int value = ((Bitwise::fixedToFixed(r, 8, des.rbits)<<des.rshift) & des.rmask) |
  965. ((Bitwise::fixedToFixed(g, 8, des.gbits)<<des.gshift) & des.gmask) |
  966. ((Bitwise::fixedToFixed(b, 8, des.bbits)<<des.bshift) & des.bmask) |
  967. ((Bitwise::fixedToFixed(a, 8, des.abits)<<des.ashift) & des.amask);
  968. // And write to memory
  969. Bitwise::intWrite(dest, des.elemBytes, value);
  970. } else {
  971. // Convert to float
  972. packColour((float)r/255.0f,(float)g/255.0f,(float)b/255.0f,(float)a/255.0f, pf, dest);
  973. }
  974. }
  975. //-----------------------------------------------------------------------
  976. void PixelUtil::packColour(const float r, const float g, const float b, const float a, const PixelFormat pf, void* dest)
  977. {
  978. // Catch-it-all here
  979. const PixelFormatDescription &des = getDescriptionFor(pf);
  980. if(des.flags & PFF_NATIVEENDIAN) {
  981. // Do the packing
  982. //std::cerr << dest << " " << r << " " << g << " " << b << " " << a << std::endl;
  983. const unsigned int value = ((Bitwise::floatToFixed(r, des.rbits)<<des.rshift) & des.rmask) |
  984. ((Bitwise::floatToFixed(g, des.gbits)<<des.gshift) & des.gmask) |
  985. ((Bitwise::floatToFixed(b, des.bbits)<<des.bshift) & des.bmask) |
  986. ((Bitwise::floatToFixed(a, des.abits)<<des.ashift) & des.amask);
  987. // And write to memory
  988. Bitwise::intWrite(dest, des.elemBytes, value);
  989. } else {
  990. switch(pf)
  991. {
  992. case PF_FLOAT32_R:
  993. ((float*)dest)[0] = r;
  994. break;
  995. case PF_FLOAT32_RG:
  996. ((float*)dest)[0] = r;
  997. ((float*)dest)[1] = g;
  998. break;
  999. case PF_FLOAT32_RGB:
  1000. ((float*)dest)[0] = r;
  1001. ((float*)dest)[1] = g;
  1002. ((float*)dest)[2] = b;
  1003. break;
  1004. case PF_FLOAT32_RGBA:
  1005. ((float*)dest)[0] = r;
  1006. ((float*)dest)[1] = g;
  1007. ((float*)dest)[2] = b;
  1008. ((float*)dest)[3] = a;
  1009. break;
  1010. case PF_FLOAT16_R:
  1011. ((UINT16*)dest)[0] = Bitwise::floatToHalf(r);
  1012. break;
  1013. case PF_FLOAT16_RG:
  1014. ((UINT16*)dest)[0] = Bitwise::floatToHalf(r);
  1015. ((UINT16*)dest)[1] = Bitwise::floatToHalf(g);
  1016. break;
  1017. case PF_FLOAT16_RGB:
  1018. ((UINT16*)dest)[0] = Bitwise::floatToHalf(r);
  1019. ((UINT16*)dest)[1] = Bitwise::floatToHalf(g);
  1020. ((UINT16*)dest)[2] = Bitwise::floatToHalf(b);
  1021. break;
  1022. case PF_FLOAT16_RGBA:
  1023. ((UINT16*)dest)[0] = Bitwise::floatToHalf(r);
  1024. ((UINT16*)dest)[1] = Bitwise::floatToHalf(g);
  1025. ((UINT16*)dest)[2] = Bitwise::floatToHalf(b);
  1026. ((UINT16*)dest)[3] = Bitwise::floatToHalf(a);
  1027. break;
  1028. case PF_R8G8:
  1029. ((UINT8*)dest)[0] = (UINT8)Bitwise::floatToFixed(r, 8);
  1030. ((UINT8*)dest)[1] = (UINT8)Bitwise::floatToFixed(g, 8);
  1031. break;
  1032. case PF_R8:
  1033. ((UINT8*)dest)[0] = (UINT8)Bitwise::floatToFixed(r, 8);
  1034. break;
  1035. default:
  1036. // Not yet supported
  1037. CM_EXCEPT(NotImplementedException,
  1038. "pack to "+getFormatName(pf)+" not implemented");
  1039. break;
  1040. }
  1041. }
  1042. }
  1043. //-----------------------------------------------------------------------
  1044. void PixelUtil::unpackColour(Color *colour, PixelFormat pf, const void* src)
  1045. {
  1046. unpackColour(&colour->r, &colour->g, &colour->b, &colour->a, pf, src);
  1047. }
  1048. //-----------------------------------------------------------------------
  1049. void PixelUtil::unpackColour(UINT8 *r, UINT8 *g, UINT8 *b, UINT8 *a, PixelFormat pf, const void* src)
  1050. {
  1051. const PixelFormatDescription &des = getDescriptionFor(pf);
  1052. if(des.flags & PFF_NATIVEENDIAN) {
  1053. // Shortcut for integer formats unpacking
  1054. const unsigned int value = Bitwise::intRead(src, des.elemBytes);
  1055. *r = (UINT8)Bitwise::fixedToFixed((value & des.rmask)>>des.rshift, des.rbits, 8);
  1056. *g = (UINT8)Bitwise::fixedToFixed((value & des.gmask)>>des.gshift, des.gbits, 8);
  1057. *b = (UINT8)Bitwise::fixedToFixed((value & des.bmask)>>des.bshift, des.bbits, 8);
  1058. if(des.flags & PFF_HASALPHA)
  1059. {
  1060. *a = (UINT8)Bitwise::fixedToFixed((value & des.amask)>>des.ashift, des.abits, 8);
  1061. }
  1062. else
  1063. {
  1064. *a = 255; // No alpha, default a component to full
  1065. }
  1066. } else {
  1067. // Do the operation with the more generic floating point
  1068. float rr, gg, bb, aa;
  1069. unpackColour(&rr,&gg,&bb,&aa, pf, src);
  1070. *r = (UINT8)Bitwise::floatToFixed(rr, 8);
  1071. *g = (UINT8)Bitwise::floatToFixed(gg, 8);
  1072. *b = (UINT8)Bitwise::floatToFixed(bb, 8);
  1073. *a = (UINT8)Bitwise::floatToFixed(aa, 8);
  1074. }
  1075. }
  1076. //-----------------------------------------------------------------------
  1077. void PixelUtil::unpackColour(float *r, float *g, float *b, float *a,
  1078. PixelFormat pf, const void* src)
  1079. {
  1080. const PixelFormatDescription &des = getDescriptionFor(pf);
  1081. if(des.flags & PFF_NATIVEENDIAN) {
  1082. // Shortcut for integer formats unpacking
  1083. const unsigned int value = Bitwise::intRead(src, des.elemBytes);
  1084. *r = Bitwise::fixedToFloat((value & des.rmask)>>des.rshift, des.rbits);
  1085. *g = Bitwise::fixedToFloat((value & des.gmask)>>des.gshift, des.gbits);
  1086. *b = Bitwise::fixedToFloat((value & des.bmask)>>des.bshift, des.bbits);
  1087. if(des.flags & PFF_HASALPHA)
  1088. {
  1089. *a = Bitwise::fixedToFloat((value & des.amask)>>des.ashift, des.abits);
  1090. }
  1091. else
  1092. {
  1093. *a = 1.0f; // No alpha, default a component to full
  1094. }
  1095. } else {
  1096. switch(pf)
  1097. {
  1098. case PF_FLOAT32_R:
  1099. *r = *g = *b = ((float*)src)[0];
  1100. *a = 1.0f;
  1101. break;
  1102. case PF_FLOAT32_RG:
  1103. *r = ((float*)src)[0];
  1104. *g = *b = ((float*)src)[1];
  1105. *a = 1.0f;
  1106. break;
  1107. case PF_FLOAT32_RGB:
  1108. *r = ((float*)src)[0];
  1109. *g = ((float*)src)[1];
  1110. *b = ((float*)src)[2];
  1111. *a = 1.0f;
  1112. break;
  1113. case PF_FLOAT32_RGBA:
  1114. *r = ((float*)src)[0];
  1115. *g = ((float*)src)[1];
  1116. *b = ((float*)src)[2];
  1117. *a = ((float*)src)[3];
  1118. break;
  1119. case PF_FLOAT16_R:
  1120. *r = *g = *b = Bitwise::halfToFloat(((UINT16*)src)[0]);
  1121. *a = 1.0f;
  1122. break;
  1123. case PF_FLOAT16_RG:
  1124. *r = Bitwise::halfToFloat(((UINT16*)src)[0]);
  1125. *g = *b = Bitwise::halfToFloat(((UINT16*)src)[1]);
  1126. *a = 1.0f;
  1127. break;
  1128. case PF_FLOAT16_RGB:
  1129. *r = Bitwise::halfToFloat(((UINT16*)src)[0]);
  1130. *g = Bitwise::halfToFloat(((UINT16*)src)[1]);
  1131. *b = Bitwise::halfToFloat(((UINT16*)src)[2]);
  1132. *a = 1.0f;
  1133. break;
  1134. case PF_FLOAT16_RGBA:
  1135. *r = Bitwise::halfToFloat(((UINT16*)src)[0]);
  1136. *g = Bitwise::halfToFloat(((UINT16*)src)[1]);
  1137. *b = Bitwise::halfToFloat(((UINT16*)src)[2]);
  1138. *a = Bitwise::halfToFloat(((UINT16*)src)[3]);
  1139. break;
  1140. case PF_R8G8:
  1141. *r = Bitwise::fixedToFloat(((UINT8*)src)[0], 8);
  1142. *g = Bitwise::fixedToFloat(((UINT8*)src)[1], 8);
  1143. *b = 0.0f;
  1144. *a = 1.0f;
  1145. break;
  1146. case PF_R8:
  1147. *r = Bitwise::fixedToFloat(((UINT8*)src)[0], 8);
  1148. *g = 0.0f;
  1149. *b = 0.0f;
  1150. *a = 1.0f;
  1151. break;
  1152. default:
  1153. // Not yet supported
  1154. CM_EXCEPT(NotImplementedException,
  1155. "unpack from "+getFormatName(pf)+" not implemented");
  1156. break;
  1157. }
  1158. }
  1159. }
  1160. //-----------------------------------------------------------------------
  1161. void PixelUtil::bulkPixelConversion(const PixelData &src, const PixelData &dst)
  1162. {
  1163. assert(src.getWidth() == dst.getWidth() &&
  1164. src.getHeight() == dst.getHeight() &&
  1165. src.getDepth() == dst.getDepth());
  1166. // Check for compressed formats, we don't support decompression, compression or recoding
  1167. if(PixelUtil::isCompressed(src.getFormat()) || PixelUtil::isCompressed(dst.getFormat()))
  1168. {
  1169. if(src.getFormat() == dst.getFormat())
  1170. {
  1171. memcpy(dst.getData(), src.getData(), src.getConsecutiveSize());
  1172. return;
  1173. }
  1174. else
  1175. {
  1176. CM_EXCEPT(NotImplementedException, "This method can not be used to compress or decompress images");
  1177. }
  1178. }
  1179. // The easy case
  1180. if(src.getFormat() == dst.getFormat()) {
  1181. // Everything consecutive?
  1182. if(src.isConsecutive() && dst.isConsecutive())
  1183. {
  1184. memcpy(dst.getData(), src.getData(), src.getConsecutiveSize());
  1185. return;
  1186. }
  1187. const size_t srcPixelSize = PixelUtil::getNumElemBytes(src.getFormat());
  1188. const size_t dstPixelSize = PixelUtil::getNumElemBytes(dst.getFormat());
  1189. UINT8 *srcptr = static_cast<UINT8*>(src.getData())
  1190. + (src.getLeft() + src.getTop() * src.getRowPitch() + src.getFront() * src.getSlicePitch()) * srcPixelSize;
  1191. UINT8 *dstptr = static_cast<UINT8*>(dst.getData())
  1192. + (dst.getLeft() + dst.getTop() * dst.getRowPitch() + dst.getFront() * dst.getSlicePitch()) * dstPixelSize;
  1193. // Calculate pitches+skips in bytes
  1194. const size_t srcRowPitchBytes = src.getRowPitch()*srcPixelSize;
  1195. //const size_t srcRowSkipBytes = src.getRowSkip()*srcPixelSize;
  1196. const size_t srcSliceSkipBytes = src.getSliceSkip()*srcPixelSize;
  1197. const size_t dstRowPitchBytes = dst.getRowPitch()*dstPixelSize;
  1198. //const size_t dstRowSkipBytes = dst.getRowSkip()*dstPixelSize;
  1199. const size_t dstSliceSkipBytes = dst.getSliceSkip()*dstPixelSize;
  1200. // Otherwise, copy per row
  1201. const size_t rowSize = src.getWidth()*srcPixelSize;
  1202. for(size_t z=src.getFront(); z<src.getBack(); z++)
  1203. {
  1204. for(size_t y=src.getTop(); y<src.getBottom(); y++)
  1205. {
  1206. memcpy(dstptr, srcptr, rowSize);
  1207. srcptr += srcRowPitchBytes;
  1208. dstptr += dstRowPitchBytes;
  1209. }
  1210. srcptr += srcSliceSkipBytes;
  1211. dstptr += dstSliceSkipBytes;
  1212. }
  1213. return;
  1214. }
  1215. // Converting to PF_X8R8G8B8 is exactly the same as converting to
  1216. // PF_A8R8G8B8. (same with PF_X8B8G8R8 and PF_A8B8G8R8)
  1217. if(dst.getFormat() == PF_X8R8G8B8 || dst.getFormat() == PF_X8B8G8R8)
  1218. {
  1219. // Do the same conversion, with PF_A8R8G8B8, which has a lot of
  1220. // optimized conversions
  1221. PixelFormat tempFormat = dst.getFormat()==PF_X8R8G8B8?PF_A8R8G8B8:PF_A8B8G8R8;
  1222. PixelData tempdst(dst.getWidth(), dst.getHeight(), dst.getDepth(), tempFormat);
  1223. bulkPixelConversion(src, tempdst);
  1224. return;
  1225. }
  1226. // Converting from PF_X8R8G8B8 is exactly the same as converting from
  1227. // PF_A8R8G8B8, given that the destination format does not have alpha.
  1228. if((src.getFormat() == PF_X8R8G8B8||src.getFormat() == PF_X8B8G8R8) && !hasAlpha(dst.getFormat()))
  1229. {
  1230. // Do the same conversion, with PF_A8R8G8B8, which has a lot of
  1231. // optimized conversions
  1232. PixelFormat tempFormat = src.getFormat()==PF_X8R8G8B8?PF_A8R8G8B8:PF_A8B8G8R8;
  1233. PixelData tempsrc(src.getWidth(), src.getHeight(), src.getDepth(), tempFormat);
  1234. tempsrc.setExternalBuffer(src.getData());
  1235. bulkPixelConversion(tempsrc, dst);
  1236. return;
  1237. }
  1238. const size_t srcPixelSize = PixelUtil::getNumElemBytes(src.getFormat());
  1239. const size_t dstPixelSize = PixelUtil::getNumElemBytes(dst.getFormat());
  1240. UINT8 *srcptr = static_cast<UINT8*>(src.getData())
  1241. + (src.getLeft() + src.getTop() * src.getRowPitch() + src.getFront() * src.getSlicePitch()) * srcPixelSize;
  1242. UINT8 *dstptr = static_cast<UINT8*>(dst.getData())
  1243. + (dst.getLeft() + dst.getTop() * dst.getRowPitch() + dst.getFront() * dst.getSlicePitch()) * dstPixelSize;
  1244. // Old way, not taking into account box dimensions
  1245. //UINT8 *srcptr = static_cast<UINT8*>(src.data), *dstptr = static_cast<UINT8*>(dst.data);
  1246. // Calculate pitches+skips in bytes
  1247. const size_t srcRowSkipBytes = src.getRowSkip()*srcPixelSize;
  1248. const size_t srcSliceSkipBytes = src.getSliceSkip()*srcPixelSize;
  1249. const size_t dstRowSkipBytes = dst.getRowSkip()*dstPixelSize;
  1250. const size_t dstSliceSkipBytes = dst.getSliceSkip()*dstPixelSize;
  1251. // The brute force fallback
  1252. float r,g,b,a;
  1253. for(size_t z=src.getFront(); z<src.getBack(); z++)
  1254. {
  1255. for(size_t y=src.getTop(); y<src.getBottom(); y++)
  1256. {
  1257. for(size_t x=src.getLeft(); x<src.getRight(); x++)
  1258. {
  1259. unpackColour(&r, &g, &b, &a, src.getFormat(), srcptr);
  1260. packColour(r, g, b, a, dst.getFormat(), dstptr);
  1261. srcptr += srcPixelSize;
  1262. dstptr += dstPixelSize;
  1263. }
  1264. srcptr += srcRowSkipBytes;
  1265. dstptr += dstRowSkipBytes;
  1266. }
  1267. srcptr += srcSliceSkipBytes;
  1268. dstptr += dstSliceSkipBytes;
  1269. }
  1270. }
  1271. void PixelUtil::scale(const PixelData &src, const PixelData &scaled, Filter filter)
  1272. {
  1273. assert(PixelUtil::isAccessible(src.getFormat()));
  1274. assert(PixelUtil::isAccessible(scaled.getFormat()));
  1275. PixelData temp;
  1276. switch (filter)
  1277. {
  1278. default:
  1279. case FILTER_NEAREST:
  1280. if(src.getFormat() == scaled.getFormat())
  1281. {
  1282. // No intermediate buffer needed
  1283. temp = scaled;
  1284. }
  1285. else
  1286. {
  1287. // Allocate temporary buffer of destination size in source format
  1288. temp = PixelData(scaled.getWidth(), scaled.getHeight(), scaled.getDepth(), src.getFormat());
  1289. temp.allocateInternalBuffer();
  1290. }
  1291. // super-optimized: no conversion
  1292. switch (PixelUtil::getNumElemBytes(src.getFormat()))
  1293. {
  1294. case 1: NearestResampler<1>::scale(src, temp); break;
  1295. case 2: NearestResampler<2>::scale(src, temp); break;
  1296. case 3: NearestResampler<3>::scale(src, temp); break;
  1297. case 4: NearestResampler<4>::scale(src, temp); break;
  1298. case 6: NearestResampler<6>::scale(src, temp); break;
  1299. case 8: NearestResampler<8>::scale(src, temp); break;
  1300. case 12: NearestResampler<12>::scale(src, temp); break;
  1301. case 16: NearestResampler<16>::scale(src, temp); break;
  1302. default:
  1303. // never reached
  1304. assert(false);
  1305. }
  1306. if(temp.getData() != scaled.getData())
  1307. {
  1308. // Blit temp buffer
  1309. PixelUtil::bulkPixelConversion(temp, scaled);
  1310. temp.freeInternalBuffer();
  1311. }
  1312. break;
  1313. case FILTER_LINEAR:
  1314. case FILTER_BILINEAR:
  1315. switch (src.getFormat())
  1316. {
  1317. case PF_R8G8:
  1318. case PF_R8G8B8: case PF_B8G8R8:
  1319. case PF_R8G8B8A8: case PF_B8G8R8A8:
  1320. case PF_A8B8G8R8: case PF_A8R8G8B8:
  1321. case PF_X8B8G8R8: case PF_X8R8G8B8:
  1322. if(src.getFormat() == scaled.getFormat())
  1323. {
  1324. // No intermediate buffer needed
  1325. temp = scaled;
  1326. }
  1327. else
  1328. {
  1329. // Allocate temp buffer of destination size in source format
  1330. temp = PixelData(scaled.getWidth(), scaled.getHeight(), scaled.getDepth(), src.getFormat());
  1331. temp.allocateInternalBuffer();
  1332. }
  1333. // super-optimized: byte-oriented math, no conversion
  1334. switch (PixelUtil::getNumElemBytes(src.getFormat()))
  1335. {
  1336. case 1: LinearResampler_Byte<1>::scale(src, temp); break;
  1337. case 2: LinearResampler_Byte<2>::scale(src, temp); break;
  1338. case 3: LinearResampler_Byte<3>::scale(src, temp); break;
  1339. case 4: LinearResampler_Byte<4>::scale(src, temp); break;
  1340. default:
  1341. // never reached
  1342. assert(false);
  1343. }
  1344. if(temp.getData() != scaled.getData())
  1345. {
  1346. // Blit temp buffer
  1347. PixelUtil::bulkPixelConversion(temp, scaled);
  1348. temp.freeInternalBuffer();
  1349. }
  1350. break;
  1351. case PF_FLOAT32_RGB:
  1352. case PF_FLOAT32_RGBA:
  1353. if (scaled.getFormat() == PF_FLOAT32_RGB || scaled.getFormat() == PF_FLOAT32_RGBA)
  1354. {
  1355. // float32 to float32, avoid unpack/repack overhead
  1356. LinearResampler_Float32::scale(src, scaled);
  1357. break;
  1358. }
  1359. // else, fall through
  1360. default:
  1361. // non-optimized: floating-point math, performs conversion but always works
  1362. LinearResampler::scale(src, scaled);
  1363. }
  1364. break;
  1365. }
  1366. }
  1367. //-----------------------------------------------------------------------------
  1368. void PixelUtil::applyGamma(UINT8 *buffer, float gamma, size_t size, UINT8 bpp)
  1369. {
  1370. if( gamma == 1.0f )
  1371. return;
  1372. //NB only 24/32-bit supported
  1373. if( bpp != 24 && bpp != 32 ) return;
  1374. UINT32 stride = bpp >> 3;
  1375. for( size_t i = 0, j = size / stride; i < j; i++, buffer += stride )
  1376. {
  1377. float r, g, b;
  1378. r = (float)buffer[0];
  1379. g = (float)buffer[1];
  1380. b = (float)buffer[2];
  1381. r = r * gamma;
  1382. g = g * gamma;
  1383. b = b * gamma;
  1384. float scale = 1.0f, tmp;
  1385. if( r > 255.0f && (tmp=(255.0f/r)) < scale )
  1386. scale = tmp;
  1387. if( g > 255.0f && (tmp=(255.0f/g)) < scale )
  1388. scale = tmp;
  1389. if( b > 255.0f && (tmp=(255.0f/b)) < scale )
  1390. scale = tmp;
  1391. r *= scale; g *= scale; b *= scale;
  1392. buffer[0] = (UINT8)r;
  1393. buffer[1] = (UINT8)g;
  1394. buffer[2] = (UINT8)b;
  1395. }
  1396. }
  1397. Color PixelData::getColorAt(UINT32 x, UINT32 y, UINT32 z)
  1398. {
  1399. Color cv;
  1400. UINT32 pixelSize = PixelUtil::getNumElemBytes(mFormat);
  1401. UINT32 pixelOffset = pixelSize * (z * mSlicePitch + y * mRowPitch + x);
  1402. PixelUtil::unpackColour(&cv, mFormat, (unsigned char *)getData() + pixelOffset);
  1403. return cv;
  1404. }
  1405. void PixelData::setColorAt(Color const &cv, UINT32 x, UINT32 y, UINT32 z)
  1406. {
  1407. UINT32 pixelSize = PixelUtil::getNumElemBytes(mFormat);
  1408. UINT32 pixelOffset = pixelSize * (z * mSlicePitch + y * mRowPitch + x);
  1409. PixelUtil::packColour(cv, mFormat, (unsigned char *)getData() + pixelOffset);
  1410. }
  1411. }