summaryrefslogtreecommitdiff
path: root/thirdparty/etc2comp/EtcBlock4x4.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'thirdparty/etc2comp/EtcBlock4x4.cpp')
-rw-r--r--thirdparty/etc2comp/EtcBlock4x4.cpp425
1 files changed, 425 insertions, 0 deletions
diff --git a/thirdparty/etc2comp/EtcBlock4x4.cpp b/thirdparty/etc2comp/EtcBlock4x4.cpp
new file mode 100644
index 0000000000..3082fe60db
--- /dev/null
+++ b/thirdparty/etc2comp/EtcBlock4x4.cpp
@@ -0,0 +1,425 @@
+/*
+ * 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.
+ */
+
+/*
+EtcBlock4x4.cpp
+
+Implements the state associated with each 4x4 block of pixels in an image
+
+Source images that are not a multiple of 4x4 are extended to fill the Block4x4 using pixels with an
+alpha of NAN
+
+*/
+
+#include "EtcConfig.h"
+#include "EtcBlock4x4.h"
+
+#include "EtcBlock4x4EncodingBits.h"
+#include "EtcColor.h"
+#include "EtcImage.h"
+#include "EtcColorFloatRGBA.h"
+#include "EtcBlock4x4Encoding_RGB8.h"
+#include "EtcBlock4x4Encoding_RGBA8.h"
+#include "EtcBlock4x4Encoding_RGB8A1.h"
+#include "EtcBlock4x4Encoding_R11.h"
+#include "EtcBlock4x4Encoding_RG11.h"
+
+#include <stdio.h>
+#include <string.h>
+#include <assert.h>
+
+namespace Etc
+{
+ // ETC pixels are scanned vertically.
+ // this mapping is for when someone wants to scan the ETC pixels horizontally
+ const unsigned int Block4x4::s_auiPixelOrderHScan[PIXELS] = { 0, 4, 8, 12, 1, 5, 9, 13, 2, 6, 10, 14, 3, 7, 11, 15 };
+
+ // ----------------------------------------------------------------------------------------------------
+ //
+ Block4x4::Block4x4(void)
+ {
+ m_pimageSource = nullptr;
+ m_uiSourceH = 0;
+ m_uiSourceV = 0;
+
+ m_sourcealphamix = SourceAlphaMix::UNKNOWN;
+ m_boolBorderPixels = false;
+ m_boolPunchThroughPixels = false;
+
+ m_pencoding = nullptr;
+
+ m_errormetric = ErrorMetric::NUMERIC;
+
+ }
+ Block4x4::~Block4x4()
+ {
+ m_pimageSource = nullptr;
+ if (m_pencoding)
+ {
+ delete m_pencoding;
+ m_pencoding = nullptr;
+ }
+ }
+ // ----------------------------------------------------------------------------------------------------
+ // initialization prior to encoding from a source image
+ // [a_uiSourceH,a_uiSourceV] is the location of the block in a_pimageSource
+ // a_paucEncodingBits is the place to store the final encoding
+ // a_errormetric is used for finding the best encoding
+ //
+ void Block4x4::InitFromSource(Image *a_pimageSource,
+ unsigned int a_uiSourceH, unsigned int a_uiSourceV,
+ unsigned char *a_paucEncodingBits,
+ ErrorMetric a_errormetric)
+ {
+
+ Block4x4();
+
+ m_pimageSource = a_pimageSource;
+ m_uiSourceH = a_uiSourceH;
+ m_uiSourceV = a_uiSourceV;
+ m_errormetric = a_errormetric;
+
+ SetSourcePixels();
+
+ // set block encoder function
+ switch (m_pimageSource->GetFormat())
+ {
+ case Image::Format::ETC1:
+ m_pencoding = new Block4x4Encoding_ETC1;
+ break;
+
+ case Image::Format::RGB8:
+ case Image::Format::SRGB8:
+ m_pencoding = new Block4x4Encoding_RGB8;
+ break;
+
+ case Image::Format::RGBA8:
+ case Image::Format::SRGBA8:
+ if (a_errormetric == RGBX)
+ {
+ m_pencoding = new Block4x4Encoding_RGBA8;
+ }
+ else
+ {
+ switch (m_sourcealphamix)
+ {
+ case SourceAlphaMix::OPAQUE:
+ m_pencoding = new Block4x4Encoding_RGBA8_Opaque;
+ break;
+
+ case SourceAlphaMix::TRANSPARENT:
+ m_pencoding = new Block4x4Encoding_RGBA8_Transparent;
+ break;
+
+ case SourceAlphaMix::TRANSLUCENT:
+ m_pencoding = new Block4x4Encoding_RGBA8;
+ break;
+
+ default:
+ assert(0);
+ break;
+ }
+ break;
+ }
+ break;
+
+ case Image::Format::RGB8A1:
+ case Image::Format::SRGB8A1:
+ switch (m_sourcealphamix)
+ {
+ case SourceAlphaMix::OPAQUE:
+ m_pencoding = new Block4x4Encoding_RGB8A1_Opaque;
+ break;
+
+ case SourceAlphaMix::TRANSPARENT:
+ m_pencoding = new Block4x4Encoding_RGB8A1_Transparent;
+ break;
+
+ case SourceAlphaMix::TRANSLUCENT:
+ if (m_boolPunchThroughPixels)
+ {
+ m_pencoding = new Block4x4Encoding_RGB8A1;
+ }
+ else
+ {
+ m_pencoding = new Block4x4Encoding_RGB8A1_Opaque;
+ }
+ break;
+
+ default:
+ assert(0);
+ break;
+ }
+ break;
+
+ case Image::Format::R11:
+ case Image::Format::SIGNED_R11:
+ m_pencoding = new Block4x4Encoding_R11;
+ break;
+ case Image::Format::RG11:
+ case Image::Format::SIGNED_RG11:
+ m_pencoding = new Block4x4Encoding_RG11;
+ break;
+ default:
+ assert(0);
+ break;
+ }
+
+ m_pencoding->InitFromSource(this, m_afrgbaSource,
+ a_paucEncodingBits, a_errormetric);
+
+ }
+
+ // ----------------------------------------------------------------------------------------------------
+ // initialization of encoding state from a prior encoding using encoding bits
+ // [a_uiSourceH,a_uiSourceV] is the location of the block in a_pimageSource
+ // a_paucEncodingBits is the place to read the prior encoding
+ // a_imageformat is used to determine how to interpret a_paucEncodingBits
+ // a_errormetric was used for the prior encoding
+ //
+ void Block4x4::InitFromEtcEncodingBits(Image::Format a_imageformat,
+ unsigned int a_uiSourceH, unsigned int a_uiSourceV,
+ unsigned char *a_paucEncodingBits,
+ Image *a_pimageSource,
+ ErrorMetric a_errormetric)
+ {
+ Block4x4();
+
+ m_pimageSource = a_pimageSource;
+ m_uiSourceH = a_uiSourceH;
+ m_uiSourceV = a_uiSourceV;
+ m_errormetric = a_errormetric;
+
+ SetSourcePixels();
+
+ // set block encoder function
+ switch (a_imageformat)
+ {
+ case Image::Format::ETC1:
+ m_pencoding = new Block4x4Encoding_ETC1;
+ break;
+
+ case Image::Format::RGB8:
+ case Image::Format::SRGB8:
+ m_pencoding = new Block4x4Encoding_RGB8;
+ break;
+
+ case Image::Format::RGBA8:
+ case Image::Format::SRGBA8:
+ m_pencoding = new Block4x4Encoding_RGBA8;
+ break;
+
+ case Image::Format::RGB8A1:
+ case Image::Format::SRGB8A1:
+ m_pencoding = new Block4x4Encoding_RGB8A1;
+ break;
+
+ case Image::Format::R11:
+ case Image::Format::SIGNED_R11:
+ m_pencoding = new Block4x4Encoding_R11;
+ break;
+ case Image::Format::RG11:
+ case Image::Format::SIGNED_RG11:
+ m_pencoding = new Block4x4Encoding_RG11;
+ break;
+ default:
+ assert(0);
+ break;
+ }
+
+ m_pencoding->InitFromEncodingBits(this, a_paucEncodingBits, m_afrgbaSource,
+ m_pimageSource->GetErrorMetric());
+
+ }
+
+ // ----------------------------------------------------------------------------------------------------
+ // set source pixels from m_pimageSource
+ // set m_alphamix
+ //
+ void Block4x4::SetSourcePixels(void)
+ {
+
+ Image::Format imageformat = m_pimageSource->GetFormat();
+
+ // alpha census
+ unsigned int uiTransparentSourcePixels = 0;
+ unsigned int uiOpaqueSourcePixels = 0;
+
+ // copy source to consecutive memory locations
+ // convert from image horizontal scan to block vertical scan
+ unsigned int uiPixel = 0;
+ for (unsigned int uiBlockPixelH = 0; uiBlockPixelH < Block4x4::COLUMNS; uiBlockPixelH++)
+ {
+ unsigned int uiSourcePixelH = m_uiSourceH + uiBlockPixelH;
+
+ for (unsigned int uiBlockPixelV = 0; uiBlockPixelV < Block4x4::ROWS; uiBlockPixelV++)
+ {
+ unsigned int uiSourcePixelV = m_uiSourceV + uiBlockPixelV;
+
+ ColorFloatRGBA *pfrgbaSource = m_pimageSource->GetSourcePixel(uiSourcePixelH, uiSourcePixelV);
+
+ // if pixel extends beyond source image because of block padding
+ if (pfrgbaSource == nullptr)
+ {
+ m_afrgbaSource[uiPixel] = ColorFloatRGBA(0.0f, 0.0f, 0.0f, NAN); // denotes border pixel
+ m_boolBorderPixels = true;
+ uiTransparentSourcePixels++;
+ }
+ else
+ {
+ //get teh current pixel data, and store some of the attributes
+ //before capping values to fit the encoder type
+
+ m_afrgbaSource[uiPixel] = (*pfrgbaSource).ClampRGBA();
+
+ if (m_afrgbaSource[uiPixel].fA == 1.0f || m_errormetric == RGBX)
+ {
+ m_pimageSource->m_iNumOpaquePixels++;
+ }
+ else if (m_afrgbaSource[uiPixel].fA == 0.0f)
+ {
+ m_pimageSource->m_iNumTransparentPixels++;
+ }
+ else if(m_afrgbaSource[uiPixel].fA > 0.0f && m_afrgbaSource[uiPixel].fA < 1.0f)
+ {
+ m_pimageSource->m_iNumTranslucentPixels++;
+ }
+ else
+ {
+ m_pimageSource->m_numOutOfRangeValues.fA++;
+ }
+
+ if (m_afrgbaSource[uiPixel].fR != 0.0f)
+ {
+ m_pimageSource->m_numColorValues.fR++;
+ //make sure we are getting a float between 0-1
+ if (m_afrgbaSource[uiPixel].fR - 1.0f > 0.0f)
+ {
+ m_pimageSource->m_numOutOfRangeValues.fR++;
+ }
+ }
+
+ if (m_afrgbaSource[uiPixel].fG != 0.0f)
+ {
+ m_pimageSource->m_numColorValues.fG++;
+ if (m_afrgbaSource[uiPixel].fG - 1.0f > 0.0f)
+ {
+ m_pimageSource->m_numOutOfRangeValues.fG++;
+ }
+ }
+ if (m_afrgbaSource[uiPixel].fB != 0.0f)
+ {
+ m_pimageSource->m_numColorValues.fB++;
+ if (m_afrgbaSource[uiPixel].fB - 1.0f > 0.0f)
+ {
+ m_pimageSource->m_numOutOfRangeValues.fB++;
+ }
+ }
+ // for formats with no alpha, set source alpha to 1
+ if (imageformat == Image::Format::ETC1 ||
+ imageformat == Image::Format::RGB8 ||
+ imageformat == Image::Format::SRGB8)
+ {
+ m_afrgbaSource[uiPixel].fA = 1.0f;
+ }
+
+ if (imageformat == Image::Format::R11 ||
+ imageformat == Image::Format::SIGNED_R11)
+ {
+ m_afrgbaSource[uiPixel].fA = 1.0f;
+ m_afrgbaSource[uiPixel].fG = 0.0f;
+ m_afrgbaSource[uiPixel].fB = 0.0f;
+ }
+
+ if (imageformat == Image::Format::RG11 ||
+ imageformat == Image::Format::SIGNED_RG11)
+ {
+ m_afrgbaSource[uiPixel].fA = 1.0f;
+ m_afrgbaSource[uiPixel].fB = 0.0f;
+ }
+
+
+ // for RGB8A1, set source alpha to 0.0 or 1.0
+ // set punch through flag
+ if (imageformat == Image::Format::RGB8A1 ||
+ imageformat == Image::Format::SRGB8A1)
+ {
+ if (m_afrgbaSource[uiPixel].fA >= 0.5f)
+ {
+ m_afrgbaSource[uiPixel].fA = 1.0f;
+ }
+ else
+ {
+ m_afrgbaSource[uiPixel].fA = 0.0f;
+ m_boolPunchThroughPixels = true;
+ }
+ }
+
+ if (m_afrgbaSource[uiPixel].fA == 1.0f || m_errormetric == RGBX)
+ {
+ uiOpaqueSourcePixels++;
+ }
+ else if (m_afrgbaSource[uiPixel].fA == 0.0f)
+ {
+ uiTransparentSourcePixels++;
+ }
+
+ }
+
+ uiPixel += 1;
+ }
+ }
+
+ if (uiOpaqueSourcePixels == PIXELS)
+ {
+ m_sourcealphamix = SourceAlphaMix::OPAQUE;
+ }
+ else if (uiTransparentSourcePixels == PIXELS)
+ {
+ m_sourcealphamix = SourceAlphaMix::TRANSPARENT;
+ }
+ else
+ {
+ m_sourcealphamix = SourceAlphaMix::TRANSLUCENT;
+ }
+
+ }
+
+ // ----------------------------------------------------------------------------------------------------
+ // return a name for the encoding mode
+ //
+ const char * Block4x4::GetEncodingModeName(void)
+ {
+
+ switch (m_pencoding->GetMode())
+ {
+ case Block4x4Encoding::MODE_ETC1:
+ return "ETC1";
+ case Block4x4Encoding::MODE_T:
+ return "T";
+ case Block4x4Encoding::MODE_H:
+ return "H";
+ case Block4x4Encoding::MODE_PLANAR:
+ return "PLANAR";
+ default:
+ return "???";
+ }
+ }
+
+ // ----------------------------------------------------------------------------------------------------
+ //
+
+}