EtcBlock4x4Encoding_RGBA8.cpp 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475
  1. /*
  2. * Copyright 2015 The Etc2Comp Authors.
  3. *
  4. * Licensed under the Apache License, Version 2.0 (the "License");
  5. * you may not use this file except in compliance with the License.
  6. * You may obtain a copy of the License at
  7. *
  8. * http://www.apache.org/licenses/LICENSE-2.0
  9. *
  10. * Unless required by applicable law or agreed to in writing, software
  11. * distributed under the License is distributed on an "AS IS" BASIS,
  12. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13. * See the License for the specific language governing permissions and
  14. * limitations under the License.
  15. */
  16. /*
  17. EtcBlock4x4Encoding_RGBA8.cpp contains:
  18. Block4x4Encoding_RGBA8
  19. Block4x4Encoding_RGBA8_Opaque
  20. Block4x4Encoding_RGBA8_Transparent
  21. These encoders are used when targetting file format RGBA8.
  22. Block4x4Encoding_RGBA8_Opaque is used when all pixels in the 4x4 block are opaque
  23. Block4x4Encoding_RGBA8_Transparent is used when all pixels in the 4x4 block are transparent
  24. Block4x4Encoding_RGBA8 is used when there is a mixture of alphas in the 4x4 block
  25. */
  26. #include "EtcConfig.h"
  27. #include "EtcBlock4x4Encoding_RGBA8.h"
  28. #include "EtcBlock4x4EncodingBits.h"
  29. #include "EtcBlock4x4.h"
  30. #include <stdio.h>
  31. #include <string.h>
  32. #include <assert.h>
  33. #include <float.h>
  34. #include <limits>
  35. namespace Etc
  36. {
  37. // ####################################################################################################
  38. // Block4x4Encoding_RGBA8
  39. // ####################################################################################################
  40. float Block4x4Encoding_RGBA8::s_aafModifierTable[MODIFIER_TABLE_ENTRYS][ALPHA_SELECTORS]
  41. {
  42. { -3.0f / 255.0f, -6.0f / 255.0f, -9.0f / 255.0f, -15.0f / 255.0f, 2.0f / 255.0f, 5.0f / 255.0f, 8.0f / 255.0f, 14.0f / 255.0f },
  43. { -3.0f / 255.0f, -7.0f / 255.0f, -10.0f / 255.0f, -13.0f / 255.0f, 2.0f / 255.0f, 6.0f / 255.0f, 9.0f / 255.0f, 12.0f / 255.0f },
  44. { -2.0f / 255.0f, -5.0f / 255.0f, -8.0f / 255.0f, -13.0f / 255.0f, 1.0f / 255.0f, 4.0f / 255.0f, 7.0f / 255.0f, 12.0f / 255.0f },
  45. { -2.0f / 255.0f, -4.0f / 255.0f, -6.0f / 255.0f, -13.0f / 255.0f, 1.0f / 255.0f, 3.0f / 255.0f, 5.0f / 255.0f, 12.0f / 255.0f },
  46. { -3.0f / 255.0f, -6.0f / 255.0f, -8.0f / 255.0f, -12.0f / 255.0f, 2.0f / 255.0f, 5.0f / 255.0f, 7.0f / 255.0f, 11.0f / 255.0f },
  47. { -3.0f / 255.0f, -7.0f / 255.0f, -9.0f / 255.0f, -11.0f / 255.0f, 2.0f / 255.0f, 6.0f / 255.0f, 8.0f / 255.0f, 10.0f / 255.0f },
  48. { -4.0f / 255.0f, -7.0f / 255.0f, -8.0f / 255.0f, -11.0f / 255.0f, 3.0f / 255.0f, 6.0f / 255.0f, 7.0f / 255.0f, 10.0f / 255.0f },
  49. { -3.0f / 255.0f, -5.0f / 255.0f, -8.0f / 255.0f, -11.0f / 255.0f, 2.0f / 255.0f, 4.0f / 255.0f, 7.0f / 255.0f, 10.0f / 255.0f },
  50. { -2.0f / 255.0f, -6.0f / 255.0f, -8.0f / 255.0f, -10.0f / 255.0f, 1.0f / 255.0f, 5.0f / 255.0f, 7.0f / 255.0f, 9.0f / 255.0f },
  51. { -2.0f / 255.0f, -5.0f / 255.0f, -8.0f / 255.0f, -10.0f / 255.0f, 1.0f / 255.0f, 4.0f / 255.0f, 7.0f / 255.0f, 9.0f / 255.0f },
  52. { -2.0f / 255.0f, -4.0f / 255.0f, -8.0f / 255.0f, -10.0f / 255.0f, 1.0f / 255.0f, 3.0f / 255.0f, 7.0f / 255.0f, 9.0f / 255.0f },
  53. { -2.0f / 255.0f, -5.0f / 255.0f, -7.0f / 255.0f, -10.0f / 255.0f, 1.0f / 255.0f, 4.0f / 255.0f, 6.0f / 255.0f, 9.0f / 255.0f },
  54. { -3.0f / 255.0f, -4.0f / 255.0f, -7.0f / 255.0f, -10.0f / 255.0f, 2.0f / 255.0f, 3.0f / 255.0f, 6.0f / 255.0f, 9.0f / 255.0f },
  55. { -1.0f / 255.0f, -2.0f / 255.0f, -3.0f / 255.0f, -10.0f / 255.0f, 0.0f / 255.0f, 1.0f / 255.0f, 2.0f / 255.0f, 9.0f / 255.0f },
  56. { -4.0f / 255.0f, -6.0f / 255.0f, -8.0f / 255.0f, -9.0f / 255.0f, 3.0f / 255.0f, 5.0f / 255.0f, 7.0f / 255.0f, 8.0f / 255.0f },
  57. { -3.0f / 255.0f, -5.0f / 255.0f, -7.0f / 255.0f, -9.0f / 255.0f, 2.0f / 255.0f, 4.0f / 255.0f, 6.0f / 255.0f, 8.0f / 255.0f }
  58. };
  59. // ----------------------------------------------------------------------------------------------------
  60. //
  61. Block4x4Encoding_RGBA8::Block4x4Encoding_RGBA8(void)
  62. {
  63. m_pencodingbitsA8 = nullptr;
  64. }
  65. Block4x4Encoding_RGBA8::~Block4x4Encoding_RGBA8(void) {}
  66. // ----------------------------------------------------------------------------------------------------
  67. // initialization prior to encoding
  68. // a_pblockParent points to the block associated with this encoding
  69. // a_errormetric is used to choose the best encoding
  70. // a_pafrgbaSource points to a 4x4 block subset of the source image
  71. // a_paucEncodingBits points to the final encoding bits
  72. //
  73. void Block4x4Encoding_RGBA8::InitFromSource(Block4x4 *a_pblockParent,
  74. ColorFloatRGBA *a_pafrgbaSource,
  75. unsigned char *a_paucEncodingBits, ErrorMetric a_errormetric)
  76. {
  77. Block4x4Encoding::Init(a_pblockParent, a_pafrgbaSource,a_errormetric);
  78. m_pencodingbitsA8 = (Block4x4EncodingBits_A8 *)a_paucEncodingBits;
  79. m_pencodingbitsRGB8 = (Block4x4EncodingBits_RGB8 *)(a_paucEncodingBits + sizeof(Block4x4EncodingBits_A8));
  80. }
  81. // ----------------------------------------------------------------------------------------------------
  82. // initialization from the encoding bits of a previous encoding
  83. // a_pblockParent points to the block associated with this encoding
  84. // a_errormetric is used to choose the best encoding
  85. // a_pafrgbaSource points to a 4x4 block subset of the source image
  86. // a_paucEncodingBits points to the final encoding bits of a previous encoding
  87. //
  88. void Block4x4Encoding_RGBA8::InitFromEncodingBits(Block4x4 *a_pblockParent,
  89. unsigned char *a_paucEncodingBits,
  90. ColorFloatRGBA *a_pafrgbaSource,
  91. ErrorMetric a_errormetric)
  92. {
  93. m_pencodingbitsA8 = (Block4x4EncodingBits_A8 *)a_paucEncodingBits;
  94. m_pencodingbitsRGB8 = (Block4x4EncodingBits_RGB8 *)(a_paucEncodingBits + sizeof(Block4x4EncodingBits_A8));
  95. // init RGB portion
  96. Block4x4Encoding_RGB8::InitFromEncodingBits(a_pblockParent,
  97. (unsigned char *) m_pencodingbitsRGB8,
  98. a_pafrgbaSource,
  99. a_errormetric);
  100. // init A8 portion
  101. // has to be done after InitFromEncodingBits()
  102. {
  103. m_fBase = m_pencodingbitsA8->data.base / 255.0f;
  104. m_fMultiplier = (float)m_pencodingbitsA8->data.multiplier;
  105. m_uiModifierTableIndex = m_pencodingbitsA8->data.table;
  106. unsigned long long int ulliSelectorBits = 0;
  107. ulliSelectorBits |= (unsigned long long int)m_pencodingbitsA8->data.selectors0 << 40;
  108. ulliSelectorBits |= (unsigned long long int)m_pencodingbitsA8->data.selectors1 << 32;
  109. ulliSelectorBits |= (unsigned long long int)m_pencodingbitsA8->data.selectors2 << 24;
  110. ulliSelectorBits |= (unsigned long long int)m_pencodingbitsA8->data.selectors3 << 16;
  111. ulliSelectorBits |= (unsigned long long int)m_pencodingbitsA8->data.selectors4 << 8;
  112. ulliSelectorBits |= (unsigned long long int)m_pencodingbitsA8->data.selectors5;
  113. for (unsigned int uiPixel = 0; uiPixel < PIXELS; uiPixel++)
  114. {
  115. unsigned int uiShift = 45 - (3 * uiPixel);
  116. m_auiAlphaSelectors[uiPixel] = (ulliSelectorBits >> uiShift) & (ALPHA_SELECTORS - 1);
  117. }
  118. // decode the alphas
  119. // calc alpha error
  120. m_fError = 0.0f;
  121. for (unsigned int uiPixel = 0; uiPixel < PIXELS; uiPixel++)
  122. {
  123. m_afDecodedAlphas[uiPixel] = DecodePixelAlpha(m_fBase, m_fMultiplier,
  124. m_uiModifierTableIndex,
  125. m_auiAlphaSelectors[uiPixel]);
  126. float fDeltaAlpha = m_afDecodedAlphas[uiPixel] - m_pafrgbaSource[uiPixel].fA;
  127. m_fError += fDeltaAlpha * fDeltaAlpha;
  128. }
  129. }
  130. // redo error calc to include alpha
  131. CalcBlockError();
  132. }
  133. // ----------------------------------------------------------------------------------------------------
  134. // perform a single encoding iteration
  135. // replace the encoding if a better encoding was found
  136. // subsequent iterations generally take longer for each iteration
  137. // set m_boolDone if encoding is perfect or encoding is finished based on a_fEffort
  138. //
  139. // similar to Block4x4Encoding_RGB8_Base::Encode_RGB8(), but with alpha added
  140. //
  141. void Block4x4Encoding_RGBA8::PerformIteration(float a_fEffort)
  142. {
  143. assert(!m_boolDone);
  144. if (m_uiEncodingIterations == 0)
  145. {
  146. if (a_fEffort < 24.9f)
  147. {
  148. CalculateA8(0.0f);
  149. }
  150. else if (a_fEffort < 49.9f)
  151. {
  152. CalculateA8(1.0f);
  153. }
  154. else
  155. {
  156. CalculateA8(2.0f);
  157. }
  158. }
  159. Block4x4Encoding_RGB8::PerformIteration(a_fEffort);
  160. }
  161. // ----------------------------------------------------------------------------------------------------
  162. // find the best combination of base alpga, multiplier and selectors
  163. //
  164. // a_fRadius limits the range of base alpha to try
  165. //
  166. void Block4x4Encoding_RGBA8::CalculateA8(float a_fRadius)
  167. {
  168. // find min/max alpha
  169. float fMinAlpha = 1.0f;
  170. float fMaxAlpha = 0.0f;
  171. for (unsigned int uiPixel = 0; uiPixel < PIXELS; uiPixel++)
  172. {
  173. float fAlpha = m_pafrgbaSource[uiPixel].fA;
  174. // ignore border pixels
  175. if (isnan(fAlpha))
  176. {
  177. continue;
  178. }
  179. if (fAlpha < fMinAlpha)
  180. {
  181. fMinAlpha = fAlpha;
  182. }
  183. if (fAlpha > fMaxAlpha)
  184. {
  185. fMaxAlpha = fAlpha;
  186. }
  187. }
  188. assert(fMinAlpha <= fMaxAlpha);
  189. float fAlphaRange = fMaxAlpha - fMinAlpha;
  190. // try each modifier table entry
  191. m_fError = FLT_MAX; // artificially high value
  192. for (unsigned int uiTableEntry = 0; uiTableEntry < MODIFIER_TABLE_ENTRYS; uiTableEntry++)
  193. {
  194. static const unsigned int MIN_VALUE_SELECTOR = 3;
  195. static const unsigned int MAX_VALUE_SELECTOR = 7;
  196. float fTableEntryCenter = -s_aafModifierTable[uiTableEntry][MIN_VALUE_SELECTOR];
  197. float fTableEntryRange = s_aafModifierTable[uiTableEntry][MAX_VALUE_SELECTOR] -
  198. s_aafModifierTable[uiTableEntry][MIN_VALUE_SELECTOR];
  199. float fCenterRatio = fTableEntryCenter / fTableEntryRange;
  200. float fCenter = fMinAlpha + fCenterRatio*fAlphaRange;
  201. fCenter = roundf(255.0f * fCenter) / 255.0f;
  202. float fMinBase = fCenter - (a_fRadius / 255.0f);
  203. if (fMinBase < 0.0f)
  204. {
  205. fMinBase = 0.0f;
  206. }
  207. float fMaxBase = fCenter + (a_fRadius / 255.0f);
  208. if (fMaxBase > 1.0f)
  209. {
  210. fMaxBase = 1.0f;
  211. }
  212. for (float fBase = fMinBase; fBase <= fMaxBase; fBase += (0.999999f / 255.0f))
  213. {
  214. float fRangeMultiplier = roundf(fAlphaRange / fTableEntryRange);
  215. float fMinMultiplier = fRangeMultiplier - a_fRadius;
  216. if (fMinMultiplier < 1.0f)
  217. {
  218. fMinMultiplier = 1.0f;
  219. }
  220. else if (fMinMultiplier > 15.0f)
  221. {
  222. fMinMultiplier = 15.0f;
  223. }
  224. float fMaxMultiplier = fRangeMultiplier + a_fRadius;
  225. if (fMaxMultiplier < 1.0f)
  226. {
  227. fMaxMultiplier = 1.0f;
  228. }
  229. else if (fMaxMultiplier > 15.0f)
  230. {
  231. fMaxMultiplier = 15.0f;
  232. }
  233. for (float fMultiplier = fMinMultiplier; fMultiplier <= fMaxMultiplier; fMultiplier += 1.0f)
  234. {
  235. // find best selector for each pixel
  236. unsigned int auiBestSelectors[PIXELS];
  237. float afBestAlphaError[PIXELS];
  238. float afBestDecodedAlphas[PIXELS];
  239. for (unsigned int uiPixel = 0; uiPixel < PIXELS; uiPixel++)
  240. {
  241. float fBestPixelAlphaError = FLT_MAX;
  242. for (unsigned int uiSelector = 0; uiSelector < ALPHA_SELECTORS; uiSelector++)
  243. {
  244. float fDecodedAlpha = DecodePixelAlpha(fBase, fMultiplier, uiTableEntry, uiSelector);
  245. // border pixels (NAN) should have zero error
  246. float fPixelDeltaAlpha = isnan(m_pafrgbaSource[uiPixel].fA) ?
  247. 0.0f :
  248. fDecodedAlpha - m_pafrgbaSource[uiPixel].fA;
  249. float fPixelAlphaError = fPixelDeltaAlpha * fPixelDeltaAlpha;
  250. if (fPixelAlphaError < fBestPixelAlphaError)
  251. {
  252. fBestPixelAlphaError = fPixelAlphaError;
  253. auiBestSelectors[uiPixel] = uiSelector;
  254. afBestAlphaError[uiPixel] = fBestPixelAlphaError;
  255. afBestDecodedAlphas[uiPixel] = fDecodedAlpha;
  256. }
  257. }
  258. }
  259. float fBlockError = 0.0f;
  260. for (unsigned int uiPixel = 0; uiPixel < PIXELS; uiPixel++)
  261. {
  262. fBlockError += afBestAlphaError[uiPixel];
  263. }
  264. if (fBlockError < m_fError)
  265. {
  266. m_fError = fBlockError;
  267. m_fBase = fBase;
  268. m_fMultiplier = fMultiplier;
  269. m_uiModifierTableIndex = uiTableEntry;
  270. for (unsigned int uiPixel = 0; uiPixel < PIXELS; uiPixel++)
  271. {
  272. m_auiAlphaSelectors[uiPixel] = auiBestSelectors[uiPixel];
  273. m_afDecodedAlphas[uiPixel] = afBestDecodedAlphas[uiPixel];
  274. }
  275. }
  276. }
  277. }
  278. }
  279. }
  280. // ----------------------------------------------------------------------------------------------------
  281. // set the encoding bits based on encoding state
  282. //
  283. void Block4x4Encoding_RGBA8::SetEncodingBits(void)
  284. {
  285. // set the RGB8 portion
  286. Block4x4Encoding_RGB8::SetEncodingBits();
  287. // set the A8 portion
  288. {
  289. m_pencodingbitsA8->data.base = (unsigned char)roundf(255.0f * m_fBase);
  290. m_pencodingbitsA8->data.table = m_uiModifierTableIndex;
  291. m_pencodingbitsA8->data.multiplier = (unsigned char)roundf(m_fMultiplier);
  292. unsigned long long int ulliSelectorBits = 0;
  293. for (unsigned int uiPixel = 0; uiPixel < PIXELS; uiPixel++)
  294. {
  295. unsigned int uiShift = 45 - (3 * uiPixel);
  296. ulliSelectorBits |= ((unsigned long long int)m_auiAlphaSelectors[uiPixel]) << uiShift;
  297. }
  298. m_pencodingbitsA8->data.selectors0 = ulliSelectorBits >> 40;
  299. m_pencodingbitsA8->data.selectors1 = ulliSelectorBits >> 32;
  300. m_pencodingbitsA8->data.selectors2 = ulliSelectorBits >> 24;
  301. m_pencodingbitsA8->data.selectors3 = ulliSelectorBits >> 16;
  302. m_pencodingbitsA8->data.selectors4 = ulliSelectorBits >> 8;
  303. m_pencodingbitsA8->data.selectors5 = ulliSelectorBits;
  304. }
  305. }
  306. // ####################################################################################################
  307. // Block4x4Encoding_RGBA8_Opaque
  308. // ####################################################################################################
  309. // ----------------------------------------------------------------------------------------------------
  310. // perform a single encoding iteration
  311. // replace the encoding if a better encoding was found
  312. // subsequent iterations generally take longer for each iteration
  313. // set m_boolDone if encoding is perfect or encoding is finished based on a_fEffort
  314. //
  315. void Block4x4Encoding_RGBA8_Opaque::PerformIteration(float a_fEffort)
  316. {
  317. assert(!m_boolDone);
  318. if (m_uiEncodingIterations == 0)
  319. {
  320. m_fError = 0.0f;
  321. for (unsigned int uiPixel = 0; uiPixel < PIXELS; uiPixel++)
  322. {
  323. m_afDecodedAlphas[uiPixel] = 1.0f;
  324. }
  325. }
  326. Block4x4Encoding_RGB8::PerformIteration(a_fEffort);
  327. }
  328. // ----------------------------------------------------------------------------------------------------
  329. // set the encoding bits based on encoding state
  330. //
  331. void Block4x4Encoding_RGBA8_Opaque::SetEncodingBits(void)
  332. {
  333. // set the RGB8 portion
  334. Block4x4Encoding_RGB8::SetEncodingBits();
  335. // set the A8 portion
  336. m_pencodingbitsA8->data.base = 255;
  337. m_pencodingbitsA8->data.table = 15;
  338. m_pencodingbitsA8->data.multiplier = 15;
  339. m_pencodingbitsA8->data.selectors0 = 0xFF;
  340. m_pencodingbitsA8->data.selectors1 = 0xFF;
  341. m_pencodingbitsA8->data.selectors2 = 0xFF;
  342. m_pencodingbitsA8->data.selectors3 = 0xFF;
  343. m_pencodingbitsA8->data.selectors4 = 0xFF;
  344. m_pencodingbitsA8->data.selectors5 = 0xFF;
  345. }
  346. // ####################################################################################################
  347. // Block4x4Encoding_RGBA8_Transparent
  348. // ####################################################################################################
  349. // ----------------------------------------------------------------------------------------------------
  350. // perform a single encoding iteration
  351. // replace the encoding if a better encoding was found
  352. // subsequent iterations generally take longer for each iteration
  353. // set m_boolDone if encoding is perfect or encoding is finished based on a_fEffort
  354. //
  355. void Block4x4Encoding_RGBA8_Transparent::PerformIteration(float )
  356. {
  357. assert(!m_boolDone);
  358. assert(m_uiEncodingIterations == 0);
  359. m_mode = MODE_ETC1;
  360. m_boolDiff = true;
  361. m_boolFlip = false;
  362. for (unsigned int uiPixel = 0; uiPixel < PIXELS; uiPixel++)
  363. {
  364. m_afrgbaDecodedColors[uiPixel] = ColorFloatRGBA();
  365. m_afDecodedAlphas[uiPixel] = 0.0f;
  366. }
  367. m_fError = 0.0f;
  368. m_boolDone = true;
  369. m_uiEncodingIterations++;
  370. }
  371. // ----------------------------------------------------------------------------------------------------
  372. // set the encoding bits based on encoding state
  373. //
  374. void Block4x4Encoding_RGBA8_Transparent::SetEncodingBits(void)
  375. {
  376. Block4x4Encoding_RGB8::SetEncodingBits();
  377. // set the A8 portion
  378. m_pencodingbitsA8->data.base = 0;
  379. m_pencodingbitsA8->data.table = 0;
  380. m_pencodingbitsA8->data.multiplier = 1;
  381. m_pencodingbitsA8->data.selectors0 = 0;
  382. m_pencodingbitsA8->data.selectors1 = 0;
  383. m_pencodingbitsA8->data.selectors2 = 0;
  384. m_pencodingbitsA8->data.selectors3 = 0;
  385. m_pencodingbitsA8->data.selectors4 = 0;
  386. m_pencodingbitsA8->data.selectors5 = 0;
  387. }
  388. // ----------------------------------------------------------------------------------------------------
  389. //
  390. }