EtcBlock4x4.cpp 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426
  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. EtcBlock4x4.cpp
  18. Implements the state associated with each 4x4 block of pixels in an image
  19. Source images that are not a multiple of 4x4 are extended to fill the Block4x4 using pixels with an
  20. alpha of NAN
  21. */
  22. #include "EtcConfig.h"
  23. #include "EtcBlock4x4.h"
  24. #include "EtcBlock4x4EncodingBits.h"
  25. #include "EtcColor.h"
  26. #include "EtcImage.h"
  27. #include "EtcColorFloatRGBA.h"
  28. #include "EtcBlock4x4Encoding_RGB8.h"
  29. #include "EtcBlock4x4Encoding_RGBA8.h"
  30. #include "EtcBlock4x4Encoding_RGB8A1.h"
  31. #include "EtcBlock4x4Encoding_R11.h"
  32. #include "EtcBlock4x4Encoding_RG11.h"
  33. #include <stdio.h>
  34. #include <string.h>
  35. #include <assert.h>
  36. namespace Etc
  37. {
  38. // ETC pixels are scanned vertically.
  39. // this mapping is for when someone wants to scan the ETC pixels horizontally
  40. const unsigned int Block4x4::s_auiPixelOrderHScan[PIXELS] = { 0, 4, 8, 12, 1, 5, 9, 13, 2, 6, 10, 14, 3, 7, 11, 15 };
  41. // ----------------------------------------------------------------------------------------------------
  42. //
  43. Block4x4::Block4x4(void)
  44. {
  45. m_pimageSource = nullptr;
  46. m_uiSourceH = 0;
  47. m_uiSourceV = 0;
  48. m_sourcealphamix = SourceAlphaMix::UNKNOWN;
  49. m_boolBorderPixels = false;
  50. m_boolPunchThroughPixels = false;
  51. m_pencoding = nullptr;
  52. m_errormetric = ErrorMetric::NUMERIC;
  53. }
  54. Block4x4::~Block4x4()
  55. {
  56. m_pimageSource = nullptr;
  57. if (m_pencoding)
  58. {
  59. delete m_pencoding;
  60. m_pencoding = nullptr;
  61. }
  62. }
  63. // ----------------------------------------------------------------------------------------------------
  64. // initialization prior to encoding from a source image
  65. // [a_uiSourceH,a_uiSourceV] is the location of the block in a_pimageSource
  66. // a_paucEncodingBits is the place to store the final encoding
  67. // a_errormetric is used for finding the best encoding
  68. //
  69. void Block4x4::InitFromSource(Image *a_pimageSource,
  70. unsigned int a_uiSourceH, unsigned int a_uiSourceV,
  71. unsigned char *a_paucEncodingBits,
  72. ErrorMetric a_errormetric)
  73. {
  74. Block4x4();
  75. m_pimageSource = a_pimageSource;
  76. m_uiSourceH = a_uiSourceH;
  77. m_uiSourceV = a_uiSourceV;
  78. m_errormetric = a_errormetric;
  79. SetSourcePixels();
  80. // set block encoder function
  81. switch (m_pimageSource->GetFormat())
  82. {
  83. case Image::Format::ETC1:
  84. m_pencoding = new Block4x4Encoding_ETC1;
  85. break;
  86. case Image::Format::RGB8:
  87. case Image::Format::SRGB8:
  88. m_pencoding = new Block4x4Encoding_RGB8;
  89. break;
  90. case Image::Format::RGBA8:
  91. case Image::Format::SRGBA8:
  92. if (a_errormetric == RGBX)
  93. {
  94. m_pencoding = new Block4x4Encoding_RGBA8;
  95. }
  96. else
  97. {
  98. switch (m_sourcealphamix)
  99. {
  100. case SourceAlphaMix::OPAQUE:
  101. m_pencoding = new Block4x4Encoding_RGBA8_Opaque;
  102. break;
  103. case SourceAlphaMix::TRANSPARENT:
  104. m_pencoding = new Block4x4Encoding_RGBA8_Transparent;
  105. break;
  106. case SourceAlphaMix::TRANSLUCENT:
  107. m_pencoding = new Block4x4Encoding_RGBA8;
  108. break;
  109. default:
  110. assert(0);
  111. break;
  112. }
  113. break;
  114. }
  115. break;
  116. case Image::Format::RGB8A1:
  117. case Image::Format::SRGB8A1:
  118. switch (m_sourcealphamix)
  119. {
  120. case SourceAlphaMix::OPAQUE:
  121. m_pencoding = new Block4x4Encoding_RGB8A1_Opaque;
  122. break;
  123. case SourceAlphaMix::TRANSPARENT:
  124. m_pencoding = new Block4x4Encoding_RGB8A1_Transparent;
  125. break;
  126. case SourceAlphaMix::TRANSLUCENT:
  127. if (m_boolPunchThroughPixels)
  128. {
  129. m_pencoding = new Block4x4Encoding_RGB8A1;
  130. }
  131. else
  132. {
  133. m_pencoding = new Block4x4Encoding_RGB8A1_Opaque;
  134. }
  135. break;
  136. default:
  137. assert(0);
  138. break;
  139. }
  140. break;
  141. case Image::Format::R11:
  142. case Image::Format::SIGNED_R11:
  143. m_pencoding = new Block4x4Encoding_R11;
  144. break;
  145. case Image::Format::RG11:
  146. case Image::Format::SIGNED_RG11:
  147. m_pencoding = new Block4x4Encoding_RG11;
  148. break;
  149. default:
  150. assert(0);
  151. break;
  152. }
  153. m_pencoding->InitFromSource(this, m_afrgbaSource,
  154. a_paucEncodingBits, a_errormetric);
  155. }
  156. // ----------------------------------------------------------------------------------------------------
  157. // initialization of encoding state from a prior encoding using encoding bits
  158. // [a_uiSourceH,a_uiSourceV] is the location of the block in a_pimageSource
  159. // a_paucEncodingBits is the place to read the prior encoding
  160. // a_imageformat is used to determine how to interpret a_paucEncodingBits
  161. // a_errormetric was used for the prior encoding
  162. //
  163. void Block4x4::InitFromEtcEncodingBits(Image::Format a_imageformat,
  164. unsigned int a_uiSourceH, unsigned int a_uiSourceV,
  165. unsigned char *a_paucEncodingBits,
  166. Image *a_pimageSource,
  167. ErrorMetric a_errormetric)
  168. {
  169. Block4x4();
  170. m_pimageSource = a_pimageSource;
  171. m_uiSourceH = a_uiSourceH;
  172. m_uiSourceV = a_uiSourceV;
  173. m_errormetric = a_errormetric;
  174. SetSourcePixels();
  175. // set block encoder function
  176. switch (a_imageformat)
  177. {
  178. case Image::Format::ETC1:
  179. m_pencoding = new Block4x4Encoding_ETC1;
  180. break;
  181. case Image::Format::RGB8:
  182. case Image::Format::SRGB8:
  183. m_pencoding = new Block4x4Encoding_RGB8;
  184. break;
  185. case Image::Format::RGBA8:
  186. case Image::Format::SRGBA8:
  187. m_pencoding = new Block4x4Encoding_RGBA8;
  188. break;
  189. case Image::Format::RGB8A1:
  190. case Image::Format::SRGB8A1:
  191. m_pencoding = new Block4x4Encoding_RGB8A1;
  192. break;
  193. case Image::Format::R11:
  194. case Image::Format::SIGNED_R11:
  195. m_pencoding = new Block4x4Encoding_R11;
  196. break;
  197. case Image::Format::RG11:
  198. case Image::Format::SIGNED_RG11:
  199. m_pencoding = new Block4x4Encoding_RG11;
  200. break;
  201. default:
  202. assert(0);
  203. break;
  204. }
  205. m_pencoding->InitFromEncodingBits(this, a_paucEncodingBits, m_afrgbaSource,
  206. m_pimageSource->GetErrorMetric());
  207. }
  208. // ----------------------------------------------------------------------------------------------------
  209. // set source pixels from m_pimageSource
  210. // set m_alphamix
  211. //
  212. void Block4x4::SetSourcePixels(void)
  213. {
  214. Image::Format imageformat = m_pimageSource->GetFormat();
  215. // alpha census
  216. unsigned int uiTransparentSourcePixels = 0;
  217. unsigned int uiOpaqueSourcePixels = 0;
  218. // copy source to consecutive memory locations
  219. // convert from image horizontal scan to block vertical scan
  220. unsigned int uiPixel = 0;
  221. for (unsigned int uiBlockPixelH = 0; uiBlockPixelH < Block4x4::COLUMNS; uiBlockPixelH++)
  222. {
  223. unsigned int uiSourcePixelH = m_uiSourceH + uiBlockPixelH;
  224. for (unsigned int uiBlockPixelV = 0; uiBlockPixelV < Block4x4::ROWS; uiBlockPixelV++)
  225. {
  226. unsigned int uiSourcePixelV = m_uiSourceV + uiBlockPixelV;
  227. ColorFloatRGBA *pfrgbaSource = m_pimageSource->GetSourcePixel(uiSourcePixelH, uiSourcePixelV);
  228. // if pixel extends beyond source image because of block padding
  229. if (pfrgbaSource == nullptr)
  230. {
  231. m_afrgbaSource[uiPixel] = ColorFloatRGBA(0.0f, 0.0f, 0.0f, NAN); // denotes border pixel
  232. m_boolBorderPixels = true;
  233. uiTransparentSourcePixels++;
  234. }
  235. else
  236. {
  237. //get teh current pixel data, and store some of the attributes
  238. //before capping values to fit the encoder type
  239. m_afrgbaSource[uiPixel] = (*pfrgbaSource).ClampRGBA();
  240. if (m_afrgbaSource[uiPixel].fA == 1.0f || m_errormetric == RGBX)
  241. {
  242. m_pimageSource->m_iNumOpaquePixels++;
  243. }
  244. else if (m_afrgbaSource[uiPixel].fA == 0.0f)
  245. {
  246. m_pimageSource->m_iNumTransparentPixels++;
  247. }
  248. else if(m_afrgbaSource[uiPixel].fA > 0.0f && m_afrgbaSource[uiPixel].fA < 1.0f)
  249. {
  250. m_pimageSource->m_iNumTranslucentPixels++;
  251. }
  252. else
  253. {
  254. m_pimageSource->m_numOutOfRangeValues.fA++;
  255. }
  256. if (m_afrgbaSource[uiPixel].fR != 0.0f)
  257. {
  258. m_pimageSource->m_numColorValues.fR++;
  259. //make sure we are getting a float between 0-1
  260. if (m_afrgbaSource[uiPixel].fR - 1.0f > 0.0f)
  261. {
  262. m_pimageSource->m_numOutOfRangeValues.fR++;
  263. }
  264. }
  265. if (m_afrgbaSource[uiPixel].fG != 0.0f)
  266. {
  267. m_pimageSource->m_numColorValues.fG++;
  268. if (m_afrgbaSource[uiPixel].fG - 1.0f > 0.0f)
  269. {
  270. m_pimageSource->m_numOutOfRangeValues.fG++;
  271. }
  272. }
  273. if (m_afrgbaSource[uiPixel].fB != 0.0f)
  274. {
  275. m_pimageSource->m_numColorValues.fB++;
  276. if (m_afrgbaSource[uiPixel].fB - 1.0f > 0.0f)
  277. {
  278. m_pimageSource->m_numOutOfRangeValues.fB++;
  279. }
  280. }
  281. // for formats with no alpha, set source alpha to 1
  282. if (imageformat == Image::Format::ETC1 ||
  283. imageformat == Image::Format::RGB8 ||
  284. imageformat == Image::Format::SRGB8)
  285. {
  286. m_afrgbaSource[uiPixel].fA = 1.0f;
  287. }
  288. if (imageformat == Image::Format::R11 ||
  289. imageformat == Image::Format::SIGNED_R11)
  290. {
  291. m_afrgbaSource[uiPixel].fA = 1.0f;
  292. m_afrgbaSource[uiPixel].fG = 0.0f;
  293. m_afrgbaSource[uiPixel].fB = 0.0f;
  294. }
  295. if (imageformat == Image::Format::RG11 ||
  296. imageformat == Image::Format::SIGNED_RG11)
  297. {
  298. m_afrgbaSource[uiPixel].fA = 1.0f;
  299. m_afrgbaSource[uiPixel].fB = 0.0f;
  300. }
  301. // for RGB8A1, set source alpha to 0.0 or 1.0
  302. // set punch through flag
  303. if (imageformat == Image::Format::RGB8A1 ||
  304. imageformat == Image::Format::SRGB8A1)
  305. {
  306. if (m_afrgbaSource[uiPixel].fA >= 0.5f)
  307. {
  308. m_afrgbaSource[uiPixel].fA = 1.0f;
  309. }
  310. else
  311. {
  312. m_afrgbaSource[uiPixel].fA = 0.0f;
  313. m_boolPunchThroughPixels = true;
  314. }
  315. }
  316. if (m_afrgbaSource[uiPixel].fA == 1.0f || m_errormetric == RGBX)
  317. {
  318. uiOpaqueSourcePixels++;
  319. }
  320. else if (m_afrgbaSource[uiPixel].fA == 0.0f)
  321. {
  322. uiTransparentSourcePixels++;
  323. }
  324. }
  325. uiPixel += 1;
  326. }
  327. }
  328. if (uiOpaqueSourcePixels == PIXELS)
  329. {
  330. m_sourcealphamix = SourceAlphaMix::OPAQUE;
  331. }
  332. else if (uiTransparentSourcePixels == PIXELS)
  333. {
  334. m_sourcealphamix = SourceAlphaMix::TRANSPARENT;
  335. }
  336. else
  337. {
  338. m_sourcealphamix = SourceAlphaMix::TRANSLUCENT;
  339. }
  340. }
  341. // ----------------------------------------------------------------------------------------------------
  342. // return a name for the encoding mode
  343. //
  344. const char * Block4x4::GetEncodingModeName(void)
  345. {
  346. switch (m_pencoding->GetMode())
  347. {
  348. case Block4x4Encoding::MODE_ETC1:
  349. return "ETC1";
  350. case Block4x4Encoding::MODE_T:
  351. return "T";
  352. case Block4x4Encoding::MODE_H:
  353. return "H";
  354. case Block4x4Encoding::MODE_PLANAR:
  355. return "PLANAR";
  356. default:
  357. return "???";
  358. }
  359. }
  360. // ----------------------------------------------------------------------------------------------------
  361. //
  362. }