basis_universal: Update to upstream commit from Apr 16, 2021
BinomialLLC/basis_universal@ba1c3e40f1.
This commit is contained in:
parent
8976594f4b
commit
2d133177e9
74 changed files with 36770 additions and 9225 deletions
152
thirdparty/basis_universal/transcoder/basisu.h
vendored
152
thirdparty/basis_universal/transcoder/basisu.h
vendored
|
|
@ -1,5 +1,5 @@
|
|||
// basisu.h
|
||||
// Copyright (C) 2019 Binomial LLC. All Rights Reserved.
|
||||
// Copyright (C) 2019-2021 Binomial LLC. All Rights Reserved.
|
||||
// Important: If compiling with gcc, be sure strict aliasing is disabled: -fno-strict-aliasing
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
|
|
@ -41,10 +41,6 @@
|
|||
#endif
|
||||
#endif // defined(_DEBUG) || defined(DEBUG)
|
||||
|
||||
#ifndef NOMINMAX
|
||||
#define NOMINMAX
|
||||
#endif
|
||||
|
||||
#endif // BASISU_NO_ITERATOR_DEBUG_LEVEL
|
||||
|
||||
#endif // _MSC_VER
|
||||
|
|
@ -63,10 +59,11 @@
|
|||
#include <functional>
|
||||
#include <iterator>
|
||||
#include <type_traits>
|
||||
#include <vector>
|
||||
#include <assert.h>
|
||||
#include <random>
|
||||
|
||||
#include "basisu_containers.h"
|
||||
|
||||
#ifdef max
|
||||
#undef max
|
||||
#endif
|
||||
|
|
@ -79,20 +76,20 @@
|
|||
#define strcasecmp _stricmp
|
||||
#endif
|
||||
|
||||
// Set to one to enable debug printf()'s when any errors occur, for development/debugging.
|
||||
#ifndef BASISU_DEVEL_MESSAGES
|
||||
#define BASISU_DEVEL_MESSAGES 0
|
||||
// Set to one to enable debug printf()'s when any errors occur, for development/debugging. Especially useful for WebGL development.
|
||||
#ifndef BASISU_FORCE_DEVEL_MESSAGES
|
||||
#define BASISU_FORCE_DEVEL_MESSAGES 0
|
||||
#endif
|
||||
|
||||
#define BASISU_NOTE_UNUSED(x) (void)(x)
|
||||
#define BASISU_ARRAY_SIZE(x) (sizeof(x) / sizeof(x[0]))
|
||||
#define BASISU_NO_EQUALS_OR_COPY_CONSTRUCT(x) x(const x &) = delete; x& operator= (const x &) = delete;
|
||||
#define BASISU_ASSUME(x) static_assert(x, #x);
|
||||
#define BASISU_OFFSETOF(s, m) (uint32_t)(intptr_t)(&((s *)(0))->m)
|
||||
#define BASISU_OFFSETOF(s, m) offsetof(s, m)
|
||||
#define BASISU_STRINGIZE(x) #x
|
||||
#define BASISU_STRINGIZE2(x) BASISU_STRINGIZE(x)
|
||||
|
||||
#if BASISU_DEVEL_MESSAGES
|
||||
#if BASISU_FORCE_DEVEL_MESSAGES
|
||||
#define BASISU_DEVEL_ERROR(...) do { basisu::debug_printf(__VA_ARGS__); } while(0)
|
||||
#else
|
||||
#define BASISU_DEVEL_ERROR(...)
|
||||
|
|
@ -108,26 +105,43 @@ namespace basisu
|
|||
const char BASISU_PATH_SEPERATOR_CHAR = '/';
|
||||
#endif
|
||||
|
||||
typedef std::vector<uint8_t> uint8_vec;
|
||||
typedef std::vector<int16_t> int16_vec;
|
||||
typedef std::vector<uint16_t> uint16_vec;
|
||||
typedef std::vector<uint32_t> uint_vec;
|
||||
typedef std::vector<uint64_t> uint64_vec;
|
||||
typedef std::vector<int> int_vec;
|
||||
typedef std::vector<bool> bool_vec;
|
||||
typedef basisu::vector<uint8_t> uint8_vec;
|
||||
typedef basisu::vector<int16_t> int16_vec;
|
||||
typedef basisu::vector<uint16_t> uint16_vec;
|
||||
typedef basisu::vector<uint32_t> uint_vec;
|
||||
typedef basisu::vector<uint64_t> uint64_vec;
|
||||
typedef basisu::vector<int> int_vec;
|
||||
typedef basisu::vector<bool> bool_vec;
|
||||
|
||||
void enable_debug_printf(bool enabled);
|
||||
void debug_printf(const char *pFmt, ...);
|
||||
|
||||
|
||||
template <typename T> inline void clear_obj(T& obj) { memset(&obj, 0, sizeof(obj)); }
|
||||
|
||||
template <typename T0, typename T1> inline T0 lerp(T0 a, T0 b, T1 c) { return a + (b - a) * c; }
|
||||
|
||||
template <typename S> inline S maximum(S a, S b) { return (a > b) ? a : b; }
|
||||
template <typename S> inline S maximum(S a, S b, S c) { return maximum(maximum(a, b), c); }
|
||||
template <typename S> inline S maximum(S a, S b, S c, S d) { return maximum(maximum(maximum(a, b), c), d); }
|
||||
|
||||
template <typename S> inline S minimum(S a, S b) { return (a < b) ? a : b; }
|
||||
template <typename S> inline S minimum(S a, S b, S c) { return minimum(minimum(a, b), c); }
|
||||
template <typename S> inline S minimum(S a, S b, S c, S d) { return minimum(minimum(minimum(a, b), c), d); }
|
||||
|
||||
inline float clampf(float value, float low, float high) { if (value < low) value = low; else if (value > high) value = high; return value; }
|
||||
inline float saturate(float value) { return clampf(value, 0, 1.0f); }
|
||||
inline uint8_t minimumub(uint8_t a, uint8_t b) { return (a < b) ? a : b; }
|
||||
inline uint32_t minimumu(uint32_t a, uint32_t b) { return (a < b) ? a : b; }
|
||||
inline int32_t minimumi(int32_t a, int32_t b) { return (a < b) ? a : b; }
|
||||
inline float minimumf(float a, float b) { return (a < b) ? a : b; }
|
||||
inline uint8_t maximumub(uint8_t a, uint8_t b) { return (a > b) ? a : b; }
|
||||
inline uint32_t maximumu(uint32_t a, uint32_t b) { return (a > b) ? a : b; }
|
||||
inline int32_t maximumi(int32_t a, int32_t b) { return (a > b) ? a : b; }
|
||||
inline float maximumf(float a, float b) { return (a > b) ? a : b; }
|
||||
inline int squarei(int i) { return i * i; }
|
||||
inline float squaref(float i) { return i * i; }
|
||||
template<typename T> inline T square(T a) { return a * a; }
|
||||
|
||||
template <typename S> inline S clamp(S value, S low, S high) { return (value < low) ? low : ((value > high) ? high : value); }
|
||||
|
||||
|
|
@ -137,12 +151,10 @@ namespace basisu
|
|||
template<typename T> inline void clear_vector(T &vec) { vec.erase(vec.begin(), vec.end()); }
|
||||
template<typename T> inline typename T::value_type *enlarge_vector(T &vec, size_t n) { size_t cs = vec.size(); vec.resize(cs + n); return &vec[cs]; }
|
||||
|
||||
template<typename S> inline S square(S val) { return val * val; }
|
||||
|
||||
inline bool is_pow2(uint32_t x) { return x && ((x & (x - 1U)) == 0U); }
|
||||
inline bool is_pow2(uint64_t x) { return x && ((x & (x - 1U)) == 0U); }
|
||||
|
||||
template<typename T> inline T open_range_check(T v, T minv, T maxv) { assert(v >= minv && v < maxv); return v; }
|
||||
template<typename T> inline T open_range_check(T v, T minv, T maxv) { assert(v >= minv && v < maxv); BASISU_NOTE_UNUSED(minv); BASISU_NOTE_UNUSED(maxv); return v; }
|
||||
template<typename T> inline T open_range_check(T v, T maxv) { assert(v < maxv); BASISU_NOTE_UNUSED(maxv); return v; }
|
||||
|
||||
inline uint32_t total_bits(uint32_t v) { uint32_t l = 0; for ( ; v > 0U; ++l) v >>= 1; return l; }
|
||||
|
|
@ -244,27 +256,92 @@ namespace basisu
|
|||
if ((ha <= lb) || (la >= hb)) return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
static inline uint32_t read_le_dword(const uint8_t *pBytes)
|
||||
{
|
||||
return (pBytes[3] << 24U) | (pBytes[2] << 16U) | (pBytes[1] << 8U) | (pBytes[0]);
|
||||
}
|
||||
|
||||
static inline void write_le_dword(uint8_t* pBytes, uint32_t val)
|
||||
{
|
||||
pBytes[0] = (uint8_t)val;
|
||||
pBytes[1] = (uint8_t)(val >> 8U);
|
||||
pBytes[2] = (uint8_t)(val >> 16U);
|
||||
pBytes[3] = (uint8_t)(val >> 24U);
|
||||
}
|
||||
|
||||
// Always little endian 2-4 byte unsigned int
|
||||
// Always little endian 1-8 byte unsigned int
|
||||
template<uint32_t NumBytes>
|
||||
struct packed_uint
|
||||
{
|
||||
uint8_t m_bytes[NumBytes];
|
||||
|
||||
inline packed_uint() { static_assert(NumBytes <= 4, "NumBytes <= 4"); }
|
||||
inline packed_uint(uint32_t v) { *this = v; }
|
||||
inline packed_uint() { static_assert(NumBytes <= sizeof(uint64_t), "Invalid NumBytes"); }
|
||||
inline packed_uint(uint64_t v) { *this = v; }
|
||||
inline packed_uint(const packed_uint& other) { *this = other; }
|
||||
|
||||
inline packed_uint& operator= (uint64_t v)
|
||||
{
|
||||
for (uint32_t i = 0; i < NumBytes; i++)
|
||||
m_bytes[i] = static_cast<uint8_t>(v >> (i * 8));
|
||||
return *this;
|
||||
}
|
||||
|
||||
inline packed_uint& operator= (uint32_t v) { for (uint32_t i = 0; i < NumBytes; i++) m_bytes[i] = static_cast<uint8_t>(v >> (i * 8)); return *this; }
|
||||
inline packed_uint& operator= (const packed_uint& rhs)
|
||||
{
|
||||
memcpy(m_bytes, rhs.m_bytes, sizeof(m_bytes));
|
||||
return *this;
|
||||
}
|
||||
|
||||
inline operator uint32_t() const
|
||||
{
|
||||
switch (NumBytes)
|
||||
{
|
||||
case 1: return m_bytes[0];
|
||||
case 2: return (m_bytes[1] << 8U) | m_bytes[0];
|
||||
case 3: return (m_bytes[2] << 16U) | (m_bytes[1] << 8U) | (m_bytes[0]);
|
||||
default: return (m_bytes[3] << 24U) | (m_bytes[2] << 16U) | (m_bytes[1] << 8U) | (m_bytes[0]);
|
||||
case 1:
|
||||
{
|
||||
return m_bytes[0];
|
||||
}
|
||||
case 2:
|
||||
{
|
||||
return (m_bytes[1] << 8U) | m_bytes[0];
|
||||
}
|
||||
case 3:
|
||||
{
|
||||
return (m_bytes[2] << 16U) | (m_bytes[1] << 8U) | m_bytes[0];
|
||||
}
|
||||
case 4:
|
||||
{
|
||||
return read_le_dword(m_bytes);
|
||||
}
|
||||
case 5:
|
||||
{
|
||||
uint32_t l = read_le_dword(m_bytes);
|
||||
uint32_t h = m_bytes[4];
|
||||
return static_cast<uint64_t>(l) | (static_cast<uint64_t>(h) << 32U);
|
||||
}
|
||||
case 6:
|
||||
{
|
||||
uint32_t l = read_le_dword(m_bytes);
|
||||
uint32_t h = (m_bytes[5] << 8U) | m_bytes[4];
|
||||
return static_cast<uint64_t>(l) | (static_cast<uint64_t>(h) << 32U);
|
||||
}
|
||||
case 7:
|
||||
{
|
||||
uint32_t l = read_le_dword(m_bytes);
|
||||
uint32_t h = (m_bytes[6] << 16U) | (m_bytes[5] << 8U) | m_bytes[4];
|
||||
return static_cast<uint64_t>(l) | (static_cast<uint64_t>(h) << 32U);
|
||||
}
|
||||
case 8:
|
||||
{
|
||||
uint32_t l = read_le_dword(m_bytes);
|
||||
uint32_t h = read_le_dword(m_bytes + 4);
|
||||
return static_cast<uint64_t>(l) | (static_cast<uint64_t>(h) << 32U);
|
||||
}
|
||||
default:
|
||||
{
|
||||
assert(0);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
|
@ -278,7 +355,7 @@ namespace basisu
|
|||
enum
|
||||
{
|
||||
cHuffmanMaxSupportedCodeSize = 16, cHuffmanMaxSupportedInternalCodeSize = 31,
|
||||
cHuffmanFastLookupBits = 10, cHuffmanFastLookupSize = 1 << cHuffmanFastLookupBits,
|
||||
cHuffmanFastLookupBits = 10,
|
||||
cHuffmanMaxSymsLog2 = 14, cHuffmanMaxSyms = 1 << cHuffmanMaxSymsLog2,
|
||||
|
||||
// Small zero runs
|
||||
|
|
@ -308,15 +385,15 @@ namespace basisu
|
|||
// Block-based formats
|
||||
cETC1, // ETC1
|
||||
cETC1S, // ETC1 (subset: diff colors only, no subblocks)
|
||||
cETC2_RGB, // ETC2 color block
|
||||
cETC2_RGBA, // ETC2 alpha block followed by ETC2 color block
|
||||
cETC2_RGB, // ETC2 color block (basisu doesn't support ETC2 planar/T/H modes - just basic ETC1)
|
||||
cETC2_RGBA, // ETC2 EAC alpha block followed by ETC2 color block
|
||||
cETC2_ALPHA, // ETC2 EAC alpha block
|
||||
cBC1, // DXT1
|
||||
cBC3, // DXT5 (DXT5A block followed by a DXT1 block)
|
||||
cBC3, // DXT5 (BC4/DXT5A block followed by a BC1/DXT1 block)
|
||||
cBC4, // DXT5A
|
||||
cBC5, // 3DC/DXN (two DXT5A blocks)
|
||||
cBC5, // 3DC/DXN (two BC4/DXT5A blocks)
|
||||
cBC7,
|
||||
cASTC4x4,
|
||||
cASTC4x4, // LDR only
|
||||
cPVRTC1_4_RGB,
|
||||
cPVRTC1_4_RGBA,
|
||||
cATC_RGB,
|
||||
|
|
@ -325,6 +402,9 @@ namespace basisu
|
|||
cPVRTC2_4_RGBA,
|
||||
cETC2_R11_EAC,
|
||||
cETC2_RG11_EAC,
|
||||
cUASTC4x4,
|
||||
cBC1_NV,
|
||||
cBC1_AMD,
|
||||
|
||||
// Uncompressed/raw pixels
|
||||
cRGBA32,
|
||||
|
|
@ -343,6 +423,8 @@ namespace basisu
|
|||
case texture_format::cETC2_RGB:
|
||||
case texture_format::cETC2_ALPHA:
|
||||
case texture_format::cBC1:
|
||||
case texture_format::cBC1_NV:
|
||||
case texture_format::cBC1_AMD:
|
||||
case texture_format::cBC4:
|
||||
case texture_format::cPVRTC1_4_RGB:
|
||||
case texture_format::cPVRTC1_4_RGBA:
|
||||
|
|
|
|||
1908
thirdparty/basis_universal/transcoder/basisu_containers.h
vendored
Normal file
1908
thirdparty/basis_universal/transcoder/basisu_containers.h
vendored
Normal file
File diff suppressed because it is too large
Load diff
311
thirdparty/basis_universal/transcoder/basisu_containers_impl.h
vendored
Normal file
311
thirdparty/basis_universal/transcoder/basisu_containers_impl.h
vendored
Normal file
|
|
@ -0,0 +1,311 @@
|
|||
// basisu_containers_impl.h
|
||||
// Do not include directly
|
||||
|
||||
#ifdef _MSC_VER
|
||||
#pragma warning (disable:4127) // warning C4127: conditional expression is constant
|
||||
#endif
|
||||
|
||||
namespace basisu
|
||||
{
|
||||
bool elemental_vector::increase_capacity(uint32_t min_new_capacity, bool grow_hint, uint32_t element_size, object_mover pMover, bool nofail)
|
||||
{
|
||||
assert(m_size <= m_capacity);
|
||||
|
||||
if (sizeof(void *) == sizeof(uint64_t))
|
||||
assert(min_new_capacity < (0x400000000ULL / element_size));
|
||||
else
|
||||
assert(min_new_capacity < (0x7FFF0000U / element_size));
|
||||
|
||||
if (m_capacity >= min_new_capacity)
|
||||
return true;
|
||||
|
||||
size_t new_capacity = min_new_capacity;
|
||||
if ((grow_hint) && (!helpers::is_power_of_2((uint64_t)new_capacity)))
|
||||
{
|
||||
new_capacity = (size_t)helpers::next_pow2((uint64_t)new_capacity);
|
||||
|
||||
assert(new_capacity && (new_capacity > m_capacity));
|
||||
|
||||
if (new_capacity < min_new_capacity)
|
||||
{
|
||||
if (nofail)
|
||||
return false;
|
||||
fprintf(stderr, "vector too large\n");
|
||||
abort();
|
||||
}
|
||||
}
|
||||
|
||||
const size_t desired_size = element_size * new_capacity;
|
||||
size_t actual_size = 0;
|
||||
if (!pMover)
|
||||
{
|
||||
void* new_p = realloc(m_p, desired_size);
|
||||
if (!new_p)
|
||||
{
|
||||
if (nofail)
|
||||
return false;
|
||||
|
||||
char buf[256];
|
||||
#ifdef _MSC_VER
|
||||
sprintf_s(buf, sizeof(buf), "vector: realloc() failed allocating %u bytes", (uint32_t)desired_size);
|
||||
#else
|
||||
sprintf(buf, "vector: realloc() failed allocating %u bytes", (uint32_t)desired_size);
|
||||
#endif
|
||||
fprintf(stderr, "%s", buf);
|
||||
abort();
|
||||
}
|
||||
|
||||
#ifdef _MSC_VER
|
||||
actual_size = _msize(new_p);
|
||||
#elif HAS_MALLOC_USABLE_SIZE
|
||||
actual_size = malloc_usable_size(new_p);
|
||||
#else
|
||||
actual_size = desired_size;
|
||||
#endif
|
||||
m_p = new_p;
|
||||
}
|
||||
else
|
||||
{
|
||||
void* new_p = malloc(desired_size);
|
||||
if (!new_p)
|
||||
{
|
||||
if (nofail)
|
||||
return false;
|
||||
|
||||
char buf[256];
|
||||
#ifdef _MSC_VER
|
||||
sprintf_s(buf, sizeof(buf), "vector: malloc() failed allocating %u bytes", (uint32_t)desired_size);
|
||||
#else
|
||||
sprintf(buf, "vector: malloc() failed allocating %u bytes", (uint32_t)desired_size);
|
||||
#endif
|
||||
fprintf(stderr, "%s", buf);
|
||||
abort();
|
||||
}
|
||||
|
||||
#ifdef _MSC_VER
|
||||
actual_size = _msize(new_p);
|
||||
#elif HAS_MALLOC_USABLE_SIZE
|
||||
actual_size = malloc_usable_size(new_p);
|
||||
#else
|
||||
actual_size = desired_size;
|
||||
#endif
|
||||
|
||||
(*pMover)(new_p, m_p, m_size);
|
||||
|
||||
if (m_p)
|
||||
free(m_p);
|
||||
|
||||
m_p = new_p;
|
||||
}
|
||||
|
||||
if (actual_size > desired_size)
|
||||
m_capacity = static_cast<uint32_t>(actual_size / element_size);
|
||||
else
|
||||
m_capacity = static_cast<uint32_t>(new_capacity);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
#if BASISU_HASHMAP_TEST
|
||||
|
||||
#define HASHMAP_TEST_VERIFY(c) do { if (!(c)) handle_hashmap_test_verify_failure(__LINE__); } while(0)
|
||||
|
||||
static void handle_hashmap_test_verify_failure(int line)
|
||||
{
|
||||
fprintf(stderr, "HASHMAP_TEST_VERIFY() faild on line %i\n", line);
|
||||
abort();
|
||||
}
|
||||
|
||||
class counted_obj
|
||||
{
|
||||
public:
|
||||
counted_obj(uint32_t v = 0) :
|
||||
m_val(v)
|
||||
{
|
||||
m_count++;
|
||||
}
|
||||
|
||||
counted_obj(const counted_obj& obj) :
|
||||
m_val(obj.m_val)
|
||||
{
|
||||
m_count++;
|
||||
}
|
||||
|
||||
~counted_obj()
|
||||
{
|
||||
assert(m_count > 0);
|
||||
m_count--;
|
||||
}
|
||||
|
||||
static uint32_t m_count;
|
||||
|
||||
uint32_t m_val;
|
||||
|
||||
operator size_t() const { return m_val; }
|
||||
|
||||
bool operator== (const counted_obj& rhs) const { return m_val == rhs.m_val; }
|
||||
bool operator== (const uint32_t rhs) const { return m_val == rhs; }
|
||||
|
||||
};
|
||||
|
||||
uint32_t counted_obj::m_count;
|
||||
|
||||
static uint32_t urand32()
|
||||
{
|
||||
uint32_t a = rand();
|
||||
uint32_t b = rand() << 15;
|
||||
uint32_t c = rand() << (32 - 15);
|
||||
return a ^ b ^ c;
|
||||
}
|
||||
|
||||
static int irand32(int l, int h)
|
||||
{
|
||||
assert(l < h);
|
||||
if (l >= h)
|
||||
return l;
|
||||
|
||||
uint32_t range = static_cast<uint32_t>(h - l);
|
||||
|
||||
uint32_t rnd = urand32();
|
||||
|
||||
uint32_t rnd_range = static_cast<uint32_t>((((uint64_t)range) * ((uint64_t)rnd)) >> 32U);
|
||||
|
||||
int result = l + rnd_range;
|
||||
assert((result >= l) && (result < h));
|
||||
return result;
|
||||
}
|
||||
|
||||
void hash_map_test()
|
||||
{
|
||||
{
|
||||
basisu::hash_map<uint64_t, uint64_t> k;
|
||||
basisu::hash_map<uint64_t, uint64_t> l;
|
||||
std::swap(k, l);
|
||||
|
||||
k.begin();
|
||||
k.end();
|
||||
k.clear();
|
||||
k.empty();
|
||||
k.erase(0);
|
||||
k.insert(0, 1);
|
||||
k.find(0);
|
||||
k.get_equals();
|
||||
k.get_hasher();
|
||||
k.get_table_size();
|
||||
k.reset();
|
||||
k.reserve(1);
|
||||
k = l;
|
||||
k.set_equals(l.get_equals());
|
||||
k.set_hasher(l.get_hasher());
|
||||
k.get_table_size();
|
||||
}
|
||||
|
||||
uint32_t seed = 0;
|
||||
for (; ; )
|
||||
{
|
||||
seed++;
|
||||
|
||||
typedef basisu::hash_map<counted_obj, counted_obj> my_hash_map;
|
||||
my_hash_map m;
|
||||
|
||||
const uint32_t n = irand32(0, 100000);
|
||||
|
||||
printf("%u\n", n);
|
||||
|
||||
srand(seed); // r1.seed(seed);
|
||||
|
||||
basisu::vector<int> q;
|
||||
|
||||
uint32_t count = 0;
|
||||
for (uint32_t i = 0; i < n; i++)
|
||||
{
|
||||
uint32_t v = urand32() & 0x7FFFFFFF;
|
||||
my_hash_map::insert_result res = m.insert(counted_obj(v), counted_obj(v ^ 0xdeadbeef));
|
||||
if (res.second)
|
||||
{
|
||||
count++;
|
||||
q.push_back(v);
|
||||
}
|
||||
}
|
||||
|
||||
HASHMAP_TEST_VERIFY(m.size() == count);
|
||||
|
||||
srand(seed);
|
||||
|
||||
my_hash_map cm(m);
|
||||
m.clear();
|
||||
m = cm;
|
||||
cm.reset();
|
||||
|
||||
for (uint32_t i = 0; i < n; i++)
|
||||
{
|
||||
uint32_t v = urand32() & 0x7FFFFFFF;
|
||||
my_hash_map::const_iterator it = m.find(counted_obj(v));
|
||||
HASHMAP_TEST_VERIFY(it != m.end());
|
||||
HASHMAP_TEST_VERIFY(it->first == v);
|
||||
HASHMAP_TEST_VERIFY(it->second == (v ^ 0xdeadbeef));
|
||||
}
|
||||
|
||||
for (uint32_t t = 0; t < 2; t++)
|
||||
{
|
||||
const uint32_t nd = irand32(1, q.size() + 1);
|
||||
for (uint32_t i = 0; i < nd; i++)
|
||||
{
|
||||
uint32_t p = irand32(0, q.size());
|
||||
|
||||
int k = q[p];
|
||||
if (k >= 0)
|
||||
{
|
||||
q[p] = -k - 1;
|
||||
|
||||
bool s = m.erase(counted_obj(k));
|
||||
HASHMAP_TEST_VERIFY(s);
|
||||
}
|
||||
}
|
||||
|
||||
typedef basisu::hash_map<uint32_t, empty_type> uint_hash_set;
|
||||
uint_hash_set s;
|
||||
|
||||
for (uint32_t i = 0; i < q.size(); i++)
|
||||
{
|
||||
int v = q[i];
|
||||
|
||||
if (v >= 0)
|
||||
{
|
||||
my_hash_map::const_iterator it = m.find(counted_obj(v));
|
||||
HASHMAP_TEST_VERIFY(it != m.end());
|
||||
HASHMAP_TEST_VERIFY(it->first == (uint32_t)v);
|
||||
HASHMAP_TEST_VERIFY(it->second == ((uint32_t)v ^ 0xdeadbeef));
|
||||
|
||||
s.insert(v);
|
||||
}
|
||||
else
|
||||
{
|
||||
my_hash_map::const_iterator it = m.find(counted_obj(-v - 1));
|
||||
HASHMAP_TEST_VERIFY(it == m.end());
|
||||
}
|
||||
}
|
||||
|
||||
uint32_t found_count = 0;
|
||||
for (my_hash_map::const_iterator it = m.begin(); it != m.end(); ++it)
|
||||
{
|
||||
HASHMAP_TEST_VERIFY(it->second == ((uint32_t)it->first ^ 0xdeadbeef));
|
||||
|
||||
uint_hash_set::const_iterator fit(s.find((uint32_t)it->first));
|
||||
HASHMAP_TEST_VERIFY(fit != s.end());
|
||||
|
||||
HASHMAP_TEST_VERIFY(fit->first == it->first);
|
||||
|
||||
found_count++;
|
||||
}
|
||||
|
||||
HASHMAP_TEST_VERIFY(found_count == s.size());
|
||||
}
|
||||
|
||||
HASHMAP_TEST_VERIFY(counted_obj::m_count == m.size() * 2);
|
||||
}
|
||||
}
|
||||
|
||||
#endif // BASISU_HASHMAP_TEST
|
||||
|
||||
} // namespace basisu
|
||||
|
|
@ -1,5 +1,5 @@
|
|||
// basis_file_headers.h
|
||||
// Copyright (C) 2019 Binomial LLC. All Rights Reserved.
|
||||
// Copyright (C) 2019-2020 Binomial LLC. All Rights Reserved.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
|
|
@ -20,8 +20,11 @@ namespace basist
|
|||
// Slice desc header flags
|
||||
enum basis_slice_desc_flags
|
||||
{
|
||||
cSliceDescFlagsIsAlphaData = 1,
|
||||
cSliceDescFlagsFrameIsIFrame = 2 // Video only: Frame doesn't refer to previous frame (no usage of conditional replenishment pred symbols)
|
||||
cSliceDescFlagsHasAlpha = 1,
|
||||
|
||||
// Video only: Frame doesn't refer to previous frame (no usage of conditional replenishment pred symbols)
|
||||
// Currently the first frame is always an I-Frame, all subsequent frames are P-Frames. This will eventually be changed to periodic I-Frames.
|
||||
cSliceDescFlagsFrameIsIFrame = 2
|
||||
};
|
||||
|
||||
#pragma pack(push)
|
||||
|
|
@ -38,7 +41,7 @@ namespace basist
|
|||
basisu::packed_uint<2> m_num_blocks_x; // The slice's block X dimensions. Each block is 4x4 pixels. The slice's pixel resolution may or may not be a power of 2.
|
||||
basisu::packed_uint<2> m_num_blocks_y; // The slice's block Y dimensions.
|
||||
|
||||
basisu::packed_uint<4> m_file_ofs; // Offset from the header to the start of the slice's data
|
||||
basisu::packed_uint<4> m_file_ofs; // Offset from the start of the file to the start of the slice's data
|
||||
basisu::packed_uint<4> m_file_size; // The size of the compressed slice data in bytes
|
||||
|
||||
basisu::packed_uint<2> m_slice_data_crc16; // The CRC16 of the compressed slice data, for extra-paranoid use cases
|
||||
|
|
@ -47,9 +50,21 @@ namespace basist
|
|||
// File header files
|
||||
enum basis_header_flags
|
||||
{
|
||||
cBASISHeaderFlagETC1S = 1, // Always set for basis universal files
|
||||
cBASISHeaderFlagYFlipped = 2, // Set if the texture had to be Y flipped before encoding
|
||||
cBASISHeaderFlagHasAlphaSlices = 4 // True if the odd slices contain alpha data
|
||||
// Always set for ETC1S files. Not set for UASTC files.
|
||||
cBASISHeaderFlagETC1S = 1,
|
||||
|
||||
// Set if the texture had to be Y flipped before encoding. The actual interpretation of this (is Y up or down?) is up to the user.
|
||||
cBASISHeaderFlagYFlipped = 2,
|
||||
|
||||
// Set if any slices contain alpha (for ETC1S, if the odd slices contain alpha data)
|
||||
cBASISHeaderFlagHasAlphaSlices = 4,
|
||||
|
||||
// For ETC1S files, this will be true if the file utilizes a codebook from another .basis file.
|
||||
cBASISHeaderFlagUsesGlobalCodebook = 8,
|
||||
|
||||
// Set if the texture data is sRGB, otherwise it's linear.
|
||||
// In reality, we have no idea if the texture data is actually linear or sRGB. This is the m_perceptual parameter passed to the compressor.
|
||||
cBASISHeaderFlagSRGB = 16,
|
||||
};
|
||||
|
||||
// The image type field attempts to describe how to interpret the image data in a Basis file.
|
||||
|
|
@ -71,6 +86,12 @@ namespace basist
|
|||
cBASISMaxUSPerFrame = 0xFFFFFF
|
||||
};
|
||||
|
||||
enum class basis_tex_format
|
||||
{
|
||||
cETC1S = 0,
|
||||
cUASTC4x4 = 1
|
||||
};
|
||||
|
||||
struct basis_file_header
|
||||
{
|
||||
enum
|
||||
|
|
@ -82,16 +103,16 @@ namespace basist
|
|||
basisu::packed_uint<2> m_sig; // 2 byte file signature
|
||||
basisu::packed_uint<2> m_ver; // Baseline file version
|
||||
basisu::packed_uint<2> m_header_size; // Header size in bytes, sizeof(basis_file_header)
|
||||
basisu::packed_uint<2> m_header_crc16; // crc16 of the remaining header data
|
||||
basisu::packed_uint<2> m_header_crc16; // CRC16 of the remaining header data
|
||||
|
||||
basisu::packed_uint<4> m_data_size; // The total size of all data after the header
|
||||
basisu::packed_uint<2> m_data_crc16; // The CRC16 of all data after the header
|
||||
|
||||
basisu::packed_uint<3> m_total_slices; // The total # of compressed slices (1 slice per image, or 2 for alpha basis files)
|
||||
basisu::packed_uint<3> m_total_slices; // The total # of compressed slices (1 slice per image, or 2 for alpha .basis files)
|
||||
|
||||
basisu::packed_uint<3> m_total_images; // The total # of images
|
||||
|
||||
basisu::packed_uint<1> m_format; // enum basist::block_format
|
||||
basisu::packed_uint<1> m_tex_format; // enum basis_tex_format
|
||||
basisu::packed_uint<2> m_flags; // enum basist::header_flags
|
||||
basisu::packed_uint<1> m_tex_type; // enum basist::basis_texture_type
|
||||
basisu::packed_uint<3> m_us_per_frame; // Framerate of video, in microseconds per frame
|
||||
|
|
@ -101,11 +122,11 @@ namespace basist
|
|||
basisu::packed_uint<4> m_userdata1; // For client use
|
||||
|
||||
basisu::packed_uint<2> m_total_endpoints; // The number of endpoints in the endpoint codebook
|
||||
basisu::packed_uint<4> m_endpoint_cb_file_ofs; // The compressed endpoint codebook's file offset relative to the header
|
||||
basisu::packed_uint<4> m_endpoint_cb_file_ofs; // The compressed endpoint codebook's file offset relative to the start of the file
|
||||
basisu::packed_uint<3> m_endpoint_cb_file_size; // The compressed endpoint codebook's size in bytes
|
||||
|
||||
basisu::packed_uint<2> m_total_selectors; // The number of selectors in the endpoint codebook
|
||||
basisu::packed_uint<4> m_selector_cb_file_ofs; // The compressed selectors codebook's file offset relative to the header
|
||||
basisu::packed_uint<4> m_selector_cb_file_ofs; // The compressed selectors codebook's file offset relative to the start of the file
|
||||
basisu::packed_uint<3> m_selector_cb_file_size; // The compressed selector codebook's size in bytes
|
||||
|
||||
basisu::packed_uint<4> m_tables_file_ofs; // The file offset of the compressed Huffman codelength tables, for decompressing slices
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
// Copyright (C) 2019 Binomial LLC. All Rights Reserved.
|
||||
// Copyright (C) 2019-2020 Binomial LLC. All Rights Reserved.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
|
|
|
|||
|
|
@ -1,5 +1,7 @@
|
|||
// basisu_global_selector_palette.h
|
||||
// Copyright (C) 2019 Binomial LLC. All Rights Reserved.
|
||||
// Copyright (C) 2019-2021 Binomial LLC. All Rights Reserved.
|
||||
//
|
||||
// TODO: NONE of this is used in .basis/.ktx2 files. It will be deleted soon.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
|
|
@ -609,7 +611,7 @@ namespace basist
|
|||
uint8_t m_selectors[16];
|
||||
};
|
||||
|
||||
typedef std::vector<etc1_selector_palette_entry> etc1_selector_palette_entry_vec;
|
||||
typedef basisu::vector<etc1_selector_palette_entry> etc1_selector_palette_entry_vec;
|
||||
|
||||
extern const uint32_t g_global_selector_cb[];
|
||||
extern const uint32_t g_global_selector_cb_size;
|
||||
|
|
@ -628,7 +630,7 @@ namespace basist
|
|||
void set(uint32_t palette_index, const etc1_global_palette_entry_modifier &modifier) { m_palette_index = palette_index; m_modifier = modifier; }
|
||||
};
|
||||
|
||||
typedef std::vector<etc1_global_selector_codebook_entry_id> etc1_global_selector_codebook_entry_id_vec;
|
||||
typedef basisu::vector<etc1_global_selector_codebook_entry_id> etc1_global_selector_codebook_entry_id_vec;
|
||||
|
||||
class etc1_global_selector_codebook
|
||||
{
|
||||
|
|
|
|||
File diff suppressed because it is too large
Load diff
|
|
@ -1,5 +1,5 @@
|
|||
// basisu_transcoder.h
|
||||
// Copyright (C) 2019 Binomial LLC. All Rights Reserved.
|
||||
// Copyright (C) 2019-2021 Binomial LLC. All Rights Reserved.
|
||||
// Important: If compiling with gcc, be sure strict aliasing is disabled: -fno-strict-aliasing
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
|
|
@ -15,10 +15,25 @@
|
|||
// limitations under the License.
|
||||
#pragma once
|
||||
|
||||
// Set BASISU_DEVEL_MESSAGES to 1 to enable debug printf()'s whenever an error occurs, for easier debugging during development.
|
||||
//#define BASISU_DEVEL_MESSAGES 1
|
||||
// By default KTX2 support is enabled to simplify compilation. This implies the need for the Zstandard library (which we distribute as a single source file in the "zstd" directory) by default.
|
||||
// Set BASISD_SUPPORT_KTX2 to 0 to completely disable KTX2 support as well as Zstd/miniz usage which is only required for UASTC supercompression in KTX2 files.
|
||||
// Also see BASISD_SUPPORT_KTX2_ZSTD in basisu_transcoder.cpp, which individually disables Zstd usage.
|
||||
#ifndef BASISD_SUPPORT_KTX2
|
||||
#define BASISD_SUPPORT_KTX2 1
|
||||
#endif
|
||||
|
||||
// Set BASISD_SUPPORT_KTX2_ZSTD to 0 to disable Zstd usage and KTX2 UASTC Zstd supercompression support
|
||||
#ifndef BASISD_SUPPORT_KTX2_ZSTD
|
||||
#define BASISD_SUPPORT_KTX2_ZSTD 1
|
||||
#endif
|
||||
|
||||
// Set BASISU_FORCE_DEVEL_MESSAGES to 1 to enable debug printf()'s whenever an error occurs, for easier debugging during development.
|
||||
#ifndef BASISU_FORCE_DEVEL_MESSAGES
|
||||
#define BASISU_FORCE_DEVEL_MESSAGES 0
|
||||
#endif
|
||||
|
||||
#include "basisu_transcoder_internal.h"
|
||||
#include "basisu_transcoder_uastc.h"
|
||||
#include "basisu_global_selector_palette.h"
|
||||
#include "basisu_file_headers.h"
|
||||
|
||||
|
|
@ -45,12 +60,11 @@ namespace basist
|
|||
cTFBC3_RGBA = 3, // Opaque+alpha, BC4 followed by a BC1 block, alpha channel will be opaque for opaque .basis files
|
||||
cTFBC4_R = 4, // Red only, alpha slice is transcoded to output if cDecodeFlagsTranscodeAlphaDataToOpaqueFormats flag is specified
|
||||
cTFBC5_RG = 5, // XY: Two BC4 blocks, X=R and Y=Alpha, .basis file should have alpha data (if not Y will be all 255's)
|
||||
cTFBC7_M6_RGB = 6, // Opaque only, RGB or alpha if cDecodeFlagsTranscodeAlphaDataToOpaqueFormats flag is specified. Highest quality of all the non-ETC1 formats.
|
||||
cTFBC7_M5_RGBA = 7, // Opaque+alpha, alpha channel will be opaque for opaque .basis files
|
||||
cTFBC7_RGBA = 6, // RGB or RGBA, mode 5 for ETC1S, modes (1,2,3,5,6,7) for UASTC
|
||||
|
||||
// PVRTC1 4bpp (mobile, PowerVR devices)
|
||||
cTFPVRTC1_4_RGB = 8, // Opaque only, RGB or alpha if cDecodeFlagsTranscodeAlphaDataToOpaqueFormats flag is specified, nearly lowest quality of any texture format.
|
||||
cTFPVRTC1_4_RGBA = 9, // Opaque+alpha, most useful for simple opacity maps. If .basis file doens't have alpha cTFPVRTC1_4_RGB will be used instead. Lowest quality of any supported texture format.
|
||||
cTFPVRTC1_4_RGBA = 9, // Opaque+alpha, most useful for simple opacity maps. If .basis file doesn't have alpha cTFPVRTC1_4_RGB will be used instead. Lowest quality of any supported texture format.
|
||||
|
||||
// ASTC (mobile, Intel devices, hopefully all desktop GPU's one day)
|
||||
cTFASTC_4x4_RGBA = 10, // Opaque+alpha, ASTC 4x4, alpha channel will be opaque for opaque .basis files. Transcoder uses RGB/RGBA/L/LA modes, void extent, and up to two ([0,47] and [0,255]) endpoint precisions.
|
||||
|
|
@ -69,10 +83,10 @@ namespace basist
|
|||
|
||||
cTFETC2_EAC_R11 = 20, // R only (ETC2 EAC R11 unsigned)
|
||||
cTFETC2_EAC_RG11 = 21, // RG only (ETC2 EAC RG11 unsigned), R=opaque.r, G=alpha - for tangent space normal maps
|
||||
|
||||
|
||||
// Uncompressed (raw pixel) formats
|
||||
cTFRGBA32 = 13, // 32bpp RGBA image stored in raster (not block) order in memory, R is first byte, A is last byte.
|
||||
cTFRGB565 = 14, // 166pp RGB image stored in raster (not block) order in memory, R at bit position 11
|
||||
cTFRGB565 = 14, // 16bpp RGB image stored in raster (not block) order in memory, R at bit position 11
|
||||
cTFBGR565 = 15, // 16bpp RGB image stored in raster (not block) order in memory, R at bit position 0
|
||||
cTFRGBA4444 = 16, // 16bpp RGBA image stored in raster (not block) order in memory, R at bit position 12, A at bit position 0
|
||||
|
||||
|
|
@ -85,27 +99,62 @@ namespace basist
|
|||
cTFBC3 = cTFBC3_RGBA,
|
||||
cTFBC4 = cTFBC4_R,
|
||||
cTFBC5 = cTFBC5_RG,
|
||||
cTFBC7_M6_OPAQUE_ONLY = cTFBC7_M6_RGB,
|
||||
cTFBC7_M5 = cTFBC7_M5_RGBA,
|
||||
|
||||
// Previously, the caller had some control over which BC7 mode the transcoder output. We've simplified this due to UASTC, which supports numerous modes.
|
||||
cTFBC7_M6_RGB = cTFBC7_RGBA, // Opaque only, RGB or alpha if cDecodeFlagsTranscodeAlphaDataToOpaqueFormats flag is specified. Highest quality of all the non-ETC1 formats.
|
||||
cTFBC7_M5_RGBA = cTFBC7_RGBA, // Opaque+alpha, alpha channel will be opaque for opaque .basis files
|
||||
cTFBC7_M6_OPAQUE_ONLY = cTFBC7_RGBA,
|
||||
cTFBC7_M5 = cTFBC7_RGBA,
|
||||
cTFBC7_ALT = 7,
|
||||
|
||||
cTFASTC_4x4 = cTFASTC_4x4_RGBA,
|
||||
|
||||
cTFATC_RGBA_INTERPOLATED_ALPHA = cTFATC_RGBA,
|
||||
};
|
||||
|
||||
uint32_t basis_get_bytes_per_block(transcoder_texture_format fmt);
|
||||
// For compressed texture formats, this returns the # of bytes per block. For uncompressed, it returns the # of bytes per pixel.
|
||||
// NOTE: Previously, this function was called basis_get_bytes_per_block(), and it always returned 16*bytes_per_pixel for uncompressed formats which was confusing.
|
||||
uint32_t basis_get_bytes_per_block_or_pixel(transcoder_texture_format fmt);
|
||||
|
||||
// Returns format's name in ASCII
|
||||
const char* basis_get_format_name(transcoder_texture_format fmt);
|
||||
|
||||
// Returns block format name in ASCII
|
||||
const char* basis_get_block_format_name(block_format fmt);
|
||||
|
||||
// Returns true if the format supports an alpha channel.
|
||||
bool basis_transcoder_format_has_alpha(transcoder_texture_format fmt);
|
||||
|
||||
// Returns the basisu::texture_format corresponding to the specified transcoder_texture_format.
|
||||
basisu::texture_format basis_get_basisu_texture_format(transcoder_texture_format fmt);
|
||||
|
||||
// Returns the texture type's name in ASCII.
|
||||
const char* basis_get_texture_type_name(basis_texture_type tex_type);
|
||||
|
||||
|
||||
// Returns true if the transcoder texture type is an uncompressed (raw pixel) format.
|
||||
bool basis_transcoder_format_is_uncompressed(transcoder_texture_format tex_type);
|
||||
|
||||
// Returns the # of bytes per pixel for uncompressed formats, or 0 for block texture formats.
|
||||
uint32_t basis_get_uncompressed_bytes_per_pixel(transcoder_texture_format fmt);
|
||||
|
||||
|
||||
// Returns the block width for the specified texture format, which is currently either 4 or 8 for FXT1.
|
||||
uint32_t basis_get_block_width(transcoder_texture_format tex_type);
|
||||
|
||||
// Returns the block height for the specified texture format, which is currently always 4.
|
||||
uint32_t basis_get_block_height(transcoder_texture_format tex_type);
|
||||
|
||||
// Returns true if the specified format was enabled at compile time.
|
||||
bool basis_is_format_supported(transcoder_texture_format tex_type);
|
||||
|
||||
bool basis_is_format_supported(transcoder_texture_format tex_type, basis_tex_format fmt = basis_tex_format::cETC1S);
|
||||
|
||||
// Validates that the output buffer is large enough to hold the entire transcoded texture.
|
||||
// For uncompressed texture formats, most input parameters are in pixels, not blocks. Blocks are 4x4 pixels.
|
||||
bool basis_validate_output_buffer_size(transcoder_texture_format target_format,
|
||||
uint32_t output_blocks_buf_size_in_blocks_or_pixels,
|
||||
uint32_t orig_width, uint32_t orig_height,
|
||||
uint32_t output_row_pitch_in_blocks_or_pixels,
|
||||
uint32_t output_rows_in_pixels,
|
||||
uint32_t total_slice_blocks);
|
||||
|
||||
class basisu_transcoder;
|
||||
|
||||
// This struct holds all state used during transcoding. For video, it needs to persist between image transcodes (it holds the previous frame).
|
||||
|
|
@ -118,46 +167,161 @@ namespace basist
|
|||
uint8_t m_pred_bits;
|
||||
};
|
||||
|
||||
std::vector<block_preds> m_block_endpoint_preds[2];
|
||||
|
||||
basisu::vector<block_preds> m_block_endpoint_preds[2];
|
||||
|
||||
enum { cMaxPrevFrameLevels = 16 };
|
||||
std::vector<uint32_t> m_prev_frame_indices[2][cMaxPrevFrameLevels]; // [alpha_flag][level_index]
|
||||
basisu::vector<uint32_t> m_prev_frame_indices[2][cMaxPrevFrameLevels]; // [alpha_flag][level_index]
|
||||
|
||||
void clear()
|
||||
{
|
||||
for (uint32_t i = 0; i < 2; i++)
|
||||
{
|
||||
m_block_endpoint_preds[i].clear();
|
||||
|
||||
for (uint32_t j = 0; j < cMaxPrevFrameLevels; j++)
|
||||
m_prev_frame_indices[i][j].clear();
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
// Low-level helper class that does the actual transcoding.
|
||||
class basisu_lowlevel_transcoder
|
||||
class basisu_lowlevel_etc1s_transcoder
|
||||
{
|
||||
friend class basisu_transcoder;
|
||||
|
||||
|
||||
public:
|
||||
basisu_lowlevel_transcoder(const basist::etc1_global_selector_codebook *pGlobal_sel_codebook);
|
||||
basisu_lowlevel_etc1s_transcoder(const basist::etc1_global_selector_codebook* pGlobal_sel_codebook);
|
||||
|
||||
void set_global_codebooks(const basisu_lowlevel_etc1s_transcoder* pGlobal_codebook) { m_pGlobal_codebook = pGlobal_codebook; }
|
||||
const basisu_lowlevel_etc1s_transcoder* get_global_codebooks() const { return m_pGlobal_codebook; }
|
||||
|
||||
bool decode_palettes(
|
||||
uint32_t num_endpoints, const uint8_t *pEndpoints_data, uint32_t endpoints_data_size,
|
||||
uint32_t num_selectors, const uint8_t *pSelectors_data, uint32_t selectors_data_size);
|
||||
uint32_t num_endpoints, const uint8_t* pEndpoints_data, uint32_t endpoints_data_size,
|
||||
uint32_t num_selectors, const uint8_t* pSelectors_data, uint32_t selectors_data_size);
|
||||
|
||||
bool decode_tables(const uint8_t *pTable_data, uint32_t table_data_size);
|
||||
bool decode_tables(const uint8_t* pTable_data, uint32_t table_data_size);
|
||||
|
||||
bool transcode_slice(void *pDst_blocks, uint32_t num_blocks_x, uint32_t num_blocks_y, const uint8_t *pImage_data, uint32_t image_data_size, block_format fmt,
|
||||
uint32_t output_block_or_pixel_stride_in_bytes, bool bc1_allow_threecolor_blocks, const basis_file_header &header, const basis_slice_desc& slice_desc, uint32_t output_row_pitch_in_blocks_or_pixels = 0,
|
||||
basisu_transcoder_state *pState = nullptr, bool astc_transcode_alpha = false, void* pAlpha_blocks = nullptr, uint32_t output_rows_in_pixels = 0);
|
||||
bool transcode_slice(void* pDst_blocks, uint32_t num_blocks_x, uint32_t num_blocks_y, const uint8_t* pImage_data, uint32_t image_data_size, block_format fmt,
|
||||
uint32_t output_block_or_pixel_stride_in_bytes, bool bc1_allow_threecolor_blocks, const bool is_video, const bool is_alpha_slice, const uint32_t level_index, const uint32_t orig_width, const uint32_t orig_height, uint32_t output_row_pitch_in_blocks_or_pixels = 0,
|
||||
basisu_transcoder_state* pState = nullptr, bool astc_transcode_alpha = false, void* pAlpha_blocks = nullptr, uint32_t output_rows_in_pixels = 0);
|
||||
|
||||
bool transcode_slice(void* pDst_blocks, uint32_t num_blocks_x, uint32_t num_blocks_y, const uint8_t* pImage_data, uint32_t image_data_size, block_format fmt,
|
||||
uint32_t output_block_or_pixel_stride_in_bytes, bool bc1_allow_threecolor_blocks, const basis_file_header& header, const basis_slice_desc& slice_desc, uint32_t output_row_pitch_in_blocks_or_pixels = 0,
|
||||
basisu_transcoder_state* pState = nullptr, bool astc_transcode_alpha = false, void* pAlpha_blocks = nullptr, uint32_t output_rows_in_pixels = 0)
|
||||
{
|
||||
return transcode_slice(pDst_blocks, num_blocks_x, num_blocks_y, pImage_data, image_data_size, fmt, output_block_or_pixel_stride_in_bytes, bc1_allow_threecolor_blocks,
|
||||
header.m_tex_type == cBASISTexTypeVideoFrames, (slice_desc.m_flags & cSliceDescFlagsHasAlpha) != 0, slice_desc.m_level_index,
|
||||
slice_desc.m_orig_width, slice_desc.m_orig_height, output_row_pitch_in_blocks_or_pixels, pState,
|
||||
astc_transcode_alpha,
|
||||
pAlpha_blocks,
|
||||
output_rows_in_pixels);
|
||||
}
|
||||
|
||||
// Container independent transcoding
|
||||
bool transcode_image(
|
||||
transcoder_texture_format target_format,
|
||||
void* pOutput_blocks, uint32_t output_blocks_buf_size_in_blocks_or_pixels,
|
||||
const uint8_t* pCompressed_data, uint32_t compressed_data_length,
|
||||
uint32_t num_blocks_x, uint32_t num_blocks_y, uint32_t orig_width, uint32_t orig_height, uint32_t level_index,
|
||||
uint32_t rgb_offset, uint32_t rgb_length, uint32_t alpha_offset, uint32_t alpha_length,
|
||||
uint32_t decode_flags = 0,
|
||||
bool basis_file_has_alpha_slices = false,
|
||||
bool is_video = false,
|
||||
uint32_t output_row_pitch_in_blocks_or_pixels = 0,
|
||||
basisu_transcoder_state* pState = nullptr,
|
||||
uint32_t output_rows_in_pixels = 0);
|
||||
|
||||
void clear()
|
||||
{
|
||||
m_local_endpoints.clear();
|
||||
m_local_selectors.clear();
|
||||
m_endpoint_pred_model.clear();
|
||||
m_delta_endpoint_model.clear();
|
||||
m_selector_model.clear();
|
||||
m_selector_history_buf_rle_model.clear();
|
||||
m_selector_history_buf_size = 0;
|
||||
}
|
||||
|
||||
// Low-level methods
|
||||
typedef basisu::vector<endpoint> endpoint_vec;
|
||||
const endpoint_vec& get_endpoints() const { return m_local_endpoints; }
|
||||
|
||||
typedef basisu::vector<selector> selector_vec;
|
||||
const selector_vec& get_selectors() const { return m_local_selectors; }
|
||||
|
||||
const etc1_global_selector_codebook* get_global_sel_codebook() const { return m_pGlobal_sel_codebook; }
|
||||
|
||||
private:
|
||||
typedef std::vector<endpoint> endpoint_vec;
|
||||
endpoint_vec m_endpoints;
|
||||
const basisu_lowlevel_etc1s_transcoder* m_pGlobal_codebook;
|
||||
|
||||
typedef std::vector<selector> selector_vec;
|
||||
selector_vec m_selectors;
|
||||
endpoint_vec m_local_endpoints;
|
||||
selector_vec m_local_selectors;
|
||||
|
||||
const etc1_global_selector_codebook *m_pGlobal_sel_codebook;
|
||||
const etc1_global_selector_codebook* m_pGlobal_sel_codebook;
|
||||
|
||||
huffman_decoding_table m_endpoint_pred_model, m_delta_endpoint_model, m_selector_model, m_selector_history_buf_rle_model;
|
||||
|
||||
uint32_t m_selector_history_buf_size;
|
||||
|
||||
|
||||
basisu_transcoder_state m_def_state;
|
||||
};
|
||||
|
||||
enum basisu_decode_flags
|
||||
{
|
||||
// PVRTC1: decode non-pow2 ETC1S texture level to the next larger power of 2 (not implemented yet, but we're going to support it). Ignored if the slice's dimensions are already a power of 2.
|
||||
cDecodeFlagsPVRTCDecodeToNextPow2 = 2,
|
||||
|
||||
// When decoding to an opaque texture format, if the basis file has alpha, decode the alpha slice instead of the color slice to the output texture format.
|
||||
// This is primarily to allow decoding of textures with alpha to multiple ETC1 textures (one for color, another for alpha).
|
||||
cDecodeFlagsTranscodeAlphaDataToOpaqueFormats = 4,
|
||||
|
||||
// Forbid usage of BC1 3 color blocks (we don't support BC1 punchthrough alpha yet).
|
||||
// This flag is used internally when decoding to BC3.
|
||||
cDecodeFlagsBC1ForbidThreeColorBlocks = 8,
|
||||
|
||||
// The output buffer contains alpha endpoint/selector indices.
|
||||
// Used internally when decoding formats like ASTC that require both color and alpha data to be available when transcoding to the output format.
|
||||
cDecodeFlagsOutputHasAlphaIndices = 16,
|
||||
|
||||
cDecodeFlagsHighQuality = 32
|
||||
};
|
||||
|
||||
class basisu_lowlevel_uastc_transcoder
|
||||
{
|
||||
friend class basisu_transcoder;
|
||||
|
||||
public:
|
||||
basisu_lowlevel_uastc_transcoder();
|
||||
|
||||
bool transcode_slice(void* pDst_blocks, uint32_t num_blocks_x, uint32_t num_blocks_y, const uint8_t* pImage_data, uint32_t image_data_size, block_format fmt,
|
||||
uint32_t output_block_or_pixel_stride_in_bytes, bool bc1_allow_threecolor_blocks, bool has_alpha, const uint32_t orig_width, const uint32_t orig_height, uint32_t output_row_pitch_in_blocks_or_pixels = 0,
|
||||
basisu_transcoder_state* pState = nullptr, uint32_t output_rows_in_pixels = 0, int channel0 = -1, int channel1 = -1, uint32_t decode_flags = 0);
|
||||
|
||||
bool transcode_slice(void* pDst_blocks, uint32_t num_blocks_x, uint32_t num_blocks_y, const uint8_t* pImage_data, uint32_t image_data_size, block_format fmt,
|
||||
uint32_t output_block_or_pixel_stride_in_bytes, bool bc1_allow_threecolor_blocks, const basis_file_header& header, const basis_slice_desc& slice_desc, uint32_t output_row_pitch_in_blocks_or_pixels = 0,
|
||||
basisu_transcoder_state* pState = nullptr, uint32_t output_rows_in_pixels = 0, int channel0 = -1, int channel1 = -1, uint32_t decode_flags = 0)
|
||||
{
|
||||
return transcode_slice(pDst_blocks, num_blocks_x, num_blocks_y, pImage_data, image_data_size, fmt,
|
||||
output_block_or_pixel_stride_in_bytes, bc1_allow_threecolor_blocks, (header.m_flags & cBASISHeaderFlagHasAlphaSlices) != 0, slice_desc.m_orig_width, slice_desc.m_orig_height, output_row_pitch_in_blocks_or_pixels,
|
||||
pState, output_rows_in_pixels, channel0, channel1, decode_flags);
|
||||
}
|
||||
|
||||
// Container independent transcoding
|
||||
bool transcode_image(
|
||||
transcoder_texture_format target_format,
|
||||
void* pOutput_blocks, uint32_t output_blocks_buf_size_in_blocks_or_pixels,
|
||||
const uint8_t* pCompressed_data, uint32_t compressed_data_length,
|
||||
uint32_t num_blocks_x, uint32_t num_blocks_y, uint32_t orig_width, uint32_t orig_height, uint32_t level_index,
|
||||
uint32_t slice_offset, uint32_t slice_length,
|
||||
uint32_t decode_flags = 0,
|
||||
bool has_alpha = false,
|
||||
bool is_video = false,
|
||||
uint32_t output_row_pitch_in_blocks_or_pixels = 0,
|
||||
basisu_transcoder_state* pState = nullptr,
|
||||
uint32_t output_rows_in_pixels = 0,
|
||||
int channel0 = -1, int channel1 = -1);
|
||||
};
|
||||
|
||||
struct basisu_slice_info
|
||||
{
|
||||
uint32_t m_orig_width;
|
||||
|
|
@ -175,19 +339,19 @@ namespace basist
|
|||
uint32_t m_slice_index; // the slice index in the .basis file
|
||||
uint32_t m_image_index; // the source image index originally provided to the encoder
|
||||
uint32_t m_level_index; // the mipmap level within this image
|
||||
|
||||
|
||||
uint32_t m_unpacked_slice_crc16;
|
||||
|
||||
|
||||
bool m_alpha_flag; // true if the slice has alpha data
|
||||
bool m_iframe_flag; // true if the slice is an I-Frame
|
||||
};
|
||||
|
||||
typedef std::vector<basisu_slice_info> basisu_slice_info_vec;
|
||||
typedef basisu::vector<basisu_slice_info> basisu_slice_info_vec;
|
||||
|
||||
struct basisu_image_info
|
||||
{
|
||||
uint32_t m_image_index;
|
||||
uint32_t m_total_levels;
|
||||
uint32_t m_total_levels;
|
||||
|
||||
uint32_t m_orig_width;
|
||||
uint32_t m_orig_height;
|
||||
|
|
@ -199,8 +363,8 @@ namespace basist
|
|||
uint32_t m_num_blocks_y;
|
||||
uint32_t m_total_blocks;
|
||||
|
||||
uint32_t m_first_slice_index;
|
||||
|
||||
uint32_t m_first_slice_index;
|
||||
|
||||
bool m_alpha_flag; // true if the image has alpha data
|
||||
bool m_iframe_flag; // true if the image is an I-Frame
|
||||
};
|
||||
|
|
@ -220,8 +384,13 @@ namespace basist
|
|||
uint32_t m_num_blocks_y;
|
||||
uint32_t m_total_blocks;
|
||||
|
||||
uint32_t m_first_slice_index;
|
||||
|
||||
uint32_t m_first_slice_index;
|
||||
|
||||
uint32_t m_rgb_file_ofs;
|
||||
uint32_t m_rgb_file_len;
|
||||
uint32_t m_alpha_file_ofs;
|
||||
uint32_t m_alpha_file_len;
|
||||
|
||||
bool m_alpha_flag; // true if the image has alpha data
|
||||
bool m_iframe_flag; // true if the image is an I-Frame
|
||||
};
|
||||
|
|
@ -232,13 +401,19 @@ namespace basist
|
|||
uint32_t m_total_header_size;
|
||||
|
||||
uint32_t m_total_selectors;
|
||||
// will be 0 for UASTC or if the file uses global codebooks
|
||||
uint32_t m_selector_codebook_ofs;
|
||||
uint32_t m_selector_codebook_size;
|
||||
|
||||
uint32_t m_total_endpoints;
|
||||
// will be 0 for UASTC or if the file uses global codebooks
|
||||
uint32_t m_endpoint_codebook_ofs;
|
||||
uint32_t m_endpoint_codebook_size;
|
||||
|
||||
uint32_t m_tables_ofs;
|
||||
uint32_t m_tables_size;
|
||||
uint32_t m_slices_size;
|
||||
|
||||
uint32_t m_slices_size;
|
||||
|
||||
basis_texture_type m_tex_type;
|
||||
uint32_t m_us_per_frame;
|
||||
|
|
@ -247,14 +422,16 @@ namespace basist
|
|||
basisu_slice_info_vec m_slice_info;
|
||||
|
||||
uint32_t m_total_images; // total # of images
|
||||
std::vector<uint32_t> m_image_mipmap_levels; // the # of mipmap levels for each image
|
||||
basisu::vector<uint32_t> m_image_mipmap_levels; // the # of mipmap levels for each image
|
||||
|
||||
uint32_t m_userdata0;
|
||||
uint32_t m_userdata1;
|
||||
|
||||
bool m_etc1s; // always true for basis universal
|
||||
|
||||
basis_tex_format m_tex_format; // ETC1S, UASTC, etc.
|
||||
|
||||
bool m_y_flipped; // true if the image was Y flipped
|
||||
bool m_has_alpha_slices; // true if the texture has alpha slices (even slices RGB, odd slices alpha)
|
||||
bool m_etc1s; // true if the file is ETC1S
|
||||
bool m_has_alpha_slices; // true if the texture has alpha slices (for ETC1S: even slices RGB, odd slices alpha)
|
||||
};
|
||||
|
||||
// High-level transcoder class which accepts .basis file data and allows the caller to query information about the file and transcode image levels to various texture formats.
|
||||
|
|
@ -265,81 +442,67 @@ namespace basist
|
|||
basisu_transcoder& operator= (const basisu_transcoder&);
|
||||
|
||||
public:
|
||||
basisu_transcoder(const etc1_global_selector_codebook *pGlobal_sel_codebook);
|
||||
basisu_transcoder(const etc1_global_selector_codebook* pGlobal_sel_codebook);
|
||||
|
||||
// Validates the .basis file. This computes a crc16 over the entire file, so it's slow.
|
||||
bool validate_file_checksums(const void *pData, uint32_t data_size, bool full_validation) const;
|
||||
bool validate_file_checksums(const void* pData, uint32_t data_size, bool full_validation) const;
|
||||
|
||||
// Quick header validation - no crc16 checks.
|
||||
bool validate_header(const void *pData, uint32_t data_size) const;
|
||||
bool validate_header(const void* pData, uint32_t data_size) const;
|
||||
|
||||
basis_texture_type get_texture_type(const void* pData, uint32_t data_size) const;
|
||||
bool get_userdata(const void* pData, uint32_t data_size, uint32_t& userdata0, uint32_t& userdata1) const;
|
||||
|
||||
basis_texture_type get_texture_type(const void *pData, uint32_t data_size) const;
|
||||
bool get_userdata(const void *pData, uint32_t data_size, uint32_t &userdata0, uint32_t &userdata1) const;
|
||||
|
||||
// Returns the total number of images in the basis file (always 1 or more).
|
||||
// Note that the number of mipmap levels for each image may differ, and that images may have different resolutions.
|
||||
uint32_t get_total_images(const void *pData, uint32_t data_size) const;
|
||||
uint32_t get_total_images(const void* pData, uint32_t data_size) const;
|
||||
|
||||
basis_tex_format get_tex_format(const void* pData, uint32_t data_size) const;
|
||||
|
||||
// Returns the number of mipmap levels in an image.
|
||||
uint32_t get_total_image_levels(const void *pData, uint32_t data_size, uint32_t image_index) const;
|
||||
|
||||
uint32_t get_total_image_levels(const void* pData, uint32_t data_size, uint32_t image_index) const;
|
||||
|
||||
// Returns basic information about an image. Note that orig_width/orig_height may not be a multiple of 4.
|
||||
bool get_image_level_desc(const void *pData, uint32_t data_size, uint32_t image_index, uint32_t level_index, uint32_t &orig_width, uint32_t &orig_height, uint32_t &total_blocks) const;
|
||||
bool get_image_level_desc(const void* pData, uint32_t data_size, uint32_t image_index, uint32_t level_index, uint32_t& orig_width, uint32_t& orig_height, uint32_t& total_blocks) const;
|
||||
|
||||
// Returns information about the specified image.
|
||||
bool get_image_info(const void *pData, uint32_t data_size, basisu_image_info &image_info, uint32_t image_index) const;
|
||||
bool get_image_info(const void* pData, uint32_t data_size, basisu_image_info& image_info, uint32_t image_index) const;
|
||||
|
||||
// Returns information about the specified image's mipmap level.
|
||||
bool get_image_level_info(const void *pData, uint32_t data_size, basisu_image_level_info &level_info, uint32_t image_index, uint32_t level_index) const;
|
||||
|
||||
bool get_image_level_info(const void* pData, uint32_t data_size, basisu_image_level_info& level_info, uint32_t image_index, uint32_t level_index) const;
|
||||
|
||||
// Get a description of the basis file and low-level information about each slice.
|
||||
bool get_file_info(const void *pData, uint32_t data_size, basisu_file_info &file_info) const;
|
||||
|
||||
bool get_file_info(const void* pData, uint32_t data_size, basisu_file_info& file_info) const;
|
||||
|
||||
// start_transcoding() must be called before calling transcode_slice() or transcode_image_level().
|
||||
// This decompresses the selector/endpoint codebooks, so ideally you would only call this once per .basis file (not each image/mipmap level).
|
||||
bool start_transcoding(const void *pData, uint32_t data_size) const;
|
||||
|
||||
// For ETC1S files, this call decompresses the selector/endpoint codebooks, so ideally you would only call this once per .basis file (not each image/mipmap level).
|
||||
bool start_transcoding(const void* pData, uint32_t data_size);
|
||||
|
||||
bool stop_transcoding();
|
||||
|
||||
// Returns true if start_transcoding() has been called.
|
||||
bool get_ready_to_transcode() const { return m_lowlevel_decoder.m_endpoints.size() > 0; }
|
||||
bool get_ready_to_transcode() const { return m_ready_to_transcode; }
|
||||
|
||||
enum
|
||||
{
|
||||
// PVRTC1: decode non-pow2 ETC1S texture level to the next larger power of 2 (not implemented yet, but we're going to support it). Ignored if the slice's dimensions are already a power of 2.
|
||||
cDecodeFlagsPVRTCDecodeToNextPow2 = 2,
|
||||
|
||||
// When decoding to an opaque texture format, if the basis file has alpha, decode the alpha slice instead of the color slice to the output texture format.
|
||||
// This is primarily to allow decoding of textures with alpha to multiple ETC1 textures (one for color, another for alpha).
|
||||
cDecodeFlagsTranscodeAlphaDataToOpaqueFormats = 4,
|
||||
|
||||
// Forbid usage of BC1 3 color blocks (we don't support BC1 punchthrough alpha yet).
|
||||
// This flag is used internally when decoding to BC3.
|
||||
cDecodeFlagsBC1ForbidThreeColorBlocks = 8,
|
||||
|
||||
// The output buffer contains alpha endpoint/selector indices.
|
||||
// Used internally when decoding formats like ASTC that require both color and alpha data to be available when transcoding to the output format.
|
||||
cDecodeFlagsOutputHasAlphaIndices = 16
|
||||
};
|
||||
|
||||
// transcode_image_level() decodes a single mipmap level from the .basis file to any of the supported output texture formats.
|
||||
// It'll first find the slice(s) to transcode, then call transcode_slice() one or two times to decode both the color and alpha texture data (or RG texture data from two slices for BC5).
|
||||
// If the .basis file doesn't have alpha slices, the output alpha blocks will be set to fully opaque (all 255's).
|
||||
// Currently, to decode to PVRTC1 the basis texture's dimensions in pixels must be a power of 2, due to PVRTC1 format requirements.
|
||||
// output_blocks_buf_size_in_blocks_or_pixels should be at least the image level's total_blocks (num_blocks_x * num_blocks_y), or the total number of output pixels if fmt==cTFRGBA32.
|
||||
// output_row_pitch_in_blocks_or_pixels: Number of blocks or pixels per row. If 0, the transcoder uses the slice's num_blocks_x or orig_width (NOT num_blocks_x * 4). Ignored for PVRTC1 (due to texture swizzling).
|
||||
// output_rows_in_pixels: Ignored unless fmt is cRGBA32. The total number of output rows in the output buffer. If 0, the transcoder assumes the slice's orig_height (NOT num_blocks_y * 4).
|
||||
// output_rows_in_pixels: Ignored unless fmt is uncompressed (cRGBA32, etc.). The total number of output rows in the output buffer. If 0, the transcoder assumes the slice's orig_height (NOT num_blocks_y * 4).
|
||||
// Notes:
|
||||
// - basisu_transcoder_init() must have been called first to initialize the transcoder lookup tables before calling this function.
|
||||
// - This method assumes the output texture buffer is readable. In some cases to handle alpha, the transcoder will write temporary data to the output texture in
|
||||
// a first pass, which will be read in a second pass.
|
||||
bool transcode_image_level(
|
||||
const void *pData, uint32_t data_size,
|
||||
uint32_t image_index, uint32_t level_index,
|
||||
void *pOutput_blocks, uint32_t output_blocks_buf_size_in_blocks_or_pixels,
|
||||
const void* pData, uint32_t data_size,
|
||||
uint32_t image_index, uint32_t level_index,
|
||||
void* pOutput_blocks, uint32_t output_blocks_buf_size_in_blocks_or_pixels,
|
||||
transcoder_texture_format fmt,
|
||||
uint32_t decode_flags = 0, uint32_t output_row_pitch_in_blocks_or_pixels = 0, basisu_transcoder_state *pState = nullptr, uint32_t output_rows_in_pixels = 0) const;
|
||||
uint32_t decode_flags = 0, uint32_t output_row_pitch_in_blocks_or_pixels = 0, basisu_transcoder_state* pState = nullptr, uint32_t output_rows_in_pixels = 0) const;
|
||||
|
||||
// Finds the basis slice corresponding to the specified image/level/alpha params, or -1 if the slice can't be found.
|
||||
int find_slice(const void *pData, uint32_t data_size, uint32_t image_index, uint32_t level_index, bool alpha_data) const;
|
||||
int find_slice(const void* pData, uint32_t data_size, uint32_t image_index, uint32_t level_index, bool alpha_data) const;
|
||||
|
||||
// transcode_slice() decodes a single slice from the .basis file. It's a low-level API - most likely you want to use transcode_image_level().
|
||||
// This is a low-level API, and will be needed to be called multiple times to decode some texture formats (like BC3, BC5, or ETC2).
|
||||
|
|
@ -350,21 +513,39 @@ namespace basist
|
|||
// output_rows_in_pixels: Ignored unless fmt is cRGBA32. The total number of output rows in the output buffer. If 0, the transcoder assumes the slice's orig_height (NOT num_blocks_y * 4).
|
||||
// Notes:
|
||||
// - basisu_transcoder_init() must have been called first to initialize the transcoder lookup tables before calling this function.
|
||||
bool transcode_slice(const void *pData, uint32_t data_size, uint32_t slice_index,
|
||||
void *pOutput_blocks, uint32_t output_blocks_buf_size_in_blocks_or_pixels,
|
||||
block_format fmt, uint32_t output_block_stride_in_bytes, uint32_t decode_flags = 0, uint32_t output_row_pitch_in_blocks_or_pixels = 0, basisu_transcoder_state * pState = nullptr, void* pAlpha_blocks = nullptr, uint32_t output_rows_in_pixels = 0) const;
|
||||
bool transcode_slice(const void* pData, uint32_t data_size, uint32_t slice_index,
|
||||
void* pOutput_blocks, uint32_t output_blocks_buf_size_in_blocks_or_pixels,
|
||||
block_format fmt, uint32_t output_block_stride_in_bytes, uint32_t decode_flags = 0, uint32_t output_row_pitch_in_blocks_or_pixels = 0, basisu_transcoder_state* pState = nullptr, void* pAlpha_blocks = nullptr,
|
||||
uint32_t output_rows_in_pixels = 0, int channel0 = -1, int channel1 = -1) const;
|
||||
|
||||
static void write_opaque_alpha_blocks(
|
||||
uint32_t num_blocks_x, uint32_t num_blocks_y,
|
||||
void* pOutput_blocks, block_format fmt,
|
||||
uint32_t block_stride_in_bytes, uint32_t output_row_pitch_in_blocks_or_pixels);
|
||||
|
||||
void set_global_codebooks(const basisu_lowlevel_etc1s_transcoder* pGlobal_codebook) { m_lowlevel_etc1s_decoder.set_global_codebooks(pGlobal_codebook); }
|
||||
const basisu_lowlevel_etc1s_transcoder* get_global_codebooks() const { return m_lowlevel_etc1s_decoder.get_global_codebooks(); }
|
||||
|
||||
const basisu_lowlevel_etc1s_transcoder& get_lowlevel_etc1s_decoder() const { return m_lowlevel_etc1s_decoder; }
|
||||
basisu_lowlevel_etc1s_transcoder& get_lowlevel_etc1s_decoder() { return m_lowlevel_etc1s_decoder; }
|
||||
|
||||
const basisu_lowlevel_uastc_transcoder& get_lowlevel_uastc_decoder() const { return m_lowlevel_uastc_decoder; }
|
||||
basisu_lowlevel_uastc_transcoder& get_lowlevel_uastc_decoder() { return m_lowlevel_uastc_decoder; }
|
||||
|
||||
private:
|
||||
mutable basisu_lowlevel_transcoder m_lowlevel_decoder;
|
||||
mutable basisu_lowlevel_etc1s_transcoder m_lowlevel_etc1s_decoder;
|
||||
mutable basisu_lowlevel_uastc_transcoder m_lowlevel_uastc_decoder;
|
||||
|
||||
bool m_ready_to_transcode;
|
||||
|
||||
int find_first_slice_index(const void* pData, uint32_t data_size, uint32_t image_index, uint32_t level_index) const;
|
||||
|
||||
|
||||
bool validate_header_quick(const void* pData, uint32_t data_size) const;
|
||||
};
|
||||
|
||||
// basisu_transcoder_init() must be called before a .basis file can be transcoded.
|
||||
// basisu_transcoder_init() MUST be called before a .basis file can be transcoded.
|
||||
void basisu_transcoder_init();
|
||||
|
||||
|
||||
enum debug_flags_t
|
||||
{
|
||||
cDebugFlagVisCRs = 1,
|
||||
|
|
@ -374,4 +555,387 @@ namespace basist
|
|||
uint32_t get_debug_flags();
|
||||
void set_debug_flags(uint32_t f);
|
||||
|
||||
// ------------------------------------------------------------------------------------------------------
|
||||
// Optional .KTX2 file format support
|
||||
// KTX2 reading optionally requires miniz or Zstd decompressors for supercompressed UASTC files.
|
||||
// ------------------------------------------------------------------------------------------------------
|
||||
#if BASISD_SUPPORT_KTX2
|
||||
#pragma pack(push)
|
||||
#pragma pack(1)
|
||||
struct ktx2_header
|
||||
{
|
||||
uint8_t m_identifier[12];
|
||||
basisu::packed_uint<4> m_vk_format;
|
||||
basisu::packed_uint<4> m_type_size;
|
||||
basisu::packed_uint<4> m_pixel_width;
|
||||
basisu::packed_uint<4> m_pixel_height;
|
||||
basisu::packed_uint<4> m_pixel_depth;
|
||||
basisu::packed_uint<4> m_layer_count;
|
||||
basisu::packed_uint<4> m_face_count;
|
||||
basisu::packed_uint<4> m_level_count;
|
||||
basisu::packed_uint<4> m_supercompression_scheme;
|
||||
basisu::packed_uint<4> m_dfd_byte_offset;
|
||||
basisu::packed_uint<4> m_dfd_byte_length;
|
||||
basisu::packed_uint<4> m_kvd_byte_offset;
|
||||
basisu::packed_uint<4> m_kvd_byte_length;
|
||||
basisu::packed_uint<8> m_sgd_byte_offset;
|
||||
basisu::packed_uint<8> m_sgd_byte_length;
|
||||
};
|
||||
|
||||
struct ktx2_level_index
|
||||
{
|
||||
basisu::packed_uint<8> m_byte_offset;
|
||||
basisu::packed_uint<8> m_byte_length;
|
||||
basisu::packed_uint<8> m_uncompressed_byte_length;
|
||||
};
|
||||
|
||||
struct ktx2_etc1s_global_data_header
|
||||
{
|
||||
basisu::packed_uint<2> m_endpoint_count;
|
||||
basisu::packed_uint<2> m_selector_count;
|
||||
basisu::packed_uint<4> m_endpoints_byte_length;
|
||||
basisu::packed_uint<4> m_selectors_byte_length;
|
||||
basisu::packed_uint<4> m_tables_byte_length;
|
||||
basisu::packed_uint<4> m_extended_byte_length;
|
||||
};
|
||||
|
||||
struct ktx2_etc1s_image_desc
|
||||
{
|
||||
basisu::packed_uint<4> m_image_flags;
|
||||
basisu::packed_uint<4> m_rgb_slice_byte_offset;
|
||||
basisu::packed_uint<4> m_rgb_slice_byte_length;
|
||||
basisu::packed_uint<4> m_alpha_slice_byte_offset;
|
||||
basisu::packed_uint<4> m_alpha_slice_byte_length;
|
||||
};
|
||||
|
||||
struct ktx2_animdata
|
||||
{
|
||||
basisu::packed_uint<4> m_duration;
|
||||
basisu::packed_uint<4> m_timescale;
|
||||
basisu::packed_uint<4> m_loopcount;
|
||||
};
|
||||
#pragma pack(pop)
|
||||
|
||||
const uint32_t KTX2_VK_FORMAT_UNDEFINED = 0;
|
||||
const uint32_t KTX2_KDF_DF_MODEL_UASTC = 166;
|
||||
const uint32_t KTX2_KDF_DF_MODEL_ETC1S = 163;
|
||||
const uint32_t KTX2_IMAGE_IS_P_FRAME = 2;
|
||||
const uint32_t KTX2_UASTC_BLOCK_SIZE = 16;
|
||||
const uint32_t KTX2_MAX_SUPPORTED_LEVEL_COUNT = 16; // this is an implementation specific constraint and can be increased
|
||||
|
||||
// The KTX2 transfer functions supported by KTX2
|
||||
const uint32_t KTX2_KHR_DF_TRANSFER_LINEAR = 1;
|
||||
const uint32_t KTX2_KHR_DF_TRANSFER_SRGB = 2;
|
||||
|
||||
enum ktx2_supercompression
|
||||
{
|
||||
KTX2_SS_NONE = 0,
|
||||
KTX2_SS_BASISLZ = 1,
|
||||
KTX2_SS_ZSTANDARD = 2
|
||||
};
|
||||
|
||||
extern const uint8_t g_ktx2_file_identifier[12];
|
||||
|
||||
enum ktx2_df_channel_id
|
||||
{
|
||||
KTX2_DF_CHANNEL_ETC1S_RGB = 0U,
|
||||
KTX2_DF_CHANNEL_ETC1S_RRR = 3U,
|
||||
KTX2_DF_CHANNEL_ETC1S_GGG = 4U,
|
||||
KTX2_DF_CHANNEL_ETC1S_AAA = 15U,
|
||||
|
||||
KTX2_DF_CHANNEL_UASTC_DATA = 0U,
|
||||
KTX2_DF_CHANNEL_UASTC_RGB = 0U,
|
||||
KTX2_DF_CHANNEL_UASTC_RGBA = 3U,
|
||||
KTX2_DF_CHANNEL_UASTC_RRR = 4U,
|
||||
KTX2_DF_CHANNEL_UASTC_RRRG = 5U,
|
||||
KTX2_DF_CHANNEL_UASTC_RG = 6U,
|
||||
};
|
||||
|
||||
inline const char* ktx2_get_etc1s_df_channel_id_str(ktx2_df_channel_id id)
|
||||
{
|
||||
switch (id)
|
||||
{
|
||||
case KTX2_DF_CHANNEL_ETC1S_RGB: return "RGB";
|
||||
case KTX2_DF_CHANNEL_ETC1S_RRR: return "RRR";
|
||||
case KTX2_DF_CHANNEL_ETC1S_GGG: return "GGG";
|
||||
case KTX2_DF_CHANNEL_ETC1S_AAA: return "AAA";
|
||||
default: break;
|
||||
}
|
||||
return "?";
|
||||
}
|
||||
|
||||
inline const char* ktx2_get_uastc_df_channel_id_str(ktx2_df_channel_id id)
|
||||
{
|
||||
switch (id)
|
||||
{
|
||||
case KTX2_DF_CHANNEL_UASTC_RGB: return "RGB";
|
||||
case KTX2_DF_CHANNEL_UASTC_RGBA: return "RGBA";
|
||||
case KTX2_DF_CHANNEL_UASTC_RRR: return "RRR";
|
||||
case KTX2_DF_CHANNEL_UASTC_RRRG: return "RRRG";
|
||||
case KTX2_DF_CHANNEL_UASTC_RG: return "RG";
|
||||
default: break;
|
||||
}
|
||||
return "?";
|
||||
}
|
||||
|
||||
enum ktx2_df_color_primaries
|
||||
{
|
||||
KTX2_DF_PRIMARIES_UNSPECIFIED = 0,
|
||||
KTX2_DF_PRIMARIES_BT709 = 1,
|
||||
KTX2_DF_PRIMARIES_SRGB = 1,
|
||||
KTX2_DF_PRIMARIES_BT601_EBU = 2,
|
||||
KTX2_DF_PRIMARIES_BT601_SMPTE = 3,
|
||||
KTX2_DF_PRIMARIES_BT2020 = 4,
|
||||
KTX2_DF_PRIMARIES_CIEXYZ = 5,
|
||||
KTX2_DF_PRIMARIES_ACES = 6,
|
||||
KTX2_DF_PRIMARIES_ACESCC = 7,
|
||||
KTX2_DF_PRIMARIES_NTSC1953 = 8,
|
||||
KTX2_DF_PRIMARIES_PAL525 = 9,
|
||||
KTX2_DF_PRIMARIES_DISPLAYP3 = 10,
|
||||
KTX2_DF_PRIMARIES_ADOBERGB = 11
|
||||
};
|
||||
|
||||
inline const char* ktx2_get_df_color_primaries_str(ktx2_df_color_primaries p)
|
||||
{
|
||||
switch (p)
|
||||
{
|
||||
case KTX2_DF_PRIMARIES_UNSPECIFIED: return "UNSPECIFIED";
|
||||
case KTX2_DF_PRIMARIES_BT709: return "BT709";
|
||||
case KTX2_DF_PRIMARIES_BT601_EBU: return "EBU";
|
||||
case KTX2_DF_PRIMARIES_BT601_SMPTE: return "SMPTE";
|
||||
case KTX2_DF_PRIMARIES_BT2020: return "BT2020";
|
||||
case KTX2_DF_PRIMARIES_CIEXYZ: return "CIEXYZ";
|
||||
case KTX2_DF_PRIMARIES_ACES: return "ACES";
|
||||
case KTX2_DF_PRIMARIES_ACESCC: return "ACESCC";
|
||||
case KTX2_DF_PRIMARIES_NTSC1953: return "NTSC1953";
|
||||
case KTX2_DF_PRIMARIES_PAL525: return "PAL525";
|
||||
case KTX2_DF_PRIMARIES_DISPLAYP3: return "DISPLAYP3";
|
||||
case KTX2_DF_PRIMARIES_ADOBERGB: return "ADOBERGB";
|
||||
default: break;
|
||||
}
|
||||
return "?";
|
||||
}
|
||||
|
||||
// Information about a single 2D texture "image" in a KTX2 file.
|
||||
struct ktx2_image_level_info
|
||||
{
|
||||
// The mipmap level index (0=largest), texture array layer index, and cubemap face index of the image.
|
||||
uint32_t m_level_index;
|
||||
uint32_t m_layer_index;
|
||||
uint32_t m_face_index;
|
||||
|
||||
// The image's actual (or the original source image's) width/height in pixels, which may not be divisible by 4 pixels.
|
||||
uint32_t m_orig_width;
|
||||
uint32_t m_orig_height;
|
||||
|
||||
// The image's physical width/height, which will always be divisible by 4 pixels.
|
||||
uint32_t m_width;
|
||||
uint32_t m_height;
|
||||
|
||||
// The texture's dimensions in 4x4 texel blocks.
|
||||
uint32_t m_num_blocks_x;
|
||||
uint32_t m_num_blocks_y;
|
||||
|
||||
// The total number of blocks
|
||||
uint32_t m_total_blocks;
|
||||
|
||||
// true if the image has alpha data
|
||||
bool m_alpha_flag;
|
||||
|
||||
// true if the image is an I-Frame. Currently, for ETC1S textures, the first frame will always be an I-Frame, and subsequent frames will always be P-Frames.
|
||||
bool m_iframe_flag;
|
||||
};
|
||||
|
||||
// Thread-specific ETC1S/supercompressed UASTC transcoder state. (If you're not doing multithreading transcoding you can ignore this.)
|
||||
struct ktx2_transcoder_state
|
||||
{
|
||||
basist::basisu_transcoder_state m_transcoder_state;
|
||||
basisu::uint8_vec m_level_uncomp_data;
|
||||
int m_uncomp_data_level_index;
|
||||
|
||||
void clear()
|
||||
{
|
||||
m_transcoder_state.clear();
|
||||
m_level_uncomp_data.clear();
|
||||
m_uncomp_data_level_index = -1;
|
||||
}
|
||||
};
|
||||
|
||||
// This class is quite similar to basisu_transcoder. It treats KTX2 files as a simple container for ETC1S/UASTC texture data.
|
||||
// It does not support 1D or 3D textures.
|
||||
// It only supports 2D and cubemap textures, with or without mipmaps, texture arrays of 2D/cubemap textures, and texture video files.
|
||||
// It only supports raw non-supercompressed UASTC, ETC1S, UASTC+Zstd, or UASTC+zlib compressed files.
|
||||
// DFD (Data Format Descriptor) parsing is purposely as simple as possible.
|
||||
// If you need to know how to interpret the texture channels you'll need to parse the DFD yourself after calling get_dfd().
|
||||
class ktx2_transcoder
|
||||
{
|
||||
public:
|
||||
ktx2_transcoder(basist::etc1_global_selector_codebook* pGlobal_sel_codebook);
|
||||
|
||||
// Frees all allocations, resets object.
|
||||
void clear();
|
||||
|
||||
// init() parses the KTX2 header, level index array, DFD, and key values, but nothing else.
|
||||
// Importantly, it does not parse or decompress the ETC1S global supercompressed data, so some things (like which frames are I/P-Frames) won't be available until start_transcoding() is called.
|
||||
// This method holds a pointer to the file data until clear() is called.
|
||||
bool init(const void* pData, uint32_t data_size);
|
||||
|
||||
// Returns the data/size passed to init().
|
||||
const uint8_t* get_data() const { return m_pData; }
|
||||
uint32_t get_data_size() const { return m_data_size; }
|
||||
|
||||
// Returns the KTX2 header. Valid after init().
|
||||
const ktx2_header& get_header() const { return m_header; }
|
||||
|
||||
// Returns the KTX2 level index array. There will be one entry for each mipmap level. Valid after init().
|
||||
const basisu::vector<ktx2_level_index>& get_level_index() const { return m_levels; }
|
||||
|
||||
// Returns the texture's width in texels. Always non-zero, might not be divisible by 4. Valid after init().
|
||||
uint32_t get_width() const { return m_header.m_pixel_width; }
|
||||
|
||||
// Returns the texture's height in texels. Always non-zero, might not be divisible by 4. Valid after init().
|
||||
uint32_t get_height() const { return m_header.m_pixel_height; }
|
||||
|
||||
// Returns the texture's number of mipmap levels. Always returns 1 or higher. Valid after init().
|
||||
uint32_t get_levels() const { return m_header.m_level_count; }
|
||||
|
||||
// Returns the number of faces. Returns 1 for 2D textures and or 6 for cubemaps. Valid after init().
|
||||
uint32_t get_faces() const { return m_header.m_face_count; }
|
||||
|
||||
// Returns 0 or the number of layers in the texture array or texture video. Valid after init().
|
||||
uint32_t get_layers() const { return m_header.m_layer_count; }
|
||||
|
||||
// Returns cETC1S or cUASTC4x4. Valid after init().
|
||||
basist::basis_tex_format get_format() const { return m_format; }
|
||||
|
||||
bool is_etc1s() const { return get_format() == basist::basis_tex_format::cETC1S; }
|
||||
|
||||
bool is_uastc() const { return get_format() == basist::basis_tex_format::cUASTC4x4; }
|
||||
|
||||
// Returns true if the ETC1S file has two planes (typically RGBA, or RRRG), or true if the UASTC file has alpha data. Valid after init().
|
||||
uint32_t get_has_alpha() const { return m_has_alpha; }
|
||||
|
||||
// Returns the entire Data Format Descriptor (DFD) from the KTX2 file. Valid after init().
|
||||
// See https://www.khronos.org/registry/DataFormat/specs/1.3/dataformat.1.3.html#_the_khronos_data_format_descriptor_overview
|
||||
const basisu::uint8_vec& get_dfd() const { return m_dfd; }
|
||||
|
||||
// Some basic DFD accessors. Valid after init().
|
||||
uint32_t get_dfd_color_model() const { return m_dfd_color_model; }
|
||||
|
||||
// Returns the DFD color primary.
|
||||
// We do not validate the color primaries, so the returned value may not be in the ktx2_df_color_primaries enum.
|
||||
ktx2_df_color_primaries get_dfd_color_primaries() const { return m_dfd_color_prims; }
|
||||
|
||||
// Returns KTX2_KHR_DF_TRANSFER_LINEAR or KTX2_KHR_DF_TRANSFER_SRGB.
|
||||
uint32_t get_dfd_transfer_func() const { return m_dfd_transfer_func; }
|
||||
|
||||
uint32_t get_dfd_flags() const { return m_dfd_flags; }
|
||||
|
||||
// Returns 1 (ETC1S/UASTC) or 2 (ETC1S with an internal alpha channel).
|
||||
uint32_t get_dfd_total_samples() const { return m_dfd_samples; }
|
||||
|
||||
// Returns the channel mapping for each DFD "sample". UASTC always has 1 sample, ETC1S can have one or two.
|
||||
// Note the returned value SHOULD be one of the ktx2_df_channel_id enums, but we don't validate that.
|
||||
// It's up to the caller to decide what to do if the value isn't in the enum.
|
||||
ktx2_df_channel_id get_dfd_channel_id0() const { return m_dfd_chan0; }
|
||||
ktx2_df_channel_id get_dfd_channel_id1() const { return m_dfd_chan1; }
|
||||
|
||||
// Key value field data.
|
||||
struct key_value
|
||||
{
|
||||
// The key field is UTF8 and always zero terminated.
|
||||
basisu::uint8_vec m_key;
|
||||
|
||||
// The value may be empty. It consists of raw bytes which may or may not be zero terminated.
|
||||
basisu::uint8_vec m_value;
|
||||
|
||||
bool operator< (const key_value& rhs) const { return strcmp((const char*)m_key.data(), (const char *)rhs.m_key.data()) < 0; }
|
||||
};
|
||||
typedef basisu::vector<key_value> key_value_vec;
|
||||
|
||||
// Returns the array of key-value entries. This may be empty. Valid after init().
|
||||
// The order of key values fields in this array exactly matches the order they were stored in the file. The keys are supposed to be sorted by their Unicode code points.
|
||||
const key_value_vec& get_key_values() const { return m_key_values; }
|
||||
|
||||
const basisu::uint8_vec *find_key(const std::string& key_name) const;
|
||||
|
||||
// Low-level ETC1S specific accessors
|
||||
|
||||
// Returns the ETC1S global supercompression data header, which is only valid after start_transcoding() is called.
|
||||
const ktx2_etc1s_global_data_header& get_etc1s_header() const { return m_etc1s_header; }
|
||||
|
||||
// Returns the array of ETC1S image descriptors, which is only valid after get_etc1s_image_descs() is called.
|
||||
const basisu::vector<ktx2_etc1s_image_desc>& get_etc1s_image_descs() const { return m_etc1s_image_descs; }
|
||||
|
||||
// Must have called startTranscoding() first
|
||||
uint32_t get_etc1s_image_descs_image_flags(uint32_t level_index, uint32_t layer_index, uint32_t face_index) const;
|
||||
|
||||
// is_video() is only valid after start_transcoding() is called.
|
||||
// For ETC1S data, if this returns true you must currently transcode the file from first to last frame, in order, without skipping any frames.
|
||||
bool is_video() const { return m_is_video; }
|
||||
|
||||
// start_transcoding() MUST be called before calling transcode_image().
|
||||
// This method decompresses the ETC1S global endpoint/selector codebooks, which is not free, so try to avoid calling it excessively.
|
||||
bool start_transcoding();
|
||||
|
||||
// get_image_level_info() be called after init(), but the m_iframe_flag's won't be valid until start_transcoding() is called.
|
||||
// You can call this method before calling transcode_image_level() to retrieve basic information about the mipmap level's dimensions, etc.
|
||||
bool get_image_level_info(ktx2_image_level_info& level_info, uint32_t level_index, uint32_t layer_index, uint32_t face_index) const;
|
||||
|
||||
// transcode_image_level() transcodes a single 2D texture or cubemap face from the KTX2 file.
|
||||
// Internally it uses the same low-level transcode API's as basisu_transcoder::transcode_image_level().
|
||||
// If the file is UASTC and is supercompressed with Zstandard, and the file is a texture array or cubemap, it's highly recommended that each mipmap level is
|
||||
// completely transcoded before switching to another level. Every time the mipmap level is changed all supercompressed level data must be decompressed using Zstandard as a single unit.
|
||||
// Currently ETC1S videos must always be transcoded from first to last frame (or KTX2 "layer"), in order, with no skipping of frames.
|
||||
// By default this method is not thread safe unless you specify a pointer to a user allocated thread-specific transcoder_state struct.
|
||||
bool transcode_image_level(
|
||||
uint32_t level_index, uint32_t layer_index, uint32_t face_index,
|
||||
void* pOutput_blocks, uint32_t output_blocks_buf_size_in_blocks_or_pixels,
|
||||
basist::transcoder_texture_format fmt,
|
||||
uint32_t decode_flags = 0, uint32_t output_row_pitch_in_blocks_or_pixels = 0, uint32_t output_rows_in_pixels = 0, int channel0 = -1, int channel1 = -1,
|
||||
ktx2_transcoder_state *pState = nullptr);
|
||||
|
||||
private:
|
||||
const uint8_t* m_pData;
|
||||
uint32_t m_data_size;
|
||||
|
||||
ktx2_header m_header;
|
||||
basisu::vector<ktx2_level_index> m_levels;
|
||||
basisu::uint8_vec m_dfd;
|
||||
key_value_vec m_key_values;
|
||||
|
||||
ktx2_etc1s_global_data_header m_etc1s_header;
|
||||
basisu::vector<ktx2_etc1s_image_desc> m_etc1s_image_descs;
|
||||
|
||||
basist::basis_tex_format m_format;
|
||||
|
||||
uint32_t m_dfd_color_model;
|
||||
ktx2_df_color_primaries m_dfd_color_prims;
|
||||
uint32_t m_dfd_transfer_func;
|
||||
uint32_t m_dfd_flags;
|
||||
uint32_t m_dfd_samples;
|
||||
ktx2_df_channel_id m_dfd_chan0, m_dfd_chan1;
|
||||
|
||||
basist::basisu_lowlevel_etc1s_transcoder m_etc1s_transcoder;
|
||||
basist::basisu_lowlevel_uastc_transcoder m_uastc_transcoder;
|
||||
|
||||
ktx2_transcoder_state m_def_transcoder_state;
|
||||
|
||||
bool m_has_alpha;
|
||||
bool m_is_video;
|
||||
|
||||
bool decompress_level_data(uint32_t level_index, basisu::uint8_vec& uncomp_data);
|
||||
bool decompress_etc1s_global_data();
|
||||
bool read_key_values();
|
||||
};
|
||||
|
||||
#endif // BASISD_SUPPORT_KTX2
|
||||
|
||||
// Returns true if the transcoder was compiled with KTX2 support.
|
||||
bool basisu_transcoder_supports_ktx2();
|
||||
|
||||
// Returns true if the transcoder was compiled with Zstandard support.
|
||||
bool basisu_transcoder_supports_ktx2_zstd();
|
||||
|
||||
} // namespace basisu
|
||||
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
// basisu_transcoder_internal.h - Universal texture format transcoder library.
|
||||
// Copyright (C) 2019 Binomial LLC. All Rights Reserved.
|
||||
// Copyright (C) 2019-2021 Binomial LLC. All Rights Reserved.
|
||||
//
|
||||
// Important: If compiling with gcc, be sure strict aliasing is disabled: -fno-strict-aliasing
|
||||
//
|
||||
|
|
@ -20,8 +20,8 @@
|
|||
#pragma warning (disable: 4127) // conditional expression is constant
|
||||
#endif
|
||||
|
||||
#define BASISD_LIB_VERSION 107
|
||||
#define BASISD_VERSION_STRING "01.11"
|
||||
#define BASISD_LIB_VERSION 115
|
||||
#define BASISD_VERSION_STRING "01.15"
|
||||
|
||||
#ifdef _DEBUG
|
||||
#define BASISD_BUILD_DEBUG
|
||||
|
|
@ -45,38 +45,44 @@ namespace basist
|
|||
enum class block_format
|
||||
{
|
||||
cETC1, // ETC1S RGB
|
||||
cETC2_RGBA, // full ETC2 EAC RGBA8 block
|
||||
cBC1, // DXT1 RGB
|
||||
cBC3, // BC4 block followed by a four color BC1 block
|
||||
cBC4, // DXT5A (alpha block only)
|
||||
cBC5, // two BC4 blocks
|
||||
cPVRTC1_4_RGB, // opaque-only PVRTC1 4bpp
|
||||
cPVRTC1_4_RGBA, // PVRTC1 4bpp RGBA
|
||||
cBC7_M6_OPAQUE_ONLY, // RGB BC7 mode 6
|
||||
cBC7, // Full BC7 block, any mode
|
||||
cBC7_M5_COLOR, // RGB BC7 mode 5 color (writes an opaque mode 5 block)
|
||||
cBC7_M5_ALPHA, // alpha portion of BC7 mode 5 (cBC7_M5_COLOR output data must have been written to the output buffer first to set the mode/rot fields etc.)
|
||||
cETC2_EAC_A8, // alpha block of ETC2 EAC (first 8 bytes of the 16-bit ETC2 EAC RGBA format)
|
||||
cASTC_4x4, // ASTC 4x4 (either color-only or color+alpha). Note that the transcoder always currently assumes sRGB is not enabled when outputting ASTC
|
||||
// data. If you use a sRGB ASTC format you'll get ~1 LSB of additional error, because of the different way ASTC decoders scale 8-bit endpoints to 16-bits during unpacking.
|
||||
|
||||
cATC_RGB,
|
||||
cATC_RGBA_INTERPOLATED_ALPHA,
|
||||
cFXT1_RGB, // Opaque-only, has oddball 8x4 pixel block size
|
||||
|
||||
cPVRTC2_4_RGB,
|
||||
cPVRTC2_4_RGBA,
|
||||
|
||||
cETC2_EAC_R11,
|
||||
cETC2_EAC_RG11,
|
||||
|
||||
cIndices, // Used internally: Write 16-bit endpoint and selector indices directly to output (output block must be at least 32-bits)
|
||||
|
||||
cRGB32, // Writes RGB components to 32bpp output pixels
|
||||
cRGBA32, // Writes RGB255 components to 32bpp output pixels
|
||||
cA32, // Writes alpha component to 32bpp output pixels
|
||||
|
||||
|
||||
cRGB565,
|
||||
cBGR565,
|
||||
|
||||
cRGBA4444_COLOR,
|
||||
cRGBA4444_ALPHA,
|
||||
cRGBA4444_COLOR_OPAQUE,
|
||||
|
||||
cPVRTC2_4_RGB,
|
||||
cPVRTC2_4_RGBA,
|
||||
|
||||
cETC2_EAC_R11,
|
||||
|
||||
cRGBA4444,
|
||||
|
||||
cTotalBlockFormats
|
||||
};
|
||||
|
||||
|
|
@ -116,7 +122,7 @@ namespace basist
|
|||
basisu::clear_vector(m_tree);
|
||||
}
|
||||
|
||||
bool init(uint32_t total_syms, const uint8_t *pCode_sizes)
|
||||
bool init(uint32_t total_syms, const uint8_t *pCode_sizes, uint32_t fast_lookup_bits = basisu::cHuffmanFastLookupBits)
|
||||
{
|
||||
if (!total_syms)
|
||||
{
|
||||
|
|
@ -127,8 +133,10 @@ namespace basist
|
|||
m_code_sizes.resize(total_syms);
|
||||
memcpy(&m_code_sizes[0], pCode_sizes, total_syms);
|
||||
|
||||
const uint32_t huffman_fast_lookup_size = 1 << fast_lookup_bits;
|
||||
|
||||
m_lookup.resize(0);
|
||||
m_lookup.resize(basisu::cHuffmanFastLookupSize);
|
||||
m_lookup.resize(huffman_fast_lookup_size);
|
||||
|
||||
m_tree.resize(0);
|
||||
m_tree.resize(total_syms * 2);
|
||||
|
|
@ -166,10 +174,10 @@ namespace basist
|
|||
for (l = code_size; l > 0; l--, cur_code >>= 1)
|
||||
rev_code = (rev_code << 1) | (cur_code & 1);
|
||||
|
||||
if (code_size <= basisu::cHuffmanFastLookupBits)
|
||||
if (code_size <= fast_lookup_bits)
|
||||
{
|
||||
uint32_t k = (code_size << 16) | sym_index;
|
||||
while (rev_code < basisu::cHuffmanFastLookupSize)
|
||||
while (rev_code < huffman_fast_lookup_size)
|
||||
{
|
||||
if (m_lookup[rev_code] != 0)
|
||||
{
|
||||
|
|
@ -184,9 +192,9 @@ namespace basist
|
|||
}
|
||||
|
||||
int tree_cur;
|
||||
if (0 == (tree_cur = m_lookup[rev_code & (basisu::cHuffmanFastLookupSize - 1)]))
|
||||
if (0 == (tree_cur = m_lookup[rev_code & (huffman_fast_lookup_size - 1)]))
|
||||
{
|
||||
const uint32_t idx = rev_code & (basisu::cHuffmanFastLookupSize - 1);
|
||||
const uint32_t idx = rev_code & (huffman_fast_lookup_size - 1);
|
||||
if (m_lookup[idx] != 0)
|
||||
{
|
||||
// Supplied codesizes can't create a valid prefix code.
|
||||
|
|
@ -204,9 +212,9 @@ namespace basist
|
|||
return false;
|
||||
}
|
||||
|
||||
rev_code >>= (basisu::cHuffmanFastLookupBits - 1);
|
||||
rev_code >>= (fast_lookup_bits - 1);
|
||||
|
||||
for (int j = code_size; j > (basisu::cHuffmanFastLookupBits + 1); j--)
|
||||
for (int j = code_size; j > ((int)fast_lookup_bits + 1); j--)
|
||||
{
|
||||
tree_cur -= ((rev_code >>= 1) & 1);
|
||||
|
||||
|
|
@ -254,6 +262,8 @@ namespace basist
|
|||
}
|
||||
|
||||
const basisu::uint8_vec &get_code_sizes() const { return m_code_sizes; }
|
||||
const basisu::int_vec get_lookup() const { return m_lookup; }
|
||||
const basisu::int16_vec get_tree() const { return m_tree; }
|
||||
|
||||
bool is_valid() const { return m_code_sizes.size() > 0; }
|
||||
|
||||
|
|
@ -430,9 +440,11 @@ namespace basist
|
|||
return v;
|
||||
}
|
||||
|
||||
inline uint32_t decode_huffman(const huffman_decoding_table &ct)
|
||||
inline uint32_t decode_huffman(const huffman_decoding_table &ct, int fast_lookup_bits = basisu::cHuffmanFastLookupBits)
|
||||
{
|
||||
assert(ct.m_code_sizes.size());
|
||||
|
||||
const uint32_t huffman_fast_lookup_size = 1 << fast_lookup_bits;
|
||||
|
||||
while (m_bit_buf_size < 16)
|
||||
{
|
||||
|
|
@ -448,14 +460,14 @@ namespace basist
|
|||
int code_len;
|
||||
|
||||
int sym;
|
||||
if ((sym = ct.m_lookup[m_bit_buf & (basisu::cHuffmanFastLookupSize - 1)]) >= 0)
|
||||
if ((sym = ct.m_lookup[m_bit_buf & (huffman_fast_lookup_size - 1)]) >= 0)
|
||||
{
|
||||
code_len = sym >> 16;
|
||||
sym &= 0xFFFF;
|
||||
}
|
||||
else
|
||||
{
|
||||
code_len = basisu::cHuffmanFastLookupBits;
|
||||
code_len = fast_lookup_bits;
|
||||
do
|
||||
{
|
||||
sym = ct.m_tree[~sym + ((m_bit_buf >> code_len++) & 1)]; // ~sym = -sym - 1
|
||||
|
|
@ -635,6 +647,11 @@ namespace basist
|
|||
return (uint8_t)((i & 0xFFFFFF00U) ? (~(i >> 31)) : i);
|
||||
}
|
||||
|
||||
enum eNoClamp
|
||||
{
|
||||
cNoClamp = 0
|
||||
};
|
||||
|
||||
struct color32
|
||||
{
|
||||
union
|
||||
|
|
@ -655,21 +672,33 @@ namespace basist
|
|||
color32() { }
|
||||
|
||||
color32(uint32_t vr, uint32_t vg, uint32_t vb, uint32_t va) { set(vr, vg, vb, va); }
|
||||
color32(eNoClamp unused, uint32_t vr, uint32_t vg, uint32_t vb, uint32_t va) { (void)unused; set_noclamp_rgba(vr, vg, vb, va); }
|
||||
|
||||
void set(uint32_t vr, uint32_t vg, uint32_t vb, uint32_t va) { c[0] = static_cast<uint8_t>(vr); c[1] = static_cast<uint8_t>(vg); c[2] = static_cast<uint8_t>(vb); c[3] = static_cast<uint8_t>(va); }
|
||||
|
||||
void set_noclamp_rgb(uint32_t vr, uint32_t vg, uint32_t vb) { c[0] = static_cast<uint8_t>(vr); c[1] = static_cast<uint8_t>(vg); c[2] = static_cast<uint8_t>(vb); }
|
||||
void set_noclamp_rgba(uint32_t vr, uint32_t vg, uint32_t vb, uint32_t va) { set(vr, vg, vb, va); }
|
||||
|
||||
void set_clamped(int vr, int vg, int vb, int va) { c[0] = clamp255(vr); c[1] = clamp255(vg); c[2] = clamp255(vb); c[3] = clamp255(va); }
|
||||
|
||||
uint8_t operator[] (uint32_t idx) const { assert(idx < 4); return c[idx]; }
|
||||
uint8_t &operator[] (uint32_t idx) { assert(idx < 4); return c[idx]; }
|
||||
|
||||
bool operator== (const color32&rhs) const { return m == rhs.m; }
|
||||
|
||||
static color32 comp_min(const color32& a, const color32& b) { return color32(cNoClamp, basisu::minimum(a[0], b[0]), basisu::minimum(a[1], b[1]), basisu::minimum(a[2], b[2]), basisu::minimum(a[3], b[3])); }
|
||||
static color32 comp_max(const color32& a, const color32& b) { return color32(cNoClamp, basisu::maximum(a[0], b[0]), basisu::maximum(a[1], b[1]), basisu::maximum(a[2], b[2]), basisu::maximum(a[3], b[3])); }
|
||||
};
|
||||
|
||||
struct endpoint
|
||||
{
|
||||
color32 m_color5;
|
||||
uint8_t m_inten5;
|
||||
bool operator== (const endpoint& rhs) const
|
||||
{
|
||||
return (m_color5.r == rhs.m_color5.r) && (m_color5.g == rhs.m_color5.g) && (m_color5.b == rhs.m_color5.b) && (m_inten5 == rhs.m_inten5);
|
||||
}
|
||||
bool operator!= (const endpoint& rhs) const { return !(*this == rhs); }
|
||||
};
|
||||
|
||||
struct selector
|
||||
|
|
@ -682,6 +711,17 @@ namespace basist
|
|||
|
||||
uint8_t m_lo_selector, m_hi_selector;
|
||||
uint8_t m_num_unique_selectors;
|
||||
bool operator== (const selector& rhs) const
|
||||
{
|
||||
return (m_selectors[0] == rhs.m_selectors[0]) &&
|
||||
(m_selectors[1] == rhs.m_selectors[1]) &&
|
||||
(m_selectors[2] == rhs.m_selectors[2]) &&
|
||||
(m_selectors[3] == rhs.m_selectors[3]);
|
||||
}
|
||||
bool operator!= (const selector& rhs) const
|
||||
{
|
||||
return !(*this == rhs);
|
||||
}
|
||||
|
||||
void init_flags()
|
||||
{
|
||||
|
|
|
|||
|
|
@ -478,4 +478,4 @@
|
|||
{31,1,10801},{47,1,12162},{14,1,6117},{14,1,6117},{8,1,50},{20,1,7322},{0,1,1241},{21,1,914},{21,1,914},{21,1,914},{7,1,274},{35,5,1513},{9,1,585},{9,1,585},{26,1,0},{27,1,1513},{26,1,0},{1,1,0},{1,1,0},{1,1,0},{1,1,0},{1,1,0},{1,1,0},{1,1,0},{0,1,0},{1,1,0},{0,1,0},{47,0,9250},{47,0,9250},{47,0,9250},{47,0,9250},{12,1,3690},
|
||||
{12,1,3690},{12,1,3690},{8,1,50},{0,1,1241},{0,1,1241},{45,1,65535},{14,1,33274},{42,1,19608},{42,1,13375},{47,1,62627},{42,1,22211},{10,1,6045},{24,1,138},{36,1,39015},{0,1,1732},{35,1,1048},{5,1,766},{5,1,666},{37,1,212},{3,3,1473},{7,1,675},{23,1,410},{14,1,1},{3,3,1473},{14,1,1},{13,1,14121},{13,1,14121},{13,1,14121},{45,1,10571},{45,1,11434},{30,1,6081},{30,1,6081},
|
||||
{40,1,137},{36,1,6926},{2,1,1445},{5,1,666},{5,1,666},{5,1,666},{37,1,212},{35,3,1105},{23,1,410},{23,1,410},{14,1,1},{25,1,1105},{14,1,1},{1,1,0},{1,1,0},{1,1,0},{1,1,0},{1,1,0},{1,1,0},{1,1,0},{0,1,0},{1,1,0},{0,1,0},{15,0,9256},{15,0,9256},{15,0,9256},{15,0,9256},{14,1,3985},{14,1,3985},{14,1,3985},{40,1,137},{2,1,1445},
|
||||
{2,1,1445},
|
||||
{2,1,1445},
|
||||
|
|
|
|||
|
|
@ -478,4 +478,4 @@
|
|||
{137,255,10742},{135,255,12066},{107,255,6089},{107,255,6089},{67,255,45},{37,255,7233},{1,255,1184},{218,255,900},{218,255,900},{218,255,900},{204,255,272},{255,167,1513},{189,255,562},{189,255,562},{86,255,0},{253,213,1513},{86,255,0},{255,252,0},{255,254,0},{254,255,0},{252,255,0},{255,252,0},{255,254,0},{252,255,0},{0,255,0},{255,254,0},{0,255,0},{132,0,9248},{132,0,9248},{132,0,9248},{132,0,9248},{98,255,3656},
|
||||
{98,255,3656},{98,255,3656},{67,255,45},{1,255,1184},{1,255,1184},{138,255,65535},{107,255,33448},{95,255,19729},{89,255,13446},{135,255,62717},{95,255,22307},{79,255,6021},{73,255,105},{40,255,38959},{0,254,1627},{230,255,996},{224,255,756},{221,255,653},{213,255,194},{255,204,1473},{207,255,675},{198,255,405},{110,255,0},{255,230,1473},{110,255,0},{162,255,14060},{162,255,14060},{162,255,14060},{146,255,10545},{141,255,11378},{116,255,6077},{116,255,6077},
|
||||
{76,255,137},{40,255,6873},{7,255,1412},{221,255,653},{221,255,653},{221,255,653},{213,255,194},{255,180,1105},{198,255,405},{198,255,405},{110,255,0},{255,218,1105},{110,255,0},{255,252,0},{255,254,0},{254,255,0},{252,255,0},{255,252,0},{255,254,0},{252,255,0},{0,255,0},{255,254,0},{0,255,0},{140,0,9248},{140,0,9248},{140,0,9248},{140,0,9248},{107,255,3929},{107,255,3929},{107,255,3929},{76,255,137},{7,255,1412},
|
||||
{7,255,1412},
|
||||
{7,255,1412},
|
||||
|
|
|
|||
|
|
@ -478,4 +478,4 @@
|
|||
{17,31,11312},{16,31,11037},{13,31,6429},{13,31,6429},{8,31,260},{6,31,10457},{0,31,2642},{26,31,872},{26,31,872},{26,31,872},{25,31,397},{31,22,1513},{23,31,794},{23,31,794},{13,31,1},{29,27,1513},{13,31,1},{31,31,0},{31,31,0},{31,31,0},{31,31,0},{31,31,0},{31,31,0},{31,31,0},{0,31,0},{31,31,0},{0,31,0},{16,0,9248},{16,0,9248},{16,0,9248},{16,0,9248},{12,31,3074},
|
||||
{12,31,3074},{12,31,3074},{8,31,260},{0,31,2642},{0,31,2642},{17,31,58848},{15,31,39619},{13,31,24975},{12,31,19007},{16,31,54474},{13,31,27057},{10,31,8569},{9,31,461},{8,31,51302},{0,31,5046},{28,31,979},{27,31,806},{27,31,637},{26,31,292},{31,26,1473},{26,31,953},{24,31,605},{16,31,0},{29,29,1473},{16,31,0},{19,31,13604},{19,31,13604},{19,31,13604},{18,31,11057},{16,31,10429},{14,31,6339},{14,31,6339},
|
||||
{10,31,424},{8,31,9713},{1,31,2900},{27,31,637},{27,31,637},{27,31,637},{26,31,292},{30,25,1105},{24,31,605},{24,31,605},{16,31,0},{30,27,1105},{16,31,0},{31,31,0},{31,31,0},{31,31,0},{31,31,0},{31,31,0},{31,31,0},{31,31,0},{0,31,0},{31,31,0},{0,31,0},{17,0,9248},{17,0,9248},{17,0,9248},{17,0,9248},{12,31,3330},{12,31,3330},{12,31,3330},{10,31,424},{1,31,2900},
|
||||
{1,31,2900},
|
||||
{1,31,2900},
|
||||
|
|
|
|||
|
|
@ -478,4 +478,4 @@
|
|||
{17,63,11312},{16,63,11037},{13,63,6429},{13,63,6429},{8,63,260},{6,63,10457},{0,63,2642},{26,63,872},{26,63,872},{26,63,872},{25,63,397},{31,45,1513},{23,63,794},{23,63,794},{13,63,1},{31,52,1513},{13,63,1},{31,63,0},{31,63,0},{31,63,0},{31,63,0},{31,63,0},{31,63,0},{31,63,0},{0,63,0},{31,63,0},{0,63,0},{16,0,9248},{16,0,9248},{16,0,9248},{16,0,9248},{12,63,3074},
|
||||
{12,63,3074},{12,63,3074},{8,63,260},{0,63,2642},{0,63,2642},{17,63,58848},{15,63,39619},{13,63,24975},{12,63,19007},{16,63,54474},{13,63,27057},{10,63,8569},{9,63,461},{8,63,51302},{0,63,5046},{28,63,979},{27,63,806},{27,63,637},{26,63,292},{30,56,1473},{26,63,953},{24,63,605},{16,63,0},{30,58,1473},{16,63,0},{19,63,13604},{19,63,13604},{19,63,13604},{18,63,11057},{16,63,10429},{14,63,6339},{14,63,6339},
|
||||
{10,63,424},{8,63,9713},{1,63,2900},{27,63,637},{27,63,637},{27,63,637},{26,63,292},{31,48,1105},{24,63,605},{24,63,605},{16,63,0},{31,54,1105},{16,63,0},{31,63,0},{31,63,0},{31,63,0},{31,63,0},{31,63,0},{31,63,0},{31,63,0},{0,63,0},{31,63,0},{0,63,0},{17,0,9248},{17,0,9248},{17,0,9248},{17,0,9248},{12,63,3330},{12,63,3330},{12,63,3330},{10,63,424},{1,63,2900},
|
||||
{1,63,2900},
|
||||
{1,63,2900},
|
||||
|
|
|
|||
|
|
@ -46,4 +46,4 @@
|
|||
{76,0,3},{255,1,27},{255,7,24},{255,1,27},{179,39,8},{255,22,16},{85,0,3},{255,2,27},{255,22,24},{255,7,27},{187,47,8},{255,47,16},{93,0,3},{255,4,27},{251,100,28},{182,0,7},{195,55,8},{255,71,16},{101,0,3},{255,4,27},{253,108,28},{191,0,7},{203,63,8},{255,95,16},{109,0,3},{255,7,27},{255,118,28},{200,0,7},{212,72,8},{255,123,16},{118,0,3},{246,0,7},
|
||||
{255,129,28},{209,0,7},{220,80,8},{255,147,16},{126,0,3},{246,0,7},{255,138,28},{218,0,7},{228,88,8},{255,172,16},{134,0,3},{249,3,7},{245,91,8},{228,3,7},{236,96,8},{255,196,16},{142,6,3},{251,14,7},{250,102,8},{237,12,7},{245,105,8},{255,223,16},{151,15,3},{253,22,7},{254,112,8},{245,20,7},{253,113,8},{255,248,16},{159,23,3},{253,31,7},{255,124,8},{249,28,7},
|
||||
{255,124,8},{255,0,0},{167,31,3},{254,39,7},{255,10,4},{252,37,7},{255,10,4},{255,0,0},{175,39,3},{255,48,7},{255,38,4},{254,48,7},{255,38,4},{255,0,0},{184,48,3},{255,56,7},{255,62,4},{255,56,7},{255,62,4},{255,0,0},{192,56,3},{255,65,7},{255,86,4},{255,65,7},{255,86,4},{255,0,0},{200,64,3},{255,74,7},{255,111,4},{255,77,7},{255,111,4},{255,0,0},
|
||||
{208,5,2},
|
||||
{208,5,2},
|
||||
|
|
|
|||
|
|
@ -478,4 +478,4 @@
|
|||
{70,127,10779},{68,127,12146},{54,127,6176},{54,127,6176},{34,127,52},{14,127,7281},{2,127,1213},{109,127,937},{109,127,937},{109,127,937},{102,127,281},{127,84,1513},{93,127,565},{93,127,565},{43,127,0},{127,106,1513},{43,127,0},{127,127,0},{127,127,0},{127,127,0},{127,127,0},{127,127,0},{127,127,0},{127,127,0},{0,127,0},{127,127,0},{0,127,0},{65,0,9250},{65,0,9250},{65,0,9250},{65,0,9250},{49,127,3656},
|
||||
{49,127,3656},{49,127,3656},{34,127,52},{2,127,1213},{2,127,1213},{71,127,63180},{60,127,37225},{52,127,26137},{48,127,18128},{68,127,59595},{51,127,22636},{42,127,8480},{37,127,164},{22,127,37455},{0,126,2073},{114,127,1019},{111,127,766},{111,127,666},{105,127,205},{127,102,1473},{102,127,681},{99,127,405},{56,127,0},{127,115,1473},{56,127,0},{79,127,14066},{79,127,14066},{79,127,14066},{73,127,10571},{71,127,11450},{59,127,6166},{59,127,6166},
|
||||
{37,127,148},{25,127,6914},{5,127,1413},{111,127,666},{111,127,666},{111,127,666},{105,127,205},{127,90,1105},{99,127,405},{99,127,405},{56,127,0},{127,109,1105},{56,127,0},{127,127,0},{127,127,0},{127,127,0},{127,127,0},{127,127,0},{127,127,0},{127,127,0},{0,127,0},{127,127,0},{0,127,0},{69,0,9250},{69,0,9250},{69,0,9250},{69,0,9250},{52,127,3940},{52,127,3940},{52,127,3940},{37,127,148},{5,127,1413},
|
||||
{5,127,1413},
|
||||
{5,127,1413},
|
||||
|
|
|
|||
File diff suppressed because it is too large
Load diff
|
|
@ -491,4 +491,4 @@
|
|||
{17,31,10897},{16,31,12077},{13,31,6285},{13,31,6285},{8,31,68},{4,31,7686},{0,31,1341},{27,31,968},{27,31,968},{27,31,968},{25,31,325},{31,21,1513},{23,31,605},{23,31,605},{11,31,0},{31,26,1513},{11,31,0},{31,31,0},{31,31,0},{31,31,0},{31,31,0},{31,31,0},{31,31,0},{31,31,0},{0,31,0},{31,31,0},{0,31,0},{16,0,9248},{16,0,9248},{16,0,9248},{16,0,9248},{12,31,3626},
|
||||
{12,31,3626},{12,31,3626},{8,31,68},{0,31,1341},{0,31,1341},{21,31,17476},{20,31,14998},{20,31,14098},{18,31,10672},{20,31,16018},{15,31,8154},{15,31,6218},{9,31,200},{10,31,11338},{0,31,1613},{28,31,1041},{27,31,801},{27,31,680},{26,31,232},{29,29,1473},{26,31,753},{24,31,442},{14,31,0},{31,28,1473},{14,31,0},{20,31,14098},{20,31,14098},{20,31,14098},{18,31,10672},{17,31,11453},{15,31,6218},{15,31,6218},
|
||||
{9,31,200},{6,31,7270},{0,31,1613},{27,31,680},{27,31,680},{27,31,680},{26,31,232},{28,28,1105},{24,31,442},{24,31,442},{14,31,0},{28,28,1105},{14,31,0},{31,31,0},{31,31,0},{31,31,0},{31,31,0},{31,31,0},{31,31,0},{31,31,0},{0,31,0},{31,31,0},{0,31,0},{17,0,9248},{17,0,9248},{17,0,9248},{17,0,9248},{13,31,3929},{13,31,3929},{13,31,3929},{9,31,200},{0,31,1613},
|
||||
{0,31,1613},
|
||||
{0,31,1613},
|
||||
|
|
|
|||
|
|
@ -491,4 +491,4 @@
|
|||
{34,63,10841},{34,63,12089},{26,63,6206},{26,63,6206},{17,63,74},{9,63,7678},{0,63,1341},{54,63,937},{54,63,937},{54,63,937},{51,63,305},{63,43,1513},{47,63,605},{47,63,605},{22,63,1},{62,53,1513},{22,63,1},{63,63,0},{63,63,0},{63,63,0},{63,63,0},{63,63,0},{63,63,0},{63,63,0},{0,63,0},{63,63,0},{0,63,0},{32,0,9256},{32,0,9256},{32,0,9256},{32,0,9256},{23,63,3650},
|
||||
{23,63,3650},{23,63,3650},{17,63,74},{0,63,1341},{0,63,1341},{43,63,17392},{40,63,15021},{40,63,14060},{37,63,10673},{40,63,16013},{32,63,8261},{29,63,6166},{19,63,194},{20,63,11338},{1,63,1594},{57,63,1041},{56,63,822},{54,63,697},{52,63,234},{63,51,1473},{51,63,737},{49,63,442},{28,63,1},{63,57,1473},{28,63,1},{40,63,14060},{40,63,14060},{40,63,14060},{37,63,10673},{34,63,11401},{29,63,6166},{29,63,6166},
|
||||
{19,63,194},{12,63,7270},{1,63,1594},{54,63,697},{54,63,697},{54,63,697},{52,63,234},{63,46,1105},{49,63,442},{49,63,442},{28,63,1},{63,54,1105},{28,63,1},{63,63,0},{63,63,0},{63,63,0},{63,63,0},{63,63,0},{63,63,0},{63,63,0},{0,63,0},{63,63,0},{0,63,0},{34,0,9256},{34,0,9256},{34,0,9256},{34,0,9256},{26,63,3898},{26,63,3898},{26,63,3898},{19,63,194},{1,63,1594},
|
||||
{1,63,1594},
|
||||
{1,63,1594},
|
||||
|
|
|
|||
|
|
@ -478,4 +478,4 @@
|
|||
{8,31,11312},{8,31,11249},{7,31,6499},{7,31,6499},{4,31,260},{3,31,10457},{0,31,2642},{13,31,925},{13,31,925},{13,31,925},{12,31,397},{15,22,1513},{11,31,794},{11,31,794},{7,31,4},{14,27,1513},{7,31,4},{15,31,0},{15,31,0},{15,31,0},{15,31,0},{15,31,0},{15,31,0},{15,31,0},{0,31,0},{15,31,0},{0,31,0},{8,0,9376},{8,0,9376},{8,0,9376},{8,0,9376},{6,31,3074},
|
||||
{6,31,3074},{6,31,3074},{4,31,260},{0,31,2642},{0,31,2642},{8,31,58848},{7,31,39683},{6,31,25130},{6,31,19007},{8,31,54849},{6,31,27132},{5,31,8569},{4,31,756},{4,31,51302},{0,31,5046},{13,31,1078},{13,31,806},{13,31,637},{12,31,365},{15,26,1473},{12,31,978},{12,31,617},{8,31,9},{14,29,1473},{8,31,9},{9,31,13604},{9,31,13604},{9,31,13604},{8,31,11184},{8,31,10433},{7,31,6339},{7,31,6339},
|
||||
{5,31,424},{4,31,9713},{0,31,2930},{13,31,637},{13,31,637},{13,31,637},{12,31,365},{14,27,1105},{12,31,617},{12,31,617},{8,31,9},{13,29,1105},{8,31,9},{15,31,0},{15,31,0},{15,31,0},{15,31,0},{15,31,0},{15,31,0},{15,31,0},{0,31,0},{15,31,0},{0,31,0},{8,0,9248},{8,0,9248},{8,0,9248},{8,0,9248},{6,31,3330},{6,31,3330},{6,31,3330},{5,31,424},{0,31,2930},
|
||||
{0,31,2930},
|
||||
{0,31,2930},
|
||||
|
|
|
|||
|
|
@ -478,4 +478,4 @@
|
|||
{4,7,11305},{4,7,11209},{3,7,6489},{3,7,6489},{2,7,272},{1,7,10377},{0,7,2642},{6,7,1040},{6,7,1040},{6,7,1040},{6,7,416},{7,6,1537},{6,7,929},{6,7,929},{3,7,9},{7,6,1513},{3,7,9},{7,7,242},{7,7,170},{7,7,121},{7,7,49},{7,7,242},{7,7,98},{7,7,49},{0,7,0},{7,7,98},{0,7,0},{4,0,9280},{4,0,9280},{4,0,9280},{4,0,9280},{3,7,3125},
|
||||
{3,7,3125},{3,7,3125},{2,7,272},{0,7,2642},{0,7,2642},{4,7,59414},{4,7,41414},{3,7,24952},{3,7,19100},{4,7,55014},{3,7,27085},{2,7,10021},{2,7,656},{1,7,52310},{0,7,5046},{7,7,1142},{7,7,1070},{7,7,1021},{6,7,416},{7,7,1538},{6,7,1025},{6,7,625},{4,7,4},{6,7,1529},{4,7,4},{5,7,13964},{5,7,13964},{5,7,13964},{4,7,11305},{4,7,10505},{3,7,6665},{3,7,6665},
|
||||
{2,7,592},{2,7,9973},{0,7,2930},{7,7,1021},{7,7,1021},{7,7,1021},{6,7,416},{7,6,1105},{6,7,625},{6,7,625},{4,7,4},{6,7,1129},{4,7,4},{7,7,242},{7,7,170},{7,7,121},{7,7,49},{7,7,242},{7,7,98},{7,7,49},{0,7,0},{7,7,98},{0,7,0},{4,0,9280},{4,0,9280},{4,0,9280},{4,0,9280},{3,7,3301},{3,7,3301},{3,7,3301},{2,7,592},{0,7,2930},
|
||||
{0,7,2930},
|
||||
{0,7,2930},
|
||||
|
|
|
|||
297
thirdparty/basis_universal/transcoder/basisu_transcoder_uastc.h
vendored
Normal file
297
thirdparty/basis_universal/transcoder/basisu_transcoder_uastc.h
vendored
Normal file
|
|
@ -0,0 +1,297 @@
|
|||
// basisu_transcoder_uastc.h
|
||||
#pragma once
|
||||
#include "basisu_transcoder_internal.h"
|
||||
|
||||
namespace basist
|
||||
{
|
||||
struct color_quad_u8
|
||||
{
|
||||
uint8_t m_c[4];
|
||||
};
|
||||
|
||||
const uint32_t TOTAL_UASTC_MODES = 19;
|
||||
const uint32_t UASTC_MODE_INDEX_SOLID_COLOR = 8;
|
||||
|
||||
const uint32_t TOTAL_ASTC_BC7_COMMON_PARTITIONS2 = 30;
|
||||
const uint32_t TOTAL_ASTC_BC7_COMMON_PARTITIONS3 = 11;
|
||||
const uint32_t TOTAL_BC7_3_ASTC2_COMMON_PARTITIONS = 19;
|
||||
|
||||
extern const uint8_t g_uastc_mode_weight_bits[TOTAL_UASTC_MODES];
|
||||
extern const uint8_t g_uastc_mode_weight_ranges[TOTAL_UASTC_MODES];
|
||||
extern const uint8_t g_uastc_mode_endpoint_ranges[TOTAL_UASTC_MODES];
|
||||
extern const uint8_t g_uastc_mode_subsets[TOTAL_UASTC_MODES];
|
||||
extern const uint8_t g_uastc_mode_planes[TOTAL_UASTC_MODES];
|
||||
extern const uint8_t g_uastc_mode_comps[TOTAL_UASTC_MODES];
|
||||
extern const uint8_t g_uastc_mode_has_etc1_bias[TOTAL_UASTC_MODES];
|
||||
extern const uint8_t g_uastc_mode_has_bc1_hint0[TOTAL_UASTC_MODES];
|
||||
extern const uint8_t g_uastc_mode_has_bc1_hint1[TOTAL_UASTC_MODES];
|
||||
extern const uint8_t g_uastc_mode_has_alpha[TOTAL_UASTC_MODES];
|
||||
extern const uint8_t g_uastc_mode_is_la[TOTAL_UASTC_MODES];
|
||||
|
||||
struct astc_bc7_common_partition2_desc
|
||||
{
|
||||
uint8_t m_bc7;
|
||||
uint16_t m_astc;
|
||||
bool m_invert;
|
||||
};
|
||||
|
||||
extern const astc_bc7_common_partition2_desc g_astc_bc7_common_partitions2[TOTAL_ASTC_BC7_COMMON_PARTITIONS2];
|
||||
|
||||
struct bc73_astc2_common_partition_desc
|
||||
{
|
||||
uint8_t m_bc73;
|
||||
uint16_t m_astc2;
|
||||
uint8_t k; // 0-5 - how to modify the BC7 3-subset pattern to match the ASTC pattern (LSB=invert)
|
||||
};
|
||||
|
||||
extern const bc73_astc2_common_partition_desc g_bc7_3_astc2_common_partitions[TOTAL_BC7_3_ASTC2_COMMON_PARTITIONS];
|
||||
|
||||
struct astc_bc7_common_partition3_desc
|
||||
{
|
||||
uint8_t m_bc7;
|
||||
uint16_t m_astc;
|
||||
uint8_t m_astc_to_bc7_perm; // converts ASTC to BC7 partition using g_astc_bc7_partition_index_perm_tables[][]
|
||||
};
|
||||
|
||||
extern const astc_bc7_common_partition3_desc g_astc_bc7_common_partitions3[TOTAL_ASTC_BC7_COMMON_PARTITIONS3];
|
||||
|
||||
extern const uint8_t g_astc_bc7_patterns2[TOTAL_ASTC_BC7_COMMON_PARTITIONS2][16];
|
||||
extern const uint8_t g_astc_bc7_patterns3[TOTAL_ASTC_BC7_COMMON_PARTITIONS3][16];
|
||||
extern const uint8_t g_bc7_3_astc2_patterns2[TOTAL_BC7_3_ASTC2_COMMON_PARTITIONS][16];
|
||||
|
||||
extern const uint8_t g_astc_bc7_pattern2_anchors[TOTAL_ASTC_BC7_COMMON_PARTITIONS2][3];
|
||||
extern const uint8_t g_astc_bc7_pattern3_anchors[TOTAL_ASTC_BC7_COMMON_PARTITIONS3][3];
|
||||
extern const uint8_t g_bc7_3_astc2_patterns2_anchors[TOTAL_BC7_3_ASTC2_COMMON_PARTITIONS][3];
|
||||
|
||||
extern const uint32_t g_uastc_mode_huff_codes[TOTAL_UASTC_MODES + 1][2];
|
||||
|
||||
extern const uint8_t g_astc_to_bc7_partition_index_perm_tables[6][3];
|
||||
extern const uint8_t g_bc7_to_astc_partition_index_perm_tables[6][3]; // inverse of g_astc_to_bc7_partition_index_perm_tables
|
||||
|
||||
extern const uint8_t* s_uastc_to_bc1_weights[6];
|
||||
|
||||
uint32_t bc7_convert_partition_index_3_to_2(uint32_t p, uint32_t k);
|
||||
|
||||
inline uint32_t astc_interpolate(uint32_t l, uint32_t h, uint32_t w, bool srgb)
|
||||
{
|
||||
if (srgb)
|
||||
{
|
||||
l = (l << 8) | 0x80;
|
||||
h = (h << 8) | 0x80;
|
||||
}
|
||||
else
|
||||
{
|
||||
l = (l << 8) | l;
|
||||
h = (h << 8) | h;
|
||||
}
|
||||
|
||||
uint32_t k = (l * (64 - w) + h * w + 32) >> 6;
|
||||
|
||||
return k >> 8;
|
||||
}
|
||||
|
||||
struct astc_block_desc
|
||||
{
|
||||
int m_weight_range; // weight BISE range
|
||||
|
||||
int m_subsets; // number of ASTC partitions
|
||||
int m_partition_seed; // partition pattern seed
|
||||
int m_cem; // color endpoint mode used by all subsets
|
||||
|
||||
int m_ccs; // color component selector (dual plane only)
|
||||
bool m_dual_plane; // true if dual plane
|
||||
|
||||
// Weight and endpoint BISE values.
|
||||
// Note these values are NOT linear, they must be BISE encoded. See Table 97 and Table 107.
|
||||
uint8_t m_endpoints[18]; // endpoint values, in RR GG BB etc. order
|
||||
uint8_t m_weights[64]; // weight index values, raster order, in P0 P1, P0 P1, etc. or P0, P0, P0, P0, etc. order
|
||||
};
|
||||
|
||||
const uint32_t BC7ENC_TOTAL_ASTC_RANGES = 21;
|
||||
|
||||
// See tables 81, 93, 18.13.Endpoint Unquantization
|
||||
const uint32_t TOTAL_ASTC_RANGES = 21;
|
||||
extern const int g_astc_bise_range_table[TOTAL_ASTC_RANGES][3];
|
||||
|
||||
struct astc_quant_bin
|
||||
{
|
||||
uint8_t m_unquant; // unquantized value
|
||||
uint8_t m_index; // sorted index
|
||||
};
|
||||
|
||||
extern astc_quant_bin g_astc_unquant[BC7ENC_TOTAL_ASTC_RANGES][256]; // [ASTC encoded endpoint index]
|
||||
|
||||
int astc_get_levels(int range);
|
||||
bool astc_is_valid_endpoint_range(uint32_t range);
|
||||
uint32_t unquant_astc_endpoint(uint32_t packed_bits, uint32_t packed_trits, uint32_t packed_quints, uint32_t range);
|
||||
uint32_t unquant_astc_endpoint_val(uint32_t packed_val, uint32_t range);
|
||||
|
||||
const uint8_t* get_anchor_indices(uint32_t subsets, uint32_t mode, uint32_t common_pattern, const uint8_t*& pPartition_pattern);
|
||||
|
||||
// BC7
|
||||
const uint32_t BC7ENC_BLOCK_SIZE = 16;
|
||||
|
||||
struct bc7_block
|
||||
{
|
||||
uint64_t m_qwords[2];
|
||||
};
|
||||
|
||||
struct bc7_optimization_results
|
||||
{
|
||||
uint32_t m_mode;
|
||||
uint32_t m_partition;
|
||||
uint8_t m_selectors[16];
|
||||
uint8_t m_alpha_selectors[16];
|
||||
color_quad_u8 m_low[3];
|
||||
color_quad_u8 m_high[3];
|
||||
uint32_t m_pbits[3][2];
|
||||
uint32_t m_index_selector;
|
||||
uint32_t m_rotation;
|
||||
};
|
||||
|
||||
extern const uint32_t g_bc7_weights1[2];
|
||||
extern const uint32_t g_bc7_weights2[4];
|
||||
extern const uint32_t g_bc7_weights3[8];
|
||||
extern const uint32_t g_bc7_weights4[16];
|
||||
extern const uint32_t g_astc_weights4[16];
|
||||
extern const uint32_t g_astc_weights5[32];
|
||||
extern const uint32_t g_astc_weights_3levels[3];
|
||||
extern const uint8_t g_bc7_partition1[16];
|
||||
extern const uint8_t g_bc7_partition2[64 * 16];
|
||||
extern const uint8_t g_bc7_partition3[64 * 16];
|
||||
extern const uint8_t g_bc7_table_anchor_index_second_subset[64];
|
||||
extern const uint8_t g_bc7_table_anchor_index_third_subset_1[64];
|
||||
extern const uint8_t g_bc7_table_anchor_index_third_subset_2[64];
|
||||
extern const uint8_t g_bc7_num_subsets[8];
|
||||
extern const uint8_t g_bc7_partition_bits[8];
|
||||
extern const uint8_t g_bc7_color_index_bitcount[8];
|
||||
extern const uint8_t g_bc7_mode_has_p_bits[8];
|
||||
extern const uint8_t g_bc7_mode_has_shared_p_bits[8];
|
||||
extern const uint8_t g_bc7_color_precision_table[8];
|
||||
extern const int8_t g_bc7_alpha_precision_table[8];
|
||||
extern const uint8_t g_bc7_alpha_index_bitcount[8];
|
||||
|
||||
inline bool get_bc7_mode_has_seperate_alpha_selectors(int mode) { return (mode == 4) || (mode == 5); }
|
||||
inline int get_bc7_color_index_size(int mode, int index_selection_bit) { return g_bc7_color_index_bitcount[mode] + index_selection_bit; }
|
||||
inline int get_bc7_alpha_index_size(int mode, int index_selection_bit) { return g_bc7_alpha_index_bitcount[mode] - index_selection_bit; }
|
||||
|
||||
struct endpoint_err
|
||||
{
|
||||
uint16_t m_error; uint8_t m_lo; uint8_t m_hi;
|
||||
};
|
||||
|
||||
extern endpoint_err g_bc7_mode_6_optimal_endpoints[256][2]; // [c][pbit]
|
||||
const uint32_t BC7ENC_MODE_6_OPTIMAL_INDEX = 5;
|
||||
|
||||
extern endpoint_err g_bc7_mode_5_optimal_endpoints[256]; // [c]
|
||||
const uint32_t BC7ENC_MODE_5_OPTIMAL_INDEX = 1;
|
||||
|
||||
// Packs a BC7 block from a high-level description. Handles all BC7 modes.
|
||||
void encode_bc7_block(void* pBlock, const bc7_optimization_results* pResults);
|
||||
|
||||
// Packs an ASTC block
|
||||
// Constraints: Always 4x4, all subset CEM's must be equal, only tested with LDR CEM's.
|
||||
bool pack_astc_block(uint32_t* pDst, const astc_block_desc* pBlock, uint32_t mode);
|
||||
|
||||
void pack_astc_solid_block(void* pDst_block, const color32& color);
|
||||
|
||||
#ifdef _DEBUG
|
||||
int astc_compute_texel_partition(int seed, int x, int y, int z, int partitioncount, bool small_block);
|
||||
#endif
|
||||
|
||||
struct uastc_block
|
||||
{
|
||||
union
|
||||
{
|
||||
uint8_t m_bytes[16];
|
||||
uint32_t m_dwords[4];
|
||||
|
||||
#ifndef __EMSCRIPTEN__
|
||||
uint64_t m_qwords[2];
|
||||
#endif
|
||||
};
|
||||
};
|
||||
|
||||
struct unpacked_uastc_block
|
||||
{
|
||||
astc_block_desc m_astc;
|
||||
|
||||
uint32_t m_mode;
|
||||
uint32_t m_common_pattern;
|
||||
|
||||
color32 m_solid_color;
|
||||
|
||||
bool m_bc1_hint0;
|
||||
bool m_bc1_hint1;
|
||||
|
||||
bool m_etc1_flip;
|
||||
bool m_etc1_diff;
|
||||
uint32_t m_etc1_inten0;
|
||||
uint32_t m_etc1_inten1;
|
||||
|
||||
uint32_t m_etc1_bias;
|
||||
|
||||
uint32_t m_etc2_hints;
|
||||
|
||||
uint32_t m_etc1_selector;
|
||||
uint32_t m_etc1_r, m_etc1_g, m_etc1_b;
|
||||
};
|
||||
|
||||
color32 apply_etc1_bias(const color32 &block_color, uint32_t bias, uint32_t limit, uint32_t subblock);
|
||||
|
||||
struct decoder_etc_block;
|
||||
struct eac_block;
|
||||
|
||||
bool unpack_uastc(uint32_t mode, uint32_t common_pattern, const color32& solid_color, const astc_block_desc& astc, color32* pPixels, bool srgb);
|
||||
bool unpack_uastc(const unpacked_uastc_block& unpacked_blk, color32* pPixels, bool srgb);
|
||||
|
||||
bool unpack_uastc(const uastc_block& blk, color32* pPixels, bool srgb);
|
||||
bool unpack_uastc(const uastc_block& blk, unpacked_uastc_block& unpacked, bool undo_blue_contract, bool read_hints = true);
|
||||
|
||||
bool transcode_uastc_to_astc(const uastc_block& src_blk, void* pDst);
|
||||
|
||||
bool transcode_uastc_to_bc7(const unpacked_uastc_block& unpacked_src_blk, bc7_optimization_results& dst_blk);
|
||||
bool transcode_uastc_to_bc7(const uastc_block& src_blk, bc7_optimization_results& dst_blk);
|
||||
bool transcode_uastc_to_bc7(const uastc_block& src_blk, void* pDst);
|
||||
|
||||
void transcode_uastc_to_etc1(unpacked_uastc_block& unpacked_src_blk, color32 block_pixels[4][4], void* pDst);
|
||||
bool transcode_uastc_to_etc1(const uastc_block& src_blk, void* pDst);
|
||||
bool transcode_uastc_to_etc1(const uastc_block& src_blk, void* pDst, uint32_t channel);
|
||||
|
||||
void transcode_uastc_to_etc2_eac_a8(unpacked_uastc_block& unpacked_src_blk, color32 block_pixels[4][4], void* pDst);
|
||||
bool transcode_uastc_to_etc2_rgba(const uastc_block& src_blk, void* pDst);
|
||||
|
||||
// Packs 16 scalar values to BC4. Same PSNR as stb_dxt's BC4 encoder, around 13% faster.
|
||||
void encode_bc4(void* pDst, const uint8_t* pPixels, uint32_t stride);
|
||||
|
||||
void encode_bc1_solid_block(void* pDst, uint32_t fr, uint32_t fg, uint32_t fb);
|
||||
|
||||
enum
|
||||
{
|
||||
cEncodeBC1HighQuality = 1,
|
||||
cEncodeBC1HigherQuality = 2,
|
||||
cEncodeBC1UseSelectors = 4,
|
||||
};
|
||||
void encode_bc1(void* pDst, const uint8_t* pPixels, uint32_t flags);
|
||||
|
||||
// Alternate PCA-free encoder, around 15% faster, same (or slightly higher) avg. PSNR
|
||||
void encode_bc1_alt(void* pDst, const uint8_t* pPixels, uint32_t flags);
|
||||
|
||||
void transcode_uastc_to_bc1_hint0(const unpacked_uastc_block& unpacked_src_blk, void* pDst);
|
||||
void transcode_uastc_to_bc1_hint1(const unpacked_uastc_block& unpacked_src_blk, const color32 block_pixels[4][4], void* pDst, bool high_quality);
|
||||
|
||||
bool transcode_uastc_to_bc1(const uastc_block& src_blk, void* pDst, bool high_quality);
|
||||
bool transcode_uastc_to_bc3(const uastc_block& src_blk, void* pDst, bool high_quality);
|
||||
bool transcode_uastc_to_bc4(const uastc_block& src_blk, void* pDst, bool high_quality, uint32_t chan0);
|
||||
bool transcode_uastc_to_bc5(const uastc_block& src_blk, void* pDst, bool high_quality, uint32_t chan0, uint32_t chan1);
|
||||
|
||||
bool transcode_uastc_to_etc2_eac_r11(const uastc_block& src_blk, void* pDst, bool high_quality, uint32_t chan0);
|
||||
bool transcode_uastc_to_etc2_eac_rg11(const uastc_block& src_blk, void* pDst, bool high_quality, uint32_t chan0, uint32_t chan1);
|
||||
|
||||
bool transcode_uastc_to_pvrtc1_4_rgb(const uastc_block* pSrc_blocks, void* pDst_blocks, uint32_t num_blocks_x, uint32_t num_blocks_y, bool high_quality, bool from_alpha);
|
||||
bool transcode_uastc_to_pvrtc1_4_rgba(const uastc_block* pSrc_blocks, void* pDst_blocks, uint32_t num_blocks_x, uint32_t num_blocks_y, bool high_quality);
|
||||
|
||||
// uastc_init() MUST be called before using this module.
|
||||
void uastc_init();
|
||||
|
||||
} // namespace basist
|
||||
Loading…
Add table
Add a link
Reference in a new issue