EtcBlock4x4Encoding.cpp 8.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262
  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.cpp
  18. Block4x4Encoding is the abstract base class for the different encoders. Each encoder targets a
  19. particular file format (e.g. ETC1, RGB8, RGBA8, R11)
  20. */
  21. #include "EtcConfig.h"
  22. #include "EtcBlock4x4Encoding.h"
  23. #include "EtcBlock4x4EncodingBits.h"
  24. #include "EtcBlock4x4.h"
  25. #include <stdio.h>
  26. #include <string.h>
  27. #include <assert.h>
  28. namespace Etc
  29. {
  30. // ----------------------------------------------------------------------------------------------------
  31. //
  32. const float Block4x4Encoding::LUMA_WEIGHT = 3.0f;
  33. const float Block4x4Encoding::CHROMA_BLUE_WEIGHT = 0.5f;
  34. // ----------------------------------------------------------------------------------------------------
  35. //
  36. Block4x4Encoding::Block4x4Encoding(void)
  37. {
  38. m_pblockParent = nullptr;
  39. m_pafrgbaSource = nullptr;
  40. m_boolBorderPixels = false;
  41. m_fError = -1.0f;
  42. m_mode = MODE_UNKNOWN;
  43. m_uiEncodingIterations = 0;
  44. m_boolDone = false;
  45. for (unsigned int uiPixel = 0; uiPixel < PIXELS; uiPixel++)
  46. {
  47. m_afrgbaDecodedColors[uiPixel] = ColorFloatRGBA(-1.0f, -1.0f, -1.0f, -1.0f);
  48. m_afDecodedAlphas[uiPixel] = -1.0f;
  49. }
  50. }
  51. // ----------------------------------------------------------------------------------------------------
  52. // initialize the generic encoding for a 4x4 block
  53. // a_pblockParent points to the block associated with this encoding
  54. // a_errormetric is used to choose the best encoding
  55. // init the decoded pixels to -1 to mark them as undefined
  56. // init the error to -1 to mark it as undefined
  57. //
  58. void Block4x4Encoding::Init(Block4x4 *a_pblockParent,
  59. ColorFloatRGBA *a_pafrgbaSource,
  60. ErrorMetric a_errormetric)
  61. {
  62. m_pblockParent = a_pblockParent;
  63. m_pafrgbaSource = a_pafrgbaSource;
  64. m_boolBorderPixels = m_pblockParent->HasBorderPixels();
  65. m_fError = -1.0f;
  66. m_uiEncodingIterations = 0;
  67. m_errormetric = a_errormetric;
  68. for (unsigned int uiPixel = 0; uiPixel < PIXELS; uiPixel++)
  69. {
  70. m_afrgbaDecodedColors[uiPixel] = ColorFloatRGBA(-1.0f, -1.0f, -1.0f, -1.0f);
  71. m_afDecodedAlphas[uiPixel] = -1.0f;
  72. }
  73. }
  74. // ----------------------------------------------------------------------------------------------------
  75. // calculate the error for the block by summing the pixel errors
  76. //
  77. void Block4x4Encoding::CalcBlockError(void)
  78. {
  79. m_fError = 0.0f;
  80. for (unsigned int uiPixel = 0; uiPixel < PIXELS; uiPixel++)
  81. {
  82. m_fError += CalcPixelError(m_afrgbaDecodedColors[uiPixel], m_afDecodedAlphas[uiPixel],
  83. m_pafrgbaSource[uiPixel]);
  84. }
  85. }
  86. // ----------------------------------------------------------------------------------------------------
  87. // calculate the error between the source pixel and the decoded pixel
  88. // the error amount is base on the error metric
  89. //
  90. float Block4x4Encoding::CalcPixelError(ColorFloatRGBA a_frgbaDecodedColor, float a_fDecodedAlpha,
  91. ColorFloatRGBA a_frgbaSourcePixel)
  92. {
  93. // if a border pixel
  94. if (isnan(a_frgbaSourcePixel.fA))
  95. {
  96. return 0.0f;
  97. }
  98. if (m_errormetric == ErrorMetric::RGBA)
  99. {
  100. assert(a_fDecodedAlpha >= 0.0f);
  101. float fDRed = (a_fDecodedAlpha * a_frgbaDecodedColor.fR) -
  102. (a_frgbaSourcePixel.fA * a_frgbaSourcePixel.fR);
  103. float fDGreen = (a_fDecodedAlpha * a_frgbaDecodedColor.fG) -
  104. (a_frgbaSourcePixel.fA * a_frgbaSourcePixel.fG);
  105. float fDBlue = (a_fDecodedAlpha * a_frgbaDecodedColor.fB) -
  106. (a_frgbaSourcePixel.fA * a_frgbaSourcePixel.fB);
  107. float fDAlpha = a_fDecodedAlpha - a_frgbaSourcePixel.fA;
  108. return fDRed*fDRed + fDGreen*fDGreen + fDBlue*fDBlue + fDAlpha*fDAlpha;
  109. }
  110. else if (m_errormetric == ErrorMetric::RGBX)
  111. {
  112. assert(a_fDecodedAlpha >= 0.0f);
  113. float fDRed = a_frgbaDecodedColor.fR - a_frgbaSourcePixel.fR;
  114. float fDGreen = a_frgbaDecodedColor.fG - a_frgbaSourcePixel.fG;
  115. float fDBlue = a_frgbaDecodedColor.fB - a_frgbaSourcePixel.fB;
  116. float fDAlpha = a_fDecodedAlpha - a_frgbaSourcePixel.fA;
  117. return fDRed*fDRed + fDGreen*fDGreen + fDBlue*fDBlue + fDAlpha*fDAlpha;
  118. }
  119. else if (m_errormetric == ErrorMetric::REC709)
  120. {
  121. assert(a_fDecodedAlpha >= 0.0f);
  122. float fLuma1 = a_frgbaSourcePixel.fR*0.2126f + a_frgbaSourcePixel.fG*0.7152f + a_frgbaSourcePixel.fB*0.0722f;
  123. float fChromaR1 = 0.5f * ((a_frgbaSourcePixel.fR - fLuma1) * (1.0f / (1.0f - 0.2126f)));
  124. float fChromaB1 = 0.5f * ((a_frgbaSourcePixel.fB - fLuma1) * (1.0f / (1.0f - 0.0722f)));
  125. float fLuma2 = a_frgbaDecodedColor.fR*0.2126f +
  126. a_frgbaDecodedColor.fG*0.7152f +
  127. a_frgbaDecodedColor.fB*0.0722f;
  128. float fChromaR2 = 0.5f * ((a_frgbaDecodedColor.fR - fLuma2) * (1.0f / (1.0f - 0.2126f)));
  129. float fChromaB2 = 0.5f * ((a_frgbaDecodedColor.fB - fLuma2) * (1.0f / (1.0f - 0.0722f)));
  130. float fDeltaL = a_frgbaSourcePixel.fA * fLuma1 - a_fDecodedAlpha * fLuma2;
  131. float fDeltaCr = a_frgbaSourcePixel.fA * fChromaR1 - a_fDecodedAlpha * fChromaR2;
  132. float fDeltaCb = a_frgbaSourcePixel.fA * fChromaB1 - a_fDecodedAlpha * fChromaB2;
  133. float fDAlpha = a_fDecodedAlpha - a_frgbaSourcePixel.fA;
  134. // Favor Luma accuracy over Chroma, and Red over Blue
  135. return LUMA_WEIGHT*fDeltaL*fDeltaL +
  136. fDeltaCr*fDeltaCr +
  137. CHROMA_BLUE_WEIGHT*fDeltaCb*fDeltaCb +
  138. fDAlpha*fDAlpha;
  139. #if 0
  140. float fDRed = a_frgbaDecodedPixel.fR - a_frgbaSourcePixel.fR;
  141. float fDGreen = a_frgbaDecodedPixel.fG - a_frgbaSourcePixel.fG;
  142. float fDBlue = a_frgbaDecodedPixel.fB - a_frgbaSourcePixel.fB;
  143. return 2.0f * 3.0f * fDeltaL * fDeltaL + fDRed*fDRed + fDGreen*fDGreen + fDBlue*fDBlue;
  144. #endif
  145. }
  146. else if (m_errormetric == ErrorMetric::NORMALXYZ)
  147. {
  148. float fDecodedX = 2.0f * a_frgbaDecodedColor.fR - 1.0f;
  149. float fDecodedY = 2.0f * a_frgbaDecodedColor.fG - 1.0f;
  150. float fDecodedZ = 2.0f * a_frgbaDecodedColor.fB - 1.0f;
  151. float fDecodedLength = sqrtf(fDecodedX*fDecodedX + fDecodedY*fDecodedY + fDecodedZ*fDecodedZ);
  152. if (fDecodedLength < 0.5f)
  153. {
  154. return 1.0f;
  155. }
  156. else if (fDecodedLength == 0.0f)
  157. {
  158. fDecodedX = 1.0f;
  159. fDecodedY = 0.0f;
  160. fDecodedZ = 0.0f;
  161. }
  162. else
  163. {
  164. fDecodedX /= fDecodedLength;
  165. fDecodedY /= fDecodedLength;
  166. fDecodedZ /= fDecodedLength;
  167. }
  168. float fSourceX = 2.0f * a_frgbaSourcePixel.fR - 1.0f;
  169. float fSourceY = 2.0f * a_frgbaSourcePixel.fG - 1.0f;
  170. float fSourceZ = 2.0f * a_frgbaSourcePixel.fB - 1.0f;
  171. float fSourceLength = sqrtf(fSourceX*fSourceX + fSourceY*fSourceY + fSourceZ*fSourceZ);
  172. if (fSourceLength == 0.0f)
  173. {
  174. fSourceX = 1.0f;
  175. fSourceY = 0.0f;
  176. fSourceZ = 0.0f;
  177. }
  178. else
  179. {
  180. fSourceX /= fSourceLength;
  181. fSourceY /= fSourceLength;
  182. fSourceZ /= fSourceLength;
  183. }
  184. float fDotProduct = fSourceX*fDecodedX + fSourceY*fDecodedY + fSourceZ*fDecodedZ;
  185. float fNormalizedDotProduct = 1.0f - 0.5f * (fDotProduct + 1.0f);
  186. float fDotProductError = fNormalizedDotProduct * fNormalizedDotProduct;
  187. float fLength2 = fDecodedX*fDecodedX + fDecodedY*fDecodedY + fDecodedZ*fDecodedZ;
  188. float fLength2Error = fabsf(1.0f - fLength2);
  189. float fDeltaW = a_frgbaDecodedColor.fA - a_frgbaSourcePixel.fA;
  190. float fErrorW = fDeltaW * fDeltaW;
  191. return fDotProductError + fLength2Error + fErrorW;
  192. }
  193. else // ErrorMetric::NUMERIC
  194. {
  195. assert(a_fDecodedAlpha >= 0.0f);
  196. float fDX = a_frgbaDecodedColor.fR - a_frgbaSourcePixel.fR;
  197. float fDY = a_frgbaDecodedColor.fG - a_frgbaSourcePixel.fG;
  198. float fDZ = a_frgbaDecodedColor.fB - a_frgbaSourcePixel.fB;
  199. float fDW = a_frgbaDecodedColor.fA - a_frgbaSourcePixel.fA;
  200. return fDX*fDX + fDY*fDY + fDZ*fDZ + fDW*fDW;
  201. }
  202. }
  203. // ----------------------------------------------------------------------------------------------------
  204. //
  205. } // namespace Etc