Initial checkin of v1.04 - KTX file format support, basic ETC1 compression/decompression, Linux makefile with proper gcc options, lots of high-level improvements to get crnlib into a state where I can more easily add additional formats.

This commit is contained in:
richgel99@gmail.com
2012-11-25 08:41:25 +00:00
parent a8011e9d7f
commit f71b49be60
92 changed files with 20362 additions and 781 deletions
+313 -13
View File
@@ -16,6 +16,17 @@ namespace crnlib
};
};
template<> struct color_quad_component_traits<int8>
{
enum
{
cSigned = true,
cFloat = false,
cMin = cINT8_MIN,
cMax = cINT8_MAX
};
};
template<> struct color_quad_component_traits<int16>
{
enum
@@ -86,21 +97,22 @@ namespace crnlib
class color_quad : public helpers::rel_ops<color_quad<component_type, parameter_type> >
{
template<typename T>
static inline T clamp(T v)
static inline parameter_type clamp(T v)
{
parameter_type result = static_cast<parameter_type>(v);
if (!component_traits::cFloat)
{
if (v < component_traits::cMin)
v = component_traits::cMin;
result = static_cast<parameter_type>(component_traits::cMin);
else if (v > component_traits::cMax)
v = component_traits::cMax;
result = static_cast<parameter_type>(component_traits::cMax);
}
return v;
return result;
}
#ifdef _MSC_VER
template<>
static inline int clamp(int v)
static inline parameter_type clamp(int v)
{
if (!component_traits::cFloat)
{
@@ -117,7 +129,7 @@ namespace crnlib
v = component_traits::cMax;
}
}
return v;
return static_cast<parameter_type>(v);
}
#endif
@@ -179,7 +191,7 @@ namespace crnlib
template<typename other_component_type, typename other_parameter_type>
inline color_quad(const color_quad<other_component_type, other_parameter_type>& other) :
r(clamp(other.r)), g(clamp(other.g)), b(clamp(other.b)), a(clamp(other.a))
r(static_cast<component_type>(clamp(other.r))), g(static_cast<component_type>(clamp(other.g))), b(static_cast<component_type>(clamp(other.b))), a(static_cast<component_type>(clamp(other.a)))
{
}
@@ -200,13 +212,21 @@ namespace crnlib
return *this;
}
inline color_quad& set_rgb(const color_quad& other)
{
r = other.r;
g = other.g;
b = other.b;
return *this;
}
template<typename other_component_type, typename other_parameter_type>
inline color_quad& operator=(const color_quad<other_component_type, other_parameter_type>& other)
{
r = clamp(other.r);
g = clamp(other.g);
b = clamp(other.b);
a = clamp(other.a);
r = static_cast<component_type>(clamp(other.r));
g = static_cast<component_type>(clamp(other.g));
b = static_cast<component_type>(clamp(other.b));
a = static_cast<component_type>(clamp(other.a));
return *this;
}
@@ -519,6 +539,7 @@ namespace crnlib
};
typedef color_quad<uint8, int> color_quad_u8;
typedef color_quad<int8, int> color_quad_i8;
typedef color_quad<int16, int> color_quad_i16;
typedef color_quad<uint16, int> color_quad_u16;
typedef color_quad<int32, int> color_quad_i32;
@@ -633,7 +654,7 @@ namespace crnlib
const int YR = 19595, YG = 38470, YB = 7471, CB_R = -11059, CB_G = -21709, CB_B = 32768, CR_R = 32768, CR_G = -27439, CR_B = -5329;
// YCbCr->RGB constants, scaled by 2^16
const int R_CR = 91881, B_CB = 116130, G_CR = -46802, G_CB = -22554;
inline int RGB_to_Y(const color_quad_u8& rgb)
{
const int r = rgb[0], g = rgb[1], b = rgb[2];
@@ -663,7 +684,7 @@ namespace crnlib
rgb.b = clamp_component(y + ((B_CB * cb + 32768) >> 16));
rgb.a = 255;
}
// Float RGB->YCbCr constants
const float S = 1.0f/65536.0f;
const float F_YR = S*YR, F_YG = S*YG, F_YB = S*YB, F_CB_R = S*CB_R, F_CB_G = S*CB_G, F_CB_B = S*CB_B, F_CR_R = S*CR_R, F_CR_G = S*CR_G, F_CR_B = S*CR_B;
@@ -690,5 +711,284 @@ namespace crnlib
} // namespace color
// This class purposely trades off speed for extremely flexibility. It can handle any component swizzle, any pixel type from 1-4 components and 1-32 bits/component,
// any pixel size between 1-16 bytes/pixel, any pixel stride, any color_quad data type (signed/unsigned/float 8/16/32 bits/component), and scaled/non-scaled components.
// On the downside, it's freaking slow.
class pixel_packer
{
public:
pixel_packer()
{
clear();
}
pixel_packer(uint num_comps, uint bits_per_comp, int pixel_stride = -1, bool reversed = false)
{
init(num_comps, bits_per_comp, pixel_stride, reversed);
}
pixel_packer(const char* pComp_map, int pixel_stride = -1, int force_comp_size = -1)
{
init(pComp_map, pixel_stride, force_comp_size);
}
void clear()
{
utils::zero_this(this);
}
inline bool is_valid() const { return m_pixel_stride > 0; }
inline uint get_pixel_stride() const { return m_pixel_stride; }
void set_pixel_stride(uint n) { m_pixel_stride = n; }
uint get_num_comps() const { return m_num_comps; }
uint get_comp_size(uint index) const { CRNLIB_ASSERT(index < 4); return m_comp_size[index]; }
uint get_comp_ofs(uint index) const { CRNLIB_ASSERT(index < 4); return m_comp_ofs[index]; }
uint get_comp_max(uint index) const { CRNLIB_ASSERT(index < 4); return m_comp_max[index]; }
bool get_rgb_is_luma() const { return m_rgb_is_luma; }
template<typename color_quad_type>
const void* unpack(const void* p, color_quad_type& color, bool rescale = true) const
{
const uint8* pSrc = static_cast<const uint8*>(p);
for (uint i = 0; i < 4; i++)
{
const uint comp_size = m_comp_size[i];
if (!comp_size)
{
if (color_quad_type::component_traits::cFloat)
color[i] = static_cast< typename color_quad_type::parameter_t >((i == 3) ? 1 : 0);
else
color[i] = static_cast< typename color_quad_type::parameter_t >((i == 3) ? color_quad_type::component_traits::cMax : 0);
continue;
}
uint n = 0, dst_bit_ofs = 0;
uint src_bit_ofs = m_comp_ofs[i];
while (dst_bit_ofs < comp_size)
{
const uint byte_bit_ofs = src_bit_ofs & 7;
n |= ((pSrc[src_bit_ofs >> 3] >> byte_bit_ofs) << dst_bit_ofs);
const uint bits_read = 8 - byte_bit_ofs;
src_bit_ofs += bits_read;
dst_bit_ofs += bits_read;
}
const uint32 mx = m_comp_max[i];
n &= mx;
const uint32 h = static_cast<uint32>(color_quad_type::component_traits::cMax);
if (color_quad_type::component_traits::cFloat)
color.set_component(i, static_cast<typename color_quad_type::parameter_t>(n));
else if (rescale)
color.set_component(i, static_cast<typename color_quad_type::parameter_t>( (static_cast<uint64>(n) * h + (mx >> 1U)) / mx ) );
else if (color_quad_type::component_traits::cSigned)
color.set_component(i, static_cast<typename color_quad_type::parameter_t>(math::minimum<uint32>(n, h)));
else
color.set_component(i, static_cast<typename color_quad_type::parameter_t>(n));
}
if (m_rgb_is_luma)
{
color[0] = color[1];
color[2] = color[1];
}
return pSrc + m_pixel_stride;
}
template<typename color_quad_type>
void* pack(const color_quad_type& color, void* p, bool rescale = true) const
{
uint8* pDst = static_cast<uint8*>(p);
for (uint i = 0; i < 4; i++)
{
const uint comp_size = m_comp_size[i];
if (!comp_size)
continue;
uint32 mx = m_comp_max[i];
uint32 n;
if (color_quad_type::component_traits::cFloat)
{
typename color_quad_type::parameter_t t = color[i];
if (t < 0.0f)
n = 0;
else if (t > static_cast<typename color_quad_type::parameter_t>(mx))
n = mx;
else
n = math::minimum<uint32>(static_cast<uint32>(floor(t + .5f)), mx);
}
else if (rescale)
{
if (color_quad_type::component_traits::cSigned)
n = math::maximum<int>(static_cast<int>(color[i]), 0);
else
n = static_cast<uint32>(color[i]);
const uint32 h = static_cast<uint32>(color_quad_type::component_traits::cMax);
n = static_cast<uint32>((static_cast<uint64>(n) * mx + (h >> 1)) / h);
}
else
{
if (color_quad_type::component_traits::cSigned)
n = math::minimum<uint32>(static_cast<uint32>(math::maximum<int>(static_cast<int>(color[i]), 0)), mx);
else
n = math::minimum<uint32>(static_cast<uint32>(color[i]), mx);
}
uint src_bit_ofs = 0;
uint dst_bit_ofs = m_comp_ofs[i];
while (src_bit_ofs < comp_size)
{
const uint cur_byte_bit_ofs = (dst_bit_ofs & 7);
const uint cur_byte_bits = 8 - cur_byte_bit_ofs;
uint byte_val = pDst[dst_bit_ofs >> 3];
uint bit_mask = (mx << cur_byte_bit_ofs) & 0xFF;
byte_val &= ~bit_mask;
byte_val |= (n << cur_byte_bit_ofs);
pDst[dst_bit_ofs >> 3] = static_cast<uint8>(byte_val);
mx >>= cur_byte_bits;
n >>= cur_byte_bits;
dst_bit_ofs += cur_byte_bits;
src_bit_ofs += cur_byte_bits;
}
}
return pDst + m_pixel_stride;
}
bool init(uint num_comps, uint bits_per_comp, int pixel_stride = -1, bool reversed = false)
{
clear();
if ((num_comps < 1) || (num_comps > 4) || (bits_per_comp < 1) || (bits_per_comp > 32))
{
CRNLIB_ASSERT(0);
return false;
}
for (uint i = 0; i < num_comps; i++)
{
m_comp_size[i] = bits_per_comp;
m_comp_ofs[i] = i * bits_per_comp;
if (reversed)
m_comp_ofs[i] = ((num_comps - 1) * bits_per_comp) - m_comp_ofs[i];
}
for (uint i = 0; i < 4; i++)
m_comp_max[i] = static_cast<uint32>((1ULL << m_comp_size[i]) - 1ULL);
m_pixel_stride = (pixel_stride >= 0) ? pixel_stride : (num_comps * bits_per_comp + 7) / 8;
return true;
}
// Format examples:
// R16G16B16
// B5G6R5
// B5G5R5x1
// Y8A8
// A8R8G8B8
// First component is at LSB in memory. Assumes unsigned integer components, 1-32bits each.
bool init(const char* pComp_map, int pixel_stride = -1, int force_comp_size = -1)
{
clear();
uint cur_bit_ofs = 0;
while (*pComp_map)
{
char c = *pComp_map++;
int comp_index = -1;
if (c == 'R')
comp_index = 0;
else if (c == 'G')
comp_index = 1;
else if (c == 'B')
comp_index = 2;
else if (c == 'A')
comp_index = 3;
else if (c == 'Y')
comp_index = 4;
else if (c != 'x')
return false;
uint comp_size = 0;
uint n = *pComp_map;
if ((n >= '0') && (n <= '9'))
{
comp_size = n - '0';
pComp_map++;
n = *pComp_map;
if ((n >= '0') && (n <= '9'))
{
comp_size = (comp_size * 10) + (n - '0');
pComp_map++;
}
}
if (force_comp_size != -1)
comp_size = force_comp_size;
if ((!comp_size) || (comp_size > 32))
return false;
if (comp_index == 4)
{
if (m_comp_size[0] || m_comp_size[1] || m_comp_size[2])
return false;
//m_comp_ofs[0] = m_comp_ofs[1] = m_comp_ofs[2] = cur_bit_ofs;
//m_comp_size[0] = m_comp_size[1] = m_comp_size[2] = comp_size;
m_comp_ofs[1] = cur_bit_ofs;
m_comp_size[1] = comp_size;
m_rgb_is_luma = true;
m_num_comps++;
}
else if (comp_index >= 0)
{
if (m_comp_size[comp_index])
return false;
m_comp_ofs[comp_index] = cur_bit_ofs;
m_comp_size[comp_index] = comp_size;
m_num_comps++;
}
cur_bit_ofs += comp_size;
}
for (uint i = 0; i < 4; i++)
m_comp_max[i] = static_cast<uint32>((1ULL << m_comp_size[i]) - 1ULL);
if (pixel_stride >= 0)
m_pixel_stride = pixel_stride;
else
m_pixel_stride = (cur_bit_ofs + 7) / 8;
return true;
}
private:
uint m_pixel_stride;
uint m_num_comps;
uint m_comp_size[4];
uint m_comp_ofs[4];
uint m_comp_max[4];
bool m_rgb_is_luma;
};
} // namespace crnlib