Add some external dependencies.
This commit is contained in:
417
extern/EtcLib/EtcCodec/EtcBlock4x4.cpp
vendored
Normal file
417
extern/EtcLib/EtcCodec/EtcBlock4x4.cpp
vendored
Normal file
@ -0,0 +1,417 @@
|
||||
/*
|
||||
* 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:
|
||||
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;
|
||||
|
||||
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_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)
|
||||
{
|
||||
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 "???";
|
||||
}
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------------------------------
|
||||
//
|
||||
|
||||
}
|
172
extern/EtcLib/EtcCodec/EtcBlock4x4.h
vendored
Normal file
172
extern/EtcLib/EtcCodec/EtcBlock4x4.h
vendored
Normal file
@ -0,0 +1,172 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "EtcColor.h"
|
||||
#include "EtcColorFloatRGBA.h"
|
||||
#include "EtcErrorMetric.h"
|
||||
#include "EtcImage.h"
|
||||
#include "EtcBlock4x4Encoding.h"
|
||||
|
||||
namespace Etc
|
||||
{
|
||||
class Block4x4EncodingBits;
|
||||
|
||||
class Block4x4
|
||||
{
|
||||
public:
|
||||
|
||||
static const unsigned int ROWS = 4;
|
||||
static const unsigned int COLUMNS = 4;
|
||||
static const unsigned int PIXELS = ROWS * COLUMNS;
|
||||
|
||||
// the alpha mix for a 4x4 block of pixels
|
||||
enum class SourceAlphaMix
|
||||
{
|
||||
UNKNOWN,
|
||||
//
|
||||
OPAQUE, // all 1.0
|
||||
TRANSPARENT, // all 0.0 or NAN
|
||||
TRANSLUCENT // not all opaque or transparent
|
||||
};
|
||||
|
||||
typedef void (Block4x4::*EncoderFunctionPtr)(void);
|
||||
|
||||
Block4x4(void);
|
||||
~Block4x4();
|
||||
void InitFromSource(Image *a_pimageSource,
|
||||
unsigned int a_uiSourceH,
|
||||
unsigned int a_uiSourceV,
|
||||
unsigned char *a_paucEncodingBits,
|
||||
ErrorMetric a_errormetric);
|
||||
|
||||
void InitFromEtcEncodingBits(Image::Format a_imageformat,
|
||||
unsigned int a_uiSourceH,
|
||||
unsigned int a_uiSourceV,
|
||||
unsigned char *a_paucEncodingBits,
|
||||
Image *a_pimageSource,
|
||||
ErrorMetric a_errormetric);
|
||||
|
||||
// return true if final iteration was performed
|
||||
inline void PerformEncodingIteration(float a_fEffort)
|
||||
{
|
||||
m_pencoding->PerformIteration(a_fEffort);
|
||||
}
|
||||
|
||||
inline void SetEncodingBitsFromEncoding(void)
|
||||
{
|
||||
m_pencoding->SetEncodingBits();
|
||||
}
|
||||
|
||||
inline unsigned int GetSourceH(void)
|
||||
{
|
||||
return m_uiSourceH;
|
||||
}
|
||||
|
||||
inline unsigned int GetSourceV(void)
|
||||
{
|
||||
return m_uiSourceV;
|
||||
}
|
||||
|
||||
inline float GetError(void)
|
||||
{
|
||||
return m_pencoding->GetError();
|
||||
}
|
||||
|
||||
static const unsigned int s_auiPixelOrderHScan[PIXELS];
|
||||
|
||||
inline ColorFloatRGBA * GetDecodedColors(void)
|
||||
{
|
||||
return m_pencoding->GetDecodedColors();
|
||||
}
|
||||
|
||||
inline float * GetDecodedAlphas(void)
|
||||
{
|
||||
return m_pencoding->GetDecodedAlphas();
|
||||
}
|
||||
|
||||
inline Block4x4Encoding::Mode GetEncodingMode(void)
|
||||
{
|
||||
return m_pencoding->GetMode();
|
||||
}
|
||||
|
||||
inline bool GetFlip(void)
|
||||
{
|
||||
return m_pencoding->GetFlip();
|
||||
}
|
||||
|
||||
inline bool IsDifferential(void)
|
||||
{
|
||||
return m_pencoding->IsDifferential();
|
||||
}
|
||||
|
||||
inline ColorFloatRGBA * GetSource()
|
||||
{
|
||||
return m_afrgbaSource;
|
||||
}
|
||||
|
||||
inline ErrorMetric GetErrorMetric()
|
||||
{
|
||||
return m_errormetric;
|
||||
}
|
||||
|
||||
const char * GetEncodingModeName(void);
|
||||
|
||||
inline Block4x4Encoding * GetEncoding(void)
|
||||
{
|
||||
return m_pencoding;
|
||||
}
|
||||
|
||||
inline SourceAlphaMix GetSourceAlphaMix(void)
|
||||
{
|
||||
return m_sourcealphamix;
|
||||
}
|
||||
|
||||
inline Image * GetImageSource(void)
|
||||
{
|
||||
return m_pimageSource;
|
||||
}
|
||||
|
||||
inline bool HasBorderPixels(void)
|
||||
{
|
||||
return m_boolBorderPixels;
|
||||
}
|
||||
|
||||
inline bool HasPunchThroughPixels(void)
|
||||
{
|
||||
return m_boolPunchThroughPixels;
|
||||
}
|
||||
|
||||
private:
|
||||
|
||||
void SetSourcePixels(void);
|
||||
|
||||
Image *m_pimageSource;
|
||||
unsigned int m_uiSourceH;
|
||||
unsigned int m_uiSourceV;
|
||||
ErrorMetric m_errormetric;
|
||||
ColorFloatRGBA m_afrgbaSource[PIXELS]; // vertical scan
|
||||
|
||||
SourceAlphaMix m_sourcealphamix;
|
||||
bool m_boolBorderPixels; // marked as rgba(NAN, NAN, NAN, NAN)
|
||||
bool m_boolPunchThroughPixels; // RGB8A1 or SRGB8A1 with any pixels with alpha < 0.5
|
||||
|
||||
Block4x4Encoding *m_pencoding;
|
||||
|
||||
};
|
||||
|
||||
} // namespace Etc
|
250
extern/EtcLib/EtcCodec/EtcBlock4x4Encoding.cpp
vendored
Normal file
250
extern/EtcLib/EtcCodec/EtcBlock4x4Encoding.cpp
vendored
Normal file
@ -0,0 +1,250 @@
|
||||
/*
|
||||
* 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::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
|
||||
|
148
extern/EtcLib/EtcCodec/EtcBlock4x4Encoding.h
vendored
Normal file
148
extern/EtcLib/EtcCodec/EtcBlock4x4Encoding.h
vendored
Normal file
@ -0,0 +1,148 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "EtcColorFloatRGBA.h"
|
||||
|
||||
#include "EtcErrorMetric.h"
|
||||
|
||||
#include <assert.h>
|
||||
#include <float.h>
|
||||
|
||||
namespace Etc
|
||||
{
|
||||
class Block4x4;
|
||||
|
||||
// abstract base class for specific encodings
|
||||
class Block4x4Encoding
|
||||
{
|
||||
public:
|
||||
|
||||
static const unsigned int ROWS = 4;
|
||||
static const unsigned int COLUMNS = 4;
|
||||
static const unsigned int PIXELS = ROWS * COLUMNS;
|
||||
static const float LUMA_WEIGHT;
|
||||
static const float CHROMA_BLUE_WEIGHT;
|
||||
|
||||
typedef enum
|
||||
{
|
||||
MODE_UNKNOWN,
|
||||
//
|
||||
MODE_ETC1,
|
||||
MODE_T,
|
||||
MODE_H,
|
||||
MODE_PLANAR,
|
||||
MODE_R11,
|
||||
MODE_RG11,
|
||||
//
|
||||
MODES
|
||||
} Mode;
|
||||
|
||||
Block4x4Encoding(void);
|
||||
//virtual ~Block4x4Encoding(void) =0;
|
||||
virtual ~Block4x4Encoding(void) {}
|
||||
virtual void InitFromSource(Block4x4 *a_pblockParent,
|
||||
ColorFloatRGBA *a_pafrgbaSource,
|
||||
|
||||
unsigned char *a_paucEncodingBits, ErrorMetric a_errormetric) = 0;
|
||||
|
||||
virtual void InitFromEncodingBits(Block4x4 *a_pblockParent,
|
||||
unsigned char *a_paucEncodingBits,
|
||||
ColorFloatRGBA *a_pafrgbaSource,
|
||||
|
||||
ErrorMetric a_errormetric) = 0;
|
||||
|
||||
// perform an iteration of the encoding
|
||||
// the first iteration must generate a complete, valid (if poor) encoding
|
||||
virtual void PerformIteration(float a_fEffort) = 0;
|
||||
|
||||
void CalcBlockError(void);
|
||||
|
||||
inline float GetError(void)
|
||||
{
|
||||
assert(m_fError >= 0.0f);
|
||||
|
||||
return m_fError;
|
||||
}
|
||||
|
||||
inline ColorFloatRGBA * GetDecodedColors(void)
|
||||
{
|
||||
return m_afrgbaDecodedColors;
|
||||
}
|
||||
|
||||
inline float * GetDecodedAlphas(void)
|
||||
{
|
||||
return m_afDecodedAlphas;
|
||||
}
|
||||
|
||||
virtual void SetEncodingBits(void) = 0;
|
||||
|
||||
virtual bool GetFlip(void) = 0;
|
||||
|
||||
virtual bool IsDifferential(void) = 0;
|
||||
|
||||
virtual bool HasSeverelyBentDifferentialColors(void) const = 0;
|
||||
|
||||
inline Mode GetMode(void)
|
||||
{
|
||||
return m_mode;
|
||||
}
|
||||
|
||||
inline bool IsDone(void)
|
||||
{
|
||||
return m_boolDone;
|
||||
}
|
||||
|
||||
inline void SetDoneIfPerfect()
|
||||
{
|
||||
if (GetError() == 0.0f)
|
||||
{
|
||||
m_boolDone = true;
|
||||
}
|
||||
}
|
||||
|
||||
float CalcPixelError(ColorFloatRGBA a_frgbaDecodedColor, float a_fDecodedAlpha,
|
||||
ColorFloatRGBA a_frgbaSourcePixel);
|
||||
|
||||
protected:
|
||||
|
||||
void Init(Block4x4 *a_pblockParent,
|
||||
ColorFloatRGBA *a_pafrgbaSource,
|
||||
|
||||
ErrorMetric a_errormetric);
|
||||
|
||||
Block4x4 *m_pblockParent;
|
||||
ColorFloatRGBA *m_pafrgbaSource;
|
||||
|
||||
bool m_boolBorderPixels; // if block has any border pixels
|
||||
|
||||
ColorFloatRGBA m_afrgbaDecodedColors[PIXELS]; // decoded RGB components, ignore Alpha
|
||||
float m_afDecodedAlphas[PIXELS]; // decoded alpha component
|
||||
float m_fError; // error for RGBA relative to m_pafrgbaSource
|
||||
|
||||
// intermediate encoding
|
||||
Mode m_mode;
|
||||
|
||||
unsigned int m_uiEncodingIterations;
|
||||
bool m_boolDone; // all iterations have been done
|
||||
ErrorMetric m_errormetric;
|
||||
|
||||
private:
|
||||
|
||||
};
|
||||
|
||||
} // namespace Etc
|
315
extern/EtcLib/EtcCodec/EtcBlock4x4EncodingBits.h
vendored
Normal file
315
extern/EtcLib/EtcCodec/EtcBlock4x4EncodingBits.h
vendored
Normal file
@ -0,0 +1,315 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <assert.h>
|
||||
|
||||
namespace Etc
|
||||
{
|
||||
|
||||
// ################################################################################
|
||||
// Block4x4EncodingBits
|
||||
// Base class for Block4x4EncodingBits_XXXX
|
||||
// ################################################################################
|
||||
|
||||
class Block4x4EncodingBits
|
||||
{
|
||||
public:
|
||||
|
||||
enum class Format
|
||||
{
|
||||
UNKNOWN,
|
||||
//
|
||||
RGB8,
|
||||
RGBA8,
|
||||
R11,
|
||||
RG11,
|
||||
RGB8A1,
|
||||
//
|
||||
FORMATS
|
||||
};
|
||||
|
||||
static unsigned int GetBytesPerBlock(Format a_format)
|
||||
{
|
||||
switch (a_format)
|
||||
{
|
||||
case Format::RGB8:
|
||||
case Format::R11:
|
||||
case Format::RGB8A1:
|
||||
return 8;
|
||||
break;
|
||||
|
||||
case Format::RGBA8:
|
||||
case Format::RG11:
|
||||
return 16;
|
||||
break;
|
||||
|
||||
default:
|
||||
return 0;
|
||||
break;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
// ################################################################################
|
||||
// Block4x4EncodingBits_RGB8
|
||||
// Encoding bits for the RGB portion of ETC1, RGB8, RGB8A1 and RGBA8
|
||||
// ################################################################################
|
||||
|
||||
class Block4x4EncodingBits_RGB8
|
||||
{
|
||||
public:
|
||||
|
||||
static const unsigned int BYTES_PER_BLOCK = 8;
|
||||
|
||||
inline Block4x4EncodingBits_RGB8(void)
|
||||
{
|
||||
assert(sizeof(Block4x4EncodingBits_RGB8) == BYTES_PER_BLOCK);
|
||||
|
||||
for (unsigned int uiByte = 0; uiByte < BYTES_PER_BLOCK; uiByte++)
|
||||
{
|
||||
auc[uiByte] = 0;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
typedef struct
|
||||
{
|
||||
unsigned red2 : 4;
|
||||
unsigned red1 : 4;
|
||||
//
|
||||
unsigned green2 : 4;
|
||||
unsigned green1 : 4;
|
||||
//
|
||||
unsigned blue2 : 4;
|
||||
unsigned blue1 : 4;
|
||||
//
|
||||
unsigned flip : 1;
|
||||
unsigned diff : 1;
|
||||
unsigned cw2 : 3;
|
||||
unsigned cw1 : 3;
|
||||
//
|
||||
unsigned int selectors;
|
||||
} Individual;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
signed dred2 : 3;
|
||||
unsigned red1 : 5;
|
||||
//
|
||||
signed dgreen2 : 3;
|
||||
unsigned green1 : 5;
|
||||
//
|
||||
signed dblue2 : 3;
|
||||
unsigned blue1 : 5;
|
||||
//
|
||||
unsigned flip : 1;
|
||||
unsigned diff : 1;
|
||||
unsigned cw2 : 3;
|
||||
unsigned cw1 : 3;
|
||||
//
|
||||
unsigned int selectors;
|
||||
} Differential;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
unsigned red1b : 2;
|
||||
unsigned detect2 : 1;
|
||||
unsigned red1a : 2;
|
||||
unsigned detect1 : 3;
|
||||
//
|
||||
unsigned blue1 : 4;
|
||||
unsigned green1 : 4;
|
||||
//
|
||||
unsigned green2 : 4;
|
||||
unsigned red2 : 4;
|
||||
//
|
||||
unsigned db : 1;
|
||||
unsigned diff : 1;
|
||||
unsigned da : 2;
|
||||
unsigned blue2 : 4;
|
||||
//
|
||||
unsigned int selectors;
|
||||
} T;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
unsigned green1a : 3;
|
||||
unsigned red1 : 4;
|
||||
unsigned detect1 : 1;
|
||||
//
|
||||
unsigned blue1b : 2;
|
||||
unsigned detect3 : 1;
|
||||
unsigned blue1a : 1;
|
||||
unsigned green1b : 1;
|
||||
unsigned detect2 : 3;
|
||||
//
|
||||
unsigned green2a : 3;
|
||||
unsigned red2 : 4;
|
||||
unsigned blue1c : 1;
|
||||
//
|
||||
unsigned db : 1;
|
||||
unsigned diff : 1;
|
||||
unsigned da : 1;
|
||||
unsigned blue2 : 4;
|
||||
unsigned green2b : 1;
|
||||
//
|
||||
unsigned int selectors;
|
||||
} H;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
unsigned originGreen1 : 1;
|
||||
unsigned originRed : 6;
|
||||
unsigned detect1 : 1;
|
||||
//
|
||||
unsigned originBlue1 : 1;
|
||||
unsigned originGreen2 : 6;
|
||||
unsigned detect2 : 1;
|
||||
//
|
||||
unsigned originBlue3 : 2;
|
||||
unsigned detect4 : 1;
|
||||
unsigned originBlue2 : 2;
|
||||
unsigned detect3 : 3;
|
||||
//
|
||||
unsigned horizRed2 : 1;
|
||||
unsigned diff : 1;
|
||||
unsigned horizRed1 : 5;
|
||||
unsigned originBlue4 : 1;
|
||||
//
|
||||
unsigned horizBlue1: 1;
|
||||
unsigned horizGreen : 7;
|
||||
//
|
||||
unsigned vertRed1 : 3;
|
||||
unsigned horizBlue2 : 5;
|
||||
//
|
||||
unsigned vertGreen1 : 5;
|
||||
unsigned vertRed2 : 3;
|
||||
//
|
||||
unsigned vertBlue : 6;
|
||||
unsigned vertGreen2 : 2;
|
||||
} Planar;
|
||||
|
||||
union
|
||||
{
|
||||
unsigned char auc[BYTES_PER_BLOCK];
|
||||
unsigned long int ul;
|
||||
Individual individual;
|
||||
Differential differential;
|
||||
T t;
|
||||
H h;
|
||||
Planar planar;
|
||||
};
|
||||
|
||||
};
|
||||
|
||||
// ################################################################################
|
||||
// Block4x4EncodingBits_A8
|
||||
// Encoding bits for the A portion of RGBA8
|
||||
// ################################################################################
|
||||
|
||||
class Block4x4EncodingBits_A8
|
||||
{
|
||||
public:
|
||||
|
||||
static const unsigned int BYTES_PER_BLOCK = 8;
|
||||
static const unsigned int SELECTOR_BYTES = 6;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
unsigned base : 8;
|
||||
unsigned table : 4;
|
||||
unsigned multiplier : 4;
|
||||
unsigned selectors0 : 8;
|
||||
unsigned selectors1 : 8;
|
||||
unsigned selectors2 : 8;
|
||||
unsigned selectors3 : 8;
|
||||
unsigned selectors4 : 8;
|
||||
unsigned selectors5 : 8;
|
||||
} Data;
|
||||
|
||||
Data data;
|
||||
|
||||
};
|
||||
|
||||
// ################################################################################
|
||||
// Block4x4EncodingBits_R11
|
||||
// Encoding bits for the R portion of R11
|
||||
// ################################################################################
|
||||
|
||||
class Block4x4EncodingBits_R11
|
||||
{
|
||||
public:
|
||||
|
||||
static const unsigned int BYTES_PER_BLOCK = 8;
|
||||
static const unsigned int SELECTOR_BYTES = 6;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
unsigned base : 8;
|
||||
unsigned table : 4;
|
||||
unsigned multiplier : 4;
|
||||
unsigned selectors0 : 8;
|
||||
unsigned selectors1 : 8;
|
||||
unsigned selectors2 : 8;
|
||||
unsigned selectors3 : 8;
|
||||
unsigned selectors4 : 8;
|
||||
unsigned selectors5 : 8;
|
||||
} Data;
|
||||
|
||||
Data data;
|
||||
|
||||
};
|
||||
|
||||
class Block4x4EncodingBits_RG11
|
||||
{
|
||||
public:
|
||||
|
||||
static const unsigned int BYTES_PER_BLOCK = 16;
|
||||
static const unsigned int SELECTOR_BYTES = 12;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
//Red portion
|
||||
unsigned baseR : 8;
|
||||
unsigned tableIndexR : 4;
|
||||
unsigned multiplierR : 4;
|
||||
unsigned selectorsR0 : 8;
|
||||
unsigned selectorsR1 : 8;
|
||||
unsigned selectorsR2 : 8;
|
||||
unsigned selectorsR3 : 8;
|
||||
unsigned selectorsR4 : 8;
|
||||
unsigned selectorsR5 : 8;
|
||||
//Green portion
|
||||
unsigned baseG : 8;
|
||||
unsigned tableIndexG : 4;
|
||||
unsigned multiplierG : 4;
|
||||
unsigned selectorsG0 : 8;
|
||||
unsigned selectorsG1 : 8;
|
||||
unsigned selectorsG2 : 8;
|
||||
unsigned selectorsG3 : 8;
|
||||
unsigned selectorsG4 : 8;
|
||||
unsigned selectorsG5 : 8;
|
||||
} Data;
|
||||
|
||||
Data data;
|
||||
|
||||
};
|
||||
|
||||
}
|
1280
extern/EtcLib/EtcCodec/EtcBlock4x4Encoding_ETC1.cpp
vendored
Normal file
1280
extern/EtcLib/EtcCodec/EtcBlock4x4Encoding_ETC1.cpp
vendored
Normal file
File diff suppressed because it is too large
Load Diff
186
extern/EtcLib/EtcCodec/EtcBlock4x4Encoding_ETC1.h
vendored
Normal file
186
extern/EtcLib/EtcCodec/EtcBlock4x4Encoding_ETC1.h
vendored
Normal file
@ -0,0 +1,186 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "EtcBlock4x4Encoding.h"
|
||||
#include "EtcBlock4x4EncodingBits.h"
|
||||
#include "EtcDifferentialTrys.h"
|
||||
#include "EtcIndividualTrys.h"
|
||||
|
||||
namespace Etc
|
||||
{
|
||||
|
||||
// base class for Block4x4Encoding_RGB8
|
||||
class Block4x4Encoding_ETC1 : public Block4x4Encoding
|
||||
{
|
||||
public:
|
||||
|
||||
Block4x4Encoding_ETC1(void);
|
||||
virtual ~Block4x4Encoding_ETC1(void);
|
||||
|
||||
virtual void InitFromSource(Block4x4 *a_pblockParent,
|
||||
ColorFloatRGBA *a_pafrgbaSource,
|
||||
|
||||
unsigned char *a_paucEncodingBits,
|
||||
ErrorMetric a_errormetric);
|
||||
|
||||
virtual void InitFromEncodingBits(Block4x4 *a_pblockParent,
|
||||
unsigned char *a_paucEncodingBits,
|
||||
ColorFloatRGBA *a_pafrgbaSource,
|
||||
|
||||
ErrorMetric a_errormetric);
|
||||
|
||||
virtual void PerformIteration(float a_fEffort);
|
||||
|
||||
inline virtual bool GetFlip(void)
|
||||
{
|
||||
return m_boolFlip;
|
||||
}
|
||||
|
||||
inline virtual bool IsDifferential(void)
|
||||
{
|
||||
return m_boolDiff;
|
||||
}
|
||||
|
||||
virtual void SetEncodingBits(void);
|
||||
|
||||
void Decode(void);
|
||||
|
||||
inline ColorFloatRGBA GetColor1(void) const
|
||||
{
|
||||
return m_frgbaColor1;
|
||||
}
|
||||
|
||||
inline ColorFloatRGBA GetColor2(void) const
|
||||
{
|
||||
return m_frgbaColor2;
|
||||
}
|
||||
|
||||
inline const unsigned int * GetSelectors(void) const
|
||||
{
|
||||
return m_auiSelectors;
|
||||
}
|
||||
|
||||
inline unsigned int GetCW1(void) const
|
||||
{
|
||||
return m_uiCW1;
|
||||
}
|
||||
|
||||
inline unsigned int GetCW2(void) const
|
||||
{
|
||||
return m_uiCW2;
|
||||
}
|
||||
|
||||
inline bool HasSeverelyBentDifferentialColors(void) const
|
||||
{
|
||||
return m_boolSeverelyBentDifferentialColors;
|
||||
}
|
||||
|
||||
protected:
|
||||
|
||||
static const unsigned int s_auiPixelOrderFlip0[PIXELS];
|
||||
static const unsigned int s_auiPixelOrderFlip1[PIXELS];
|
||||
static const unsigned int s_auiPixelOrderHScan[PIXELS];
|
||||
|
||||
static const unsigned int s_auiLeftPixelMapping[8];
|
||||
static const unsigned int s_auiRightPixelMapping[8];
|
||||
static const unsigned int s_auiTopPixelMapping[8];
|
||||
static const unsigned int s_auiBottomPixelMapping[8];
|
||||
|
||||
static const unsigned int SELECTOR_BITS = 2;
|
||||
static const unsigned int SELECTORS = 1 << SELECTOR_BITS;
|
||||
|
||||
static const unsigned int CW_BITS = 3;
|
||||
static const unsigned int CW_RANGES = 1 << CW_BITS;
|
||||
|
||||
static float s_aafCwTable[CW_RANGES][SELECTORS];
|
||||
static unsigned char s_aucDifferentialCwRange[256];
|
||||
|
||||
static const int MAX_DIFFERENTIAL = 3;
|
||||
static const int MIN_DIFFERENTIAL = -4;
|
||||
|
||||
void InitFromEncodingBits_Selectors(void);
|
||||
|
||||
void PerformFirstIteration(void);
|
||||
void CalculateMostLikelyFlip(void);
|
||||
|
||||
void TryDifferential(bool a_boolFlip, unsigned int a_uiRadius,
|
||||
int a_iGrayOffset1, int a_iGrayOffset2);
|
||||
void TryDifferentialHalf(DifferentialTrys::Half *a_phalf);
|
||||
|
||||
void TryIndividual(bool a_boolFlip, unsigned int a_uiRadius);
|
||||
void TryIndividualHalf(IndividualTrys::Half *a_phalf);
|
||||
|
||||
void TryDegenerates1(void);
|
||||
void TryDegenerates2(void);
|
||||
void TryDegenerates3(void);
|
||||
void TryDegenerates4(void);
|
||||
|
||||
void CalculateSelectors();
|
||||
void CalculateHalfOfTheSelectors(unsigned int a_uiHalf,
|
||||
const unsigned int *pauiPixelMapping);
|
||||
|
||||
// calculate the distance2 of r_frgbaPixel from r_frgbaTarget's gray line
|
||||
inline float CalcGrayDistance2(ColorFloatRGBA &r_frgbaPixel,
|
||||
ColorFloatRGBA &r_frgbaTarget)
|
||||
{
|
||||
float fDeltaGray = ((r_frgbaPixel.fR - r_frgbaTarget.fR) +
|
||||
(r_frgbaPixel.fG - r_frgbaTarget.fG) +
|
||||
(r_frgbaPixel.fB - r_frgbaTarget.fB)) / 3.0f;
|
||||
|
||||
ColorFloatRGBA frgbaPointOnGrayLine = (r_frgbaTarget + fDeltaGray).ClampRGB();
|
||||
|
||||
float fDR = r_frgbaPixel.fR - frgbaPointOnGrayLine.fR;
|
||||
float fDG = r_frgbaPixel.fG - frgbaPointOnGrayLine.fG;
|
||||
float fDB = r_frgbaPixel.fB - frgbaPointOnGrayLine.fB;
|
||||
|
||||
return (fDR*fDR) + (fDG*fDG) + (fDB*fDB);
|
||||
}
|
||||
|
||||
void SetEncodingBits_Selectors(void);
|
||||
|
||||
// intermediate encoding
|
||||
bool m_boolDiff;
|
||||
bool m_boolFlip;
|
||||
ColorFloatRGBA m_frgbaColor1;
|
||||
ColorFloatRGBA m_frgbaColor2;
|
||||
unsigned int m_uiCW1;
|
||||
unsigned int m_uiCW2;
|
||||
unsigned int m_auiSelectors[PIXELS];
|
||||
|
||||
// state shared between iterations
|
||||
ColorFloatRGBA m_frgbaSourceAverageLeft;
|
||||
ColorFloatRGBA m_frgbaSourceAverageRight;
|
||||
ColorFloatRGBA m_frgbaSourceAverageTop;
|
||||
ColorFloatRGBA m_frgbaSourceAverageBottom;
|
||||
bool m_boolMostLikelyFlip;
|
||||
|
||||
// stats
|
||||
float m_fError1; // error for Etc1 half 1
|
||||
float m_fError2; // error for Etc1 half 2
|
||||
bool m_boolSeverelyBentDifferentialColors; // only valid if m_boolDiff;
|
||||
|
||||
// final encoding
|
||||
Block4x4EncodingBits_RGB8 *m_pencodingbitsRGB8; // or RGB8 portion of Block4x4EncodingBits_RGB8A8
|
||||
|
||||
private:
|
||||
|
||||
void CalculateSourceAverages(void);
|
||||
|
||||
};
|
||||
|
||||
} // namespace Etc
|
429
extern/EtcLib/EtcCodec/EtcBlock4x4Encoding_R11.cpp
vendored
Normal file
429
extern/EtcLib/EtcCodec/EtcBlock4x4Encoding_R11.cpp
vendored
Normal file
@ -0,0 +1,429 @@
|
||||
/*
|
||||
* 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_R11.cpp
|
||||
|
||||
Block4x4Encoding_R11 is the encoder to use when targetting file format R11 and SR11 (signed R11).
|
||||
|
||||
*/
|
||||
|
||||
#include "EtcConfig.h"
|
||||
#include "EtcBlock4x4Encoding_R11.h"
|
||||
|
||||
#include "EtcBlock4x4EncodingBits.h"
|
||||
#include "EtcBlock4x4.h"
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <assert.h>
|
||||
#include <float.h>
|
||||
#include <limits>
|
||||
|
||||
namespace Etc
|
||||
{
|
||||
|
||||
// modifier values to use for R11, SR11, RG11 and SRG11
|
||||
float Block4x4Encoding_R11::s_aafModifierTable[MODIFIER_TABLE_ENTRYS][SELECTORS]
|
||||
{
|
||||
{ -3.0f / 255.0f, -6.0f / 255.0f, -9.0f / 255.0f, -15.0f / 255.0f, 2.0f / 255.0f, 5.0f / 255.0f, 8.0f / 255.0f, 14.0f / 255.0f },
|
||||
{ -3.0f / 255.0f, -7.0f / 255.0f, -10.0f / 255.0f, -13.0f / 255.0f, 2.0f / 255.0f, 6.0f / 255.0f, 9.0f / 255.0f, 12.0f / 255.0f },
|
||||
{ -2.0f / 255.0f, -5.0f / 255.0f, -8.0f / 255.0f, -13.0f / 255.0f, 1.0f / 255.0f, 4.0f / 255.0f, 7.0f / 255.0f, 12.0f / 255.0f },
|
||||
{ -2.0f / 255.0f, -4.0f / 255.0f, -6.0f / 255.0f, -13.0f / 255.0f, 1.0f / 255.0f, 3.0f / 255.0f, 5.0f / 255.0f, 12.0f / 255.0f },
|
||||
|
||||
{ -3.0f / 255.0f, -6.0f / 255.0f, -8.0f / 255.0f, -12.0f / 255.0f, 2.0f / 255.0f, 5.0f / 255.0f, 7.0f / 255.0f, 11.0f / 255.0f },
|
||||
{ -3.0f / 255.0f, -7.0f / 255.0f, -9.0f / 255.0f, -11.0f / 255.0f, 2.0f / 255.0f, 6.0f / 255.0f, 8.0f / 255.0f, 10.0f / 255.0f },
|
||||
{ -4.0f / 255.0f, -7.0f / 255.0f, -8.0f / 255.0f, -11.0f / 255.0f, 3.0f / 255.0f, 6.0f / 255.0f, 7.0f / 255.0f, 10.0f / 255.0f },
|
||||
{ -3.0f / 255.0f, -5.0f / 255.0f, -8.0f / 255.0f, -11.0f / 255.0f, 2.0f / 255.0f, 4.0f / 255.0f, 7.0f / 255.0f, 10.0f / 255.0f },
|
||||
|
||||
{ -2.0f / 255.0f, -6.0f / 255.0f, -8.0f / 255.0f, -10.0f / 255.0f, 1.0f / 255.0f, 5.0f / 255.0f, 7.0f / 255.0f, 9.0f / 255.0f },
|
||||
{ -2.0f / 255.0f, -5.0f / 255.0f, -8.0f / 255.0f, -10.0f / 255.0f, 1.0f / 255.0f, 4.0f / 255.0f, 7.0f / 255.0f, 9.0f / 255.0f },
|
||||
{ -2.0f / 255.0f, -4.0f / 255.0f, -8.0f / 255.0f, -10.0f / 255.0f, 1.0f / 255.0f, 3.0f / 255.0f, 7.0f / 255.0f, 9.0f / 255.0f },
|
||||
{ -2.0f / 255.0f, -5.0f / 255.0f, -7.0f / 255.0f, -10.0f / 255.0f, 1.0f / 255.0f, 4.0f / 255.0f, 6.0f / 255.0f, 9.0f / 255.0f },
|
||||
|
||||
{ -3.0f / 255.0f, -4.0f / 255.0f, -7.0f / 255.0f, -10.0f / 255.0f, 2.0f / 255.0f, 3.0f / 255.0f, 6.0f / 255.0f, 9.0f / 255.0f },
|
||||
{ -1.0f / 255.0f, -2.0f / 255.0f, -3.0f / 255.0f, -10.0f / 255.0f, 0.0f / 255.0f, 1.0f / 255.0f, 2.0f / 255.0f, 9.0f / 255.0f },
|
||||
{ -4.0f / 255.0f, -6.0f / 255.0f, -8.0f / 255.0f, -9.0f / 255.0f, 3.0f / 255.0f, 5.0f / 255.0f, 7.0f / 255.0f, 8.0f / 255.0f },
|
||||
{ -3.0f / 255.0f, -5.0f / 255.0f, -7.0f / 255.0f, -9.0f / 255.0f, 2.0f / 255.0f, 4.0f / 255.0f, 6.0f / 255.0f, 8.0f / 255.0f }
|
||||
};
|
||||
|
||||
// ----------------------------------------------------------------------------------------------------
|
||||
//
|
||||
Block4x4Encoding_R11::Block4x4Encoding_R11(void)
|
||||
{
|
||||
|
||||
m_pencodingbitsR11 = nullptr;
|
||||
|
||||
}
|
||||
|
||||
Block4x4Encoding_R11::~Block4x4Encoding_R11(void) {}
|
||||
// ----------------------------------------------------------------------------------------------------
|
||||
// initialization prior to encoding
|
||||
// a_pblockParent points to the block associated with this encoding
|
||||
// a_errormetric is used to choose the best encoding
|
||||
// a_pafrgbaSource points to a 4x4 block subset of the source image
|
||||
// a_paucEncodingBits points to the final encoding bits
|
||||
//
|
||||
void Block4x4Encoding_R11::InitFromSource(Block4x4 *a_pblockParent,
|
||||
ColorFloatRGBA *a_pafrgbaSource,
|
||||
unsigned char *a_paucEncodingBits, ErrorMetric a_errormetric)
|
||||
{
|
||||
Block4x4Encoding::Init(a_pblockParent, a_pafrgbaSource,a_errormetric);
|
||||
|
||||
m_pencodingbitsR11 = (Block4x4EncodingBits_R11 *)a_paucEncodingBits;
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------------------------------
|
||||
// initialization from the encoding bits of a previous encoding
|
||||
// a_pblockParent points to the block associated with this encoding
|
||||
// a_errormetric is used to choose the best encoding
|
||||
// a_pafrgbaSource points to a 4x4 block subset of the source image
|
||||
// a_paucEncodingBits points to the final encoding bits of a previous encoding
|
||||
//
|
||||
void Block4x4Encoding_R11::InitFromEncodingBits(Block4x4 *a_pblockParent,
|
||||
unsigned char *a_paucEncodingBits,
|
||||
ColorFloatRGBA *a_pafrgbaSource,
|
||||
ErrorMetric a_errormetric)
|
||||
{
|
||||
m_pencodingbitsR11 = (Block4x4EncodingBits_R11 *)a_paucEncodingBits;
|
||||
|
||||
// init RGB portion
|
||||
Block4x4Encoding_RGB8::InitFromEncodingBits(a_pblockParent,
|
||||
(unsigned char *)m_pencodingbitsR11,
|
||||
a_pafrgbaSource,
|
||||
a_errormetric);
|
||||
|
||||
// init R11 portion
|
||||
{
|
||||
m_mode = MODE_R11;
|
||||
if (a_pblockParent->GetImageSource()->GetFormat() == Image::Format::SIGNED_R11 || a_pblockParent->GetImageSource()->GetFormat() == Image::Format::SIGNED_RG11)
|
||||
{
|
||||
m_fRedBase = (float)(signed char)m_pencodingbitsR11->data.base;
|
||||
}
|
||||
else
|
||||
{
|
||||
m_fRedBase = (float)(unsigned char)m_pencodingbitsR11->data.base;
|
||||
}
|
||||
m_fRedMultiplier = (float)m_pencodingbitsR11->data.multiplier;
|
||||
m_uiRedModifierTableIndex = m_pencodingbitsR11->data.table;
|
||||
|
||||
unsigned long long int ulliSelectorBits = 0;
|
||||
ulliSelectorBits |= (unsigned long long int)m_pencodingbitsR11->data.selectors0 << 40;
|
||||
ulliSelectorBits |= (unsigned long long int)m_pencodingbitsR11->data.selectors1 << 32;
|
||||
ulliSelectorBits |= (unsigned long long int)m_pencodingbitsR11->data.selectors2 << 24;
|
||||
ulliSelectorBits |= (unsigned long long int)m_pencodingbitsR11->data.selectors3 << 16;
|
||||
ulliSelectorBits |= (unsigned long long int)m_pencodingbitsR11->data.selectors4 << 8;
|
||||
ulliSelectorBits |= (unsigned long long int)m_pencodingbitsR11->data.selectors5;
|
||||
for (unsigned int uiPixel = 0; uiPixel < PIXELS; uiPixel++)
|
||||
{
|
||||
unsigned int uiShift = 45 - (3 * uiPixel);
|
||||
m_auiRedSelectors[uiPixel] = (ulliSelectorBits >> uiShift) & (SELECTORS - 1);
|
||||
}
|
||||
|
||||
// decode the red channel
|
||||
// calc red error
|
||||
for (unsigned int uiPixel = 0; uiPixel < PIXELS; uiPixel++)
|
||||
{
|
||||
float fDecodedPixelData = 0.0f;
|
||||
if (a_pblockParent->GetImageSource()->GetFormat() == Image::Format::R11 || a_pblockParent->GetImageSource()->GetFormat() == Image::Format::RG11)
|
||||
{
|
||||
fDecodedPixelData = DecodePixelRed(m_fRedBase, m_fRedMultiplier,
|
||||
m_uiRedModifierTableIndex,
|
||||
m_auiRedSelectors[uiPixel]);
|
||||
}
|
||||
else if (a_pblockParent->GetImageSource()->GetFormat() == Image::Format::SIGNED_R11 || a_pblockParent->GetImageSource()->GetFormat() == Image::Format::SIGNED_RG11)
|
||||
{
|
||||
fDecodedPixelData = DecodePixelRed(m_fRedBase + 128, m_fRedMultiplier,
|
||||
m_uiRedModifierTableIndex,
|
||||
m_auiRedSelectors[uiPixel]);
|
||||
}
|
||||
else
|
||||
{
|
||||
assert(0);
|
||||
}
|
||||
m_afrgbaDecodedColors[uiPixel] = ColorFloatRGBA(fDecodedPixelData, 0.0f, 0.0f, 1.0f);
|
||||
}
|
||||
CalcBlockError();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------------------------------
|
||||
// perform a single encoding iteration
|
||||
// replace the encoding if a better encoding was found
|
||||
// subsequent iterations generally take longer for each iteration
|
||||
// set m_boolDone if encoding is perfect or encoding is finished based on a_fEffort
|
||||
//
|
||||
void Block4x4Encoding_R11::PerformIteration(float a_fEffort)
|
||||
{
|
||||
assert(!m_boolDone);
|
||||
m_mode = MODE_R11;
|
||||
|
||||
switch (m_uiEncodingIterations)
|
||||
{
|
||||
case 0:
|
||||
m_fError = FLT_MAX;
|
||||
m_fRedBlockError = FLT_MAX; // artificially high value
|
||||
CalculateR11(8, 0.0f, 0.0f);
|
||||
m_fError = m_fRedBlockError;
|
||||
break;
|
||||
|
||||
case 1:
|
||||
CalculateR11(8, 2.0f, 1.0f);
|
||||
m_fError = m_fRedBlockError;
|
||||
if (a_fEffort <= 24.5f)
|
||||
{
|
||||
m_boolDone = true;
|
||||
}
|
||||
break;
|
||||
|
||||
case 2:
|
||||
CalculateR11(8, 12.0f, 1.0f);
|
||||
m_fError = m_fRedBlockError;
|
||||
if (a_fEffort <= 49.5f)
|
||||
{
|
||||
m_boolDone = true;
|
||||
}
|
||||
break;
|
||||
|
||||
case 3:
|
||||
CalculateR11(7, 6.0f, 1.0f);
|
||||
m_fError = m_fRedBlockError;
|
||||
break;
|
||||
|
||||
case 4:
|
||||
CalculateR11(6, 3.0f, 1.0f);
|
||||
m_fError = m_fRedBlockError;
|
||||
break;
|
||||
|
||||
case 5:
|
||||
CalculateR11(5, 1.0f, 0.0f);
|
||||
m_fError = m_fRedBlockError;
|
||||
m_boolDone = true;
|
||||
break;
|
||||
|
||||
default:
|
||||
assert(0);
|
||||
break;
|
||||
}
|
||||
|
||||
m_uiEncodingIterations++;
|
||||
SetDoneIfPerfect();
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------------------------------
|
||||
// find the best combination of base color, multiplier and selectors
|
||||
//
|
||||
// a_uiSelectorsUsed limits the number of selector combinations to try
|
||||
// a_fBaseRadius limits the range of base colors to try
|
||||
// a_fMultiplierRadius limits the range of multipliers to try
|
||||
//
|
||||
void Block4x4Encoding_R11::CalculateR11(unsigned int a_uiSelectorsUsed,
|
||||
float a_fBaseRadius, float a_fMultiplierRadius)
|
||||
{
|
||||
// maps from virtual (monotonic) selector to ETC selector
|
||||
static const unsigned int auiVirtualSelectorMap[8] = {3, 2, 1, 0, 4, 5, 6, 7};
|
||||
|
||||
// find min/max red
|
||||
float fMinRed = 1.0f;
|
||||
float fMaxRed = 0.0f;
|
||||
for (unsigned int uiPixel = 0; uiPixel < PIXELS; uiPixel++)
|
||||
{
|
||||
// ignore border pixels
|
||||
float fAlpha = m_pafrgbaSource[uiPixel].fA;
|
||||
if (isnan(fAlpha))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
float fRed = m_pafrgbaSource[uiPixel].fR;
|
||||
|
||||
if (fRed < fMinRed)
|
||||
{
|
||||
fMinRed = fRed;
|
||||
}
|
||||
if (fRed > fMaxRed)
|
||||
{
|
||||
fMaxRed = fRed;
|
||||
}
|
||||
}
|
||||
assert(fMinRed <= fMaxRed);
|
||||
|
||||
float fRedRange = (fMaxRed - fMinRed);
|
||||
|
||||
// try each modifier table entry
|
||||
for (unsigned int uiTableEntry = 0; uiTableEntry < MODIFIER_TABLE_ENTRYS; uiTableEntry++)
|
||||
{
|
||||
for (unsigned int uiMinVirtualSelector = 0;
|
||||
uiMinVirtualSelector <= (8- a_uiSelectorsUsed);
|
||||
uiMinVirtualSelector++)
|
||||
{
|
||||
unsigned int uiMaxVirtualSelector = uiMinVirtualSelector + a_uiSelectorsUsed - 1;
|
||||
|
||||
unsigned int uiMinSelector = auiVirtualSelectorMap[uiMinVirtualSelector];
|
||||
unsigned int uiMaxSelector = auiVirtualSelectorMap[uiMaxVirtualSelector];
|
||||
|
||||
float fTableEntryCenter = -s_aafModifierTable[uiTableEntry][uiMinSelector];
|
||||
|
||||
float fTableEntryRange = s_aafModifierTable[uiTableEntry][uiMaxSelector] -
|
||||
s_aafModifierTable[uiTableEntry][uiMinSelector];
|
||||
|
||||
float fCenterRatio = fTableEntryCenter / fTableEntryRange;
|
||||
|
||||
float fCenter = fMinRed + fCenterRatio*fRedRange;
|
||||
fCenter = roundf(255.0f * fCenter) / 255.0f;
|
||||
|
||||
float fMinBase = fCenter - (a_fBaseRadius / 255.0f);
|
||||
if (fMinBase < 0.0f)
|
||||
{
|
||||
fMinBase = 0.0f;
|
||||
}
|
||||
|
||||
float fMaxBase = fCenter + (a_fBaseRadius / 255.0f);
|
||||
if (fMaxBase > 1.0f)
|
||||
{
|
||||
fMaxBase = 1.0f;
|
||||
}
|
||||
|
||||
for (float fBase = fMinBase; fBase <= fMaxBase; fBase += (0.999999f / 255.0f))
|
||||
{
|
||||
float fRangeMultiplier = roundf(fRedRange / fTableEntryRange);
|
||||
|
||||
float fMinMultiplier = fRangeMultiplier - a_fMultiplierRadius;
|
||||
if (fMinMultiplier < 1.0f)
|
||||
{
|
||||
fMinMultiplier = 0.0f;
|
||||
}
|
||||
else if (fMinMultiplier > 15.0f)
|
||||
{
|
||||
fMinMultiplier = 15.0f;
|
||||
}
|
||||
|
||||
float fMaxMultiplier = fRangeMultiplier + a_fMultiplierRadius;
|
||||
if (fMaxMultiplier < 1.0f)
|
||||
{
|
||||
fMaxMultiplier = 1.0f;
|
||||
}
|
||||
else if (fMaxMultiplier > 15.0f)
|
||||
{
|
||||
fMaxMultiplier = 15.0f;
|
||||
}
|
||||
|
||||
for (float fMultiplier = fMinMultiplier; fMultiplier <= fMaxMultiplier; fMultiplier += 1.0f)
|
||||
{
|
||||
// find best selector for each pixel
|
||||
unsigned int auiBestSelectors[PIXELS];
|
||||
float afBestRedError[PIXELS];
|
||||
float afBestPixelRed[PIXELS];
|
||||
|
||||
for (unsigned int uiPixel = 0; uiPixel < PIXELS; uiPixel++)
|
||||
{
|
||||
float fBestPixelRedError = FLT_MAX;
|
||||
|
||||
for (unsigned int uiSelector = 0; uiSelector < SELECTORS; uiSelector++)
|
||||
{
|
||||
float fPixelRed = DecodePixelRed(fBase * 255.0f, fMultiplier, uiTableEntry, uiSelector);
|
||||
|
||||
ColorFloatRGBA frgba(fPixelRed, m_pafrgbaSource[uiPixel].fG,0.0f,1.0f);
|
||||
|
||||
float fPixelRedError = CalcPixelError(frgba, 1.0f, m_pafrgbaSource[uiPixel]);
|
||||
|
||||
if (fPixelRedError < fBestPixelRedError)
|
||||
{
|
||||
fBestPixelRedError = fPixelRedError;
|
||||
auiBestSelectors[uiPixel] = uiSelector;
|
||||
afBestRedError[uiPixel] = fBestPixelRedError;
|
||||
afBestPixelRed[uiPixel] = fPixelRed;
|
||||
}
|
||||
}
|
||||
}
|
||||
float fBlockError = 0.0f;
|
||||
for (unsigned int uiPixel = 0; uiPixel < PIXELS; uiPixel++)
|
||||
{
|
||||
fBlockError += afBestRedError[uiPixel];
|
||||
}
|
||||
if (fBlockError < m_fRedBlockError)
|
||||
{
|
||||
m_fRedBlockError = fBlockError;
|
||||
|
||||
if (m_pblockParent->GetImageSource()->GetFormat() == Image::Format::R11 || m_pblockParent->GetImageSource()->GetFormat() == Image::Format::RG11)
|
||||
{
|
||||
m_fRedBase = 255.0f * fBase;
|
||||
}
|
||||
else if (m_pblockParent->GetImageSource()->GetFormat() == Image::Format::SIGNED_R11 || m_pblockParent->GetImageSource()->GetFormat() == Image::Format::SIGNED_RG11)
|
||||
{
|
||||
m_fRedBase = (fBase * 255) - 128;
|
||||
}
|
||||
else
|
||||
{
|
||||
assert(0);
|
||||
}
|
||||
m_fRedMultiplier = fMultiplier;
|
||||
m_uiRedModifierTableIndex = uiTableEntry;
|
||||
|
||||
for (unsigned int uiPixel = 0; uiPixel < PIXELS; uiPixel++)
|
||||
{
|
||||
m_auiRedSelectors[uiPixel] = auiBestSelectors[uiPixel];
|
||||
float fBestPixelRed = afBestPixelRed[uiPixel];
|
||||
m_afrgbaDecodedColors[uiPixel] = ColorFloatRGBA(fBestPixelRed, 0.0f, 0.0f, 1.0f);
|
||||
m_afDecodedAlphas[uiPixel] = 1.0f;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------------------------------
|
||||
// set the encoding bits based on encoding state
|
||||
//
|
||||
void Block4x4Encoding_R11::SetEncodingBits(void)
|
||||
{
|
||||
if (m_pblockParent->GetImageSource()->GetFormat() == Image::Format::R11 || m_pblockParent->GetImageSource()->GetFormat() == Image::Format::RG11)
|
||||
{
|
||||
m_pencodingbitsR11->data.base = (unsigned char)roundf(m_fRedBase);
|
||||
}
|
||||
else if (m_pblockParent->GetImageSource()->GetFormat() == Image::Format::SIGNED_R11 || m_pblockParent->GetImageSource()->GetFormat() == Image::Format::SIGNED_RG11)
|
||||
{
|
||||
m_pencodingbitsR11->data.base = (signed char)roundf(m_fRedBase);
|
||||
}
|
||||
else
|
||||
{
|
||||
assert(0);
|
||||
}
|
||||
m_pencodingbitsR11->data.table = m_uiRedModifierTableIndex;
|
||||
m_pencodingbitsR11->data.multiplier = (unsigned char)roundf(m_fRedMultiplier);
|
||||
|
||||
unsigned long long int ulliSelectorBits = 0;
|
||||
for (unsigned int uiPixel = 0; uiPixel < PIXELS; uiPixel++)
|
||||
{
|
||||
unsigned int uiShift = 45 - (3 * uiPixel);
|
||||
ulliSelectorBits |= ((unsigned long long int)m_auiRedSelectors[uiPixel]) << uiShift;
|
||||
}
|
||||
|
||||
m_pencodingbitsR11->data.selectors0 = ulliSelectorBits >> 40;
|
||||
m_pencodingbitsR11->data.selectors1 = ulliSelectorBits >> 32;
|
||||
m_pencodingbitsR11->data.selectors2 = ulliSelectorBits >> 24;
|
||||
m_pencodingbitsR11->data.selectors3 = ulliSelectorBits >> 16;
|
||||
m_pencodingbitsR11->data.selectors4 = ulliSelectorBits >> 8;
|
||||
m_pencodingbitsR11->data.selectors5 = ulliSelectorBits;
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------------------------------
|
||||
//
|
||||
}
|
122
extern/EtcLib/EtcCodec/EtcBlock4x4Encoding_R11.h
vendored
Normal file
122
extern/EtcLib/EtcCodec/EtcBlock4x4Encoding_R11.h
vendored
Normal file
@ -0,0 +1,122 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "EtcBlock4x4Encoding_RGB8.h"
|
||||
|
||||
namespace Etc
|
||||
{
|
||||
class Block4x4EncodingBits_R11;
|
||||
|
||||
// ################################################################################
|
||||
// Block4x4Encoding_R11
|
||||
// ################################################################################
|
||||
|
||||
class Block4x4Encoding_R11 : public Block4x4Encoding_RGB8
|
||||
{
|
||||
public:
|
||||
|
||||
Block4x4Encoding_R11(void);
|
||||
virtual ~Block4x4Encoding_R11(void);
|
||||
|
||||
virtual void InitFromSource(Block4x4 *a_pblockParent,
|
||||
ColorFloatRGBA *a_pafrgbaSource,
|
||||
unsigned char *a_paucEncodingBits, ErrorMetric a_errormetric);
|
||||
|
||||
virtual void InitFromEncodingBits(Block4x4 *a_pblockParent,
|
||||
unsigned char *a_paucEncodingBits,
|
||||
ColorFloatRGBA *a_pafrgbaSource,
|
||||
ErrorMetric a_errormetric);
|
||||
|
||||
virtual void PerformIteration(float a_fEffort);
|
||||
|
||||
virtual void SetEncodingBits(void);
|
||||
|
||||
inline float GetRedBase(void) const
|
||||
{
|
||||
return m_fRedBase;
|
||||
}
|
||||
|
||||
inline float GetRedMultiplier(void) const
|
||||
{
|
||||
return m_fRedMultiplier;
|
||||
}
|
||||
|
||||
inline int GetRedTableIndex(void) const
|
||||
{
|
||||
return m_uiRedModifierTableIndex;
|
||||
}
|
||||
|
||||
inline const unsigned int * GetRedSelectors(void) const
|
||||
{
|
||||
return m_auiRedSelectors;
|
||||
}
|
||||
|
||||
protected:
|
||||
|
||||
static const unsigned int MODIFIER_TABLE_ENTRYS = 16;
|
||||
static const unsigned int SELECTOR_BITS = 3;
|
||||
static const unsigned int SELECTORS = 1 << SELECTOR_BITS;
|
||||
|
||||
static float s_aafModifierTable[MODIFIER_TABLE_ENTRYS][SELECTORS];
|
||||
|
||||
void CalculateR11(unsigned int a_uiSelectorsUsed,
|
||||
float a_fBaseRadius, float a_fMultiplierRadius);
|
||||
|
||||
|
||||
|
||||
|
||||
inline float DecodePixelRed(float a_fBase, float a_fMultiplier,
|
||||
unsigned int a_uiTableIndex, unsigned int a_uiSelector)
|
||||
{
|
||||
float fMultiplier = a_fMultiplier;
|
||||
if (fMultiplier <= 0.0f)
|
||||
{
|
||||
fMultiplier = 1.0f / 8.0f;
|
||||
}
|
||||
|
||||
float fPixelRed = a_fBase * 8 + 4 +
|
||||
8 * fMultiplier*s_aafModifierTable[a_uiTableIndex][a_uiSelector]*255;
|
||||
fPixelRed /= 2047.0f;
|
||||
|
||||
if (fPixelRed < 0.0f)
|
||||
{
|
||||
fPixelRed = 0.0f;
|
||||
}
|
||||
else if (fPixelRed > 1.0f)
|
||||
{
|
||||
fPixelRed = 1.0f;
|
||||
}
|
||||
|
||||
return fPixelRed;
|
||||
}
|
||||
|
||||
Block4x4EncodingBits_R11 *m_pencodingbitsR11;
|
||||
|
||||
float m_fRedBase;
|
||||
float m_fRedMultiplier;
|
||||
float m_fRedBlockError;
|
||||
unsigned int m_uiRedModifierTableIndex;
|
||||
unsigned int m_auiRedSelectors[PIXELS];
|
||||
|
||||
|
||||
};
|
||||
|
||||
// ----------------------------------------------------------------------------------------------------
|
||||
//
|
||||
|
||||
} // namespace Etc
|
447
extern/EtcLib/EtcCodec/EtcBlock4x4Encoding_RG11.cpp
vendored
Normal file
447
extern/EtcLib/EtcCodec/EtcBlock4x4Encoding_RG11.cpp
vendored
Normal file
@ -0,0 +1,447 @@
|
||||
/*
|
||||
* 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_RG11.cpp
|
||||
|
||||
Block4x4Encoding_RG11 is the encoder to use when targetting file format RG11 and SRG11 (signed RG11).
|
||||
|
||||
*/
|
||||
|
||||
#include "EtcConfig.h"
|
||||
#include "EtcBlock4x4Encoding_RG11.h"
|
||||
|
||||
#include "EtcBlock4x4EncodingBits.h"
|
||||
#include "EtcBlock4x4.h"
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <assert.h>
|
||||
#include <float.h>
|
||||
#include <limits>
|
||||
|
||||
namespace Etc
|
||||
{
|
||||
// ----------------------------------------------------------------------------------------------------
|
||||
//
|
||||
Block4x4Encoding_RG11::Block4x4Encoding_RG11(void)
|
||||
{
|
||||
m_pencodingbitsRG11 = nullptr;
|
||||
}
|
||||
|
||||
Block4x4Encoding_RG11::~Block4x4Encoding_RG11(void) {}
|
||||
// ----------------------------------------------------------------------------------------------------
|
||||
// initialization prior to encoding
|
||||
// a_pblockParent points to the block associated with this encoding
|
||||
// a_errormetric is used to choose the best encoding
|
||||
// a_pafrgbaSource points to a 4x4 block subset of the source image
|
||||
// a_paucEncodingBits points to the final encoding bits
|
||||
//
|
||||
void Block4x4Encoding_RG11::InitFromSource(Block4x4 *a_pblockParent,
|
||||
ColorFloatRGBA *a_pafrgbaSource,
|
||||
unsigned char *a_paucEncodingBits, ErrorMetric a_errormetric)
|
||||
{
|
||||
Block4x4Encoding::Init(a_pblockParent, a_pafrgbaSource,a_errormetric);
|
||||
|
||||
m_pencodingbitsRG11 = (Block4x4EncodingBits_RG11 *)a_paucEncodingBits;
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------------------------------
|
||||
// initialization from the encoding bits of a previous encoding
|
||||
// a_pblockParent points to the block associated with this encoding
|
||||
// a_errormetric is used to choose the best encoding
|
||||
// a_pafrgbaSource points to a 4x4 block subset of the source image
|
||||
// a_paucEncodingBits points to the final encoding bits of a previous encoding
|
||||
//
|
||||
void Block4x4Encoding_RG11::InitFromEncodingBits(Block4x4 *a_pblockParent,
|
||||
unsigned char *a_paucEncodingBits,
|
||||
ColorFloatRGBA *a_pafrgbaSource,
|
||||
ErrorMetric a_errormetric)
|
||||
{
|
||||
|
||||
m_pencodingbitsRG11 = (Block4x4EncodingBits_RG11 *)a_paucEncodingBits;
|
||||
|
||||
// init RGB portion
|
||||
Block4x4Encoding_RGB8::InitFromEncodingBits(a_pblockParent,
|
||||
(unsigned char *)m_pencodingbitsRG11,
|
||||
a_pafrgbaSource,
|
||||
a_errormetric);
|
||||
m_fError = 0.0f;
|
||||
|
||||
{
|
||||
m_mode = MODE_RG11;
|
||||
if (a_pblockParent->GetImageSource()->GetFormat() == Image::Format::SIGNED_RG11)
|
||||
{
|
||||
m_fRedBase = (float)(signed char)m_pencodingbitsRG11->data.baseR;
|
||||
m_fGrnBase = (float)(signed char)m_pencodingbitsRG11->data.baseG;
|
||||
}
|
||||
else
|
||||
{
|
||||
m_fRedBase = (float)(unsigned char)m_pencodingbitsRG11->data.baseR;
|
||||
m_fGrnBase = (float)(unsigned char)m_pencodingbitsRG11->data.baseG;
|
||||
}
|
||||
m_fRedMultiplier = (float)m_pencodingbitsRG11->data.multiplierR;
|
||||
m_fGrnMultiplier = (float)m_pencodingbitsRG11->data.multiplierG;
|
||||
m_uiRedModifierTableIndex = m_pencodingbitsRG11->data.tableIndexR;
|
||||
m_uiGrnModifierTableIndex = m_pencodingbitsRG11->data.tableIndexG;
|
||||
|
||||
unsigned long long int ulliSelectorBitsR = 0;
|
||||
ulliSelectorBitsR |= (unsigned long long int)m_pencodingbitsRG11->data.selectorsR0 << 40;
|
||||
ulliSelectorBitsR |= (unsigned long long int)m_pencodingbitsRG11->data.selectorsR1 << 32;
|
||||
ulliSelectorBitsR |= (unsigned long long int)m_pencodingbitsRG11->data.selectorsR2 << 24;
|
||||
ulliSelectorBitsR |= (unsigned long long int)m_pencodingbitsRG11->data.selectorsR3 << 16;
|
||||
ulliSelectorBitsR |= (unsigned long long int)m_pencodingbitsRG11->data.selectorsR4 << 8;
|
||||
ulliSelectorBitsR |= (unsigned long long int)m_pencodingbitsRG11->data.selectorsR5;
|
||||
|
||||
unsigned long long int ulliSelectorBitsG = 0;
|
||||
ulliSelectorBitsG |= (unsigned long long int)m_pencodingbitsRG11->data.selectorsG0 << 40;
|
||||
ulliSelectorBitsG |= (unsigned long long int)m_pencodingbitsRG11->data.selectorsG1 << 32;
|
||||
ulliSelectorBitsG |= (unsigned long long int)m_pencodingbitsRG11->data.selectorsG2 << 24;
|
||||
ulliSelectorBitsG |= (unsigned long long int)m_pencodingbitsRG11->data.selectorsG3 << 16;
|
||||
ulliSelectorBitsG |= (unsigned long long int)m_pencodingbitsRG11->data.selectorsG4 << 8;
|
||||
ulliSelectorBitsG |= (unsigned long long int)m_pencodingbitsRG11->data.selectorsG5;
|
||||
|
||||
|
||||
for (unsigned int uiPixel = 0; uiPixel < PIXELS; uiPixel++)
|
||||
{
|
||||
unsigned int uiShift = 45 - (3 * uiPixel);
|
||||
m_auiRedSelectors[uiPixel] = (ulliSelectorBitsR >> uiShift) & (SELECTORS - 1);
|
||||
m_auiGrnSelectors[uiPixel] = (ulliSelectorBitsG >> uiShift) & (SELECTORS - 1);
|
||||
}
|
||||
|
||||
|
||||
for (unsigned int uiPixel = 0; uiPixel < PIXELS; uiPixel++)
|
||||
{
|
||||
float fRedDecodedData = 0.0f;
|
||||
float fGrnDecodedData = 0.0f;
|
||||
if (a_pblockParent->GetImageSource()->GetFormat() == Image::Format::RG11)
|
||||
{
|
||||
fRedDecodedData = DecodePixelRed(m_fRedBase, m_fRedMultiplier, m_uiRedModifierTableIndex, m_auiRedSelectors[uiPixel]);
|
||||
fGrnDecodedData = DecodePixelRed(m_fGrnBase, m_fGrnMultiplier, m_uiGrnModifierTableIndex, m_auiGrnSelectors[uiPixel]);
|
||||
}
|
||||
else if (a_pblockParent->GetImageSource()->GetFormat() == Image::Format::SIGNED_RG11)
|
||||
{
|
||||
fRedDecodedData = DecodePixelRed(m_fRedBase + 128, m_fRedMultiplier, m_uiRedModifierTableIndex, m_auiRedSelectors[uiPixel]);
|
||||
fGrnDecodedData = DecodePixelRed(m_fGrnBase + 128, m_fGrnMultiplier, m_uiGrnModifierTableIndex, m_auiGrnSelectors[uiPixel]);
|
||||
}
|
||||
else
|
||||
{
|
||||
assert(0);
|
||||
}
|
||||
m_afrgbaDecodedColors[uiPixel] = ColorFloatRGBA(fRedDecodedData, fGrnDecodedData, 0.0f, 1.0f);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
CalcBlockError();
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------------------------------
|
||||
// perform a single encoding iteration
|
||||
// replace the encoding if a better encoding was found
|
||||
// subsequent iterations generally take longer for each iteration
|
||||
// set m_boolDone if encoding is perfect or encoding is finished based on a_fEffort
|
||||
//
|
||||
void Block4x4Encoding_RG11::PerformIteration(float a_fEffort)
|
||||
{
|
||||
assert(!m_boolDone);
|
||||
|
||||
switch (m_uiEncodingIterations)
|
||||
{
|
||||
case 0:
|
||||
m_fError = FLT_MAX;
|
||||
m_fGrnBlockError = FLT_MAX; // artificially high value
|
||||
m_fRedBlockError = FLT_MAX;
|
||||
CalculateR11(8, 0.0f, 0.0f);
|
||||
CalculateG11(8, 0.0f, 0.0f);
|
||||
m_fError = (m_fGrnBlockError + m_fRedBlockError);
|
||||
break;
|
||||
|
||||
case 1:
|
||||
CalculateR11(8, 2.0f, 1.0f);
|
||||
CalculateG11(8, 2.0f, 1.0f);
|
||||
m_fError = (m_fGrnBlockError + m_fRedBlockError);
|
||||
if (a_fEffort <= 24.5f)
|
||||
{
|
||||
m_boolDone = true;
|
||||
}
|
||||
break;
|
||||
|
||||
case 2:
|
||||
CalculateR11(8, 12.0f, 1.0f);
|
||||
CalculateG11(8, 12.0f, 1.0f);
|
||||
m_fError = (m_fGrnBlockError + m_fRedBlockError);
|
||||
if (a_fEffort <= 49.5f)
|
||||
{
|
||||
m_boolDone = true;
|
||||
}
|
||||
break;
|
||||
|
||||
case 3:
|
||||
CalculateR11(7, 6.0f, 1.0f);
|
||||
CalculateG11(7, 6.0f, 1.0f);
|
||||
m_fError = (m_fGrnBlockError + m_fRedBlockError);
|
||||
break;
|
||||
|
||||
case 4:
|
||||
CalculateR11(6, 3.0f, 1.0f);
|
||||
CalculateG11(6, 3.0f, 1.0f);
|
||||
m_fError = (m_fGrnBlockError + m_fRedBlockError);
|
||||
break;
|
||||
|
||||
case 5:
|
||||
CalculateR11(5, 1.0f, 0.0f);
|
||||
CalculateG11(5, 1.0f, 0.0f);
|
||||
m_fError = (m_fGrnBlockError + m_fRedBlockError);
|
||||
m_boolDone = true;
|
||||
break;
|
||||
|
||||
default:
|
||||
assert(0);
|
||||
break;
|
||||
}
|
||||
|
||||
m_uiEncodingIterations++;
|
||||
SetDoneIfPerfect();
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------------------------------
|
||||
// find the best combination of base color, multiplier and selectors
|
||||
//
|
||||
// a_uiSelectorsUsed limits the number of selector combinations to try
|
||||
// a_fBaseRadius limits the range of base colors to try
|
||||
// a_fMultiplierRadius limits the range of multipliers to try
|
||||
//
|
||||
void Block4x4Encoding_RG11::CalculateG11(unsigned int a_uiSelectorsUsed,
|
||||
float a_fBaseRadius, float a_fMultiplierRadius)
|
||||
{
|
||||
// maps from virtual (monotonic) selector to etc selector
|
||||
static const unsigned int auiVirtualSelectorMap[8] = { 3, 2, 1, 0, 4, 5, 6, 7 };
|
||||
|
||||
// find min/max Grn
|
||||
float fMinGrn = 1.0f;
|
||||
float fMaxGrn = 0.0f;
|
||||
for (unsigned int uiPixel = 0; uiPixel < PIXELS; uiPixel++)
|
||||
{
|
||||
// ignore border pixels
|
||||
float fAlpha = m_pafrgbaSource[uiPixel].fA;
|
||||
if (isnan(fAlpha))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
float fGrn = m_pafrgbaSource[uiPixel].fG;
|
||||
|
||||
if (fGrn < fMinGrn)
|
||||
{
|
||||
fMinGrn = fGrn;
|
||||
}
|
||||
if (fGrn > fMaxGrn)
|
||||
{
|
||||
fMaxGrn = fGrn;
|
||||
}
|
||||
}
|
||||
assert(fMinGrn <= fMaxGrn);
|
||||
|
||||
float fGrnRange = (fMaxGrn - fMinGrn);
|
||||
|
||||
// try each modifier table entry
|
||||
for (unsigned int uiTableEntry = 0; uiTableEntry < MODIFIER_TABLE_ENTRYS; uiTableEntry++)
|
||||
{
|
||||
for (unsigned int uiMinVirtualSelector = 0;
|
||||
uiMinVirtualSelector <= (8 - a_uiSelectorsUsed);
|
||||
uiMinVirtualSelector++)
|
||||
{
|
||||
unsigned int uiMaxVirtualSelector = uiMinVirtualSelector + a_uiSelectorsUsed - 1;
|
||||
|
||||
unsigned int uiMinSelector = auiVirtualSelectorMap[uiMinVirtualSelector];
|
||||
unsigned int uiMaxSelector = auiVirtualSelectorMap[uiMaxVirtualSelector];
|
||||
|
||||
float fTableEntryCenter = -s_aafModifierTable[uiTableEntry][uiMinSelector];
|
||||
|
||||
float fTableEntryRange = s_aafModifierTable[uiTableEntry][uiMaxSelector] -
|
||||
s_aafModifierTable[uiTableEntry][uiMinSelector];
|
||||
|
||||
float fCenterRatio = fTableEntryCenter / fTableEntryRange;
|
||||
|
||||
float fCenter = fMinGrn + fCenterRatio*fGrnRange;
|
||||
fCenter = roundf(255.0f * fCenter) / 255.0f;
|
||||
|
||||
float fMinBase = fCenter - (a_fBaseRadius / 255.0f);
|
||||
if (fMinBase < 0.0f)
|
||||
{
|
||||
fMinBase = 0.0f;
|
||||
}
|
||||
|
||||
float fMaxBase = fCenter + (a_fBaseRadius / 255.0f);
|
||||
if (fMaxBase > 1.0f)
|
||||
{
|
||||
fMaxBase = 1.0f;
|
||||
}
|
||||
|
||||
for (float fBase = fMinBase; fBase <= fMaxBase; fBase += (0.999999f / 255.0f))
|
||||
{
|
||||
float fRangeMultiplier = roundf(fGrnRange / fTableEntryRange);
|
||||
|
||||
float fMinMultiplier = fRangeMultiplier - a_fMultiplierRadius;
|
||||
if (fMinMultiplier < 1.0f)
|
||||
{
|
||||
fMinMultiplier = 0.0f;
|
||||
}
|
||||
else if (fMinMultiplier > 15.0f)
|
||||
{
|
||||
fMinMultiplier = 15.0f;
|
||||
}
|
||||
|
||||
float fMaxMultiplier = fRangeMultiplier + a_fMultiplierRadius;
|
||||
if (fMaxMultiplier < 1.0f)
|
||||
{
|
||||
fMaxMultiplier = 1.0f;
|
||||
}
|
||||
else if (fMaxMultiplier > 15.0f)
|
||||
{
|
||||
fMaxMultiplier = 15.0f;
|
||||
}
|
||||
|
||||
for (float fMultiplier = fMinMultiplier; fMultiplier <= fMaxMultiplier; fMultiplier += 1.0f)
|
||||
{
|
||||
// find best selector for each pixel
|
||||
unsigned int auiBestSelectors[PIXELS];
|
||||
float afBestGrnError[PIXELS];
|
||||
float afBestPixelGrn[PIXELS];
|
||||
|
||||
for (unsigned int uiPixel = 0; uiPixel < PIXELS; uiPixel++)
|
||||
{
|
||||
float fBestPixelGrnError = FLT_MAX;
|
||||
|
||||
for (unsigned int uiSelector = 0; uiSelector < SELECTORS; uiSelector++)
|
||||
{
|
||||
//DecodePixelRed is not red channel specific
|
||||
float fPixelGrn = DecodePixelRed(fBase * 255.0f, fMultiplier, uiTableEntry, uiSelector);
|
||||
|
||||
ColorFloatRGBA frgba(m_pafrgbaSource[uiPixel].fR, fPixelGrn, 0.0f, 1.0f);
|
||||
|
||||
float fPixelGrnError = CalcPixelError(frgba, 1.0f, m_pafrgbaSource[uiPixel]);
|
||||
|
||||
if (fPixelGrnError < fBestPixelGrnError)
|
||||
{
|
||||
fBestPixelGrnError = fPixelGrnError;
|
||||
auiBestSelectors[uiPixel] = uiSelector;
|
||||
afBestGrnError[uiPixel] = fBestPixelGrnError;
|
||||
afBestPixelGrn[uiPixel] = fPixelGrn;
|
||||
}
|
||||
}
|
||||
}
|
||||
float fBlockError = 0.0f;
|
||||
for (unsigned int uiPixel = 0; uiPixel < PIXELS; uiPixel++)
|
||||
{
|
||||
fBlockError += afBestGrnError[uiPixel];
|
||||
}
|
||||
|
||||
if (fBlockError < m_fGrnBlockError)
|
||||
{
|
||||
m_fGrnBlockError = fBlockError;
|
||||
|
||||
if (m_pblockParent->GetImageSource()->GetFormat() == Image::Format::RG11)
|
||||
{
|
||||
m_fGrnBase = 255.0f * fBase;
|
||||
}
|
||||
else if (m_pblockParent->GetImageSource()->GetFormat() == Image::Format::SIGNED_RG11)
|
||||
{
|
||||
m_fGrnBase = (fBase * 255) - 128;
|
||||
}
|
||||
else
|
||||
{
|
||||
assert(0);
|
||||
}
|
||||
m_fGrnMultiplier = fMultiplier;
|
||||
m_uiGrnModifierTableIndex = uiTableEntry;
|
||||
for (unsigned int uiPixel = 0; uiPixel < PIXELS; uiPixel++)
|
||||
{
|
||||
m_auiGrnSelectors[uiPixel] = auiBestSelectors[uiPixel];
|
||||
m_afrgbaDecodedColors[uiPixel].fG = afBestPixelGrn[uiPixel];
|
||||
m_afDecodedAlphas[uiPixel] = 1.0f;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------------------------------
|
||||
// set the encoding bits based on encoding state
|
||||
//
|
||||
void Block4x4Encoding_RG11::SetEncodingBits(void)
|
||||
{
|
||||
unsigned long long int ulliSelectorBitsR = 0;
|
||||
unsigned long long int ulliSelectorBitsG = 0;
|
||||
for (unsigned int uiPixel = 0; uiPixel < PIXELS; uiPixel++)
|
||||
{
|
||||
unsigned int uiShift = 45 - (3 * uiPixel);
|
||||
ulliSelectorBitsR |= ((unsigned long long int)m_auiRedSelectors[uiPixel]) << uiShift;
|
||||
ulliSelectorBitsG |= ((unsigned long long int)m_auiGrnSelectors[uiPixel]) << uiShift;
|
||||
}
|
||||
if (m_pblockParent->GetImageSource()->GetFormat() == Image::Format::RG11)
|
||||
{
|
||||
m_pencodingbitsRG11->data.baseR = (unsigned char)roundf(m_fRedBase);
|
||||
}
|
||||
else if (m_pblockParent->GetImageSource()->GetFormat() == Image::Format::SIGNED_RG11)
|
||||
{
|
||||
m_pencodingbitsRG11->data.baseR = (signed char)roundf(m_fRedBase);
|
||||
}
|
||||
else
|
||||
{
|
||||
assert(0);
|
||||
}
|
||||
m_pencodingbitsRG11->data.tableIndexR = m_uiRedModifierTableIndex;
|
||||
m_pencodingbitsRG11->data.multiplierR = (unsigned char)roundf(m_fRedMultiplier);
|
||||
|
||||
m_pencodingbitsRG11->data.selectorsR0 = ulliSelectorBitsR >> 40;
|
||||
m_pencodingbitsRG11->data.selectorsR1 = ulliSelectorBitsR >> 32;
|
||||
m_pencodingbitsRG11->data.selectorsR2 = ulliSelectorBitsR >> 24;
|
||||
m_pencodingbitsRG11->data.selectorsR3 = ulliSelectorBitsR >> 16;
|
||||
m_pencodingbitsRG11->data.selectorsR4 = ulliSelectorBitsR >> 8;
|
||||
m_pencodingbitsRG11->data.selectorsR5 = ulliSelectorBitsR;
|
||||
|
||||
if (m_pblockParent->GetImageSource()->GetFormat() == Image::Format::RG11)
|
||||
{
|
||||
m_pencodingbitsRG11->data.baseG = (unsigned char)roundf(m_fGrnBase);
|
||||
}
|
||||
else if (m_pblockParent->GetImageSource()->GetFormat() == Image::Format::SIGNED_RG11)
|
||||
{
|
||||
m_pencodingbitsRG11->data.baseG = (signed char)roundf(m_fGrnBase);
|
||||
}
|
||||
else
|
||||
{
|
||||
assert(0);
|
||||
}
|
||||
m_pencodingbitsRG11->data.tableIndexG = m_uiGrnModifierTableIndex;
|
||||
m_pencodingbitsRG11->data.multiplierG = (unsigned char)roundf(m_fGrnMultiplier);
|
||||
|
||||
m_pencodingbitsRG11->data.selectorsG0 = ulliSelectorBitsG >> 40;
|
||||
m_pencodingbitsRG11->data.selectorsG1 = ulliSelectorBitsG >> 32;
|
||||
m_pencodingbitsRG11->data.selectorsG2 = ulliSelectorBitsG >> 24;
|
||||
m_pencodingbitsRG11->data.selectorsG3 = ulliSelectorBitsG >> 16;
|
||||
m_pencodingbitsRG11->data.selectorsG4 = ulliSelectorBitsG >> 8;
|
||||
m_pencodingbitsRG11->data.selectorsG5 = ulliSelectorBitsG;
|
||||
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------------------------------
|
||||
//
|
||||
}
|
86
extern/EtcLib/EtcCodec/EtcBlock4x4Encoding_RG11.h
vendored
Normal file
86
extern/EtcLib/EtcCodec/EtcBlock4x4Encoding_RG11.h
vendored
Normal file
@ -0,0 +1,86 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "EtcBlock4x4Encoding_RGB8.h"
|
||||
#include "EtcBlock4x4Encoding_R11.h"
|
||||
|
||||
namespace Etc
|
||||
{
|
||||
class Block4x4EncodingBits_RG11;
|
||||
|
||||
// ################################################################################
|
||||
// Block4x4Encoding_RG11
|
||||
// ################################################################################
|
||||
|
||||
class Block4x4Encoding_RG11 : public Block4x4Encoding_R11
|
||||
{
|
||||
float m_fGrnBase;
|
||||
float m_fGrnMultiplier;
|
||||
float m_fGrnBlockError;
|
||||
unsigned int m_auiGrnSelectors[PIXELS];
|
||||
unsigned int m_uiGrnModifierTableIndex;
|
||||
public:
|
||||
|
||||
Block4x4Encoding_RG11(void);
|
||||
virtual ~Block4x4Encoding_RG11(void);
|
||||
|
||||
virtual void InitFromSource(Block4x4 *a_pblockParent,
|
||||
ColorFloatRGBA *a_pafrgbaSource,
|
||||
|
||||
unsigned char *a_paucEncodingBits, ErrorMetric a_errormetric);
|
||||
|
||||
virtual void InitFromEncodingBits(Block4x4 *a_pblockParent,
|
||||
unsigned char *a_paucEncodingBits,
|
||||
ColorFloatRGBA *a_pafrgbaSource,
|
||||
|
||||
ErrorMetric a_errormetric);
|
||||
|
||||
virtual void PerformIteration(float a_fEffort);
|
||||
|
||||
virtual void SetEncodingBits(void);
|
||||
|
||||
Block4x4EncodingBits_RG11 *m_pencodingbitsRG11;
|
||||
|
||||
void CalculateG11(unsigned int a_uiSelectorsUsed, float a_fBaseRadius, float a_fMultiplierRadius);
|
||||
|
||||
inline float GetGrnBase(void) const
|
||||
{
|
||||
return m_fGrnBase;
|
||||
}
|
||||
|
||||
inline float GetGrnMultiplier(void) const
|
||||
{
|
||||
return m_fGrnMultiplier;
|
||||
}
|
||||
|
||||
inline int GetGrnTableIndex(void) const
|
||||
{
|
||||
return m_uiGrnModifierTableIndex;
|
||||
}
|
||||
|
||||
inline const unsigned int * GetGrnSelectors(void) const
|
||||
{
|
||||
return m_auiGrnSelectors;
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
// ----------------------------------------------------------------------------------------------------
|
||||
//
|
||||
|
||||
} // namespace Etc
|
1728
extern/EtcLib/EtcCodec/EtcBlock4x4Encoding_RGB8.cpp
vendored
Normal file
1728
extern/EtcLib/EtcCodec/EtcBlock4x4Encoding_RGB8.cpp
vendored
Normal file
File diff suppressed because it is too large
Load Diff
96
extern/EtcLib/EtcCodec/EtcBlock4x4Encoding_RGB8.h
vendored
Normal file
96
extern/EtcLib/EtcCodec/EtcBlock4x4Encoding_RGB8.h
vendored
Normal file
@ -0,0 +1,96 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "EtcBlock4x4Encoding_ETC1.h"
|
||||
|
||||
namespace Etc
|
||||
{
|
||||
|
||||
class Block4x4Encoding_RGB8 : public Block4x4Encoding_ETC1
|
||||
{
|
||||
public:
|
||||
|
||||
Block4x4Encoding_RGB8(void);
|
||||
virtual ~Block4x4Encoding_RGB8(void);
|
||||
|
||||
virtual void InitFromEncodingBits(Block4x4 *a_pblockParent,
|
||||
unsigned char *a_paucEncodingBits,
|
||||
ColorFloatRGBA *a_pafrgbaSource,
|
||||
|
||||
ErrorMetric a_errormetric);
|
||||
|
||||
virtual void PerformIteration(float a_fEffort);
|
||||
|
||||
virtual void SetEncodingBits(void);
|
||||
|
||||
inline ColorFloatRGBA GetColor3(void) const
|
||||
{
|
||||
return m_frgbaColor3;
|
||||
}
|
||||
|
||||
protected:
|
||||
|
||||
static const unsigned int PLANAR_CORNER_COLORS = 3;
|
||||
static const unsigned int MAX_PLANAR_REGRESSION_SIZE = 4;
|
||||
static const unsigned int TH_DISTANCES = 8;
|
||||
|
||||
static float s_afTHDistanceTable[TH_DISTANCES];
|
||||
|
||||
void TryPlanar(unsigned int a_uiRadius);
|
||||
void TryTAndH(unsigned int a_uiRadius);
|
||||
|
||||
void InitFromEncodingBits_Planar(void);
|
||||
|
||||
ColorFloatRGBA m_frgbaColor3; // used for planar
|
||||
|
||||
void SetEncodingBits_T(void);
|
||||
void SetEncodingBits_H(void);
|
||||
void SetEncodingBits_Planar(void);
|
||||
|
||||
// state shared between iterations
|
||||
ColorFloatRGBA m_frgbaOriginalColor1_TAndH;
|
||||
ColorFloatRGBA m_frgbaOriginalColor2_TAndH;
|
||||
|
||||
void CalculateBaseColorsForTAndH(void);
|
||||
void TryT(unsigned int a_uiRadius);
|
||||
void TryT_BestSelectorCombination(void);
|
||||
void TryH(unsigned int a_uiRadius);
|
||||
void TryH_BestSelectorCombination(void);
|
||||
|
||||
private:
|
||||
|
||||
void InitFromEncodingBits_T(void);
|
||||
void InitFromEncodingBits_H(void);
|
||||
|
||||
void CalculatePlanarCornerColors(void);
|
||||
|
||||
void ColorRegression(ColorFloatRGBA *a_pafrgbaPixels, unsigned int a_uiPixels,
|
||||
ColorFloatRGBA *a_pfrgbaSlope, ColorFloatRGBA *a_pfrgbaOffset);
|
||||
|
||||
bool TwiddlePlanar(void);
|
||||
bool TwiddlePlanarR();
|
||||
bool TwiddlePlanarG();
|
||||
bool TwiddlePlanarB();
|
||||
|
||||
void DecodePixels_T(void);
|
||||
void DecodePixels_H(void);
|
||||
void DecodePixels_Planar(void);
|
||||
|
||||
};
|
||||
|
||||
} // namespace Etc
|
1819
extern/EtcLib/EtcCodec/EtcBlock4x4Encoding_RGB8A1.cpp
vendored
Normal file
1819
extern/EtcLib/EtcCodec/EtcBlock4x4Encoding_RGB8A1.cpp
vendored
Normal file
File diff suppressed because it is too large
Load Diff
129
extern/EtcLib/EtcCodec/EtcBlock4x4Encoding_RGB8A1.h
vendored
Normal file
129
extern/EtcLib/EtcCodec/EtcBlock4x4Encoding_RGB8A1.h
vendored
Normal file
@ -0,0 +1,129 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "EtcBlock4x4Encoding_RGB8.h"
|
||||
#include "EtcErrorMetric.h"
|
||||
#include "EtcBlock4x4EncodingBits.h"
|
||||
|
||||
namespace Etc
|
||||
{
|
||||
|
||||
// ################################################################################
|
||||
// Block4x4Encoding_RGB8A1
|
||||
// RGB8A1 if not completely opaque or transparent
|
||||
// ################################################################################
|
||||
|
||||
class Block4x4Encoding_RGB8A1 : public Block4x4Encoding_RGB8
|
||||
{
|
||||
public:
|
||||
|
||||
static const unsigned int TRANSPARENT_SELECTOR = 2;
|
||||
|
||||
Block4x4Encoding_RGB8A1(void);
|
||||
virtual ~Block4x4Encoding_RGB8A1(void);
|
||||
|
||||
virtual void InitFromSource(Block4x4 *a_pblockParent,
|
||||
ColorFloatRGBA *a_pafrgbaSource,
|
||||
unsigned char *a_paucEncodingBits,
|
||||
ErrorMetric a_errormetric);
|
||||
|
||||
virtual void InitFromEncodingBits(Block4x4 *a_pblockParent,
|
||||
unsigned char *a_paucEncodingBits,
|
||||
ColorFloatRGBA *a_pafrgbaSource,
|
||||
ErrorMetric a_errormetric);
|
||||
|
||||
virtual void PerformIteration(float a_fEffort);
|
||||
|
||||
virtual void SetEncodingBits(void);
|
||||
|
||||
void InitFromEncodingBits_ETC1(Block4x4 *a_pblockParent,
|
||||
unsigned char *a_paucEncodingBits,
|
||||
ColorFloatRGBA *a_pafrgbaSource,
|
||||
ErrorMetric a_errormetric);
|
||||
|
||||
void InitFromEncodingBits_T(void);
|
||||
void InitFromEncodingBits_H(void);
|
||||
|
||||
void PerformFirstIteration(void);
|
||||
|
||||
void Decode_ETC1(void);
|
||||
void DecodePixels_T(void);
|
||||
void DecodePixels_H(void);
|
||||
void SetEncodingBits_ETC1(void);
|
||||
void SetEncodingBits_T(void);
|
||||
void SetEncodingBits_H(void);
|
||||
|
||||
protected:
|
||||
|
||||
bool m_boolOpaque; // all source pixels have alpha >= 0.5
|
||||
bool m_boolTransparent; // all source pixels have alpha < 0.5
|
||||
bool m_boolPunchThroughPixels; // some source pixels have alpha < 0.5
|
||||
|
||||
static float s_aafCwOpaqueUnsetTable[CW_RANGES][SELECTORS];
|
||||
|
||||
private:
|
||||
|
||||
void TryDifferential(bool a_boolFlip, unsigned int a_uiRadius,
|
||||
int a_iGrayOffset1, int a_iGrayOffset2);
|
||||
void TryDifferentialHalf(DifferentialTrys::Half *a_phalf);
|
||||
|
||||
void TryT(unsigned int a_uiRadius);
|
||||
void TryT_BestSelectorCombination(void);
|
||||
void TryH(unsigned int a_uiRadius);
|
||||
void TryH_BestSelectorCombination(void);
|
||||
|
||||
void TryDegenerates1(void);
|
||||
void TryDegenerates2(void);
|
||||
void TryDegenerates3(void);
|
||||
void TryDegenerates4(void);
|
||||
|
||||
};
|
||||
|
||||
// ################################################################################
|
||||
// Block4x4Encoding_RGB8A1_Opaque
|
||||
// RGB8A1 if all pixels have alpha==1
|
||||
// ################################################################################
|
||||
|
||||
class Block4x4Encoding_RGB8A1_Opaque : public Block4x4Encoding_RGB8A1
|
||||
{
|
||||
public:
|
||||
|
||||
virtual void PerformIteration(float a_fEffort);
|
||||
|
||||
void PerformFirstIteration(void);
|
||||
|
||||
private:
|
||||
|
||||
};
|
||||
|
||||
// ################################################################################
|
||||
// Block4x4Encoding_RGB8A1_Transparent
|
||||
// RGB8A1 if all pixels have alpha==0
|
||||
// ################################################################################
|
||||
|
||||
class Block4x4Encoding_RGB8A1_Transparent : public Block4x4Encoding_RGB8A1
|
||||
{
|
||||
public:
|
||||
|
||||
virtual void PerformIteration(float a_fEffort);
|
||||
|
||||
private:
|
||||
|
||||
};
|
||||
|
||||
} // namespace Etc
|
474
extern/EtcLib/EtcCodec/EtcBlock4x4Encoding_RGBA8.cpp
vendored
Normal file
474
extern/EtcLib/EtcCodec/EtcBlock4x4Encoding_RGBA8.cpp
vendored
Normal file
@ -0,0 +1,474 @@
|
||||
/*
|
||||
* 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_RGBA8.cpp contains:
|
||||
Block4x4Encoding_RGBA8
|
||||
Block4x4Encoding_RGBA8_Opaque
|
||||
Block4x4Encoding_RGBA8_Transparent
|
||||
|
||||
These encoders are used when targetting file format RGBA8.
|
||||
|
||||
Block4x4Encoding_RGBA8_Opaque is used when all pixels in the 4x4 block are opaque
|
||||
Block4x4Encoding_RGBA8_Transparent is used when all pixels in the 4x4 block are transparent
|
||||
Block4x4Encoding_RGBA8 is used when there is a mixture of alphas in the 4x4 block
|
||||
|
||||
*/
|
||||
|
||||
#include "EtcConfig.h"
|
||||
#include "EtcBlock4x4Encoding_RGBA8.h"
|
||||
|
||||
#include "EtcBlock4x4EncodingBits.h"
|
||||
#include "EtcBlock4x4.h"
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <assert.h>
|
||||
#include <float.h>
|
||||
#include <limits>
|
||||
|
||||
namespace Etc
|
||||
{
|
||||
|
||||
// ####################################################################################################
|
||||
// Block4x4Encoding_RGBA8
|
||||
// ####################################################################################################
|
||||
|
||||
float Block4x4Encoding_RGBA8::s_aafModifierTable[MODIFIER_TABLE_ENTRYS][ALPHA_SELECTORS]
|
||||
{
|
||||
{ -3.0f / 255.0f, -6.0f / 255.0f, -9.0f / 255.0f, -15.0f / 255.0f, 2.0f / 255.0f, 5.0f / 255.0f, 8.0f / 255.0f, 14.0f / 255.0f },
|
||||
{ -3.0f / 255.0f, -7.0f / 255.0f, -10.0f / 255.0f, -13.0f / 255.0f, 2.0f / 255.0f, 6.0f / 255.0f, 9.0f / 255.0f, 12.0f / 255.0f },
|
||||
{ -2.0f / 255.0f, -5.0f / 255.0f, -8.0f / 255.0f, -13.0f / 255.0f, 1.0f / 255.0f, 4.0f / 255.0f, 7.0f / 255.0f, 12.0f / 255.0f },
|
||||
{ -2.0f / 255.0f, -4.0f / 255.0f, -6.0f / 255.0f, -13.0f / 255.0f, 1.0f / 255.0f, 3.0f / 255.0f, 5.0f / 255.0f, 12.0f / 255.0f },
|
||||
|
||||
{ -3.0f / 255.0f, -6.0f / 255.0f, -8.0f / 255.0f, -12.0f / 255.0f, 2.0f / 255.0f, 5.0f / 255.0f, 7.0f / 255.0f, 11.0f / 255.0f },
|
||||
{ -3.0f / 255.0f, -7.0f / 255.0f, -9.0f / 255.0f, -11.0f / 255.0f, 2.0f / 255.0f, 6.0f / 255.0f, 8.0f / 255.0f, 10.0f / 255.0f },
|
||||
{ -4.0f / 255.0f, -7.0f / 255.0f, -8.0f / 255.0f, -11.0f / 255.0f, 3.0f / 255.0f, 6.0f / 255.0f, 7.0f / 255.0f, 10.0f / 255.0f },
|
||||
{ -3.0f / 255.0f, -5.0f / 255.0f, -8.0f / 255.0f, -11.0f / 255.0f, 2.0f / 255.0f, 4.0f / 255.0f, 7.0f / 255.0f, 10.0f / 255.0f },
|
||||
|
||||
{ -2.0f / 255.0f, -6.0f / 255.0f, -8.0f / 255.0f, -10.0f / 255.0f, 1.0f / 255.0f, 5.0f / 255.0f, 7.0f / 255.0f, 9.0f / 255.0f },
|
||||
{ -2.0f / 255.0f, -5.0f / 255.0f, -8.0f / 255.0f, -10.0f / 255.0f, 1.0f / 255.0f, 4.0f / 255.0f, 7.0f / 255.0f, 9.0f / 255.0f },
|
||||
{ -2.0f / 255.0f, -4.0f / 255.0f, -8.0f / 255.0f, -10.0f / 255.0f, 1.0f / 255.0f, 3.0f / 255.0f, 7.0f / 255.0f, 9.0f / 255.0f },
|
||||
{ -2.0f / 255.0f, -5.0f / 255.0f, -7.0f / 255.0f, -10.0f / 255.0f, 1.0f / 255.0f, 4.0f / 255.0f, 6.0f / 255.0f, 9.0f / 255.0f },
|
||||
|
||||
{ -3.0f / 255.0f, -4.0f / 255.0f, -7.0f / 255.0f, -10.0f / 255.0f, 2.0f / 255.0f, 3.0f / 255.0f, 6.0f / 255.0f, 9.0f / 255.0f },
|
||||
{ -1.0f / 255.0f, -2.0f / 255.0f, -3.0f / 255.0f, -10.0f / 255.0f, 0.0f / 255.0f, 1.0f / 255.0f, 2.0f / 255.0f, 9.0f / 255.0f },
|
||||
{ -4.0f / 255.0f, -6.0f / 255.0f, -8.0f / 255.0f, -9.0f / 255.0f, 3.0f / 255.0f, 5.0f / 255.0f, 7.0f / 255.0f, 8.0f / 255.0f },
|
||||
{ -3.0f / 255.0f, -5.0f / 255.0f, -7.0f / 255.0f, -9.0f / 255.0f, 2.0f / 255.0f, 4.0f / 255.0f, 6.0f / 255.0f, 8.0f / 255.0f }
|
||||
};
|
||||
|
||||
// ----------------------------------------------------------------------------------------------------
|
||||
//
|
||||
Block4x4Encoding_RGBA8::Block4x4Encoding_RGBA8(void)
|
||||
{
|
||||
|
||||
m_pencodingbitsA8 = nullptr;
|
||||
|
||||
}
|
||||
Block4x4Encoding_RGBA8::~Block4x4Encoding_RGBA8(void) {}
|
||||
// ----------------------------------------------------------------------------------------------------
|
||||
// initialization prior to encoding
|
||||
// a_pblockParent points to the block associated with this encoding
|
||||
// a_errormetric is used to choose the best encoding
|
||||
// a_pafrgbaSource points to a 4x4 block subset of the source image
|
||||
// a_paucEncodingBits points to the final encoding bits
|
||||
//
|
||||
void Block4x4Encoding_RGBA8::InitFromSource(Block4x4 *a_pblockParent,
|
||||
ColorFloatRGBA *a_pafrgbaSource,
|
||||
unsigned char *a_paucEncodingBits, ErrorMetric a_errormetric)
|
||||
{
|
||||
Block4x4Encoding::Init(a_pblockParent, a_pafrgbaSource,a_errormetric);
|
||||
|
||||
m_pencodingbitsA8 = (Block4x4EncodingBits_A8 *)a_paucEncodingBits;
|
||||
m_pencodingbitsRGB8 = (Block4x4EncodingBits_RGB8 *)(a_paucEncodingBits + sizeof(Block4x4EncodingBits_A8));
|
||||
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------------------------------
|
||||
// initialization from the encoding bits of a previous encoding
|
||||
// a_pblockParent points to the block associated with this encoding
|
||||
// a_errormetric is used to choose the best encoding
|
||||
// a_pafrgbaSource points to a 4x4 block subset of the source image
|
||||
// a_paucEncodingBits points to the final encoding bits of a previous encoding
|
||||
//
|
||||
void Block4x4Encoding_RGBA8::InitFromEncodingBits(Block4x4 *a_pblockParent,
|
||||
unsigned char *a_paucEncodingBits,
|
||||
ColorFloatRGBA *a_pafrgbaSource,
|
||||
ErrorMetric a_errormetric)
|
||||
{
|
||||
|
||||
m_pencodingbitsA8 = (Block4x4EncodingBits_A8 *)a_paucEncodingBits;
|
||||
m_pencodingbitsRGB8 = (Block4x4EncodingBits_RGB8 *)(a_paucEncodingBits + sizeof(Block4x4EncodingBits_A8));
|
||||
|
||||
// init RGB portion
|
||||
Block4x4Encoding_RGB8::InitFromEncodingBits(a_pblockParent,
|
||||
(unsigned char *) m_pencodingbitsRGB8,
|
||||
a_pafrgbaSource,
|
||||
a_errormetric);
|
||||
|
||||
// init A8 portion
|
||||
// has to be done after InitFromEncodingBits()
|
||||
{
|
||||
m_fBase = m_pencodingbitsA8->data.base / 255.0f;
|
||||
m_fMultiplier = (float)m_pencodingbitsA8->data.multiplier;
|
||||
m_uiModifierTableIndex = m_pencodingbitsA8->data.table;
|
||||
|
||||
unsigned long long int ulliSelectorBits = 0;
|
||||
ulliSelectorBits |= (unsigned long long int)m_pencodingbitsA8->data.selectors0 << 40;
|
||||
ulliSelectorBits |= (unsigned long long int)m_pencodingbitsA8->data.selectors1 << 32;
|
||||
ulliSelectorBits |= (unsigned long long int)m_pencodingbitsA8->data.selectors2 << 24;
|
||||
ulliSelectorBits |= (unsigned long long int)m_pencodingbitsA8->data.selectors3 << 16;
|
||||
ulliSelectorBits |= (unsigned long long int)m_pencodingbitsA8->data.selectors4 << 8;
|
||||
ulliSelectorBits |= (unsigned long long int)m_pencodingbitsA8->data.selectors5;
|
||||
for (unsigned int uiPixel = 0; uiPixel < PIXELS; uiPixel++)
|
||||
{
|
||||
unsigned int uiShift = 45 - (3 * uiPixel);
|
||||
m_auiAlphaSelectors[uiPixel] = (ulliSelectorBits >> uiShift) & (ALPHA_SELECTORS - 1);
|
||||
}
|
||||
|
||||
// decode the alphas
|
||||
// calc alpha error
|
||||
m_fError = 0.0f;
|
||||
for (unsigned int uiPixel = 0; uiPixel < PIXELS; uiPixel++)
|
||||
{
|
||||
m_afDecodedAlphas[uiPixel] = DecodePixelAlpha(m_fBase, m_fMultiplier,
|
||||
m_uiModifierTableIndex,
|
||||
m_auiAlphaSelectors[uiPixel]);
|
||||
|
||||
float fDeltaAlpha = m_afDecodedAlphas[uiPixel] - m_pafrgbaSource[uiPixel].fA;
|
||||
m_fError += fDeltaAlpha * fDeltaAlpha;
|
||||
}
|
||||
}
|
||||
|
||||
// redo error calc to include alpha
|
||||
CalcBlockError();
|
||||
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------------------------------
|
||||
// perform a single encoding iteration
|
||||
// replace the encoding if a better encoding was found
|
||||
// subsequent iterations generally take longer for each iteration
|
||||
// set m_boolDone if encoding is perfect or encoding is finished based on a_fEffort
|
||||
//
|
||||
// similar to Block4x4Encoding_RGB8_Base::Encode_RGB8(), but with alpha added
|
||||
//
|
||||
void Block4x4Encoding_RGBA8::PerformIteration(float a_fEffort)
|
||||
{
|
||||
assert(!m_boolDone);
|
||||
|
||||
if (m_uiEncodingIterations == 0)
|
||||
{
|
||||
if (a_fEffort < 24.9f)
|
||||
{
|
||||
CalculateA8(0.0f);
|
||||
}
|
||||
else if (a_fEffort < 49.9f)
|
||||
{
|
||||
CalculateA8(1.0f);
|
||||
}
|
||||
else
|
||||
{
|
||||
CalculateA8(2.0f);
|
||||
}
|
||||
}
|
||||
|
||||
Block4x4Encoding_RGB8::PerformIteration(a_fEffort);
|
||||
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------------------------------
|
||||
// find the best combination of base alpga, multiplier and selectors
|
||||
//
|
||||
// a_fRadius limits the range of base alpha to try
|
||||
//
|
||||
void Block4x4Encoding_RGBA8::CalculateA8(float a_fRadius)
|
||||
{
|
||||
|
||||
// find min/max alpha
|
||||
float fMinAlpha = 1.0f;
|
||||
float fMaxAlpha = 0.0f;
|
||||
for (unsigned int uiPixel = 0; uiPixel < PIXELS; uiPixel++)
|
||||
{
|
||||
float fAlpha = m_pafrgbaSource[uiPixel].fA;
|
||||
|
||||
// ignore border pixels
|
||||
if (isnan(fAlpha))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if (fAlpha < fMinAlpha)
|
||||
{
|
||||
fMinAlpha = fAlpha;
|
||||
}
|
||||
if (fAlpha > fMaxAlpha)
|
||||
{
|
||||
fMaxAlpha = fAlpha;
|
||||
}
|
||||
}
|
||||
assert(fMinAlpha <= fMaxAlpha);
|
||||
|
||||
float fAlphaRange = fMaxAlpha - fMinAlpha;
|
||||
|
||||
// try each modifier table entry
|
||||
m_fError = FLT_MAX; // artificially high value
|
||||
for (unsigned int uiTableEntry = 0; uiTableEntry < MODIFIER_TABLE_ENTRYS; uiTableEntry++)
|
||||
{
|
||||
static const unsigned int MIN_VALUE_SELECTOR = 3;
|
||||
static const unsigned int MAX_VALUE_SELECTOR = 7;
|
||||
|
||||
float fTableEntryCenter = -s_aafModifierTable[uiTableEntry][MIN_VALUE_SELECTOR];
|
||||
|
||||
float fTableEntryRange = s_aafModifierTable[uiTableEntry][MAX_VALUE_SELECTOR] -
|
||||
s_aafModifierTable[uiTableEntry][MIN_VALUE_SELECTOR];
|
||||
|
||||
float fCenterRatio = fTableEntryCenter / fTableEntryRange;
|
||||
|
||||
float fCenter = fMinAlpha + fCenterRatio*fAlphaRange;
|
||||
fCenter = roundf(255.0f * fCenter) / 255.0f;
|
||||
|
||||
float fMinBase = fCenter - (a_fRadius / 255.0f);
|
||||
if (fMinBase < 0.0f)
|
||||
{
|
||||
fMinBase = 0.0f;
|
||||
}
|
||||
|
||||
float fMaxBase = fCenter + (a_fRadius / 255.0f);
|
||||
if (fMaxBase > 1.0f)
|
||||
{
|
||||
fMaxBase = 1.0f;
|
||||
}
|
||||
|
||||
for (float fBase = fMinBase; fBase <= fMaxBase; fBase += (0.999999f / 255.0f))
|
||||
{
|
||||
|
||||
float fRangeMultiplier = roundf(fAlphaRange / fTableEntryRange);
|
||||
|
||||
float fMinMultiplier = fRangeMultiplier - a_fRadius;
|
||||
if (fMinMultiplier < 1.0f)
|
||||
{
|
||||
fMinMultiplier = 1.0f;
|
||||
}
|
||||
else if (fMinMultiplier > 15.0f)
|
||||
{
|
||||
fMinMultiplier = 15.0f;
|
||||
}
|
||||
|
||||
float fMaxMultiplier = fRangeMultiplier + a_fRadius;
|
||||
if (fMaxMultiplier < 1.0f)
|
||||
{
|
||||
fMaxMultiplier = 1.0f;
|
||||
}
|
||||
else if (fMaxMultiplier > 15.0f)
|
||||
{
|
||||
fMaxMultiplier = 15.0f;
|
||||
}
|
||||
|
||||
for (float fMultiplier = fMinMultiplier; fMultiplier <= fMaxMultiplier; fMultiplier += 1.0f)
|
||||
{
|
||||
// find best selector for each pixel
|
||||
unsigned int auiBestSelectors[PIXELS];
|
||||
float afBestAlphaError[PIXELS];
|
||||
float afBestDecodedAlphas[PIXELS];
|
||||
for (unsigned int uiPixel = 0; uiPixel < PIXELS; uiPixel++)
|
||||
{
|
||||
float fBestPixelAlphaError = FLT_MAX;
|
||||
for (unsigned int uiSelector = 0; uiSelector < ALPHA_SELECTORS; uiSelector++)
|
||||
{
|
||||
float fDecodedAlpha = DecodePixelAlpha(fBase, fMultiplier, uiTableEntry, uiSelector);
|
||||
|
||||
// border pixels (NAN) should have zero error
|
||||
float fPixelDeltaAlpha = isnan(m_pafrgbaSource[uiPixel].fA) ?
|
||||
0.0f :
|
||||
fDecodedAlpha - m_pafrgbaSource[uiPixel].fA;
|
||||
|
||||
float fPixelAlphaError = fPixelDeltaAlpha * fPixelDeltaAlpha;
|
||||
|
||||
if (fPixelAlphaError < fBestPixelAlphaError)
|
||||
{
|
||||
fBestPixelAlphaError = fPixelAlphaError;
|
||||
auiBestSelectors[uiPixel] = uiSelector;
|
||||
afBestAlphaError[uiPixel] = fBestPixelAlphaError;
|
||||
afBestDecodedAlphas[uiPixel] = fDecodedAlpha;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
float fBlockError = 0.0f;
|
||||
for (unsigned int uiPixel = 0; uiPixel < PIXELS; uiPixel++)
|
||||
{
|
||||
fBlockError += afBestAlphaError[uiPixel];
|
||||
}
|
||||
|
||||
if (fBlockError < m_fError)
|
||||
{
|
||||
m_fError = fBlockError;
|
||||
|
||||
m_fBase = fBase;
|
||||
m_fMultiplier = fMultiplier;
|
||||
m_uiModifierTableIndex = uiTableEntry;
|
||||
for (unsigned int uiPixel = 0; uiPixel < PIXELS; uiPixel++)
|
||||
{
|
||||
m_auiAlphaSelectors[uiPixel] = auiBestSelectors[uiPixel];
|
||||
m_afDecodedAlphas[uiPixel] = afBestDecodedAlphas[uiPixel];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------------------------------
|
||||
// set the encoding bits based on encoding state
|
||||
//
|
||||
void Block4x4Encoding_RGBA8::SetEncodingBits(void)
|
||||
{
|
||||
|
||||
// set the RGB8 portion
|
||||
Block4x4Encoding_RGB8::SetEncodingBits();
|
||||
|
||||
// set the A8 portion
|
||||
{
|
||||
m_pencodingbitsA8->data.base = (unsigned char)roundf(255.0f * m_fBase);
|
||||
m_pencodingbitsA8->data.table = m_uiModifierTableIndex;
|
||||
m_pencodingbitsA8->data.multiplier = (unsigned char)roundf(m_fMultiplier);
|
||||
|
||||
unsigned long long int ulliSelectorBits = 0;
|
||||
for (unsigned int uiPixel = 0; uiPixel < PIXELS; uiPixel++)
|
||||
{
|
||||
unsigned int uiShift = 45 - (3 * uiPixel);
|
||||
ulliSelectorBits |= ((unsigned long long int)m_auiAlphaSelectors[uiPixel]) << uiShift;
|
||||
}
|
||||
|
||||
m_pencodingbitsA8->data.selectors0 = ulliSelectorBits >> 40;
|
||||
m_pencodingbitsA8->data.selectors1 = ulliSelectorBits >> 32;
|
||||
m_pencodingbitsA8->data.selectors2 = ulliSelectorBits >> 24;
|
||||
m_pencodingbitsA8->data.selectors3 = ulliSelectorBits >> 16;
|
||||
m_pencodingbitsA8->data.selectors4 = ulliSelectorBits >> 8;
|
||||
m_pencodingbitsA8->data.selectors5 = ulliSelectorBits;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// ####################################################################################################
|
||||
// Block4x4Encoding_RGBA8_Opaque
|
||||
// ####################################################################################################
|
||||
|
||||
// ----------------------------------------------------------------------------------------------------
|
||||
// perform a single encoding iteration
|
||||
// replace the encoding if a better encoding was found
|
||||
// subsequent iterations generally take longer for each iteration
|
||||
// set m_boolDone if encoding is perfect or encoding is finished based on a_fEffort
|
||||
//
|
||||
void Block4x4Encoding_RGBA8_Opaque::PerformIteration(float a_fEffort)
|
||||
{
|
||||
assert(!m_boolDone);
|
||||
|
||||
if (m_uiEncodingIterations == 0)
|
||||
{
|
||||
m_fError = 0.0f;
|
||||
|
||||
for (unsigned int uiPixel = 0; uiPixel < PIXELS; uiPixel++)
|
||||
{
|
||||
m_afDecodedAlphas[uiPixel] = 1.0f;
|
||||
}
|
||||
}
|
||||
|
||||
Block4x4Encoding_RGB8::PerformIteration(a_fEffort);
|
||||
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------------------------------
|
||||
// set the encoding bits based on encoding state
|
||||
//
|
||||
void Block4x4Encoding_RGBA8_Opaque::SetEncodingBits(void)
|
||||
{
|
||||
|
||||
// set the RGB8 portion
|
||||
Block4x4Encoding_RGB8::SetEncodingBits();
|
||||
|
||||
// set the A8 portion
|
||||
m_pencodingbitsA8->data.base = 255;
|
||||
m_pencodingbitsA8->data.table = 15;
|
||||
m_pencodingbitsA8->data.multiplier = 15;
|
||||
m_pencodingbitsA8->data.selectors0 = 0xFF;
|
||||
m_pencodingbitsA8->data.selectors1 = 0xFF;
|
||||
m_pencodingbitsA8->data.selectors2 = 0xFF;
|
||||
m_pencodingbitsA8->data.selectors3 = 0xFF;
|
||||
m_pencodingbitsA8->data.selectors4 = 0xFF;
|
||||
m_pencodingbitsA8->data.selectors5 = 0xFF;
|
||||
|
||||
}
|
||||
|
||||
// ####################################################################################################
|
||||
// Block4x4Encoding_RGBA8_Transparent
|
||||
// ####################################################################################################
|
||||
|
||||
// ----------------------------------------------------------------------------------------------------
|
||||
// perform a single encoding iteration
|
||||
// replace the encoding if a better encoding was found
|
||||
// subsequent iterations generally take longer for each iteration
|
||||
// set m_boolDone if encoding is perfect or encoding is finished based on a_fEffort
|
||||
//
|
||||
void Block4x4Encoding_RGBA8_Transparent::PerformIteration(float )
|
||||
{
|
||||
assert(!m_boolDone);
|
||||
assert(m_uiEncodingIterations == 0);
|
||||
|
||||
m_mode = MODE_ETC1;
|
||||
m_boolDiff = true;
|
||||
m_boolFlip = false;
|
||||
|
||||
for (unsigned int uiPixel = 0; uiPixel < PIXELS; uiPixel++)
|
||||
{
|
||||
m_afrgbaDecodedColors[uiPixel] = ColorFloatRGBA();
|
||||
m_afDecodedAlphas[uiPixel] = 0.0f;
|
||||
}
|
||||
|
||||
m_fError = 0.0f;
|
||||
|
||||
m_boolDone = true;
|
||||
m_uiEncodingIterations++;
|
||||
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------------------------------
|
||||
// set the encoding bits based on encoding state
|
||||
//
|
||||
void Block4x4Encoding_RGBA8_Transparent::SetEncodingBits(void)
|
||||
{
|
||||
|
||||
Block4x4Encoding_RGB8::SetEncodingBits();
|
||||
|
||||
// set the A8 portion
|
||||
m_pencodingbitsA8->data.base = 0;
|
||||
m_pencodingbitsA8->data.table = 0;
|
||||
m_pencodingbitsA8->data.multiplier = 1;
|
||||
m_pencodingbitsA8->data.selectors0 = 0;
|
||||
m_pencodingbitsA8->data.selectors1 = 0;
|
||||
m_pencodingbitsA8->data.selectors2 = 0;
|
||||
m_pencodingbitsA8->data.selectors3 = 0;
|
||||
m_pencodingbitsA8->data.selectors4 = 0;
|
||||
m_pencodingbitsA8->data.selectors5 = 0;
|
||||
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------------------------------
|
||||
//
|
||||
}
|
121
extern/EtcLib/EtcCodec/EtcBlock4x4Encoding_RGBA8.h
vendored
Normal file
121
extern/EtcLib/EtcCodec/EtcBlock4x4Encoding_RGBA8.h
vendored
Normal file
@ -0,0 +1,121 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "EtcBlock4x4Encoding_RGB8.h"
|
||||
|
||||
namespace Etc
|
||||
{
|
||||
class Block4x4EncodingBits_A8;
|
||||
|
||||
// ################################################################################
|
||||
// Block4x4Encoding_RGBA8
|
||||
// RGBA8 if not completely opaque or transparent
|
||||
// ################################################################################
|
||||
|
||||
class Block4x4Encoding_RGBA8 : public Block4x4Encoding_RGB8
|
||||
{
|
||||
public:
|
||||
|
||||
Block4x4Encoding_RGBA8(void);
|
||||
virtual ~Block4x4Encoding_RGBA8(void);
|
||||
|
||||
virtual void InitFromSource(Block4x4 *a_pblockParent,
|
||||
ColorFloatRGBA *a_pafrgbaSource,
|
||||
unsigned char *a_paucEncodingBits, ErrorMetric a_errormetric);
|
||||
|
||||
virtual void InitFromEncodingBits(Block4x4 *a_pblockParent,
|
||||
unsigned char *a_paucEncodingBits,
|
||||
ColorFloatRGBA *a_pafrgbaSource,
|
||||
ErrorMetric a_errormetric);
|
||||
|
||||
virtual void PerformIteration(float a_fEffort);
|
||||
|
||||
virtual void SetEncodingBits(void);
|
||||
|
||||
protected:
|
||||
|
||||
static const unsigned int MODIFIER_TABLE_ENTRYS = 16;
|
||||
static const unsigned int ALPHA_SELECTOR_BITS = 3;
|
||||
static const unsigned int ALPHA_SELECTORS = 1 << ALPHA_SELECTOR_BITS;
|
||||
|
||||
static float s_aafModifierTable[MODIFIER_TABLE_ENTRYS][ALPHA_SELECTORS];
|
||||
|
||||
void CalculateA8(float a_fRadius);
|
||||
|
||||
Block4x4EncodingBits_A8 *m_pencodingbitsA8; // A8 portion of Block4x4EncodingBits_RGBA8
|
||||
|
||||
float m_fBase;
|
||||
float m_fMultiplier;
|
||||
unsigned int m_uiModifierTableIndex;
|
||||
unsigned int m_auiAlphaSelectors[PIXELS];
|
||||
|
||||
private:
|
||||
|
||||
inline float DecodePixelAlpha(float a_fBase, float a_fMultiplier,
|
||||
unsigned int a_uiTableIndex, unsigned int a_uiSelector)
|
||||
{
|
||||
float fPixelAlpha = a_fBase +
|
||||
a_fMultiplier*s_aafModifierTable[a_uiTableIndex][a_uiSelector];
|
||||
if (fPixelAlpha < 0.0f)
|
||||
{
|
||||
fPixelAlpha = 0.0f;
|
||||
}
|
||||
else if (fPixelAlpha > 1.0f)
|
||||
{
|
||||
fPixelAlpha = 1.0f;
|
||||
}
|
||||
|
||||
return fPixelAlpha;
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
// ################################################################################
|
||||
// Block4x4Encoding_RGBA8_Opaque
|
||||
// RGBA8 if all pixels have alpha==1
|
||||
// ################################################################################
|
||||
|
||||
class Block4x4Encoding_RGBA8_Opaque : public Block4x4Encoding_RGBA8
|
||||
{
|
||||
public:
|
||||
|
||||
virtual void PerformIteration(float a_fEffort);
|
||||
|
||||
virtual void SetEncodingBits(void);
|
||||
|
||||
};
|
||||
|
||||
// ################################################################################
|
||||
// Block4x4Encoding_RGBA8_Transparent
|
||||
// RGBA8 if all pixels have alpha==0
|
||||
// ################################################################################
|
||||
|
||||
class Block4x4Encoding_RGBA8_Transparent : public Block4x4Encoding_RGBA8
|
||||
{
|
||||
public:
|
||||
|
||||
virtual void PerformIteration(float a_fEffort);
|
||||
|
||||
virtual void SetEncodingBits(void);
|
||||
|
||||
};
|
||||
|
||||
// ----------------------------------------------------------------------------------------------------
|
||||
//
|
||||
|
||||
} // namespace Etc
|
173
extern/EtcLib/EtcCodec/EtcDifferentialTrys.cpp
vendored
Normal file
173
extern/EtcLib/EtcCodec/EtcDifferentialTrys.cpp
vendored
Normal file
@ -0,0 +1,173 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
/*
|
||||
EtcDifferentialTrys.cpp
|
||||
|
||||
Gathers the results of the various encoding trys for both halves of a 4x4 block for Differential mode
|
||||
|
||||
*/
|
||||
|
||||
#include "EtcConfig.h"
|
||||
#include "EtcDifferentialTrys.h"
|
||||
|
||||
#include <assert.h>
|
||||
|
||||
namespace Etc
|
||||
{
|
||||
|
||||
// ----------------------------------------------------------------------------------------------------
|
||||
// construct a list of trys (encoding attempts)
|
||||
//
|
||||
// a_frgbaColor1 is the basecolor for the first half
|
||||
// a_frgbaColor2 is the basecolor for the second half
|
||||
// a_pauiPixelMapping1 is the pixel order for the first half
|
||||
// a_pauiPixelMapping2 is the pixel order for the second half
|
||||
// a_uiRadius is the amount to vary the base colors
|
||||
//
|
||||
DifferentialTrys::DifferentialTrys(ColorFloatRGBA a_frgbaColor1, ColorFloatRGBA a_frgbaColor2,
|
||||
const unsigned int *a_pauiPixelMapping1,
|
||||
const unsigned int *a_pauiPixelMapping2,
|
||||
unsigned int a_uiRadius,
|
||||
int a_iGrayOffset1, int a_iGrayOffset2)
|
||||
{
|
||||
assert(a_uiRadius <= MAX_RADIUS);
|
||||
|
||||
m_boolSeverelyBentColors = false;
|
||||
|
||||
ColorFloatRGBA frgbaQuantizedColor1 = a_frgbaColor1.QuantizeR5G5B5();
|
||||
ColorFloatRGBA frgbaQuantizedColor2 = a_frgbaColor2.QuantizeR5G5B5();
|
||||
|
||||
// quantize base colors
|
||||
// ensure that trys with a_uiRadius don't overflow
|
||||
int iRed1 = MoveAwayFromEdge(frgbaQuantizedColor1.IntRed(31.0f)+a_iGrayOffset1, a_uiRadius);
|
||||
int iGreen1 = MoveAwayFromEdge(frgbaQuantizedColor1.IntGreen(31.0f) + a_iGrayOffset1, a_uiRadius);
|
||||
int iBlue1 = MoveAwayFromEdge(frgbaQuantizedColor1.IntBlue(31.0f) + a_iGrayOffset1, a_uiRadius);
|
||||
int iRed2 = MoveAwayFromEdge(frgbaQuantizedColor2.IntRed(31.0f) + a_iGrayOffset2, a_uiRadius);
|
||||
int iGreen2 = MoveAwayFromEdge(frgbaQuantizedColor2.IntGreen(31.0f) + a_iGrayOffset2, a_uiRadius);
|
||||
int iBlue2 = MoveAwayFromEdge(frgbaQuantizedColor2.IntBlue(31.0f) + a_iGrayOffset2, a_uiRadius);
|
||||
|
||||
int iDeltaRed = iRed2 - iRed1;
|
||||
int iDeltaGreen = iGreen2 - iGreen1;
|
||||
int iDeltaBlue = iBlue2 - iBlue1;
|
||||
|
||||
// make sure components are within range
|
||||
{
|
||||
if (iDeltaRed > 3)
|
||||
{
|
||||
if (iDeltaRed > 7)
|
||||
{
|
||||
m_boolSeverelyBentColors = true;
|
||||
}
|
||||
|
||||
iRed1 += (iDeltaRed - 3) / 2;
|
||||
iRed2 = iRed1 + 3;
|
||||
iDeltaRed = 3;
|
||||
}
|
||||
else if (iDeltaRed < -4)
|
||||
{
|
||||
if (iDeltaRed < -8)
|
||||
{
|
||||
m_boolSeverelyBentColors = true;
|
||||
}
|
||||
|
||||
iRed1 += (iDeltaRed + 4) / 2;
|
||||
iRed2 = iRed1 - 4;
|
||||
iDeltaRed = -4;
|
||||
}
|
||||
assert(iRed1 >= (signed)(0 + a_uiRadius) && iRed1 <= (signed)(31 - a_uiRadius));
|
||||
assert(iRed2 >= (signed)(0 + a_uiRadius) && iRed2 <= (signed)(31 - a_uiRadius));
|
||||
assert(iDeltaRed >= -4 && iDeltaRed <= 3);
|
||||
|
||||
if (iDeltaGreen > 3)
|
||||
{
|
||||
if (iDeltaGreen > 7)
|
||||
{
|
||||
m_boolSeverelyBentColors = true;
|
||||
}
|
||||
|
||||
iGreen1 += (iDeltaGreen - 3) / 2;
|
||||
iGreen2 = iGreen1 + 3;
|
||||
iDeltaGreen = 3;
|
||||
}
|
||||
else if (iDeltaGreen < -4)
|
||||
{
|
||||
if (iDeltaGreen < -8)
|
||||
{
|
||||
m_boolSeverelyBentColors = true;
|
||||
}
|
||||
|
||||
iGreen1 += (iDeltaGreen + 4) / 2;
|
||||
iGreen2 = iGreen1 - 4;
|
||||
iDeltaGreen = -4;
|
||||
}
|
||||
assert(iGreen1 >= (signed)(0 + a_uiRadius) && iGreen1 <= (signed)(31 - a_uiRadius));
|
||||
assert(iGreen2 >= (signed)(0 + a_uiRadius) && iGreen2 <= (signed)(31 - a_uiRadius));
|
||||
assert(iDeltaGreen >= -4 && iDeltaGreen <= 3);
|
||||
|
||||
if (iDeltaBlue > 3)
|
||||
{
|
||||
if (iDeltaBlue > 7)
|
||||
{
|
||||
m_boolSeverelyBentColors = true;
|
||||
}
|
||||
|
||||
iBlue1 += (iDeltaBlue - 3) / 2;
|
||||
iBlue2 = iBlue1 + 3;
|
||||
iDeltaBlue = 3;
|
||||
}
|
||||
else if (iDeltaBlue < -4)
|
||||
{
|
||||
if (iDeltaBlue < -8)
|
||||
{
|
||||
m_boolSeverelyBentColors = true;
|
||||
}
|
||||
|
||||
iBlue1 += (iDeltaBlue + 4) / 2;
|
||||
iBlue2 = iBlue1 - 4;
|
||||
iDeltaBlue = -4;
|
||||
}
|
||||
assert(iBlue1 >= (signed)(0+a_uiRadius) && iBlue1 <= (signed)(31 - a_uiRadius));
|
||||
assert(iBlue2 >= (signed)(0 + a_uiRadius) && iBlue2 <= (signed)(31 - a_uiRadius));
|
||||
assert(iDeltaBlue >= -4 && iDeltaBlue <= 3);
|
||||
}
|
||||
|
||||
m_half1.Init(iRed1, iGreen1, iBlue1, a_pauiPixelMapping1, a_uiRadius);
|
||||
m_half2.Init(iRed2, iGreen2, iBlue2, a_pauiPixelMapping2, a_uiRadius);
|
||||
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------------------------------
|
||||
//
|
||||
void DifferentialTrys::Half::Init(int a_iRed, int a_iGreen, int a_iBlue,
|
||||
const unsigned int *a_pauiPixelMapping, unsigned int a_uiRadius)
|
||||
{
|
||||
|
||||
m_iRed = a_iRed;
|
||||
m_iGreen = a_iGreen;
|
||||
m_iBlue = a_iBlue;
|
||||
|
||||
m_pauiPixelMapping = a_pauiPixelMapping;
|
||||
m_uiRadius = a_uiRadius;
|
||||
|
||||
m_uiTrys = 0;
|
||||
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------------------------------
|
||||
//
|
||||
|
||||
} // namespace Etc
|
97
extern/EtcLib/EtcCodec/EtcDifferentialTrys.h
vendored
Normal file
97
extern/EtcLib/EtcCodec/EtcDifferentialTrys.h
vendored
Normal file
@ -0,0 +1,97 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "EtcColorFloatRGBA.h"
|
||||
|
||||
namespace Etc
|
||||
{
|
||||
|
||||
class DifferentialTrys
|
||||
{
|
||||
public:
|
||||
|
||||
static const unsigned int MAX_RADIUS = 2;
|
||||
|
||||
DifferentialTrys(ColorFloatRGBA a_frgbaColor1,
|
||||
ColorFloatRGBA a_frgbaColor2,
|
||||
const unsigned int *a_pauiPixelMapping1,
|
||||
const unsigned int *a_pauiPixelMapping2,
|
||||
unsigned int a_uiRadius,
|
||||
int a_iGrayOffset1, int a_iGrayOffset2);
|
||||
|
||||
inline static int MoveAwayFromEdge(int a_i, int a_iDistance)
|
||||
{
|
||||
if (a_i < (0+ a_iDistance))
|
||||
{
|
||||
return (0 + a_iDistance);
|
||||
}
|
||||
else if (a_i > (31- a_iDistance))
|
||||
{
|
||||
return (31 - a_iDistance);
|
||||
}
|
||||
|
||||
return a_i;
|
||||
}
|
||||
|
||||
class Try
|
||||
{
|
||||
public :
|
||||
static const unsigned int SELECTORS = 8; // per half
|
||||
|
||||
int m_iRed;
|
||||
int m_iGreen;
|
||||
int m_iBlue;
|
||||
unsigned int m_uiCW;
|
||||
unsigned int m_auiSelectors[SELECTORS];
|
||||
float m_fError;
|
||||
};
|
||||
|
||||
class Half
|
||||
{
|
||||
public:
|
||||
|
||||
static const unsigned int MAX_TRYS = 125;
|
||||
|
||||
void Init(int a_iRed, int a_iGreen, int a_iBlue,
|
||||
const unsigned int *a_pauiPixelMapping,
|
||||
unsigned int a_uiRadius);
|
||||
|
||||
// center of trys
|
||||
int m_iRed;
|
||||
int m_iGreen;
|
||||
int m_iBlue;
|
||||
|
||||
const unsigned int *m_pauiPixelMapping;
|
||||
unsigned int m_uiRadius;
|
||||
|
||||
unsigned int m_uiTrys;
|
||||
Try m_atry[MAX_TRYS];
|
||||
|
||||
Try *m_ptryBest;
|
||||
};
|
||||
|
||||
Half m_half1;
|
||||
Half m_half2;
|
||||
|
||||
bool m_boolSeverelyBentColors;
|
||||
};
|
||||
|
||||
// ----------------------------------------------------------------------------------------------------
|
||||
//
|
||||
|
||||
} // namespace Etc
|
51
extern/EtcLib/EtcCodec/EtcErrorMetric.h
vendored
Normal file
51
extern/EtcLib/EtcCodec/EtcErrorMetric.h
vendored
Normal file
@ -0,0 +1,51 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
namespace Etc
|
||||
{
|
||||
|
||||
enum ErrorMetric
|
||||
{
|
||||
RGBA,
|
||||
REC709,
|
||||
NUMERIC,
|
||||
NORMALXYZ,
|
||||
//
|
||||
ERROR_METRICS,
|
||||
//
|
||||
BT709 = REC709
|
||||
};
|
||||
|
||||
inline const char *ErrorMetricToString(ErrorMetric errorMetric)
|
||||
{
|
||||
switch (errorMetric)
|
||||
{
|
||||
case RGBA:
|
||||
return "RGBA";
|
||||
case REC709:
|
||||
return "REC709";
|
||||
case NUMERIC:
|
||||
return "NUMERIC";
|
||||
case NORMALXYZ:
|
||||
return "NORMALXYZ";
|
||||
case ERROR_METRICS:
|
||||
default:
|
||||
return "UNKNOWN";
|
||||
}
|
||||
}
|
||||
} // namespace Etc
|
85
extern/EtcLib/EtcCodec/EtcIndividualTrys.cpp
vendored
Normal file
85
extern/EtcLib/EtcCodec/EtcIndividualTrys.cpp
vendored
Normal file
@ -0,0 +1,85 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
/*
|
||||
EtcIndividualTrys.cpp
|
||||
|
||||
Gathers the results of the various encoding trys for both halves of a 4x4 block for Individual mode
|
||||
|
||||
*/
|
||||
|
||||
#include "EtcConfig.h"
|
||||
#include "EtcIndividualTrys.h"
|
||||
|
||||
#include <assert.h>
|
||||
|
||||
namespace Etc
|
||||
{
|
||||
|
||||
// ----------------------------------------------------------------------------------------------------
|
||||
// construct a list of trys (encoding attempts)
|
||||
//
|
||||
// a_frgbaColor1 is the basecolor for the first half
|
||||
// a_frgbaColor2 is the basecolor for the second half
|
||||
// a_pauiPixelMapping1 is the pixel order for the first half
|
||||
// a_pauiPixelMapping2 is the pixel order for the second half
|
||||
// a_uiRadius is the amount to vary the base colors
|
||||
//
|
||||
IndividualTrys::IndividualTrys(ColorFloatRGBA a_frgbaColor1, ColorFloatRGBA a_frgbaColor2,
|
||||
const unsigned int *a_pauiPixelMapping1,
|
||||
const unsigned int *a_pauiPixelMapping2,
|
||||
unsigned int a_uiRadius)
|
||||
{
|
||||
assert(a_uiRadius <= MAX_RADIUS);
|
||||
|
||||
ColorFloatRGBA frgbaQuantizedColor1 = a_frgbaColor1.QuantizeR4G4B4();
|
||||
ColorFloatRGBA frgbaQuantizedColor2 = a_frgbaColor2.QuantizeR4G4B4();
|
||||
|
||||
// quantize base colors
|
||||
// ensure that trys with a_uiRadius don't overflow
|
||||
int iRed1 = MoveAwayFromEdge(frgbaQuantizedColor1.IntRed(15.0f), a_uiRadius);
|
||||
int iGreen1 = MoveAwayFromEdge(frgbaQuantizedColor1.IntGreen(15.0f), a_uiRadius);
|
||||
int iBlue1 = MoveAwayFromEdge(frgbaQuantizedColor1.IntBlue(15.0f), a_uiRadius);
|
||||
int iRed2 = MoveAwayFromEdge(frgbaQuantizedColor2.IntRed(15.0f), a_uiRadius);
|
||||
int iGreen2 = MoveAwayFromEdge(frgbaQuantizedColor2.IntGreen(15.0f), a_uiRadius);
|
||||
int iBlue2 = MoveAwayFromEdge(frgbaQuantizedColor2.IntBlue(15.0f), a_uiRadius);
|
||||
|
||||
m_half1.Init(iRed1, iGreen1, iBlue1, a_pauiPixelMapping1, a_uiRadius);
|
||||
m_half2.Init(iRed2, iGreen2, iBlue2, a_pauiPixelMapping2, a_uiRadius);
|
||||
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------------------------------
|
||||
//
|
||||
void IndividualTrys::Half::Init(int a_iRed, int a_iGreen, int a_iBlue,
|
||||
const unsigned int *a_pauiPixelMapping, unsigned int a_uiRadius)
|
||||
{
|
||||
|
||||
m_iRed = a_iRed;
|
||||
m_iGreen = a_iGreen;
|
||||
m_iBlue = a_iBlue;
|
||||
|
||||
m_pauiPixelMapping = a_pauiPixelMapping;
|
||||
m_uiRadius = a_uiRadius;
|
||||
|
||||
m_uiTrys = 0;
|
||||
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------------------------------
|
||||
//
|
||||
|
||||
} // namespace Etc
|
95
extern/EtcLib/EtcCodec/EtcIndividualTrys.h
vendored
Normal file
95
extern/EtcLib/EtcCodec/EtcIndividualTrys.h
vendored
Normal file
@ -0,0 +1,95 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "EtcColorFloatRGBA.h"
|
||||
|
||||
namespace Etc
|
||||
{
|
||||
|
||||
class IndividualTrys
|
||||
{
|
||||
public:
|
||||
|
||||
static const unsigned int MAX_RADIUS = 1;
|
||||
|
||||
IndividualTrys(ColorFloatRGBA a_frgbaColor1,
|
||||
ColorFloatRGBA a_frgbaColor2,
|
||||
const unsigned int *a_pauiPixelMapping1,
|
||||
const unsigned int *a_pauiPixelMapping2,
|
||||
unsigned int a_uiRadius);
|
||||
|
||||
inline static int MoveAwayFromEdge(int a_i, int a_iDistance)
|
||||
{
|
||||
if (a_i < (0+ a_iDistance))
|
||||
{
|
||||
return (0 + a_iDistance);
|
||||
}
|
||||
else if (a_i > (15- a_iDistance))
|
||||
{
|
||||
return (15 - a_iDistance);
|
||||
}
|
||||
|
||||
return a_i;
|
||||
}
|
||||
|
||||
class Try
|
||||
{
|
||||
public :
|
||||
static const unsigned int SELECTORS = 8; // per half
|
||||
|
||||
int m_iRed;
|
||||
int m_iGreen;
|
||||
int m_iBlue;
|
||||
unsigned int m_uiCW;
|
||||
unsigned int m_auiSelectors[SELECTORS];
|
||||
float m_fError;
|
||||
};
|
||||
|
||||
class Half
|
||||
{
|
||||
public:
|
||||
|
||||
static const unsigned int MAX_TRYS = 27;
|
||||
|
||||
void Init(int a_iRed, int a_iGreen, int a_iBlue,
|
||||
const unsigned int *a_pauiPixelMapping,
|
||||
unsigned int a_uiRadius);
|
||||
|
||||
// center of trys
|
||||
int m_iRed;
|
||||
int m_iGreen;
|
||||
int m_iBlue;
|
||||
|
||||
const unsigned int *m_pauiPixelMapping;
|
||||
unsigned int m_uiRadius;
|
||||
|
||||
unsigned int m_uiTrys;
|
||||
Try m_atry[MAX_TRYS];
|
||||
|
||||
Try *m_ptryBest;
|
||||
};
|
||||
|
||||
Half m_half1;
|
||||
Half m_half2;
|
||||
|
||||
};
|
||||
|
||||
// ----------------------------------------------------------------------------------------------------
|
||||
//
|
||||
|
||||
} // namespace Etc
|
228
extern/EtcLib/EtcCodec/EtcSortedBlockList.cpp
vendored
Normal file
228
extern/EtcLib/EtcCodec/EtcSortedBlockList.cpp
vendored
Normal file
@ -0,0 +1,228 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
/*
|
||||
EtcSortedBlockList.cpp
|
||||
|
||||
SortedBlockList is a list of 4x4 blocks that can be used by the "effort" system to prioritize
|
||||
the encoding of the 4x4 blocks.
|
||||
|
||||
The sorting is done with buckets, where each bucket is an indication of how much error each 4x4 block has
|
||||
|
||||
*/
|
||||
|
||||
#include "EtcConfig.h"
|
||||
#include "EtcSortedBlockList.h"
|
||||
|
||||
#include "EtcBlock4x4.h"
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <assert.h>
|
||||
|
||||
namespace Etc
|
||||
{
|
||||
|
||||
// ----------------------------------------------------------------------------------------------------
|
||||
// construct an empty list
|
||||
//
|
||||
// allocate enough memory to add all of the image's 4x4 blocks later
|
||||
// allocate enough buckets to sort the blocks
|
||||
//
|
||||
SortedBlockList::SortedBlockList(unsigned int a_uiImageBlocks, unsigned int a_uiBuckets)
|
||||
{
|
||||
m_uiImageBlocks = a_uiImageBlocks;
|
||||
m_iBuckets = (int)a_uiBuckets;
|
||||
|
||||
m_uiAddedBlocks = 0;
|
||||
m_uiSortedBlocks = 0;
|
||||
m_palinkPool = new Link[m_uiImageBlocks];
|
||||
m_pabucket = new Bucket[m_iBuckets];
|
||||
m_fMaxError = 0.0f;
|
||||
|
||||
InitBuckets();
|
||||
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------------------------------
|
||||
//
|
||||
SortedBlockList::~SortedBlockList(void)
|
||||
{
|
||||
delete[] m_palinkPool;
|
||||
delete[] m_pabucket;
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------------------------------
|
||||
// add a 4x4 block to the list
|
||||
// the 4x4 block will be sorted later
|
||||
//
|
||||
void SortedBlockList::AddBlock(Block4x4 *a_pblock)
|
||||
{
|
||||
assert(m_uiAddedBlocks < m_uiImageBlocks);
|
||||
Link *plink = &m_palinkPool[m_uiAddedBlocks++];
|
||||
plink->Init(a_pblock);
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------------------------------
|
||||
// sort all of the 4x4 blocks that have been added to the list
|
||||
//
|
||||
// first, determine the maximum error, then assign an error range to each bucket
|
||||
// next, determine which bucket each 4x4 block belongs to based on the 4x4 block's error
|
||||
// add the 4x4 block to the appropriate bucket
|
||||
// lastly, walk thru the buckets and add each bucket to a sorted linked list
|
||||
//
|
||||
// the resultant sorting is an approximate sorting from most to least error
|
||||
//
|
||||
void SortedBlockList::Sort(void)
|
||||
{
|
||||
assert(m_uiAddedBlocks == m_uiImageBlocks);
|
||||
InitBuckets();
|
||||
|
||||
// find max block error
|
||||
m_fMaxError = -1.0f;
|
||||
|
||||
for (unsigned int uiLink = 0; uiLink < m_uiAddedBlocks; uiLink++)
|
||||
{
|
||||
Link *plinkBlock = &m_palinkPool[uiLink];
|
||||
|
||||
float fBlockError = plinkBlock->GetBlock()->GetError();
|
||||
if (fBlockError > m_fMaxError)
|
||||
{
|
||||
m_fMaxError = fBlockError;
|
||||
}
|
||||
}
|
||||
// prevent divide by zero or divide by negative
|
||||
if (m_fMaxError <= 0.0f)
|
||||
{
|
||||
m_fMaxError = 1.0f;
|
||||
}
|
||||
//used for debugging
|
||||
//int numDone = 0;
|
||||
// put all of the blocks with unfinished encodings into the appropriate bucket
|
||||
m_uiSortedBlocks = 0;
|
||||
for (unsigned int uiLink = 0; uiLink < m_uiAddedBlocks; uiLink++)
|
||||
{
|
||||
Link *plinkBlock = &m_palinkPool[uiLink];
|
||||
|
||||
// if the encoding is done, don't add it to the list
|
||||
if (plinkBlock->GetBlock()->GetEncoding()->IsDone())
|
||||
{
|
||||
//numDone++;
|
||||
continue;
|
||||
}
|
||||
|
||||
// calculate the appropriate sort bucket
|
||||
float fBlockError = plinkBlock->GetBlock()->GetError();
|
||||
int iBucket = (int) floorf(m_iBuckets * fBlockError / m_fMaxError);
|
||||
// clamp to bucket index
|
||||
iBucket = iBucket < 0 ? 0 : iBucket >= m_iBuckets ? m_iBuckets - 1 : iBucket;
|
||||
|
||||
// add block to bucket
|
||||
{
|
||||
Bucket *pbucket = &m_pabucket[iBucket];
|
||||
if (pbucket->plinkLast)
|
||||
{
|
||||
pbucket->plinkLast->SetNext(plinkBlock);
|
||||
pbucket->plinkLast = plinkBlock;
|
||||
}
|
||||
else
|
||||
{
|
||||
pbucket->plinkFirst = pbucket->plinkLast = plinkBlock;
|
||||
}
|
||||
plinkBlock->SetNext(nullptr);
|
||||
}
|
||||
|
||||
m_uiSortedBlocks++;
|
||||
|
||||
if (0)
|
||||
{
|
||||
printf("%u: e=%.3f\n", uiLink, fBlockError);
|
||||
Print();
|
||||
printf("\n\n\n");
|
||||
}
|
||||
}
|
||||
//printf("num blocks already done: %d\n",numDone);
|
||||
//link the blocks together across buckets
|
||||
m_plinkFirst = nullptr;
|
||||
m_plinkLast = nullptr;
|
||||
for (int iBucket = m_iBuckets - 1; iBucket >= 0; iBucket--)
|
||||
{
|
||||
Bucket *pbucket = &m_pabucket[iBucket];
|
||||
|
||||
if (pbucket->plinkFirst)
|
||||
{
|
||||
if (m_plinkFirst == nullptr)
|
||||
{
|
||||
m_plinkFirst = pbucket->plinkFirst;
|
||||
}
|
||||
else
|
||||
{
|
||||
assert(pbucket->plinkLast->GetNext() == nullptr);
|
||||
m_plinkLast->SetNext(pbucket->plinkFirst);
|
||||
}
|
||||
|
||||
m_plinkLast = pbucket->plinkLast;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------------------------------
|
||||
// clear all of the buckets. normally done in preparation for a sort
|
||||
//
|
||||
void SortedBlockList::InitBuckets(void)
|
||||
{
|
||||
for (int iBucket = 0; iBucket < m_iBuckets; iBucket++)
|
||||
{
|
||||
Bucket *pbucket = &m_pabucket[iBucket];
|
||||
|
||||
pbucket->plinkFirst = 0;
|
||||
pbucket->plinkLast = 0;
|
||||
}
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------------------------------
|
||||
// print out the list of sorted 4x4 blocks
|
||||
// normally used for debugging
|
||||
//
|
||||
void SortedBlockList::Print(void)
|
||||
{
|
||||
for (int iBucket = m_iBuckets-1; iBucket >= 0; iBucket--)
|
||||
{
|
||||
Bucket *pbucket = &m_pabucket[iBucket];
|
||||
|
||||
unsigned int uiBlocks = 0;
|
||||
for (Link *plink = pbucket->plinkFirst; plink != nullptr; plink = plink->GetNext() )
|
||||
{
|
||||
uiBlocks++;
|
||||
|
||||
if (plink == pbucket->plinkLast)
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
float fBucketError = m_fMaxError * iBucket / m_iBuckets;
|
||||
float fBucketRMS = sqrtf(fBucketError / (4.0f*16.0f) );
|
||||
printf("%3d: e=%.3f rms=%.6f %u\n", iBucket, fBucketError, fBucketRMS, uiBlocks);
|
||||
}
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------------------------------
|
||||
//
|
||||
|
||||
} // namespace Etc
|
124
extern/EtcLib/EtcCodec/EtcSortedBlockList.h
vendored
Normal file
124
extern/EtcLib/EtcCodec/EtcSortedBlockList.h
vendored
Normal file
@ -0,0 +1,124 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
namespace Etc
|
||||
{
|
||||
class Block4x4;
|
||||
|
||||
class SortedBlockList
|
||||
{
|
||||
public:
|
||||
|
||||
class Link
|
||||
{
|
||||
public:
|
||||
|
||||
inline void Init(Block4x4 *a_pblock)
|
||||
{
|
||||
m_pblock = a_pblock;
|
||||
m_plinkNext = nullptr;
|
||||
}
|
||||
|
||||
inline Block4x4 * GetBlock(void)
|
||||
{
|
||||
return m_pblock;
|
||||
}
|
||||
|
||||
inline void SetNext(Link *a_plinkNext)
|
||||
{
|
||||
m_plinkNext = a_plinkNext;
|
||||
}
|
||||
|
||||
inline Link * GetNext(void)
|
||||
{
|
||||
return m_plinkNext;
|
||||
}
|
||||
|
||||
inline Link * Advance(unsigned int a_uiSteps = 1)
|
||||
{
|
||||
Link *plink = this;
|
||||
|
||||
for (unsigned int uiStep = 0; uiStep < a_uiSteps; uiStep++)
|
||||
{
|
||||
if (plink == nullptr)
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
plink = plink->m_plinkNext;
|
||||
}
|
||||
|
||||
return plink;
|
||||
}
|
||||
|
||||
private:
|
||||
|
||||
Block4x4 *m_pblock;
|
||||
Link *m_plinkNext;
|
||||
};
|
||||
|
||||
SortedBlockList(unsigned int a_uiImageBlocks, unsigned int a_uiBuckets);
|
||||
~SortedBlockList(void);
|
||||
|
||||
void AddBlock(Block4x4 *a_pblock);
|
||||
|
||||
void Sort(void);
|
||||
|
||||
inline Link * GetLinkToFirstBlock(void)
|
||||
{
|
||||
return m_plinkFirst;
|
||||
}
|
||||
|
||||
inline unsigned int GetNumberOfAddedBlocks(void)
|
||||
{
|
||||
return m_uiAddedBlocks;
|
||||
}
|
||||
|
||||
inline unsigned int GetNumberOfSortedBlocks(void)
|
||||
{
|
||||
return m_uiSortedBlocks;
|
||||
}
|
||||
|
||||
void Print(void);
|
||||
|
||||
private:
|
||||
|
||||
void InitBuckets(void);
|
||||
|
||||
class Bucket
|
||||
{
|
||||
public:
|
||||
Link *plinkFirst;
|
||||
Link *plinkLast;
|
||||
};
|
||||
|
||||
unsigned int m_uiImageBlocks;
|
||||
int m_iBuckets;
|
||||
|
||||
unsigned int m_uiAddedBlocks;
|
||||
unsigned int m_uiSortedBlocks;
|
||||
Link *m_palinkPool;
|
||||
Bucket *m_pabucket;
|
||||
float m_fMaxError;
|
||||
|
||||
Link *m_plinkFirst;
|
||||
Link *m_plinkLast;
|
||||
|
||||
};
|
||||
|
||||
} // namespace Etc
|
Reference in New Issue
Block a user