summaryrefslogtreecommitdiff
path: root/thirdparty/etc2comp/EtcBlock4x4Encoding.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'thirdparty/etc2comp/EtcBlock4x4Encoding.cpp')
-rw-r--r--thirdparty/etc2comp/EtcBlock4x4Encoding.cpp261
1 files changed, 261 insertions, 0 deletions
diff --git a/thirdparty/etc2comp/EtcBlock4x4Encoding.cpp b/thirdparty/etc2comp/EtcBlock4x4Encoding.cpp
new file mode 100644
index 0000000000..7a9e68c4cf
--- /dev/null
+++ b/thirdparty/etc2comp/EtcBlock4x4Encoding.cpp
@@ -0,0 +1,261 @@
+/*
+ * Copyright 2015 The Etc2Comp Authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/*
+EtcBlock4x4Encoding.cpp
+
+Block4x4Encoding is the abstract base class for the different encoders. Each encoder targets a
+particular file format (e.g. ETC1, RGB8, RGBA8, R11)
+
+*/
+
+#include "EtcConfig.h"
+#include "EtcBlock4x4Encoding.h"
+
+#include "EtcBlock4x4EncodingBits.h"
+#include "EtcBlock4x4.h"
+
+#include <stdio.h>
+#include <string.h>
+#include <assert.h>
+
+namespace Etc
+{
+ // ----------------------------------------------------------------------------------------------------
+ //
+ const float Block4x4Encoding::LUMA_WEIGHT = 3.0f;
+ const float Block4x4Encoding::CHROMA_BLUE_WEIGHT = 0.5f;
+
+ // ----------------------------------------------------------------------------------------------------
+ //
+ Block4x4Encoding::Block4x4Encoding(void)
+ {
+
+ m_pblockParent = nullptr;
+
+ m_pafrgbaSource = nullptr;
+
+ m_boolBorderPixels = false;
+
+ m_fError = -1.0f;
+
+ m_mode = MODE_UNKNOWN;
+
+ m_uiEncodingIterations = 0;
+ m_boolDone = false;
+
+ for (unsigned int uiPixel = 0; uiPixel < PIXELS; uiPixel++)
+ {
+ m_afrgbaDecodedColors[uiPixel] = ColorFloatRGBA(-1.0f, -1.0f, -1.0f, -1.0f);
+ m_afDecodedAlphas[uiPixel] = -1.0f;
+ }
+
+ }
+
+ // ----------------------------------------------------------------------------------------------------
+ // initialize the generic encoding for a 4x4 block
+ // a_pblockParent points to the block associated with this encoding
+ // a_errormetric is used to choose the best encoding
+ // init the decoded pixels to -1 to mark them as undefined
+ // init the error to -1 to mark it as undefined
+ //
+ void Block4x4Encoding::Init(Block4x4 *a_pblockParent,
+ ColorFloatRGBA *a_pafrgbaSource,
+ ErrorMetric a_errormetric)
+ {
+
+ m_pblockParent = a_pblockParent;
+
+ m_pafrgbaSource = a_pafrgbaSource;
+
+ m_boolBorderPixels = m_pblockParent->HasBorderPixels();
+
+ m_fError = -1.0f;
+
+ m_uiEncodingIterations = 0;
+
+ m_errormetric = a_errormetric;
+
+ for (unsigned int uiPixel = 0; uiPixel < PIXELS; uiPixel++)
+ {
+ m_afrgbaDecodedColors[uiPixel] = ColorFloatRGBA(-1.0f, -1.0f, -1.0f, -1.0f);
+ m_afDecodedAlphas[uiPixel] = -1.0f;
+ }
+
+ }
+
+ // ----------------------------------------------------------------------------------------------------
+ // calculate the error for the block by summing the pixel errors
+ //
+ void Block4x4Encoding::CalcBlockError(void)
+ {
+ m_fError = 0.0f;
+
+ for (unsigned int uiPixel = 0; uiPixel < PIXELS; uiPixel++)
+ {
+ m_fError += CalcPixelError(m_afrgbaDecodedColors[uiPixel], m_afDecodedAlphas[uiPixel],
+ m_pafrgbaSource[uiPixel]);
+ }
+
+ }
+
+ // ----------------------------------------------------------------------------------------------------
+ // calculate the error between the source pixel and the decoded pixel
+ // the error amount is base on the error metric
+ //
+ float Block4x4Encoding::CalcPixelError(ColorFloatRGBA a_frgbaDecodedColor, float a_fDecodedAlpha,
+ ColorFloatRGBA a_frgbaSourcePixel)
+ {
+
+ // if a border pixel
+ if (isnan(a_frgbaSourcePixel.fA))
+ {
+ return 0.0f;
+ }
+
+ if (m_errormetric == ErrorMetric::RGBA)
+ {
+ assert(a_fDecodedAlpha >= 0.0f);
+
+ float fDRed = (a_fDecodedAlpha * a_frgbaDecodedColor.fR) -
+ (a_frgbaSourcePixel.fA * a_frgbaSourcePixel.fR);
+ float fDGreen = (a_fDecodedAlpha * a_frgbaDecodedColor.fG) -
+ (a_frgbaSourcePixel.fA * a_frgbaSourcePixel.fG);
+ float fDBlue = (a_fDecodedAlpha * a_frgbaDecodedColor.fB) -
+ (a_frgbaSourcePixel.fA * a_frgbaSourcePixel.fB);
+
+ float fDAlpha = a_fDecodedAlpha - a_frgbaSourcePixel.fA;
+
+ return fDRed*fDRed + fDGreen*fDGreen + fDBlue*fDBlue + fDAlpha*fDAlpha;
+ }
+ else if (m_errormetric == ErrorMetric::RGBX)
+ {
+ assert(a_fDecodedAlpha >= 0.0f);
+
+ float fDRed = a_frgbaDecodedColor.fR - a_frgbaSourcePixel.fR;
+ float fDGreen = a_frgbaDecodedColor.fG - a_frgbaSourcePixel.fG;
+ float fDBlue = a_frgbaDecodedColor.fB - a_frgbaSourcePixel.fB;
+ float fDAlpha = a_fDecodedAlpha - a_frgbaSourcePixel.fA;
+
+ return fDRed*fDRed + fDGreen*fDGreen + fDBlue*fDBlue + fDAlpha*fDAlpha;
+ }
+ else if (m_errormetric == ErrorMetric::REC709)
+ {
+ assert(a_fDecodedAlpha >= 0.0f);
+
+ float fLuma1 = a_frgbaSourcePixel.fR*0.2126f + a_frgbaSourcePixel.fG*0.7152f + a_frgbaSourcePixel.fB*0.0722f;
+ float fChromaR1 = 0.5f * ((a_frgbaSourcePixel.fR - fLuma1) * (1.0f / (1.0f - 0.2126f)));
+ float fChromaB1 = 0.5f * ((a_frgbaSourcePixel.fB - fLuma1) * (1.0f / (1.0f - 0.0722f)));
+
+ float fLuma2 = a_frgbaDecodedColor.fR*0.2126f +
+ a_frgbaDecodedColor.fG*0.7152f +
+ a_frgbaDecodedColor.fB*0.0722f;
+ float fChromaR2 = 0.5f * ((a_frgbaDecodedColor.fR - fLuma2) * (1.0f / (1.0f - 0.2126f)));
+ float fChromaB2 = 0.5f * ((a_frgbaDecodedColor.fB - fLuma2) * (1.0f / (1.0f - 0.0722f)));
+
+ float fDeltaL = a_frgbaSourcePixel.fA * fLuma1 - a_fDecodedAlpha * fLuma2;
+ float fDeltaCr = a_frgbaSourcePixel.fA * fChromaR1 - a_fDecodedAlpha * fChromaR2;
+ float fDeltaCb = a_frgbaSourcePixel.fA * fChromaB1 - a_fDecodedAlpha * fChromaB2;
+
+ float fDAlpha = a_fDecodedAlpha - a_frgbaSourcePixel.fA;
+
+ // Favor Luma accuracy over Chroma, and Red over Blue
+ return LUMA_WEIGHT*fDeltaL*fDeltaL +
+ fDeltaCr*fDeltaCr +
+ CHROMA_BLUE_WEIGHT*fDeltaCb*fDeltaCb +
+ fDAlpha*fDAlpha;
+ #if 0
+ float fDRed = a_frgbaDecodedPixel.fR - a_frgbaSourcePixel.fR;
+ float fDGreen = a_frgbaDecodedPixel.fG - a_frgbaSourcePixel.fG;
+ float fDBlue = a_frgbaDecodedPixel.fB - a_frgbaSourcePixel.fB;
+ return 2.0f * 3.0f * fDeltaL * fDeltaL + fDRed*fDRed + fDGreen*fDGreen + fDBlue*fDBlue;
+#endif
+ }
+ else if (m_errormetric == ErrorMetric::NORMALXYZ)
+ {
+ float fDecodedX = 2.0f * a_frgbaDecodedColor.fR - 1.0f;
+ float fDecodedY = 2.0f * a_frgbaDecodedColor.fG - 1.0f;
+ float fDecodedZ = 2.0f * a_frgbaDecodedColor.fB - 1.0f;
+
+ float fDecodedLength = sqrtf(fDecodedX*fDecodedX + fDecodedY*fDecodedY + fDecodedZ*fDecodedZ);
+
+ if (fDecodedLength < 0.5f)
+ {
+ return 1.0f;
+ }
+ else if (fDecodedLength == 0.0f)
+ {
+ fDecodedX = 1.0f;
+ fDecodedY = 0.0f;
+ fDecodedZ = 0.0f;
+ }
+ else
+ {
+ fDecodedX /= fDecodedLength;
+ fDecodedY /= fDecodedLength;
+ fDecodedZ /= fDecodedLength;
+ }
+
+ float fSourceX = 2.0f * a_frgbaSourcePixel.fR - 1.0f;
+ float fSourceY = 2.0f * a_frgbaSourcePixel.fG - 1.0f;
+ float fSourceZ = 2.0f * a_frgbaSourcePixel.fB - 1.0f;
+
+ float fSourceLength = sqrtf(fSourceX*fSourceX + fSourceY*fSourceY + fSourceZ*fSourceZ);
+
+ if (fSourceLength == 0.0f)
+ {
+ fSourceX = 1.0f;
+ fSourceY = 0.0f;
+ fSourceZ = 0.0f;
+ }
+ else
+ {
+ fSourceX /= fSourceLength;
+ fSourceY /= fSourceLength;
+ fSourceZ /= fSourceLength;
+ }
+
+ float fDotProduct = fSourceX*fDecodedX + fSourceY*fDecodedY + fSourceZ*fDecodedZ;
+ float fNormalizedDotProduct = 1.0f - 0.5f * (fDotProduct + 1.0f);
+ float fDotProductError = fNormalizedDotProduct * fNormalizedDotProduct;
+
+ float fLength2 = fDecodedX*fDecodedX + fDecodedY*fDecodedY + fDecodedZ*fDecodedZ;
+ float fLength2Error = fabsf(1.0f - fLength2);
+
+ float fDeltaW = a_frgbaDecodedColor.fA - a_frgbaSourcePixel.fA;
+ float fErrorW = fDeltaW * fDeltaW;
+
+ return fDotProductError + fLength2Error + fErrorW;
+ }
+ else // ErrorMetric::NUMERIC
+ {
+ assert(a_fDecodedAlpha >= 0.0f);
+
+ float fDX = a_frgbaDecodedColor.fR - a_frgbaSourcePixel.fR;
+ float fDY = a_frgbaDecodedColor.fG - a_frgbaSourcePixel.fG;
+ float fDZ = a_frgbaDecodedColor.fB - a_frgbaSourcePixel.fB;
+ float fDW = a_frgbaDecodedColor.fA - a_frgbaSourcePixel.fA;
+
+ return fDX*fDX + fDY*fDY + fDZ*fDZ + fDW*fDW;
+ }
+
+ }
+
+ // ----------------------------------------------------------------------------------------------------
+ //
+
+} // namespace Etc
+