123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426 |
- /*
- * 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 "???";
- }
- }
- // ----------------------------------------------------------------------------------------------------
- //
- }
|