Add some external dependencies.
This commit is contained in:
58
extern/EtcLib/Etc/Etc.cpp
vendored
Normal file
58
extern/EtcLib/Etc/Etc.cpp
vendored
Normal file
@ -0,0 +1,58 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#include "EtcConfig.h"
|
||||
#include "Etc.h"
|
||||
|
||||
#include <string.h>
|
||||
|
||||
namespace Etc
|
||||
{
|
||||
// ----------------------------------------------------------------------------------------------------
|
||||
// C-style inteface to the encoder
|
||||
//
|
||||
void Encode(float *a_pafSourceRGBA,
|
||||
unsigned int a_uiSourceWidth,
|
||||
unsigned int a_uiSourceHeight,
|
||||
Image::Format a_format,
|
||||
ErrorMetric a_eErrMetric,
|
||||
float a_fEffort,
|
||||
unsigned int a_uiJobs,
|
||||
unsigned int a_uiMaxJobs,
|
||||
unsigned char **a_ppaucEncodingBits,
|
||||
unsigned int *a_puiEncodingBitsBytes,
|
||||
unsigned int *a_puiExtendedWidth,
|
||||
unsigned int *a_puiExtendedHeight,
|
||||
int *a_piEncodingTime_ms, bool a_bVerboseOutput)
|
||||
{
|
||||
|
||||
Image image(a_pafSourceRGBA, a_uiSourceWidth,
|
||||
a_uiSourceHeight,
|
||||
a_eErrMetric);
|
||||
image.m_bVerboseOutput = a_bVerboseOutput;
|
||||
image.Encode(a_format, a_eErrMetric, a_fEffort, a_uiJobs, a_uiMaxJobs);
|
||||
|
||||
*a_ppaucEncodingBits = image.GetEncodingBits();
|
||||
*a_puiEncodingBitsBytes = image.GetEncodingBitsBytes();
|
||||
*a_puiExtendedWidth = image.GetExtendedWidth();
|
||||
*a_puiExtendedHeight = image.GetExtendedHeight();
|
||||
*a_piEncodingTime_ms = image.GetEncodingTimeMs();
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------------------------------
|
||||
//
|
||||
|
||||
}
|
47
extern/EtcLib/Etc/Etc.h
vendored
Normal file
47
extern/EtcLib/Etc/Etc.h
vendored
Normal file
@ -0,0 +1,47 @@
|
||||
/*
|
||||
* 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 "EtcConfig.h"
|
||||
#include "EtcImage.h"
|
||||
#include "EtcColor.h"
|
||||
#include "EtcErrorMetric.h"
|
||||
|
||||
#define ETCCOMP_MIN_EFFORT_LEVEL (0.0f)
|
||||
#define ETCCOMP_DEFAULT_EFFORT_LEVEL (40.0f)
|
||||
#define ETCCOMP_MAX_EFFORT_LEVEL (100.0f)
|
||||
|
||||
namespace Etc
|
||||
{
|
||||
class Block4x4EncodingBits;
|
||||
|
||||
// C-style inteface to the encoder
|
||||
void Encode(float *a_pafSourceRGBA,
|
||||
unsigned int a_uiSourceWidth,
|
||||
unsigned int a_uiSourceHeight,
|
||||
Image::Format a_format,
|
||||
ErrorMetric a_eErrMetric,
|
||||
float a_fEffort,
|
||||
unsigned int a_uiJobs,
|
||||
unsigned int a_uimaxJobs,
|
||||
unsigned char **a_ppaucEncodingBits,
|
||||
unsigned int *a_puiEncodingBitsBytes,
|
||||
unsigned int *a_puiExtendedWidth,
|
||||
unsigned int *a_puiExtendedHeight,
|
||||
int *a_piEncodingTime_ms, bool a_bVerboseOutput = false);
|
||||
|
||||
}
|
64
extern/EtcLib/Etc/EtcColor.h
vendored
Normal file
64
extern/EtcLib/Etc/EtcColor.h
vendored
Normal file
@ -0,0 +1,64 @@
|
||||
/*
|
||||
* 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 <math.h>
|
||||
|
||||
namespace Etc
|
||||
{
|
||||
|
||||
inline float LogToLinear(float a_fLog)
|
||||
{
|
||||
static const float ALPHA = 0.055f;
|
||||
static const float ONE_PLUS_ALPHA = 1.0f + ALPHA;
|
||||
|
||||
if (a_fLog <= 0.04045f)
|
||||
{
|
||||
return a_fLog / 12.92f;
|
||||
}
|
||||
else
|
||||
{
|
||||
return powf((a_fLog + ALPHA) / ONE_PLUS_ALPHA, 2.4f);
|
||||
}
|
||||
}
|
||||
|
||||
inline float LinearToLog(float &a_fLinear)
|
||||
{
|
||||
static const float ALPHA = 0.055f;
|
||||
static const float ONE_PLUS_ALPHA = 1.0f + ALPHA;
|
||||
|
||||
if (a_fLinear <= 0.0031308f)
|
||||
{
|
||||
return 12.92f * a_fLinear;
|
||||
}
|
||||
else
|
||||
{
|
||||
return ONE_PLUS_ALPHA * powf(a_fLinear, (1.0f/2.4f)) - ALPHA;
|
||||
}
|
||||
}
|
||||
|
||||
class ColorR8G8B8A8
|
||||
{
|
||||
public:
|
||||
|
||||
unsigned char ucR;
|
||||
unsigned char ucG;
|
||||
unsigned char ucB;
|
||||
unsigned char ucA;
|
||||
|
||||
};
|
||||
}
|
321
extern/EtcLib/Etc/EtcColorFloatRGBA.h
vendored
Normal file
321
extern/EtcLib/Etc/EtcColorFloatRGBA.h
vendored
Normal file
@ -0,0 +1,321 @@
|
||||
/*
|
||||
* 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 "EtcConfig.h"
|
||||
#include "EtcColor.h"
|
||||
|
||||
#include <math.h>
|
||||
|
||||
namespace Etc
|
||||
{
|
||||
|
||||
class ColorFloatRGBA
|
||||
{
|
||||
public:
|
||||
|
||||
ColorFloatRGBA(void)
|
||||
{
|
||||
fR = fG = fB = fA = 0.0f;
|
||||
}
|
||||
|
||||
ColorFloatRGBA(float a_fR, float a_fG, float a_fB, float a_fA)
|
||||
{
|
||||
fR = a_fR;
|
||||
fG = a_fG;
|
||||
fB = a_fB;
|
||||
fA = a_fA;
|
||||
}
|
||||
|
||||
inline ColorFloatRGBA operator+(ColorFloatRGBA& a_rfrgba)
|
||||
{
|
||||
ColorFloatRGBA frgba;
|
||||
frgba.fR = fR + a_rfrgba.fR;
|
||||
frgba.fG = fG + a_rfrgba.fG;
|
||||
frgba.fB = fB + a_rfrgba.fB;
|
||||
frgba.fA = fA + a_rfrgba.fA;
|
||||
return frgba;
|
||||
}
|
||||
|
||||
inline ColorFloatRGBA operator+(float a_f)
|
||||
{
|
||||
ColorFloatRGBA frgba;
|
||||
frgba.fR = fR + a_f;
|
||||
frgba.fG = fG + a_f;
|
||||
frgba.fB = fB + a_f;
|
||||
frgba.fA = fA;
|
||||
return frgba;
|
||||
}
|
||||
|
||||
inline ColorFloatRGBA operator-(float a_f)
|
||||
{
|
||||
ColorFloatRGBA frgba;
|
||||
frgba.fR = fR - a_f;
|
||||
frgba.fG = fG - a_f;
|
||||
frgba.fB = fB - a_f;
|
||||
frgba.fA = fA;
|
||||
return frgba;
|
||||
}
|
||||
|
||||
inline ColorFloatRGBA operator-(ColorFloatRGBA& a_rfrgba)
|
||||
{
|
||||
ColorFloatRGBA frgba;
|
||||
frgba.fR = fR - a_rfrgba.fR;
|
||||
frgba.fG = fG - a_rfrgba.fG;
|
||||
frgba.fB = fB - a_rfrgba.fB;
|
||||
frgba.fA = fA - a_rfrgba.fA;
|
||||
return frgba;
|
||||
}
|
||||
|
||||
inline ColorFloatRGBA operator*(float a_f)
|
||||
{
|
||||
ColorFloatRGBA frgba;
|
||||
frgba.fR = fR * a_f;
|
||||
frgba.fG = fG * a_f;
|
||||
frgba.fB = fB * a_f;
|
||||
frgba.fA = fA;
|
||||
|
||||
return frgba;
|
||||
}
|
||||
|
||||
inline ColorFloatRGBA ScaleRGB(float a_f)
|
||||
{
|
||||
ColorFloatRGBA frgba;
|
||||
frgba.fR = a_f * fR;
|
||||
frgba.fG = a_f * fG;
|
||||
frgba.fB = a_f * fB;
|
||||
frgba.fA = fA;
|
||||
|
||||
return frgba;
|
||||
}
|
||||
|
||||
inline ColorFloatRGBA RoundRGB(void)
|
||||
{
|
||||
ColorFloatRGBA frgba;
|
||||
frgba.fR = roundf(fR);
|
||||
frgba.fG = roundf(fG);
|
||||
frgba.fB = roundf(fB);
|
||||
|
||||
return frgba;
|
||||
}
|
||||
|
||||
inline ColorFloatRGBA ToLinear()
|
||||
{
|
||||
ColorFloatRGBA frgbaLinear;
|
||||
frgbaLinear.fR = LogToLinear(fR);
|
||||
frgbaLinear.fG = LogToLinear(fG);
|
||||
frgbaLinear.fB = LogToLinear(fB);
|
||||
frgbaLinear.fA = fA;
|
||||
|
||||
return frgbaLinear;
|
||||
}
|
||||
|
||||
inline ColorFloatRGBA ToLog(void)
|
||||
{
|
||||
ColorFloatRGBA frgbaLog;
|
||||
frgbaLog.fR = LinearToLog(fR);
|
||||
frgbaLog.fG = LinearToLog(fG);
|
||||
frgbaLog.fB = LinearToLog(fB);
|
||||
frgbaLog.fA = fA;
|
||||
|
||||
return frgbaLog;
|
||||
}
|
||||
|
||||
inline static ColorFloatRGBA ConvertFromRGBA8(unsigned char a_ucR,
|
||||
unsigned char a_ucG, unsigned char a_ucB, unsigned char a_ucA)
|
||||
{
|
||||
ColorFloatRGBA frgba;
|
||||
|
||||
frgba.fR = (float)a_ucR / 255.0f;
|
||||
frgba.fG = (float)a_ucG / 255.0f;
|
||||
frgba.fB = (float)a_ucB / 255.0f;
|
||||
frgba.fA = (float)a_ucA / 255.0f;
|
||||
|
||||
return frgba;
|
||||
}
|
||||
|
||||
inline static ColorFloatRGBA ConvertFromRGB4(unsigned char a_ucR4,
|
||||
unsigned char a_ucG4,
|
||||
unsigned char a_ucB4)
|
||||
{
|
||||
ColorFloatRGBA frgba;
|
||||
|
||||
unsigned char ucR8 = (unsigned char)((a_ucR4 << 4) + a_ucR4);
|
||||
unsigned char ucG8 = (unsigned char)((a_ucG4 << 4) + a_ucG4);
|
||||
unsigned char ucB8 = (unsigned char)((a_ucB4 << 4) + a_ucB4);
|
||||
|
||||
frgba.fR = (float)ucR8 / 255.0f;
|
||||
frgba.fG = (float)ucG8 / 255.0f;
|
||||
frgba.fB = (float)ucB8 / 255.0f;
|
||||
frgba.fA = 1.0f;
|
||||
|
||||
return frgba;
|
||||
}
|
||||
|
||||
inline static ColorFloatRGBA ConvertFromRGB5(unsigned char a_ucR5,
|
||||
unsigned char a_ucG5,
|
||||
unsigned char a_ucB5)
|
||||
{
|
||||
ColorFloatRGBA frgba;
|
||||
|
||||
unsigned char ucR8 = (unsigned char)((a_ucR5 << 3) + (a_ucR5 >> 2));
|
||||
unsigned char ucG8 = (unsigned char)((a_ucG5 << 3) + (a_ucG5 >> 2));
|
||||
unsigned char ucB8 = (unsigned char)((a_ucB5 << 3) + (a_ucB5 >> 2));
|
||||
|
||||
frgba.fR = (float)ucR8 / 255.0f;
|
||||
frgba.fG = (float)ucG8 / 255.0f;
|
||||
frgba.fB = (float)ucB8 / 255.0f;
|
||||
frgba.fA = 1.0f;
|
||||
|
||||
return frgba;
|
||||
}
|
||||
|
||||
inline static ColorFloatRGBA ConvertFromR6G7B6(unsigned char a_ucR6,
|
||||
unsigned char a_ucG7,
|
||||
unsigned char a_ucB6)
|
||||
{
|
||||
ColorFloatRGBA frgba;
|
||||
|
||||
unsigned char ucR8 = (unsigned char)((a_ucR6 << 2) + (a_ucR6 >> 4));
|
||||
unsigned char ucG8 = (unsigned char)((a_ucG7 << 1) + (a_ucG7 >> 6));
|
||||
unsigned char ucB8 = (unsigned char)((a_ucB6 << 2) + (a_ucB6 >> 4));
|
||||
|
||||
frgba.fR = (float)ucR8 / 255.0f;
|
||||
frgba.fG = (float)ucG8 / 255.0f;
|
||||
frgba.fB = (float)ucB8 / 255.0f;
|
||||
frgba.fA = 1.0f;
|
||||
|
||||
return frgba;
|
||||
}
|
||||
|
||||
// quantize to 4 bits, expand to 8 bits
|
||||
inline ColorFloatRGBA QuantizeR4G4B4(void) const
|
||||
{
|
||||
ColorFloatRGBA frgba = *this;
|
||||
|
||||
// quantize to 4 bits
|
||||
frgba = frgba.ClampRGB().ScaleRGB(15.0f).RoundRGB();
|
||||
unsigned int uiR4 = (unsigned int)frgba.fR;
|
||||
unsigned int uiG4 = (unsigned int)frgba.fG;
|
||||
unsigned int uiB4 = (unsigned int)frgba.fB;
|
||||
|
||||
// expand to 8 bits
|
||||
frgba.fR = (float) ((uiR4 << 4) + uiR4);
|
||||
frgba.fG = (float) ((uiG4 << 4) + uiG4);
|
||||
frgba.fB = (float) ((uiB4 << 4) + uiB4);
|
||||
|
||||
frgba = frgba.ScaleRGB(1.0f/255.0f);
|
||||
|
||||
return frgba;
|
||||
}
|
||||
|
||||
// quantize to 5 bits, expand to 8 bits
|
||||
inline ColorFloatRGBA QuantizeR5G5B5(void) const
|
||||
{
|
||||
ColorFloatRGBA frgba = *this;
|
||||
|
||||
// quantize to 5 bits
|
||||
frgba = frgba.ClampRGB().ScaleRGB(31.0f).RoundRGB();
|
||||
unsigned int uiR5 = (unsigned int)frgba.fR;
|
||||
unsigned int uiG5 = (unsigned int)frgba.fG;
|
||||
unsigned int uiB5 = (unsigned int)frgba.fB;
|
||||
|
||||
// expand to 8 bits
|
||||
frgba.fR = (float)((uiR5 << 3) + (uiR5 >> 2));
|
||||
frgba.fG = (float)((uiG5 << 3) + (uiG5 >> 2));
|
||||
frgba.fB = (float)((uiB5 << 3) + (uiB5 >> 2));
|
||||
|
||||
frgba = frgba.ScaleRGB(1.0f / 255.0f);
|
||||
|
||||
return frgba;
|
||||
}
|
||||
|
||||
// quantize to 6/7/6 bits, expand to 8 bits
|
||||
inline ColorFloatRGBA QuantizeR6G7B6(void) const
|
||||
{
|
||||
ColorFloatRGBA frgba = *this;
|
||||
|
||||
// quantize to 6/7/6 bits
|
||||
ColorFloatRGBA frgba6 = frgba.ClampRGB().ScaleRGB(63.0f).RoundRGB();
|
||||
ColorFloatRGBA frgba7 = frgba.ClampRGB().ScaleRGB(127.0f).RoundRGB();
|
||||
unsigned int uiR6 = (unsigned int)frgba6.fR;
|
||||
unsigned int uiG7 = (unsigned int)frgba7.fG;
|
||||
unsigned int uiB6 = (unsigned int)frgba6.fB;
|
||||
|
||||
// expand to 8 bits
|
||||
frgba.fR = (float)((uiR6 << 2) + (uiR6 >> 4));
|
||||
frgba.fG = (float)((uiG7 << 1) + (uiG7 >> 6));
|
||||
frgba.fB = (float)((uiB6 << 2) + (uiB6 >> 4));
|
||||
|
||||
frgba = frgba.ScaleRGB(1.0f / 255.0f);
|
||||
|
||||
return frgba;
|
||||
}
|
||||
|
||||
inline ColorFloatRGBA ClampRGB(void)
|
||||
{
|
||||
ColorFloatRGBA frgba = *this;
|
||||
if (frgba.fR < 0.0f) { frgba.fR = 0.0f; }
|
||||
if (frgba.fR > 1.0f) { frgba.fR = 1.0f; }
|
||||
if (frgba.fG < 0.0f) { frgba.fG = 0.0f; }
|
||||
if (frgba.fG > 1.0f) { frgba.fG = 1.0f; }
|
||||
if (frgba.fB < 0.0f) { frgba.fB = 0.0f; }
|
||||
if (frgba.fB > 1.0f) { frgba.fB = 1.0f; }
|
||||
|
||||
return frgba;
|
||||
}
|
||||
|
||||
inline ColorFloatRGBA ClampRGBA(void)
|
||||
{
|
||||
ColorFloatRGBA frgba = *this;
|
||||
if (frgba.fR < 0.0f) { frgba.fR = 0.0f; }
|
||||
if (frgba.fR > 1.0f) { frgba.fR = 1.0f; }
|
||||
if (frgba.fG < 0.0f) { frgba.fG = 0.0f; }
|
||||
if (frgba.fG > 1.0f) { frgba.fG = 1.0f; }
|
||||
if (frgba.fB < 0.0f) { frgba.fB = 0.0f; }
|
||||
if (frgba.fB > 1.0f) { frgba.fB = 1.0f; }
|
||||
if (frgba.fA < 0.0f) { frgba.fA = 0.0f; }
|
||||
if (frgba.fA > 1.0f) { frgba.fA = 1.0f; }
|
||||
|
||||
return frgba;
|
||||
}
|
||||
|
||||
inline int IntRed(float a_fScale)
|
||||
{
|
||||
return (int)roundf(fR * a_fScale);
|
||||
}
|
||||
|
||||
inline int IntGreen(float a_fScale)
|
||||
{
|
||||
return (int)roundf(fG * a_fScale);
|
||||
}
|
||||
|
||||
inline int IntBlue(float a_fScale)
|
||||
{
|
||||
return (int)roundf(fB * a_fScale);
|
||||
}
|
||||
|
||||
inline int IntAlpha(float a_fScale)
|
||||
{
|
||||
return (int)roundf(fA * a_fScale);
|
||||
}
|
||||
|
||||
float fR, fG, fB, fA;
|
||||
};
|
||||
|
||||
}
|
||||
|
67
extern/EtcLib/Etc/EtcConfig.h
vendored
Normal file
67
extern/EtcLib/Etc/EtcConfig.h
vendored
Normal file
@ -0,0 +1,67 @@
|
||||
/*
|
||||
* 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
|
||||
|
||||
#ifdef _WIN32
|
||||
#define ETC_WINDOWS (1)
|
||||
#else
|
||||
#define ETC_WINDOWS (0)
|
||||
#endif
|
||||
|
||||
#if __APPLE__
|
||||
#define ETC_OSX (1)
|
||||
#else
|
||||
#define ETC_OSX (0)
|
||||
#endif
|
||||
|
||||
#if __unix__
|
||||
#define ETC_UNIX (1)
|
||||
#else
|
||||
#define ETC_UNIX (0)
|
||||
#endif
|
||||
|
||||
|
||||
// short names for common types
|
||||
#include <stdint.h>
|
||||
typedef int8_t i8;
|
||||
typedef int16_t i16;
|
||||
typedef int32_t i32;
|
||||
typedef int64_t i64;
|
||||
|
||||
typedef uint8_t u8;
|
||||
typedef uint16_t u16;
|
||||
typedef uint32_t u32;
|
||||
typedef uint64_t u64;
|
||||
|
||||
typedef float f32;
|
||||
typedef double f64;
|
||||
|
||||
// Keep asserts enabled in release builds during development
|
||||
#undef NDEBUG
|
||||
|
||||
// 0=disable. stb_image can be used if you need to compress
|
||||
//other image formats like jpg
|
||||
#define USE_STB_IMAGE_LOAD 0
|
||||
|
||||
#if ETC_WINDOWS
|
||||
#include <SDKDDKVer.h>
|
||||
#define _CRT_SECURE_NO_WARNINGS (1)
|
||||
#include <tchar.h>
|
||||
#endif
|
||||
|
||||
#include <stdio.h>
|
||||
|
685
extern/EtcLib/Etc/EtcImage.cpp
vendored
Normal file
685
extern/EtcLib/Etc/EtcImage.cpp
vendored
Normal file
@ -0,0 +1,685 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
/*
|
||||
EtcImage.cpp
|
||||
|
||||
Image is an array of 4x4 blocks that represent the encoding of the source image
|
||||
|
||||
*/
|
||||
|
||||
#include "EtcConfig.h"
|
||||
|
||||
#include <stdlib.h>
|
||||
|
||||
#include "EtcImage.h"
|
||||
|
||||
#include "Etc.h"
|
||||
#include "EtcBlock4x4.h"
|
||||
#include "EtcBlock4x4EncodingBits.h"
|
||||
#include "EtcSortedBlockList.h"
|
||||
|
||||
#if ETC_WINDOWS
|
||||
#include <windows.h>
|
||||
#endif
|
||||
#include <ctime>
|
||||
#include <chrono>
|
||||
#include <future>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <assert.h>
|
||||
|
||||
// fix conflict with Block4x4::AlphaMix
|
||||
#ifdef OPAQUE
|
||||
#undef OPAQUE
|
||||
#endif
|
||||
#ifdef TRANSPARENT
|
||||
#undef TRANSPARENT
|
||||
#endif
|
||||
|
||||
namespace Etc
|
||||
{
|
||||
|
||||
// ----------------------------------------------------------------------------------------------------
|
||||
//
|
||||
Image::Image(void)
|
||||
{
|
||||
m_encodingStatus = EncodingStatus::SUCCESS;
|
||||
m_warningsToCapture = EncodingStatus::SUCCESS;
|
||||
m_pafrgbaSource = nullptr;
|
||||
|
||||
m_pablock = nullptr;
|
||||
|
||||
m_encodingbitsformat = Block4x4EncodingBits::Format::UNKNOWN;
|
||||
m_uiEncodingBitsBytes = 0;
|
||||
m_paucEncodingBits = nullptr;
|
||||
|
||||
m_format = Format::UNKNOWN;
|
||||
m_iNumOpaquePixels = 0;
|
||||
m_iNumTranslucentPixels = 0;
|
||||
m_iNumTransparentPixels = 0;
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------------------------------
|
||||
// constructor using source image
|
||||
// used to set state before Encode() is called
|
||||
//
|
||||
Image::Image(float *a_pafSourceRGBA, unsigned int a_uiSourceWidth,
|
||||
unsigned int a_uiSourceHeight,
|
||||
ErrorMetric a_errormetric)
|
||||
{
|
||||
m_encodingStatus = EncodingStatus::SUCCESS;
|
||||
m_warningsToCapture = EncodingStatus::SUCCESS;
|
||||
m_pafrgbaSource = (ColorFloatRGBA *) a_pafSourceRGBA;
|
||||
m_uiSourceWidth = a_uiSourceWidth;
|
||||
m_uiSourceHeight = a_uiSourceHeight;
|
||||
|
||||
m_uiExtendedWidth = CalcExtendedDimension((unsigned short)m_uiSourceWidth);
|
||||
m_uiExtendedHeight = CalcExtendedDimension((unsigned short)m_uiSourceHeight);
|
||||
|
||||
m_uiBlockColumns = m_uiExtendedWidth >> 2;
|
||||
m_uiBlockRows = m_uiExtendedHeight >> 2;
|
||||
|
||||
m_pablock = new Block4x4[GetNumberOfBlocks()];
|
||||
assert(m_pablock);
|
||||
|
||||
m_format = Format::UNKNOWN;
|
||||
|
||||
m_encodingbitsformat = Block4x4EncodingBits::Format::UNKNOWN;
|
||||
m_uiEncodingBitsBytes = 0;
|
||||
m_paucEncodingBits = nullptr;
|
||||
|
||||
m_errormetric = a_errormetric;
|
||||
m_fEffort = 0.0f;
|
||||
|
||||
m_iEncodeTime_ms = -1;
|
||||
|
||||
m_iNumOpaquePixels = 0;
|
||||
m_iNumTranslucentPixels = 0;
|
||||
m_iNumTransparentPixels = 0;
|
||||
m_bVerboseOutput = false;
|
||||
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------------------------------
|
||||
// constructor using encoding bits
|
||||
// recreates encoding state using a previously encoded image
|
||||
//
|
||||
Image::Image(Format a_format,
|
||||
unsigned int a_uiSourceWidth, unsigned int a_uiSourceHeight,
|
||||
unsigned char *a_paucEncidingBits, unsigned int a_uiEncodingBitsBytes,
|
||||
Image *a_pimageSource, ErrorMetric a_errormetric)
|
||||
{
|
||||
m_encodingStatus = EncodingStatus::SUCCESS;
|
||||
m_pafrgbaSource = nullptr;
|
||||
m_uiSourceWidth = a_uiSourceWidth;
|
||||
m_uiSourceHeight = a_uiSourceHeight;
|
||||
|
||||
m_uiExtendedWidth = CalcExtendedDimension((unsigned short)m_uiSourceWidth);
|
||||
m_uiExtendedHeight = CalcExtendedDimension((unsigned short)m_uiSourceHeight);
|
||||
|
||||
m_uiBlockColumns = m_uiExtendedWidth >> 2;
|
||||
m_uiBlockRows = m_uiExtendedHeight >> 2;
|
||||
|
||||
unsigned int uiBlocks = GetNumberOfBlocks();
|
||||
|
||||
m_pablock = new Block4x4[uiBlocks];
|
||||
assert(m_pablock);
|
||||
|
||||
m_format = a_format;
|
||||
|
||||
m_iNumOpaquePixels = 0;
|
||||
m_iNumTranslucentPixels = 0;
|
||||
m_iNumTransparentPixels = 0;
|
||||
|
||||
m_encodingbitsformat = DetermineEncodingBitsFormat(m_format);
|
||||
if (m_encodingbitsformat == Block4x4EncodingBits::Format::UNKNOWN)
|
||||
{
|
||||
AddToEncodingStatus(ERROR_UNKNOWN_FORMAT);
|
||||
return;
|
||||
}
|
||||
m_uiEncodingBitsBytes = a_uiEncodingBitsBytes;
|
||||
m_paucEncodingBits = a_paucEncidingBits;
|
||||
|
||||
m_errormetric = a_errormetric;
|
||||
m_fEffort = 0.0f;
|
||||
m_bVerboseOutput = false;
|
||||
m_iEncodeTime_ms = -1;
|
||||
|
||||
unsigned char *paucEncodingBits = m_paucEncodingBits;
|
||||
unsigned int uiEncodingBitsBytesPerBlock = Block4x4EncodingBits::GetBytesPerBlock(m_encodingbitsformat);
|
||||
|
||||
unsigned int uiH = 0;
|
||||
unsigned int uiV = 0;
|
||||
for (unsigned int uiBlock = 0; uiBlock < uiBlocks; uiBlock++)
|
||||
{
|
||||
m_pablock[uiBlock].InitFromEtcEncodingBits(a_format, uiH, uiV, paucEncodingBits,
|
||||
a_pimageSource, a_errormetric);
|
||||
paucEncodingBits += uiEncodingBitsBytesPerBlock;
|
||||
uiH += 4;
|
||||
if (uiH >= m_uiSourceWidth)
|
||||
{
|
||||
uiH = 0;
|
||||
uiV += 4;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------------------------------
|
||||
//
|
||||
Image::~Image(void)
|
||||
{
|
||||
if (m_pablock != nullptr)
|
||||
{
|
||||
delete[] m_pablock;
|
||||
m_pablock = nullptr;
|
||||
}
|
||||
|
||||
/*if (m_paucEncodingBits != nullptr)
|
||||
{
|
||||
delete[] m_paucEncodingBits;
|
||||
m_paucEncodingBits = nullptr;
|
||||
}*/
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------------------------------
|
||||
// encode an image
|
||||
// create a set of encoding bits that conforms to a_format
|
||||
// find best fit using a_errormetric
|
||||
// explore a range of possible encodings based on a_fEffort (range = [0:100])
|
||||
// speed up process using a_uiJobs as the number of process threads (a_uiJobs must not excede a_uiMaxJobs)
|
||||
//
|
||||
Image::EncodingStatus Image::Encode(Format a_format, ErrorMetric a_errormetric, float a_fEffort, unsigned int a_uiJobs, unsigned int a_uiMaxJobs)
|
||||
{
|
||||
|
||||
auto start = std::chrono::steady_clock::now();
|
||||
|
||||
m_encodingStatus = EncodingStatus::SUCCESS;
|
||||
|
||||
m_format = a_format;
|
||||
m_errormetric = a_errormetric;
|
||||
m_fEffort = a_fEffort;
|
||||
|
||||
if (m_errormetric < 0 || m_errormetric > ERROR_METRICS)
|
||||
{
|
||||
AddToEncodingStatus(ERROR_UNKNOWN_ERROR_METRIC);
|
||||
return m_encodingStatus;
|
||||
}
|
||||
|
||||
if (m_fEffort < ETCCOMP_MIN_EFFORT_LEVEL)
|
||||
{
|
||||
AddToEncodingStatus(WARNING_EFFORT_OUT_OF_RANGE);
|
||||
m_fEffort = ETCCOMP_MIN_EFFORT_LEVEL;
|
||||
}
|
||||
else if (m_fEffort > ETCCOMP_MAX_EFFORT_LEVEL)
|
||||
{
|
||||
AddToEncodingStatus(WARNING_EFFORT_OUT_OF_RANGE);
|
||||
m_fEffort = ETCCOMP_MAX_EFFORT_LEVEL;
|
||||
}
|
||||
if (a_uiJobs < 1)
|
||||
{
|
||||
a_uiJobs = 1;
|
||||
AddToEncodingStatus(WARNING_JOBS_OUT_OF_RANGE);
|
||||
}
|
||||
else if (a_uiJobs > a_uiMaxJobs)
|
||||
{
|
||||
a_uiJobs = a_uiMaxJobs;
|
||||
AddToEncodingStatus(WARNING_JOBS_OUT_OF_RANGE);
|
||||
}
|
||||
|
||||
m_encodingbitsformat = DetermineEncodingBitsFormat(m_format);
|
||||
|
||||
if (m_encodingbitsformat == Block4x4EncodingBits::Format::UNKNOWN)
|
||||
{
|
||||
AddToEncodingStatus(ERROR_UNKNOWN_FORMAT);
|
||||
return m_encodingStatus;
|
||||
}
|
||||
|
||||
assert(m_paucEncodingBits == nullptr);
|
||||
m_uiEncodingBitsBytes = GetNumberOfBlocks() * Block4x4EncodingBits::GetBytesPerBlock(m_encodingbitsformat);
|
||||
m_paucEncodingBits = new unsigned char[m_uiEncodingBitsBytes];
|
||||
|
||||
InitBlocksAndBlockSorter();
|
||||
|
||||
|
||||
std::future<void> *handle = new std::future<void>[a_uiMaxJobs];
|
||||
|
||||
unsigned int uiNumThreadsNeeded = 0;
|
||||
unsigned int uiUnfinishedBlocks = GetNumberOfBlocks();
|
||||
|
||||
uiNumThreadsNeeded = (uiUnfinishedBlocks < a_uiJobs) ? uiUnfinishedBlocks : a_uiJobs;
|
||||
|
||||
for (int i = 0; i < (int)uiNumThreadsNeeded - 1; i++)
|
||||
{
|
||||
handle[i] = async(std::launch::async, &Image::RunFirstPass, this, i, uiNumThreadsNeeded);
|
||||
}
|
||||
|
||||
RunFirstPass(uiNumThreadsNeeded - 1, uiNumThreadsNeeded);
|
||||
|
||||
for (int i = 0; i < (int)uiNumThreadsNeeded - 1; i++)
|
||||
{
|
||||
handle[i].get();
|
||||
}
|
||||
|
||||
// perform effort-based encoding
|
||||
if (m_fEffort > ETCCOMP_MIN_EFFORT_LEVEL)
|
||||
{
|
||||
unsigned int uiFinishedBlocks = 0;
|
||||
unsigned int uiTotalEffortBlocks = static_cast<unsigned int>(roundf(0.01f * m_fEffort * GetNumberOfBlocks()));
|
||||
|
||||
if (m_bVerboseOutput)
|
||||
{
|
||||
printf("effortblocks = %d\n", uiTotalEffortBlocks);
|
||||
}
|
||||
unsigned int uiPass = 0;
|
||||
while (1)
|
||||
{
|
||||
if (m_bVerboseOutput)
|
||||
{
|
||||
uiPass++;
|
||||
printf("pass %u\n", uiPass);
|
||||
}
|
||||
m_psortedblocklist->Sort();
|
||||
uiUnfinishedBlocks = m_psortedblocklist->GetNumberOfSortedBlocks();
|
||||
uiFinishedBlocks = GetNumberOfBlocks() - uiUnfinishedBlocks;
|
||||
if (m_bVerboseOutput)
|
||||
{
|
||||
printf(" %u unfinished blocks\n", uiUnfinishedBlocks);
|
||||
// m_psortedblocklist->Print();
|
||||
}
|
||||
|
||||
|
||||
|
||||
//stop enocding when we did enough to satify the effort percentage
|
||||
if (uiFinishedBlocks >= uiTotalEffortBlocks)
|
||||
{
|
||||
if (m_bVerboseOutput)
|
||||
{
|
||||
printf("Finished %d Blocks out of %d\n", uiFinishedBlocks, uiTotalEffortBlocks);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
unsigned int uiIteratedBlocks = 0;
|
||||
unsigned int blocksToIterateThisPass = (uiTotalEffortBlocks - uiFinishedBlocks);
|
||||
uiNumThreadsNeeded = (uiUnfinishedBlocks < a_uiJobs) ? uiUnfinishedBlocks : a_uiJobs;
|
||||
|
||||
if (uiNumThreadsNeeded <= 1)
|
||||
{
|
||||
//since we already how many blocks each thread will process
|
||||
//cap the thread limit to do the proper amount of work, and not more
|
||||
uiIteratedBlocks = IterateThroughWorstBlocks(blocksToIterateThisPass, 0, 1);
|
||||
}
|
||||
else
|
||||
{
|
||||
//we have a lot of work to do, so lets multi thread it
|
||||
std::future<unsigned int> *handleToBlockEncoders = new std::future<unsigned int>[uiNumThreadsNeeded-1];
|
||||
|
||||
for (int i = 0; i < (int)uiNumThreadsNeeded - 1; i++)
|
||||
{
|
||||
handleToBlockEncoders[i] = async(std::launch::async, &Image::IterateThroughWorstBlocks, this, blocksToIterateThisPass, i, uiNumThreadsNeeded);
|
||||
}
|
||||
uiIteratedBlocks = IterateThroughWorstBlocks(blocksToIterateThisPass, uiNumThreadsNeeded - 1, uiNumThreadsNeeded);
|
||||
|
||||
for (int i = 0; i < (int)uiNumThreadsNeeded - 1; i++)
|
||||
{
|
||||
uiIteratedBlocks += handleToBlockEncoders[i].get();
|
||||
}
|
||||
|
||||
delete[] handleToBlockEncoders;
|
||||
}
|
||||
|
||||
if (m_bVerboseOutput)
|
||||
{
|
||||
printf(" %u iterated blocks\n", uiIteratedBlocks);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// generate Etc2-compatible bit-format 4x4 blocks
|
||||
for (int i = 0; i < (int)a_uiJobs - 1; i++)
|
||||
{
|
||||
handle[i] = async(std::launch::async, &Image::SetEncodingBits, this, i, a_uiJobs);
|
||||
}
|
||||
SetEncodingBits(a_uiJobs - 1, a_uiJobs);
|
||||
|
||||
for (int i = 0; i < (int)a_uiJobs - 1; i++)
|
||||
{
|
||||
handle[i].get();
|
||||
}
|
||||
|
||||
auto end = std::chrono::steady_clock::now();
|
||||
std::chrono::milliseconds elapsed = std::chrono::duration_cast<std::chrono::milliseconds>(end - start);
|
||||
m_iEncodeTime_ms = (int)elapsed.count();
|
||||
|
||||
delete[] handle;
|
||||
delete m_psortedblocklist;
|
||||
return m_encodingStatus;
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------------------------------
|
||||
// iterate the encoding thru the blocks with the worst error
|
||||
// stop when a_uiMaxBlocks blocks have been iterated
|
||||
// split the blocks between the process threads using a_uiMultithreadingOffset and a_uiMultithreadingStride
|
||||
//
|
||||
unsigned int Image::IterateThroughWorstBlocks(unsigned int a_uiMaxBlocks,
|
||||
unsigned int a_uiMultithreadingOffset,
|
||||
unsigned int a_uiMultithreadingStride)
|
||||
{
|
||||
assert(a_uiMultithreadingStride > 0);
|
||||
unsigned int uiIteratedBlocks = a_uiMultithreadingOffset;
|
||||
|
||||
SortedBlockList::Link *plink = m_psortedblocklist->GetLinkToFirstBlock();
|
||||
for (plink = plink->Advance(a_uiMultithreadingOffset);
|
||||
plink != nullptr;
|
||||
plink = plink->Advance(a_uiMultithreadingStride) )
|
||||
{
|
||||
if (uiIteratedBlocks >= a_uiMaxBlocks)
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
plink->GetBlock()->PerformEncodingIteration(m_fEffort);
|
||||
|
||||
uiIteratedBlocks += a_uiMultithreadingStride;
|
||||
}
|
||||
|
||||
return uiIteratedBlocks;
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------------------------------
|
||||
// determine which warnings to check for during Encode() based on encoding format
|
||||
//
|
||||
void Image::FindEncodingWarningTypesForCurFormat()
|
||||
{
|
||||
TrackEncodingWarning(WARNING_ALL_TRANSPARENT_PIXELS);
|
||||
TrackEncodingWarning(WARNING_SOME_RGBA_NOT_0_TO_1);
|
||||
switch (m_format)
|
||||
{
|
||||
case Image::Format::ETC1:
|
||||
case Image::Format::RGB8:
|
||||
case Image::Format::SRGB8:
|
||||
TrackEncodingWarning(WARNING_SOME_NON_OPAQUE_PIXELS);
|
||||
TrackEncodingWarning(WARNING_SOME_TRANSLUCENT_PIXELS);
|
||||
break;
|
||||
|
||||
case Image::Format::RGB8A1:
|
||||
case Image::Format::SRGB8A1:
|
||||
TrackEncodingWarning(WARNING_SOME_TRANSLUCENT_PIXELS);
|
||||
TrackEncodingWarning(WARNING_ALL_OPAQUE_PIXELS);
|
||||
break;
|
||||
case Image::Format::RGBA8:
|
||||
case Image::Format::SRGBA8:
|
||||
TrackEncodingWarning(WARNING_ALL_OPAQUE_PIXELS);
|
||||
break;
|
||||
|
||||
case Image::Format::R11:
|
||||
case Image::Format::SIGNED_R11:
|
||||
TrackEncodingWarning(WARNING_SOME_NON_OPAQUE_PIXELS);
|
||||
TrackEncodingWarning(WARNING_SOME_TRANSLUCENT_PIXELS);
|
||||
TrackEncodingWarning(WARNING_SOME_GREEN_VALUES_ARE_NOT_ZERO);
|
||||
TrackEncodingWarning(WARNING_SOME_BLUE_VALUES_ARE_NOT_ZERO);
|
||||
break;
|
||||
|
||||
case Image::Format::RG11:
|
||||
case Image::Format::SIGNED_RG11:
|
||||
TrackEncodingWarning(WARNING_SOME_NON_OPAQUE_PIXELS);
|
||||
TrackEncodingWarning(WARNING_SOME_TRANSLUCENT_PIXELS);
|
||||
TrackEncodingWarning(WARNING_SOME_BLUE_VALUES_ARE_NOT_ZERO);
|
||||
break;
|
||||
case Image::Format::FORMATS:
|
||||
case Image::Format::UNKNOWN:
|
||||
default:
|
||||
assert(0);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------------------------------
|
||||
// examine source pixels to check for warnings
|
||||
//
|
||||
void Image::FindAndSetEncodingWarnings()
|
||||
{
|
||||
int numPixels = (m_uiBlockRows * 4) * (m_uiBlockColumns * 4);
|
||||
if (m_iNumOpaquePixels == numPixels)
|
||||
{
|
||||
AddToEncodingStatusIfSignfigant(Image::EncodingStatus::WARNING_ALL_OPAQUE_PIXELS);
|
||||
}
|
||||
if (m_iNumOpaquePixels < numPixels)
|
||||
{
|
||||
AddToEncodingStatusIfSignfigant(Image::EncodingStatus::WARNING_SOME_NON_OPAQUE_PIXELS);
|
||||
}
|
||||
if (m_iNumTranslucentPixels > 0)
|
||||
{
|
||||
AddToEncodingStatusIfSignfigant(Image::EncodingStatus::WARNING_SOME_TRANSLUCENT_PIXELS);
|
||||
}
|
||||
if (m_iNumTransparentPixels == numPixels)
|
||||
{
|
||||
AddToEncodingStatusIfSignfigant(Image::EncodingStatus::WARNING_ALL_TRANSPARENT_PIXELS);
|
||||
}
|
||||
if (m_numColorValues.fB > 0.0f)
|
||||
{
|
||||
AddToEncodingStatusIfSignfigant(Image::EncodingStatus::WARNING_SOME_BLUE_VALUES_ARE_NOT_ZERO);
|
||||
}
|
||||
if (m_numColorValues.fG > 0.0f)
|
||||
{
|
||||
AddToEncodingStatusIfSignfigant(Image::EncodingStatus::WARNING_SOME_GREEN_VALUES_ARE_NOT_ZERO);
|
||||
}
|
||||
|
||||
if (m_numOutOfRangeValues.fR > 0.0f || m_numOutOfRangeValues.fG > 0.0f)
|
||||
{
|
||||
AddToEncodingStatusIfSignfigant(Image::EncodingStatus::WARNING_SOME_RGBA_NOT_0_TO_1);
|
||||
}
|
||||
if (m_numOutOfRangeValues.fB > 0.0f || m_numOutOfRangeValues.fA > 0.0f)
|
||||
{
|
||||
AddToEncodingStatusIfSignfigant(Image::EncodingStatus::WARNING_SOME_RGBA_NOT_0_TO_1);
|
||||
}
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------------------------------
|
||||
// return a string name for a given image format
|
||||
//
|
||||
const char * Image::EncodingFormatToString(Image::Format a_format)
|
||||
{
|
||||
switch (a_format)
|
||||
{
|
||||
case Image::Format::ETC1:
|
||||
return "ETC1";
|
||||
case Image::Format::RGB8:
|
||||
return "RGB8";
|
||||
case Image::Format::SRGB8:
|
||||
return "SRGB8";
|
||||
|
||||
case Image::Format::RGB8A1:
|
||||
return "RGB8A1";
|
||||
case Image::Format::SRGB8A1:
|
||||
return "SRGB8A1";
|
||||
case Image::Format::RGBA8:
|
||||
return "RGBA8";
|
||||
case Image::Format::SRGBA8:
|
||||
return "SRGBA8";
|
||||
|
||||
case Image::Format::R11:
|
||||
return "R11";
|
||||
case Image::Format::SIGNED_R11:
|
||||
return "SIGNED_R11";
|
||||
|
||||
case Image::Format::RG11:
|
||||
return "RG11";
|
||||
case Image::Format::SIGNED_RG11:
|
||||
return "SIGNED_RG11";
|
||||
case Image::Format::FORMATS:
|
||||
case Image::Format::UNKNOWN:
|
||||
default:
|
||||
return "UNKNOWN";
|
||||
}
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------------------------------
|
||||
// return a string name for the image's format
|
||||
//
|
||||
const char * Image::EncodingFormatToString(void)
|
||||
{
|
||||
return EncodingFormatToString(m_format);
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------------------------------
|
||||
// init image blocks prior to encoding
|
||||
// init block sorter for subsequent sortings
|
||||
// check for encoding warnings
|
||||
//
|
||||
void Image::InitBlocksAndBlockSorter(void)
|
||||
{
|
||||
|
||||
FindEncodingWarningTypesForCurFormat();
|
||||
|
||||
// init each block
|
||||
Block4x4 *pblock = m_pablock;
|
||||
unsigned char *paucEncodingBits = m_paucEncodingBits;
|
||||
for (unsigned int uiBlockRow = 0; uiBlockRow < m_uiBlockRows; uiBlockRow++)
|
||||
{
|
||||
unsigned int uiBlockV = uiBlockRow * 4;
|
||||
|
||||
for (unsigned int uiBlockColumn = 0; uiBlockColumn < m_uiBlockColumns; uiBlockColumn++)
|
||||
{
|
||||
unsigned int uiBlockH = uiBlockColumn * 4;
|
||||
|
||||
pblock->InitFromSource(this, uiBlockH, uiBlockV, paucEncodingBits, m_errormetric);
|
||||
|
||||
paucEncodingBits += Block4x4EncodingBits::GetBytesPerBlock(m_encodingbitsformat);
|
||||
|
||||
pblock++;
|
||||
}
|
||||
}
|
||||
|
||||
FindAndSetEncodingWarnings();
|
||||
|
||||
// init block sorter
|
||||
{
|
||||
m_psortedblocklist = new SortedBlockList(GetNumberOfBlocks(), 100);
|
||||
|
||||
for (unsigned int uiBlock = 0; uiBlock < GetNumberOfBlocks(); uiBlock++)
|
||||
{
|
||||
pblock = &m_pablock[uiBlock];
|
||||
m_psortedblocklist->AddBlock(pblock);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------------------------------
|
||||
// run the first pass of the encoder
|
||||
// the encoder generally finds a reasonable, fast encoding
|
||||
// this is run on all blocks regardless of effort to ensure that all blocks have a valid encoding
|
||||
//
|
||||
void Image::RunFirstPass(unsigned int a_uiMultithreadingOffset, unsigned int a_uiMultithreadingStride)
|
||||
{
|
||||
assert(a_uiMultithreadingStride > 0);
|
||||
|
||||
for (unsigned int uiBlock = a_uiMultithreadingOffset;
|
||||
uiBlock < GetNumberOfBlocks();
|
||||
uiBlock += a_uiMultithreadingStride)
|
||||
{
|
||||
Block4x4 *pblock = &m_pablock[uiBlock];
|
||||
pblock->PerformEncodingIteration(m_fEffort);
|
||||
}
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------------------------------
|
||||
// set the encoding bits (for the output file) based on the best encoding for each block
|
||||
//
|
||||
void Image::SetEncodingBits(unsigned int a_uiMultithreadingOffset,
|
||||
unsigned int a_uiMultithreadingStride)
|
||||
{
|
||||
assert(a_uiMultithreadingStride > 0);
|
||||
|
||||
for (unsigned int uiBlock = a_uiMultithreadingOffset;
|
||||
uiBlock < GetNumberOfBlocks();
|
||||
uiBlock += a_uiMultithreadingStride)
|
||||
{
|
||||
Block4x4 *pblock = &m_pablock[uiBlock];
|
||||
pblock->SetEncodingBitsFromEncoding();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------------------------------
|
||||
// return the image error
|
||||
// image error is the sum of all block errors
|
||||
//
|
||||
float Image::GetError(void)
|
||||
{
|
||||
float fError = 0.0f;
|
||||
|
||||
for (unsigned int uiBlock = 0; uiBlock < GetNumberOfBlocks(); uiBlock++)
|
||||
{
|
||||
Block4x4 *pblock = &m_pablock[uiBlock];
|
||||
fError += pblock->GetError();
|
||||
}
|
||||
|
||||
return fError;
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------------------------------
|
||||
// determine the encoding bits format based on the encoding format
|
||||
// the encoding bits format is a family of bit encodings that are shared across various encoding formats
|
||||
//
|
||||
Block4x4EncodingBits::Format Image::DetermineEncodingBitsFormat(Format a_format)
|
||||
{
|
||||
Block4x4EncodingBits::Format encodingbitsformat;
|
||||
|
||||
// determine encoding bits format from image format
|
||||
switch (a_format)
|
||||
{
|
||||
case Format::ETC1:
|
||||
case Format::RGB8:
|
||||
case Format::SRGB8:
|
||||
encodingbitsformat = Block4x4EncodingBits::Format::RGB8;
|
||||
break;
|
||||
|
||||
case Format::RGBA8:
|
||||
case Format::SRGBA8:
|
||||
encodingbitsformat = Block4x4EncodingBits::Format::RGBA8;
|
||||
break;
|
||||
|
||||
case Format::R11:
|
||||
case Format::SIGNED_R11:
|
||||
encodingbitsformat = Block4x4EncodingBits::Format::R11;
|
||||
break;
|
||||
|
||||
case Format::RG11:
|
||||
case Format::SIGNED_RG11:
|
||||
encodingbitsformat = Block4x4EncodingBits::Format::RG11;
|
||||
break;
|
||||
|
||||
case Format::RGB8A1:
|
||||
case Format::SRGB8A1:
|
||||
encodingbitsformat = Block4x4EncodingBits::Format::RGB8A1;
|
||||
break;
|
||||
|
||||
default:
|
||||
encodingbitsformat = Block4x4EncodingBits::Format::UNKNOWN;
|
||||
break;
|
||||
}
|
||||
|
||||
return encodingbitsformat;
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------------------------------
|
||||
//
|
||||
|
||||
} // namespace Etc
|
249
extern/EtcLib/Etc/EtcImage.h
vendored
Normal file
249
extern/EtcLib/Etc/EtcImage.h
vendored
Normal file
@ -0,0 +1,249 @@
|
||||
/*
|
||||
* 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 "Etc.h"
|
||||
#include "EtcColorFloatRGBA.h"
|
||||
#include "EtcBlock4x4EncodingBits.h"
|
||||
#include "EtcErrorMetric.h"
|
||||
|
||||
|
||||
namespace Etc
|
||||
{
|
||||
class Block4x4;
|
||||
class EncoderSpec;
|
||||
class SortedBlockList;
|
||||
|
||||
class Image
|
||||
{
|
||||
public:
|
||||
|
||||
//the differnt warning and errors that can come up during encoding
|
||||
enum EncodingStatus
|
||||
{
|
||||
SUCCESS = 0,
|
||||
//
|
||||
WARNING_THRESHOLD = 1 << 0,
|
||||
//
|
||||
WARNING_EFFORT_OUT_OF_RANGE = 1 << 1,
|
||||
WARNING_JOBS_OUT_OF_RANGE = 1 << 2,
|
||||
WARNING_SOME_NON_OPAQUE_PIXELS = 1 << 3,//just for opaque formats, etc1, rgb8, r11, rg11
|
||||
WARNING_ALL_OPAQUE_PIXELS = 1 << 4,
|
||||
WARNING_ALL_TRANSPARENT_PIXELS = 1 << 5,
|
||||
WARNING_SOME_TRANSLUCENT_PIXELS = 1 << 6,//just for rgb8A1
|
||||
WARNING_SOME_RGBA_NOT_0_TO_1 = 1 << 7,
|
||||
WARNING_SOME_BLUE_VALUES_ARE_NOT_ZERO = 1 << 8,
|
||||
WARNING_SOME_GREEN_VALUES_ARE_NOT_ZERO = 1 << 9,
|
||||
//
|
||||
ERROR_THRESHOLD = 1 << 16,
|
||||
//
|
||||
ERROR_UNKNOWN_FORMAT = 1 << 17,
|
||||
ERROR_UNKNOWN_ERROR_METRIC = 1 << 18,
|
||||
ERROR_ZERO_WIDTH_OR_HEIGHT = 1 << 19,
|
||||
//
|
||||
};
|
||||
|
||||
enum class Format
|
||||
{
|
||||
UNKNOWN,
|
||||
//
|
||||
ETC1,
|
||||
//
|
||||
// ETC2 formats
|
||||
RGB8,
|
||||
SRGB8,
|
||||
RGBA8,
|
||||
SRGBA8,
|
||||
R11,
|
||||
SIGNED_R11,
|
||||
RG11,
|
||||
SIGNED_RG11,
|
||||
RGB8A1,
|
||||
SRGB8A1,
|
||||
//
|
||||
FORMATS,
|
||||
//
|
||||
DEFAULT = SRGB8
|
||||
};
|
||||
|
||||
// constructor using source image
|
||||
Image(float *a_pafSourceRGBA, unsigned int a_uiSourceWidth,
|
||||
unsigned int a_uiSourceHeight,
|
||||
ErrorMetric a_errormetric);
|
||||
|
||||
// constructor using encoding bits
|
||||
Image(Format a_format,
|
||||
unsigned int a_uiSourceWidth, unsigned int a_uiSourceHeight,
|
||||
unsigned char *a_paucEncidingBits, unsigned int a_uiEncodingBitsBytes,
|
||||
Image *a_pimageSource,
|
||||
ErrorMetric a_errormetric);
|
||||
|
||||
~Image(void);
|
||||
|
||||
EncodingStatus Encode(Format a_format, ErrorMetric a_errormetric, float a_fEffort,
|
||||
unsigned int a_uiJobs, unsigned int a_uiMaxJobs);
|
||||
|
||||
inline void AddToEncodingStatus(EncodingStatus a_encStatus)
|
||||
{
|
||||
m_encodingStatus = (EncodingStatus)((unsigned int)m_encodingStatus | (unsigned int)a_encStatus);
|
||||
}
|
||||
|
||||
inline unsigned int GetSourceWidth(void)
|
||||
{
|
||||
return m_uiSourceWidth;
|
||||
}
|
||||
|
||||
inline unsigned int GetSourceHeight(void)
|
||||
{
|
||||
return m_uiSourceHeight;
|
||||
}
|
||||
|
||||
inline unsigned int GetExtendedWidth(void)
|
||||
{
|
||||
return m_uiExtendedWidth;
|
||||
}
|
||||
|
||||
inline unsigned int GetExtendedHeight(void)
|
||||
{
|
||||
return m_uiExtendedHeight;
|
||||
}
|
||||
|
||||
inline unsigned int GetNumberOfBlocks()
|
||||
{
|
||||
return m_uiBlockColumns * m_uiBlockRows;
|
||||
}
|
||||
|
||||
inline Block4x4 * GetBlocks()
|
||||
{
|
||||
return m_pablock;
|
||||
}
|
||||
|
||||
inline unsigned char * GetEncodingBits(void)
|
||||
{
|
||||
return m_paucEncodingBits;
|
||||
}
|
||||
|
||||
inline unsigned int GetEncodingBitsBytes(void)
|
||||
{
|
||||
return m_uiEncodingBitsBytes;
|
||||
}
|
||||
|
||||
inline int GetEncodingTimeMs(void)
|
||||
{
|
||||
return m_iEncodeTime_ms;
|
||||
}
|
||||
|
||||
float GetError(void);
|
||||
|
||||
inline ColorFloatRGBA * GetSourcePixel(unsigned int a_uiH, unsigned int a_uiV)
|
||||
{
|
||||
if (a_uiH >= m_uiSourceWidth || a_uiV >= m_uiSourceHeight)
|
||||
{
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
return &m_pafrgbaSource[a_uiV*m_uiSourceWidth + a_uiH];
|
||||
}
|
||||
|
||||
inline Format GetFormat(void)
|
||||
{
|
||||
return m_format;
|
||||
}
|
||||
|
||||
static Block4x4EncodingBits::Format DetermineEncodingBitsFormat(Format a_format);
|
||||
|
||||
inline static unsigned short CalcExtendedDimension(unsigned short a_ushOriginalDimension)
|
||||
{
|
||||
return (unsigned short)((a_ushOriginalDimension + 3) & ~3);
|
||||
}
|
||||
|
||||
inline ErrorMetric GetErrorMetric(void)
|
||||
{
|
||||
return m_errormetric;
|
||||
}
|
||||
|
||||
static const char * EncodingFormatToString(Image::Format a_format);
|
||||
const char * EncodingFormatToString(void);
|
||||
//used to get basic information about the image data
|
||||
int m_iNumOpaquePixels;
|
||||
int m_iNumTranslucentPixels;
|
||||
int m_iNumTransparentPixels;
|
||||
|
||||
ColorFloatRGBA m_numColorValues;
|
||||
ColorFloatRGBA m_numOutOfRangeValues;
|
||||
|
||||
bool m_bVerboseOutput;
|
||||
private:
|
||||
//add a warning or error to check for while encoding
|
||||
inline void TrackEncodingWarning(EncodingStatus a_encStatus)
|
||||
{
|
||||
m_warningsToCapture = (EncodingStatus)((unsigned int)m_warningsToCapture | (unsigned int)a_encStatus);
|
||||
}
|
||||
|
||||
//report the warning if it is something we care about for this encoding
|
||||
inline void AddToEncodingStatusIfSignfigant(EncodingStatus a_encStatus)
|
||||
{
|
||||
if ((EncodingStatus)((unsigned int)m_warningsToCapture & (unsigned int)a_encStatus) == a_encStatus)
|
||||
{
|
||||
AddToEncodingStatus(a_encStatus);
|
||||
}
|
||||
}
|
||||
|
||||
Image(void);
|
||||
void FindEncodingWarningTypesForCurFormat();
|
||||
void FindAndSetEncodingWarnings();
|
||||
|
||||
void InitBlocksAndBlockSorter(void);
|
||||
|
||||
void RunFirstPass(unsigned int a_uiMultithreadingOffset,
|
||||
unsigned int a_uiMultithreadingStride);
|
||||
|
||||
void SetEncodingBits(unsigned int a_uiMultithreadingOffset,
|
||||
unsigned int a_uiMultithreadingStride);
|
||||
|
||||
unsigned int IterateThroughWorstBlocks(unsigned int a_uiMaxBlocks,
|
||||
unsigned int a_uiMultithreadingOffset,
|
||||
unsigned int a_uiMultithreadingStride);
|
||||
|
||||
// inputs
|
||||
ColorFloatRGBA *m_pafrgbaSource;
|
||||
unsigned int m_uiSourceWidth;
|
||||
unsigned int m_uiSourceHeight;
|
||||
unsigned int m_uiExtendedWidth;
|
||||
unsigned int m_uiExtendedHeight;
|
||||
unsigned int m_uiBlockColumns;
|
||||
unsigned int m_uiBlockRows;
|
||||
// intermediate data
|
||||
Block4x4 *m_pablock;
|
||||
// encoding
|
||||
Format m_format;
|
||||
Block4x4EncodingBits::Format m_encodingbitsformat;
|
||||
unsigned int m_uiEncodingBitsBytes; // for entire image
|
||||
unsigned char *m_paucEncodingBits;
|
||||
ErrorMetric m_errormetric;
|
||||
float m_fEffort;
|
||||
// stats
|
||||
int m_iEncodeTime_ms;
|
||||
|
||||
SortedBlockList *m_psortedblocklist;
|
||||
//this will hold any warning or errors that happen during encoding
|
||||
EncodingStatus m_encodingStatus;
|
||||
//these will be the warnings we are tracking
|
||||
EncodingStatus m_warningsToCapture;
|
||||
};
|
||||
|
||||
} // namespace Etc
|
64
extern/EtcLib/Etc/EtcMath.cpp
vendored
Normal file
64
extern/EtcLib/Etc/EtcMath.cpp
vendored
Normal file
@ -0,0 +1,64 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#include "EtcConfig.h"
|
||||
#include "EtcMath.h"
|
||||
|
||||
namespace Etc
|
||||
{
|
||||
|
||||
// ----------------------------------------------------------------------------------------------------
|
||||
// calculate the line that best fits the set of XY points contained in a_afX[] and a_afY[]
|
||||
// use a_fSlope and a_fOffset to define that line
|
||||
//
|
||||
bool Regression(float a_afX[], float a_afY[], unsigned int a_Points,
|
||||
float *a_fSlope, float *a_fOffset)
|
||||
{
|
||||
float fPoints = (float)a_Points;
|
||||
|
||||
float fSumX = 0.0f;
|
||||
float fSumY = 0.0f;
|
||||
float fSumXY = 0.0f;
|
||||
float fSumX2 = 0.0f;
|
||||
|
||||
for (unsigned int uiPoint = 0; uiPoint < a_Points; uiPoint++)
|
||||
{
|
||||
fSumX += a_afX[uiPoint];
|
||||
fSumY += a_afY[uiPoint];
|
||||
fSumXY += a_afX[uiPoint] * a_afY[uiPoint];
|
||||
fSumX2 += a_afX[uiPoint] * a_afX[uiPoint];
|
||||
}
|
||||
|
||||
float fDivisor = fPoints*fSumX2 - fSumX*fSumX;
|
||||
|
||||
// if vertical line
|
||||
if (fDivisor == 0.0f)
|
||||
{
|
||||
*a_fSlope = 0.0f;
|
||||
*a_fOffset = 0.0f;
|
||||
return true;
|
||||
}
|
||||
|
||||
*a_fSlope = (fPoints*fSumXY - fSumX*fSumY) / fDivisor;
|
||||
*a_fOffset = (fSumY - (*a_fSlope)*fSumX) / fPoints;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------------------------------
|
||||
//
|
||||
|
||||
} // namespace Etc
|
40
extern/EtcLib/Etc/EtcMath.h
vendored
Normal file
40
extern/EtcLib/Etc/EtcMath.h
vendored
Normal file
@ -0,0 +1,40 @@
|
||||
/*
|
||||
* 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 <math.h>
|
||||
|
||||
namespace Etc
|
||||
{
|
||||
|
||||
// ----------------------------------------------------------------------------------------------------
|
||||
// return true if vertical line
|
||||
bool Regression(float a_afX[], float a_afY[], unsigned int a_Points,
|
||||
float *a_fSlope, float *a_fOffset);
|
||||
|
||||
inline float ConvertMSEToPSNR(float a_fMSE)
|
||||
{
|
||||
if (a_fMSE == 0.0f)
|
||||
{
|
||||
return INFINITY;
|
||||
}
|
||||
|
||||
return 10.0f * log10f(1.0f / a_fMSE);
|
||||
}
|
||||
|
||||
|
||||
}
|
Reference in New Issue
Block a user