610 lines
19 KiB
C
610 lines
19 KiB
C
|
// File: crn_etc.h
|
||
|
// See Copyright Notice and license at the end of inc/crnlib.h
|
||
|
#pragma once
|
||
|
#include "../inc/crnlib.h"
|
||
|
#include "crn_dxt.h"
|
||
|
|
||
|
namespace crnlib
|
||
|
{
|
||
|
enum etc_constants
|
||
|
{
|
||
|
cETC1BytesPerBlock = 8U,
|
||
|
|
||
|
cETC1SelectorBits = 2U,
|
||
|
cETC1SelectorValues = 1U << cETC1SelectorBits,
|
||
|
cETC1SelectorMask = cETC1SelectorValues - 1U,
|
||
|
|
||
|
cETC1BlockShift = 2U,
|
||
|
cETC1BlockSize = 1U << cETC1BlockShift,
|
||
|
|
||
|
cETC1LSBSelectorIndicesBitOffset = 0,
|
||
|
cETC1MSBSelectorIndicesBitOffset = 16,
|
||
|
|
||
|
cETC1FlipBitOffset = 32,
|
||
|
cETC1DiffBitOffset = 33,
|
||
|
|
||
|
cETC1IntenModifierNumBits = 3,
|
||
|
cETC1IntenModifierValues = 1 << cETC1IntenModifierNumBits,
|
||
|
cETC1RightIntenModifierTableBitOffset = 34,
|
||
|
cETC1LeftIntenModifierTableBitOffset = 37,
|
||
|
|
||
|
// Base+Delta encoding (5 bit bases, 3 bit delta)
|
||
|
cETC1BaseColorCompNumBits = 5,
|
||
|
cETC1BaseColorCompMax = 1 << cETC1BaseColorCompNumBits,
|
||
|
|
||
|
cETC1DeltaColorCompNumBits = 3,
|
||
|
cETC1DeltaColorComp = 1 << cETC1DeltaColorCompNumBits,
|
||
|
cETC1DeltaColorCompMax = 1 << cETC1DeltaColorCompNumBits,
|
||
|
|
||
|
cETC1BaseColor5RBitOffset = 59,
|
||
|
cETC1BaseColor5GBitOffset = 51,
|
||
|
cETC1BaseColor5BBitOffset = 43,
|
||
|
|
||
|
cETC1DeltaColor3RBitOffset = 56,
|
||
|
cETC1DeltaColor3GBitOffset = 48,
|
||
|
cETC1DeltaColor3BBitOffset = 40,
|
||
|
|
||
|
// Absolute (non-delta) encoding (two 4-bit per component bases)
|
||
|
cETC1AbsColorCompNumBits = 4,
|
||
|
cETC1AbsColorCompMax = 1 << cETC1AbsColorCompNumBits,
|
||
|
|
||
|
cETC1AbsColor4R1BitOffset = 60,
|
||
|
cETC1AbsColor4G1BitOffset = 52,
|
||
|
cETC1AbsColor4B1BitOffset = 44,
|
||
|
|
||
|
cETC1AbsColor4R2BitOffset = 56,
|
||
|
cETC1AbsColor4G2BitOffset = 48,
|
||
|
cETC1AbsColor4B2BitOffset = 40,
|
||
|
|
||
|
cETC1ColorDeltaMin = -4,
|
||
|
cETC1ColorDeltaMax = 3,
|
||
|
|
||
|
// Delta3:
|
||
|
// 0 1 2 3 4 5 6 7
|
||
|
// 000 001 010 011 100 101 110 111
|
||
|
// 0 1 2 3 -4 -3 -2 -1
|
||
|
};
|
||
|
|
||
|
extern const int g_etc1_inten_tables[cETC1IntenModifierValues][cETC1SelectorValues];
|
||
|
extern const uint8 g_etc1_to_selector_index[cETC1SelectorValues];
|
||
|
extern const uint8 g_selector_index_to_etc1[cETC1SelectorValues];
|
||
|
|
||
|
struct etc1_coord2
|
||
|
{
|
||
|
uint8 m_x, m_y;
|
||
|
};
|
||
|
extern const etc1_coord2 g_etc1_pixel_coords[2][2][8]; // [flipped][subblock][subblock_pixel]
|
||
|
|
||
|
struct etc1_block
|
||
|
{
|
||
|
// big endian uint64:
|
||
|
// bit ofs: 56 48 40 32 24 16 8 0
|
||
|
// byte ofs: b0, b1, b2, b3, b4, b5, b6, b7
|
||
|
union
|
||
|
{
|
||
|
uint64 m_uint64;
|
||
|
uint8 m_bytes[8];
|
||
|
};
|
||
|
|
||
|
uint8 m_low_color[2];
|
||
|
uint8 m_high_color[2];
|
||
|
|
||
|
enum { cNumSelectorBytes = 4 };
|
||
|
uint8 m_selectors[cNumSelectorBytes];
|
||
|
|
||
|
inline void clear()
|
||
|
{
|
||
|
utils::zero_this(this);
|
||
|
}
|
||
|
|
||
|
inline uint get_general_bits(uint ofs, uint num) const
|
||
|
{
|
||
|
CRNLIB_ASSERT((ofs + num) <= 64U);
|
||
|
CRNLIB_ASSERT(num && (num < 32U));
|
||
|
return (utils::read_be64(&m_uint64) >> ofs) & ((1UL << num) - 1UL);
|
||
|
}
|
||
|
|
||
|
inline void set_general_bits(uint ofs, uint num, uint bits)
|
||
|
{
|
||
|
CRNLIB_ASSERT((ofs + num) <= 64U);
|
||
|
CRNLIB_ASSERT(num && (num < 32U));
|
||
|
|
||
|
uint64 x = utils::read_be64(&m_uint64);
|
||
|
uint64 msk = ((1ULL << static_cast<uint64>(num)) - 1ULL) << static_cast<uint64>(ofs);
|
||
|
x &= ~msk;
|
||
|
x |= (static_cast<uint64>(bits) << static_cast<uint64>(ofs));
|
||
|
utils::write_be64(&m_uint64, x);
|
||
|
}
|
||
|
|
||
|
inline uint get_byte_bits(uint ofs, uint num) const
|
||
|
{
|
||
|
CRNLIB_ASSERT((ofs + num) <= 64U);
|
||
|
CRNLIB_ASSERT(num && (num <= 8U));
|
||
|
CRNLIB_ASSERT((ofs >> 3) == ((ofs + num - 1) >> 3));
|
||
|
const uint byte_ofs = 7 - (ofs >> 3);
|
||
|
const uint byte_bit_ofs = ofs & 7;
|
||
|
return (m_bytes[byte_ofs] >> byte_bit_ofs) & ((1 << num) - 1);
|
||
|
}
|
||
|
|
||
|
inline void set_byte_bits(uint ofs, uint num, uint bits)
|
||
|
{
|
||
|
CRNLIB_ASSERT((ofs + num) <= 64U);
|
||
|
CRNLIB_ASSERT(num && (num < 32U));
|
||
|
CRNLIB_ASSERT((ofs >> 3) == ((ofs + num - 1) >> 3));
|
||
|
CRNLIB_ASSERT(bits < (1U << num));
|
||
|
const uint byte_ofs = 7 - (ofs >> 3);
|
||
|
const uint byte_bit_ofs = ofs & 7;
|
||
|
const uint mask = (1 << num) - 1;
|
||
|
m_bytes[byte_ofs] &= ~(mask << byte_bit_ofs);
|
||
|
m_bytes[byte_ofs] |= (bits << byte_bit_ofs);
|
||
|
}
|
||
|
|
||
|
// false = left/right subblocks
|
||
|
// true = upper/lower subblocks
|
||
|
inline bool get_flip_bit() const
|
||
|
{
|
||
|
return (m_bytes[3] & 1) != 0;
|
||
|
}
|
||
|
|
||
|
inline void set_flip_bit(bool flip)
|
||
|
{
|
||
|
m_bytes[3] &= ~1;
|
||
|
m_bytes[3] |= static_cast<uint8>(flip);
|
||
|
}
|
||
|
|
||
|
inline bool get_diff_bit() const
|
||
|
{
|
||
|
return (m_bytes[3] & 2) != 0;
|
||
|
}
|
||
|
|
||
|
inline void set_diff_bit(bool diff)
|
||
|
{
|
||
|
m_bytes[3] &= ~2;
|
||
|
m_bytes[3] |= (static_cast<uint>(diff) << 1);
|
||
|
}
|
||
|
|
||
|
// Returns intensity modifier table (0-7) used by subblock subblock_id.
|
||
|
// subblock_id=0 left/top (CW 1), 1=right/bottom (CW 2)
|
||
|
inline uint get_inten_table(uint subblock_id) const
|
||
|
{
|
||
|
CRNLIB_ASSERT(subblock_id < 2);
|
||
|
const uint ofs = subblock_id ? 2 : 5;
|
||
|
return (m_bytes[3] >> ofs) & 7;
|
||
|
}
|
||
|
|
||
|
// Sets intensity modifier table (0-7) used by subblock subblock_id (0 or 1)
|
||
|
inline void set_inten_table(uint subblock_id, uint t)
|
||
|
{
|
||
|
CRNLIB_ASSERT(subblock_id < 2);
|
||
|
CRNLIB_ASSERT(t < 8);
|
||
|
const uint ofs = subblock_id ? 2 : 5;
|
||
|
m_bytes[3] &= ~(7 << ofs);
|
||
|
m_bytes[3] |= (t << ofs);
|
||
|
}
|
||
|
|
||
|
// Returned selector value ranges from 0-3 and is a direct index into g_etc1_inten_tables.
|
||
|
inline uint get_selector(uint x, uint y) const
|
||
|
{
|
||
|
CRNLIB_ASSERT((x | y) < 4);
|
||
|
|
||
|
const uint bit_index = x * 4 + y;
|
||
|
const uint byte_bit_ofs = bit_index & 7;
|
||
|
const uint8 *p = &m_bytes[7 - (bit_index >> 3)];
|
||
|
const uint lsb = (p[0] >> byte_bit_ofs) & 1;
|
||
|
const uint msb = (p[-2] >> byte_bit_ofs) & 1;
|
||
|
const uint val = lsb | (msb << 1);
|
||
|
|
||
|
return g_etc1_to_selector_index[val];
|
||
|
}
|
||
|
|
||
|
// Selector "val" ranges from 0-3 and is a direct index into g_etc1_inten_tables.
|
||
|
inline void set_selector(uint x, uint y, uint val)
|
||
|
{
|
||
|
CRNLIB_ASSERT((x | y | val) < 4);
|
||
|
const uint bit_index = x * 4 + y;
|
||
|
|
||
|
uint8 *p = &m_bytes[7 - (bit_index >> 3)];
|
||
|
|
||
|
const uint byte_bit_ofs = bit_index & 7;
|
||
|
const uint mask = 1 << byte_bit_ofs;
|
||
|
|
||
|
const uint etc1_val = g_selector_index_to_etc1[val];
|
||
|
|
||
|
const uint lsb = etc1_val & 1;
|
||
|
const uint msb = etc1_val >> 1;
|
||
|
|
||
|
p[0] &= ~mask;
|
||
|
p[0] |= (lsb << byte_bit_ofs);
|
||
|
|
||
|
p[-2] &= ~mask;
|
||
|
p[-2] |= (msb << byte_bit_ofs);
|
||
|
}
|
||
|
|
||
|
inline void set_base4_color(uint idx, uint16 c)
|
||
|
{
|
||
|
if (idx)
|
||
|
{
|
||
|
set_byte_bits(cETC1AbsColor4R2BitOffset, 4, (c >> 8) & 15);
|
||
|
set_byte_bits(cETC1AbsColor4G2BitOffset, 4, (c >> 4) & 15);
|
||
|
set_byte_bits(cETC1AbsColor4B2BitOffset, 4, c & 15);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
set_byte_bits(cETC1AbsColor4R1BitOffset, 4, (c >> 8) & 15);
|
||
|
set_byte_bits(cETC1AbsColor4G1BitOffset, 4, (c >> 4) & 15);
|
||
|
set_byte_bits(cETC1AbsColor4B1BitOffset, 4, c & 15);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
inline uint16 get_base4_color(uint idx) const
|
||
|
{
|
||
|
uint r, g, b;
|
||
|
if (idx)
|
||
|
{
|
||
|
r = get_byte_bits(cETC1AbsColor4R2BitOffset, 4);
|
||
|
g = get_byte_bits(cETC1AbsColor4G2BitOffset, 4);
|
||
|
b = get_byte_bits(cETC1AbsColor4B2BitOffset, 4);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
r = get_byte_bits(cETC1AbsColor4R1BitOffset, 4);
|
||
|
g = get_byte_bits(cETC1AbsColor4G1BitOffset, 4);
|
||
|
b = get_byte_bits(cETC1AbsColor4B1BitOffset, 4);
|
||
|
}
|
||
|
return static_cast<uint16>(b | (g << 4U) | (r << 8U));
|
||
|
}
|
||
|
|
||
|
inline void set_base5_color(uint16 c)
|
||
|
{
|
||
|
set_byte_bits(cETC1BaseColor5RBitOffset, 5, (c >> 10) & 31);
|
||
|
set_byte_bits(cETC1BaseColor5GBitOffset, 5, (c >> 5) & 31);
|
||
|
set_byte_bits(cETC1BaseColor5BBitOffset, 5, c & 31);
|
||
|
}
|
||
|
|
||
|
inline uint16 get_base5_color() const
|
||
|
{
|
||
|
const uint r = get_byte_bits(cETC1BaseColor5RBitOffset, 5);
|
||
|
const uint g = get_byte_bits(cETC1BaseColor5GBitOffset, 5);
|
||
|
const uint b = get_byte_bits(cETC1BaseColor5BBitOffset, 5);
|
||
|
return static_cast<uint16>(b | (g << 5U) | (r << 10U));
|
||
|
}
|
||
|
|
||
|
void set_delta3_color(uint16 c)
|
||
|
{
|
||
|
set_byte_bits(cETC1DeltaColor3RBitOffset, 3, (c >> 6) & 7);
|
||
|
set_byte_bits(cETC1DeltaColor3GBitOffset, 3, (c >> 3) & 7);
|
||
|
set_byte_bits(cETC1DeltaColor3BBitOffset, 3, c & 7);
|
||
|
}
|
||
|
|
||
|
inline uint16 get_delta3_color() const
|
||
|
{
|
||
|
const uint r = get_byte_bits(cETC1DeltaColor3RBitOffset, 3);
|
||
|
const uint g = get_byte_bits(cETC1DeltaColor3GBitOffset, 3);
|
||
|
const uint b = get_byte_bits(cETC1DeltaColor3BBitOffset, 3);
|
||
|
return static_cast<uint16>(b | (g << 3U) | (r << 6U));
|
||
|
}
|
||
|
|
||
|
// Base color 5
|
||
|
static uint16 pack_color5(const color_quad_u8& color, bool scaled, uint bias = 127U);
|
||
|
static uint16 pack_color5(uint r, uint g, uint b, bool scaled, uint bias = 127U);
|
||
|
|
||
|
static color_quad_u8 unpack_color5(uint16 packed_color5, bool scaled, uint alpha = 255U);
|
||
|
static void unpack_color5(uint& r, uint& g, uint& b, uint16 packed_color, bool scaled);
|
||
|
|
||
|
static bool unpack_color5(color_quad_u8& result, uint16 packed_color5, uint16 packed_delta3, bool scaled, uint alpha = 255U);
|
||
|
static bool unpack_color5(uint& r, uint& g, uint& b, uint16 packed_color5, uint16 packed_delta3, bool scaled, uint alpha = 255U);
|
||
|
|
||
|
// Delta color 3
|
||
|
// Inputs range from -4 to 3 (cETC1ColorDeltaMin to cETC1ColorDeltaMax)
|
||
|
static uint16 pack_delta3(const color_quad_i16& color);
|
||
|
static uint16 pack_delta3(int r, int g, int b);
|
||
|
|
||
|
// Results range from -4 to 3 (cETC1ColorDeltaMin to cETC1ColorDeltaMax)
|
||
|
static color_quad_i16 unpack_delta3(uint16 packed_delta3);
|
||
|
static void unpack_delta3(int& r, int& g, int& b, uint16 packed_delta3);
|
||
|
|
||
|
// Abs color 4
|
||
|
static uint16 pack_color4(const color_quad_u8& color, bool scaled, uint bias = 127U);
|
||
|
static uint16 pack_color4(uint r, uint g, uint b, bool scaled, uint bias = 127U);
|
||
|
|
||
|
static color_quad_u8 unpack_color4(uint16 packed_color4, bool scaled, uint alpha = 255U);
|
||
|
static void unpack_color4(uint& r, uint& g, uint& b, uint16 packed_color4, bool scaled);
|
||
|
|
||
|
// subblock colors
|
||
|
static void get_diff_subblock_colors(color_quad_u8* pDst, uint16 packed_color5, uint table_idx);
|
||
|
static bool get_diff_subblock_colors(color_quad_u8* pDst, uint16 packed_color5, uint16 packed_delta3, uint table_idx);
|
||
|
static void get_abs_subblock_colors(color_quad_u8* pDst, uint16 packed_color4, uint table_idx);
|
||
|
|
||
|
static inline void unscaled_to_scaled_color(color_quad_u8& dst, const color_quad_u8& src, bool color4)
|
||
|
{
|
||
|
if (color4)
|
||
|
{
|
||
|
dst.r = src.r | (src.r << 4);
|
||
|
dst.g = src.g | (src.g << 4);
|
||
|
dst.b = src.b | (src.b << 4);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
dst.r = (src.r >> 2) | (src.r << 3);
|
||
|
dst.g = (src.g >> 2) | (src.g << 3);
|
||
|
dst.b = (src.b >> 2) | (src.b << 3);
|
||
|
}
|
||
|
dst.a = src.a;
|
||
|
}
|
||
|
};
|
||
|
|
||
|
CRNLIB_DEFINE_BITWISE_COPYABLE(etc1_block);
|
||
|
|
||
|
// Returns false if the block is invalid (it will still be unpacked with clamping).
|
||
|
bool unpack_etc1(const etc1_block& block, color_quad_u8 *pDst, bool preserve_alpha = false);
|
||
|
|
||
|
enum crn_etc_quality
|
||
|
{
|
||
|
cCRNETCQualityFast,
|
||
|
cCRNETCQualityMedium,
|
||
|
cCRNETCQualitySlow,
|
||
|
|
||
|
cCRNETCQualityTotal,
|
||
|
|
||
|
cCRNETCQualityForceDWORD = 0xFFFFFFFF
|
||
|
};
|
||
|
|
||
|
struct crn_etc1_pack_params
|
||
|
{
|
||
|
crn_etc_quality m_quality;
|
||
|
bool m_perceptual;
|
||
|
bool m_dithering;
|
||
|
|
||
|
inline crn_etc1_pack_params()
|
||
|
{
|
||
|
clear();
|
||
|
}
|
||
|
|
||
|
void clear()
|
||
|
{
|
||
|
m_quality = cCRNETCQualitySlow;
|
||
|
m_perceptual = true;
|
||
|
m_dithering = false;
|
||
|
}
|
||
|
};
|
||
|
|
||
|
struct etc1_solution_coordinates
|
||
|
{
|
||
|
inline etc1_solution_coordinates() :
|
||
|
m_unscaled_color(0, 0, 0, 0),
|
||
|
m_inten_table(0),
|
||
|
m_color4(false)
|
||
|
{
|
||
|
}
|
||
|
|
||
|
inline etc1_solution_coordinates(uint r, uint g, uint b, uint inten_table, bool color4) :
|
||
|
m_unscaled_color(r, g, b, 255),
|
||
|
m_inten_table(inten_table),
|
||
|
m_color4(color4)
|
||
|
{
|
||
|
}
|
||
|
|
||
|
inline etc1_solution_coordinates(const color_quad_u8& c, uint inten_table, bool color4) :
|
||
|
m_unscaled_color(c),
|
||
|
m_inten_table(inten_table),
|
||
|
m_color4(color4)
|
||
|
{
|
||
|
}
|
||
|
|
||
|
inline etc1_solution_coordinates(const etc1_solution_coordinates& other)
|
||
|
{
|
||
|
*this = other;
|
||
|
}
|
||
|
|
||
|
inline etc1_solution_coordinates& operator= (const etc1_solution_coordinates& rhs)
|
||
|
{
|
||
|
m_unscaled_color = rhs.m_unscaled_color;
|
||
|
m_inten_table = rhs.m_inten_table;
|
||
|
m_color4 = rhs.m_color4;
|
||
|
return *this;
|
||
|
}
|
||
|
|
||
|
inline void clear()
|
||
|
{
|
||
|
m_unscaled_color.clear();
|
||
|
m_inten_table = 0;
|
||
|
m_color4 = false;
|
||
|
}
|
||
|
|
||
|
inline color_quad_u8 get_scaled_color() const
|
||
|
{
|
||
|
int br, bg, bb;
|
||
|
if (m_color4)
|
||
|
{
|
||
|
br = m_unscaled_color.r | (m_unscaled_color.r << 4);
|
||
|
bg = m_unscaled_color.g | (m_unscaled_color.g << 4);
|
||
|
bb = m_unscaled_color.b | (m_unscaled_color.b << 4);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
br = (m_unscaled_color.r >> 2) | (m_unscaled_color.r << 3);
|
||
|
bg = (m_unscaled_color.g >> 2) | (m_unscaled_color.g << 3);
|
||
|
bb = (m_unscaled_color.b >> 2) | (m_unscaled_color.b << 3);
|
||
|
}
|
||
|
return color_quad_u8(br, bg, bb);
|
||
|
}
|
||
|
|
||
|
inline void get_block_colors(color_quad_u8* pBlock_colors)
|
||
|
{
|
||
|
int br, bg, bb;
|
||
|
if (m_color4)
|
||
|
{
|
||
|
br = m_unscaled_color.r | (m_unscaled_color.r << 4);
|
||
|
bg = m_unscaled_color.g | (m_unscaled_color.g << 4);
|
||
|
bb = m_unscaled_color.b | (m_unscaled_color.b << 4);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
br = (m_unscaled_color.r >> 2) | (m_unscaled_color.r << 3);
|
||
|
bg = (m_unscaled_color.g >> 2) | (m_unscaled_color.g << 3);
|
||
|
bb = (m_unscaled_color.b >> 2) | (m_unscaled_color.b << 3);
|
||
|
}
|
||
|
const int* pInten_table = g_etc1_inten_tables[m_inten_table];
|
||
|
pBlock_colors[0].set(br + pInten_table[0], bg + pInten_table[0], bb + pInten_table[0]);
|
||
|
pBlock_colors[1].set(br + pInten_table[1], bg + pInten_table[1], bb + pInten_table[1]);
|
||
|
pBlock_colors[2].set(br + pInten_table[2], bg + pInten_table[2], bb + pInten_table[2]);
|
||
|
pBlock_colors[3].set(br + pInten_table[3], bg + pInten_table[3], bb + pInten_table[3]);
|
||
|
}
|
||
|
|
||
|
color_quad_u8 m_unscaled_color;
|
||
|
uint m_inten_table;
|
||
|
bool m_color4;
|
||
|
};
|
||
|
|
||
|
class etc1_optimizer
|
||
|
{
|
||
|
CRNLIB_NO_COPY_OR_ASSIGNMENT_OP(etc1_optimizer);
|
||
|
|
||
|
public:
|
||
|
etc1_optimizer()
|
||
|
{
|
||
|
clear();
|
||
|
}
|
||
|
|
||
|
void clear()
|
||
|
{
|
||
|
m_pParams = NULL;
|
||
|
m_pResult = NULL;
|
||
|
m_pSorted_luma = NULL;
|
||
|
m_pSorted_luma_indices = NULL;
|
||
|
}
|
||
|
|
||
|
struct params : crn_etc1_pack_params
|
||
|
{
|
||
|
params()
|
||
|
{
|
||
|
clear();
|
||
|
}
|
||
|
|
||
|
params(const crn_etc1_pack_params& base_params) :
|
||
|
crn_etc1_pack_params(base_params)
|
||
|
{
|
||
|
clear_optimizer_params();
|
||
|
}
|
||
|
|
||
|
void clear()
|
||
|
{
|
||
|
crn_etc1_pack_params::clear();
|
||
|
clear_optimizer_params();
|
||
|
}
|
||
|
|
||
|
void clear_optimizer_params()
|
||
|
{
|
||
|
m_num_src_pixels = 0;
|
||
|
m_pSrc_pixels = 0;
|
||
|
|
||
|
m_use_color4 = false;
|
||
|
static const int s_default_scan_delta[] = { 0 };
|
||
|
m_pScan_deltas = s_default_scan_delta;
|
||
|
m_scan_delta_size = 1;
|
||
|
|
||
|
m_base_color5.clear();
|
||
|
m_constrain_against_base_color5 = false;
|
||
|
}
|
||
|
|
||
|
uint m_num_src_pixels;
|
||
|
const color_quad_u8* m_pSrc_pixels;
|
||
|
|
||
|
bool m_use_color4;
|
||
|
const int* m_pScan_deltas;
|
||
|
uint m_scan_delta_size;
|
||
|
|
||
|
color_quad_u8 m_base_color5;
|
||
|
bool m_constrain_against_base_color5;
|
||
|
};
|
||
|
|
||
|
struct results
|
||
|
{
|
||
|
uint64 m_error;
|
||
|
color_quad_u8 m_block_color_unscaled;
|
||
|
uint m_block_inten_table;
|
||
|
uint m_n;
|
||
|
uint8* m_pSelectors;
|
||
|
bool m_block_color4;
|
||
|
|
||
|
inline results& operator= (const results& rhs)
|
||
|
{
|
||
|
m_block_color_unscaled = rhs.m_block_color_unscaled;
|
||
|
m_block_color4 = rhs.m_block_color4;
|
||
|
m_block_inten_table = rhs.m_block_inten_table;
|
||
|
m_error = rhs.m_error;
|
||
|
CRNLIB_ASSERT(m_n == rhs.m_n);
|
||
|
memcpy(m_pSelectors, rhs.m_pSelectors, rhs.m_n);
|
||
|
return *this;
|
||
|
}
|
||
|
};
|
||
|
|
||
|
void init(const params& params, results& result);
|
||
|
bool compute();
|
||
|
|
||
|
private:
|
||
|
struct potential_solution
|
||
|
{
|
||
|
potential_solution() : m_coords(), m_error(cUINT64_MAX), m_valid(false)
|
||
|
{
|
||
|
}
|
||
|
|
||
|
etc1_solution_coordinates m_coords;
|
||
|
crnlib::vector<uint8> m_selectors;
|
||
|
uint64 m_error;
|
||
|
bool m_valid;
|
||
|
|
||
|
void clear()
|
||
|
{
|
||
|
m_coords.clear();
|
||
|
m_selectors.resize(0);
|
||
|
m_error = cUINT64_MAX;
|
||
|
m_valid = false;
|
||
|
}
|
||
|
|
||
|
bool are_selectors_all_equal() const
|
||
|
{
|
||
|
if (m_selectors.empty())
|
||
|
return false;
|
||
|
const uint s = m_selectors[0];
|
||
|
for (uint i = 1; i < m_selectors.size(); i++)
|
||
|
if (m_selectors[i] != s)
|
||
|
return false;
|
||
|
return true;
|
||
|
}
|
||
|
};
|
||
|
|
||
|
const params* m_pParams;
|
||
|
results* m_pResult;
|
||
|
|
||
|
int m_limit;
|
||
|
|
||
|
vec3F m_avg_color;
|
||
|
int m_br, m_bg, m_bb;
|
||
|
crnlib::vector<uint16> m_luma;
|
||
|
crnlib::vector<uint32> m_sorted_luma[2];
|
||
|
const uint32* m_pSorted_luma_indices;
|
||
|
uint32* m_pSorted_luma;
|
||
|
|
||
|
crnlib::vector<uint8> m_selectors;
|
||
|
crnlib::vector<uint8> m_best_selectors;
|
||
|
|
||
|
potential_solution m_best_solution;
|
||
|
potential_solution m_trial_solution;
|
||
|
crnlib::vector<uint8> m_temp_selectors;
|
||
|
|
||
|
bool evaluate_solution(const etc1_solution_coordinates& coords, potential_solution& trial_solution, potential_solution* pBest_solution);
|
||
|
bool evaluate_solution_fast(const etc1_solution_coordinates& coords, potential_solution& trial_solution, potential_solution* pBest_solution);
|
||
|
};
|
||
|
|
||
|
struct pack_etc1_block_context
|
||
|
{
|
||
|
etc1_optimizer m_optimizer;
|
||
|
};
|
||
|
|
||
|
void pack_etc1_block_init();
|
||
|
|
||
|
uint64 pack_etc1_block(etc1_block& block, const color_quad_u8* pSrc_pixels, crn_etc1_pack_params& pack_params, pack_etc1_block_context& context);
|
||
|
|
||
|
} // namespace crnlib
|