123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262 |
- /*
- * 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
|