Reformat the source files.

This commit is contained in:
Alexander Suvorov
2017-04-26 11:41:07 +02:00
parent 41d7b962b0
commit 7c02055d05
197 changed files with 66650 additions and 70743 deletions
Binary file not shown.
+456 -528
View File
File diff suppressed because it is too large Load Diff
+49 -52
View File
@@ -2,73 +2,70 @@
// See Copyright Notice and license at the end of inc/crnlib.h
#pragma once
namespace crnlib
{
struct Area
{
struct Area *Pprev, *Pnext;
namespace crnlib {
struct Area {
struct Area *Pprev, *Pnext;
int x1, y1, x2, y2;
uint get_width() const { return x2 - x1 + 1; }
uint get_height() const { return y2 - y1 + 1; }
uint get_area() const { return get_width() * get_height(); }
};
int x1, y1, x2, y2;
typedef Area * Area_Ptr;
uint get_width() const { return x2 - x1 + 1; }
uint get_height() const { return y2 - y1 + 1; }
uint get_area() const { return get_width() * get_height(); }
};
struct Area_List
{
int total_areas;
int next_free;
typedef Area* Area_Ptr;
Area *Phead, *Ptail, *Pfree;
};
struct Area_List {
int total_areas;
int next_free;
typedef Area_List * Area_List_Ptr;
Area *Phead, *Ptail, *Pfree;
};
Area_List * Area_List_init(int max_areas);
void Area_List_deinit(Area_List* Pobj_base);
typedef Area_List* Area_List_Ptr;
void Area_List_print(Area_List *Plist);
Area_List* Area_List_init(int max_areas);
void Area_List_deinit(Area_List* Pobj_base);
Area_List * Area_List_dup_new(Area_List *Plist,
int x_ofs, int y_ofs);
uint Area_List_get_num(Area_List* Plist);
void Area_List_print(Area_List* Plist);
// src and dst area lists must have the same number of total areas.
void Area_List_dup(Area_List *Psrc_list,
Area_List *Pdst_list,
int x_ofs, int y_ofs);
Area_List* Area_List_dup_new(Area_List* Plist,
int x_ofs, int y_ofs);
void Area_List_copy(Area_List *Psrc_list,
Area_List *Pdst_list,
int x_ofs, int y_ofs);
uint Area_List_get_num(Area_List* Plist);
void Area_List_clear(Area_List *Plist);
// src and dst area lists must have the same number of total areas.
void Area_List_dup(Area_List* Psrc_list,
Area_List* Pdst_list,
int x_ofs, int y_ofs);
void Area_List_set(Area_List *Plist,
void Area_List_copy(Area_List* Psrc_list,
Area_List* Pdst_list,
int x_ofs, int y_ofs);
void Area_List_clear(Area_List* Plist);
void Area_List_set(Area_List* Plist,
int x1, int y1, int x2, int y2);
// logical: x and (not y)
void Area_List_remove(Area_List* Plist,
int x1, int y1, int x2, int y2);
// logical: x and (not y)
void Area_List_remove(Area_List *Plist,
int x1, int y1, int x2, int y2);
// logical: x or y
void Area_List_insert(Area_List* Plist,
int x1, int y1, int x2, int y2,
bool combine);
// logical: x or y
void Area_List_insert(Area_List *Plist,
int x1, int y1, int x2, int y2,
bool combine);
// logical: x and y
void Area_List_intersect_area(Area_List* Plist,
int x1, int y1, int x2, int y2);
// logical: x and y
void Area_List_intersect_area(Area_List *Plist,
int x1, int y1, int x2, int y2);
// logical: x and y
void Area_List_intersect_Area_List(Area_List* Pouter_list,
Area_List* Pinner_list,
Area_List* Pdst_list);
// logical: x and y
void Area_List_intersect_Area_List(Area_List *Pouter_list,
Area_List *Pinner_list,
Area_List *Pdst_list);
Area_List_Ptr Area_List_create_optimal(Area_List_Ptr Plist);
Area_List_Ptr Area_List_create_optimal(Area_List_Ptr Plist);
} // namespace crnlib
} // namespace crnlib
+32 -38
View File
@@ -8,62 +8,56 @@
static bool g_fail_exceptions;
static bool g_exit_on_failure = true;
void crnlib_enable_fail_exceptions(bool enabled)
{
g_fail_exceptions = enabled;
void crnlib_enable_fail_exceptions(bool enabled) {
g_fail_exceptions = enabled;
}
void crnlib_assert(const char* pExp, const char* pFile, unsigned line)
{
char buf[512];
void crnlib_assert(const char* pExp, const char* pFile, unsigned line) {
char buf[512];
sprintf_s(buf, sizeof(buf), "%s(%u): Assertion failed: \"%s\"\n", pFile, line, pExp);
sprintf_s(buf, sizeof(buf), "%s(%u): Assertion failed: \"%s\"\n", pFile, line, pExp);
crnlib_output_debug_string(buf);
crnlib_output_debug_string(buf);
fputs(buf, stderr);
fputs(buf, stderr);
if (crnlib_is_debugger_present())
crnlib_debug_break();
if (crnlib_is_debugger_present())
crnlib_debug_break();
}
void crnlib_fail(const char* pExp, const char* pFile, unsigned line)
{
char buf[512];
void crnlib_fail(const char* pExp, const char* pFile, unsigned line) {
char buf[512];
sprintf_s(buf, sizeof(buf), "%s(%u): Failure: \"%s\"\n", pFile, line, pExp);
sprintf_s(buf, sizeof(buf), "%s(%u): Failure: \"%s\"\n", pFile, line, pExp);
crnlib_output_debug_string(buf);
crnlib_output_debug_string(buf);
fputs(buf, stderr);
fputs(buf, stderr);
if (crnlib_is_debugger_present())
crnlib_debug_break();
if (crnlib_is_debugger_present())
crnlib_debug_break();
#if CRNLIB_USE_WIN32_API
if (g_fail_exceptions)
RaiseException(CRNLIB_FAIL_EXCEPTION_CODE, 0, 0, NULL);
else
if (g_fail_exceptions)
RaiseException(CRNLIB_FAIL_EXCEPTION_CODE, 0, 0, NULL);
else
#endif
if (g_exit_on_failure)
exit(EXIT_FAILURE);
if (g_exit_on_failure)
exit(EXIT_FAILURE);
}
void trace(const char* pFmt, va_list args)
{
if (crnlib_is_debugger_present())
{
char buf[512];
vsprintf_s(buf, sizeof(buf), pFmt, args);
void trace(const char* pFmt, va_list args) {
if (crnlib_is_debugger_present()) {
char buf[512];
vsprintf_s(buf, sizeof(buf), pFmt, args);
crnlib_output_debug_string(buf);
}
crnlib_output_debug_string(buf);
}
};
void trace(const char* pFmt, ...)
{
va_list args;
va_start(args, pFmt);
trace(pFmt, args);
va_end(args);
void trace(const char* pFmt, ...) {
va_list args;
va_start(args, pFmt);
trace(pFmt, args);
va_end(args);
};
+34 -26
View File
@@ -9,16 +9,19 @@ void crnlib_assert(const char* pExp, const char* pFile, unsigned line);
void crnlib_fail(const char* pExp, const char* pFile, unsigned line);
#ifdef NDEBUG
#define CRNLIB_ASSERT(x) ((void)0)
#undef CRNLIB_ASSERTS_ENABLED
#define CRNLIB_ASSERT(x) ((void)0)
#undef CRNLIB_ASSERTS_ENABLED
#else
#define CRNLIB_ASSERT(_exp) (void)( (!!(_exp)) || (crnlib_assert(#_exp, __FILE__, __LINE__), 0) )
#define CRNLIB_ASSERTS_ENABLED
#define CRNLIB_ASSERT(_exp) (void)((!!(_exp)) || (crnlib_assert(#_exp, __FILE__, __LINE__), 0))
#define CRNLIB_ASSERTS_ENABLED
#endif
#define CRNLIB_VERIFY(_exp) (void)( (!!(_exp)) || (crnlib_assert(#_exp, __FILE__, __LINE__), 0) )
#define CRNLIB_VERIFY(_exp) (void)((!!(_exp)) || (crnlib_assert(#_exp, __FILE__, __LINE__), 0))
#define CRNLIB_FAIL(msg) do { crnlib_fail(#msg, __FILE__, __LINE__); } while(0)
#define CRNLIB_FAIL(msg) \
do { \
crnlib_fail(#msg, __FILE__, __LINE__); \
} while (0)
#define CRNLIB_ASSERT_OPEN_RANGE(x, l, h) CRNLIB_ASSERT((x >= l) && (x < h))
#define CRNLIB_ASSERT_CLOSED_RANGE(x, l, h) CRNLIB_ASSERT((x >= l) && (x <= h))
@@ -27,35 +30,40 @@ void trace(const char* pFmt, va_list args);
void trace(const char* pFmt, ...);
// Borrowed from boost libraries.
template <bool x> struct crnlib_assume_failure;
template <> struct crnlib_assume_failure<true> { enum { blah = 1 }; };
template<int x> struct crnlib_assume_try { };
template <bool x>
struct crnlib_assume_failure;
template <>
struct crnlib_assume_failure<true> {
enum { blah = 1 };
};
template <int x>
struct crnlib_assume_try {};
#define CRNLIB_JOINER_FINAL(a, b) a##b
#define CRNLIB_JOINER(a, b) CRNLIB_JOINER_FINAL(a, b)
#define CRNLIB_JOIN(a, b) CRNLIB_JOINER(a, b)
#define CRNLIB_ASSUME(p) typedef crnlib_assume_try < sizeof(crnlib_assume_failure< (bool)(p) > ) > CRNLIB_JOIN(crnlib_assume_typedef, __COUNTER__)
#define CRNLIB_ASSUME(p) typedef crnlib_assume_try<sizeof(crnlib_assume_failure<(bool)(p)>)> CRNLIB_JOIN(crnlib_assume_typedef, __COUNTER__)
#ifdef NDEBUG
template<typename T> inline T crnlib_assert_range(T i, T m)
{
m;
return i;
template <typename T>
inline T crnlib_assert_range(T i, T m) {
m;
return i;
}
template<typename T> inline T crnlib_assert_range_incl(T i, T m)
{
m;
return i;
template <typename T>
inline T crnlib_assert_range_incl(T i, T m) {
m;
return i;
}
#else
template<typename T> inline T crnlib_assert_range(T i, T m)
{
CRNLIB_ASSERT((i >= 0) && (i < m));
return i;
template <typename T>
inline T crnlib_assert_range(T i, T m) {
CRNLIB_ASSERT((i >= 0) && (i < m));
return i;
}
template<typename T> inline T crnlib_assert_range_incl(T i, T m)
{
CRNLIB_ASSERT((i >= 0) && (i <= m));
return i;
template <typename T>
inline T crnlib_assert_range_incl(T i, T m) {
CRNLIB_ASSERT((i >= 0) && (i <= m));
return i;
}
#endif
+133 -157
View File
@@ -11,198 +11,174 @@
#endif
#if defined(__GNUC__) && CRNLIB_PLATFORM_PC
extern __inline__ __attribute__((__always_inline__,__gnu_inline__)) void crnlib_yield_processor()
{
__asm__ __volatile__("pause");
extern __inline__ __attribute__((__always_inline__, __gnu_inline__)) void crnlib_yield_processor() {
__asm__ __volatile__("pause");
}
#else
CRNLIB_FORCE_INLINE void crnlib_yield_processor()
{
CRNLIB_FORCE_INLINE void crnlib_yield_processor() {
#if CRNLIB_USE_MSVC_INTRINSICS
#if CRNLIB_PLATFORM_PC_X64
_mm_pause();
#else
YieldProcessor();
#endif
#if CRNLIB_PLATFORM_PC_X64
_mm_pause();
#else
// No implementation
YieldProcessor();
#endif
#else
// No implementation
#endif
}
#endif
#if CRNLIB_USE_WIN32_ATOMIC_FUNCTIONS
extern "C" __int64 _InterlockedCompareExchange64(__int64 volatile * Destination, __int64 Exchange, __int64 Comperand);
#if defined(_MSC_VER)
#pragma intrinsic(_InterlockedCompareExchange64)
#endif
#endif // CRNLIB_USE_WIN32_ATOMIC_FUNCTIONS
extern "C" __int64 _InterlockedCompareExchange64(__int64 volatile* Destination, __int64 Exchange, __int64 Comperand);
#if defined(_MSC_VER)
#pragma intrinsic(_InterlockedCompareExchange64)
#endif
#endif // CRNLIB_USE_WIN32_ATOMIC_FUNCTIONS
namespace crnlib
{
namespace crnlib {
#if CRNLIB_USE_WIN32_ATOMIC_FUNCTIONS
typedef LONG atomic32_t;
typedef LONGLONG atomic64_t;
typedef LONG atomic32_t;
typedef LONGLONG atomic64_t;
// Returns the original value.
inline atomic32_t atomic_compare_exchange32(atomic32_t volatile *pDest, atomic32_t exchange, atomic32_t comparand)
{
CRNLIB_ASSERT((reinterpret_cast<ptr_bits_t>(pDest) & 3) == 0);
return InterlockedCompareExchange(pDest, exchange, comparand);
}
// Returns the original value.
inline atomic32_t atomic_compare_exchange32(atomic32_t volatile* pDest, atomic32_t exchange, atomic32_t comparand) {
CRNLIB_ASSERT((reinterpret_cast<ptr_bits_t>(pDest) & 3) == 0);
return InterlockedCompareExchange(pDest, exchange, comparand);
}
// Returns the original value.
inline atomic64_t atomic_compare_exchange64(atomic64_t volatile *pDest, atomic64_t exchange, atomic64_t comparand)
{
CRNLIB_ASSERT((reinterpret_cast<ptr_bits_t>(pDest) & 7) == 0);
return _InterlockedCompareExchange64(pDest, exchange, comparand);
}
// Returns the original value.
inline atomic64_t atomic_compare_exchange64(atomic64_t volatile* pDest, atomic64_t exchange, atomic64_t comparand) {
CRNLIB_ASSERT((reinterpret_cast<ptr_bits_t>(pDest) & 7) == 0);
return _InterlockedCompareExchange64(pDest, exchange, comparand);
}
// Returns the resulting incremented value.
inline atomic32_t atomic_increment32(atomic32_t volatile *pDest)
{
CRNLIB_ASSERT((reinterpret_cast<ptr_bits_t>(pDest) & 3) == 0);
return InterlockedIncrement(pDest);
}
// Returns the resulting incremented value.
inline atomic32_t atomic_increment32(atomic32_t volatile* pDest) {
CRNLIB_ASSERT((reinterpret_cast<ptr_bits_t>(pDest) & 3) == 0);
return InterlockedIncrement(pDest);
}
// Returns the resulting decremented value.
inline atomic32_t atomic_decrement32(atomic32_t volatile *pDest)
{
CRNLIB_ASSERT((reinterpret_cast<ptr_bits_t>(pDest) & 3) == 0);
return InterlockedDecrement(pDest);
}
// Returns the resulting decremented value.
inline atomic32_t atomic_decrement32(atomic32_t volatile* pDest) {
CRNLIB_ASSERT((reinterpret_cast<ptr_bits_t>(pDest) & 3) == 0);
return InterlockedDecrement(pDest);
}
// Returns the original value.
inline atomic32_t atomic_exchange32(atomic32_t volatile *pDest, atomic32_t val)
{
CRNLIB_ASSERT((reinterpret_cast<ptr_bits_t>(pDest) & 3) == 0);
return InterlockedExchange(pDest, val);
}
// Returns the original value.
inline atomic32_t atomic_exchange32(atomic32_t volatile* pDest, atomic32_t val) {
CRNLIB_ASSERT((reinterpret_cast<ptr_bits_t>(pDest) & 3) == 0);
return InterlockedExchange(pDest, val);
}
// Returns the resulting value.
inline atomic32_t atomic_add32(atomic32_t volatile *pDest, atomic32_t val)
{
CRNLIB_ASSERT((reinterpret_cast<ptr_bits_t>(pDest) & 3) == 0);
return InterlockedExchangeAdd(pDest, val) + val;
}
// Returns the resulting value.
inline atomic32_t atomic_add32(atomic32_t volatile* pDest, atomic32_t val) {
CRNLIB_ASSERT((reinterpret_cast<ptr_bits_t>(pDest) & 3) == 0);
return InterlockedExchangeAdd(pDest, val) + val;
}
// Returns the original value.
inline atomic32_t atomic_exchange_add32(atomic32_t volatile *pDest, atomic32_t val)
{
CRNLIB_ASSERT((reinterpret_cast<ptr_bits_t>(pDest) & 3) == 0);
return InterlockedExchangeAdd(pDest, val);
}
// Returns the original value.
inline atomic32_t atomic_exchange_add32(atomic32_t volatile* pDest, atomic32_t val) {
CRNLIB_ASSERT((reinterpret_cast<ptr_bits_t>(pDest) & 3) == 0);
return InterlockedExchangeAdd(pDest, val);
}
#elif CRNLIB_USE_GCC_ATOMIC_BUILTINS
typedef long atomic32_t;
typedef long long atomic64_t;
typedef long atomic32_t;
typedef long long atomic64_t;
// Returns the original value.
inline atomic32_t atomic_compare_exchange32(atomic32_t volatile *pDest, atomic32_t exchange, atomic32_t comparand)
{
CRNLIB_ASSERT((reinterpret_cast<ptr_bits_t>(pDest) & 3) == 0);
return __sync_val_compare_and_swap(pDest, comparand, exchange);
}
// Returns the original value.
inline atomic32_t atomic_compare_exchange32(atomic32_t volatile* pDest, atomic32_t exchange, atomic32_t comparand) {
CRNLIB_ASSERT((reinterpret_cast<ptr_bits_t>(pDest) & 3) == 0);
return __sync_val_compare_and_swap(pDest, comparand, exchange);
}
// Returns the original value.
inline atomic64_t atomic_compare_exchange64(atomic64_t volatile *pDest, atomic64_t exchange, atomic64_t comparand)
{
CRNLIB_ASSERT((reinterpret_cast<ptr_bits_t>(pDest) & 7) == 0);
return __sync_val_compare_and_swap(pDest, comparand, exchange);
}
// Returns the original value.
inline atomic64_t atomic_compare_exchange64(atomic64_t volatile* pDest, atomic64_t exchange, atomic64_t comparand) {
CRNLIB_ASSERT((reinterpret_cast<ptr_bits_t>(pDest) & 7) == 0);
return __sync_val_compare_and_swap(pDest, comparand, exchange);
}
// Returns the resulting incremented value.
inline atomic32_t atomic_increment32(atomic32_t volatile *pDest)
{
CRNLIB_ASSERT((reinterpret_cast<ptr_bits_t>(pDest) & 3) == 0);
return __sync_add_and_fetch(pDest, 1);
}
// Returns the resulting incremented value.
inline atomic32_t atomic_increment32(atomic32_t volatile* pDest) {
CRNLIB_ASSERT((reinterpret_cast<ptr_bits_t>(pDest) & 3) == 0);
return __sync_add_and_fetch(pDest, 1);
}
// Returns the resulting decremented value.
inline atomic32_t atomic_decrement32(atomic32_t volatile *pDest)
{
CRNLIB_ASSERT((reinterpret_cast<ptr_bits_t>(pDest) & 3) == 0);
return __sync_sub_and_fetch(pDest, 1);
}
// Returns the resulting decremented value.
inline atomic32_t atomic_decrement32(atomic32_t volatile* pDest) {
CRNLIB_ASSERT((reinterpret_cast<ptr_bits_t>(pDest) & 3) == 0);
return __sync_sub_and_fetch(pDest, 1);
}
// Returns the original value.
inline atomic32_t atomic_exchange32(atomic32_t volatile *pDest, atomic32_t val)
{
CRNLIB_ASSERT((reinterpret_cast<ptr_bits_t>(pDest) & 3) == 0);
return __sync_lock_test_and_set(pDest, val);
}
// Returns the original value.
inline atomic32_t atomic_exchange32(atomic32_t volatile* pDest, atomic32_t val) {
CRNLIB_ASSERT((reinterpret_cast<ptr_bits_t>(pDest) & 3) == 0);
return __sync_lock_test_and_set(pDest, val);
}
// Returns the resulting value.
inline atomic32_t atomic_add32(atomic32_t volatile *pDest, atomic32_t val)
{
CRNLIB_ASSERT((reinterpret_cast<ptr_bits_t>(pDest) & 3) == 0);
return __sync_add_and_fetch(pDest, val);
}
// Returns the resulting value.
inline atomic32_t atomic_add32(atomic32_t volatile* pDest, atomic32_t val) {
CRNLIB_ASSERT((reinterpret_cast<ptr_bits_t>(pDest) & 3) == 0);
return __sync_add_and_fetch(pDest, val);
}
// Returns the original value.
inline atomic32_t atomic_exchange_add32(atomic32_t volatile *pDest, atomic32_t val)
{
CRNLIB_ASSERT((reinterpret_cast<ptr_bits_t>(pDest) & 3) == 0);
return __sync_fetch_and_add(pDest, val);
}
// Returns the original value.
inline atomic32_t atomic_exchange_add32(atomic32_t volatile* pDest, atomic32_t val) {
CRNLIB_ASSERT((reinterpret_cast<ptr_bits_t>(pDest) & 3) == 0);
return __sync_fetch_and_add(pDest, val);
}
#else
#define CRNLIB_NO_ATOMICS 1
#define CRNLIB_NO_ATOMICS 1
// Atomic ops not supported - but try to do something reasonable. Assumes no threading at all.
typedef long atomic32_t;
typedef long long atomic64_t;
// Atomic ops not supported - but try to do something reasonable. Assumes no threading at all.
typedef long atomic32_t;
typedef long long atomic64_t;
inline atomic32_t atomic_compare_exchange32(atomic32_t volatile *pDest, atomic32_t exchange, atomic32_t comparand)
{
CRNLIB_ASSERT((reinterpret_cast<ptr_bits_t>(pDest) & 3) == 0);
atomic32_t cur = *pDest;
if (cur == comparand)
*pDest = exchange;
return cur;
}
inline atomic32_t atomic_compare_exchange32(atomic32_t volatile* pDest, atomic32_t exchange, atomic32_t comparand) {
CRNLIB_ASSERT((reinterpret_cast<ptr_bits_t>(pDest) & 3) == 0);
atomic32_t cur = *pDest;
if (cur == comparand)
*pDest = exchange;
return cur;
}
inline atomic64_t atomic_compare_exchange64(atomic64_t volatile *pDest, atomic64_t exchange, atomic64_t comparand)
{
CRNLIB_ASSERT((reinterpret_cast<ptr_bits_t>(pDest) & 7) == 0);
atomic64_t cur = *pDest;
if (cur == comparand)
*pDest = exchange;
return cur;
}
inline atomic64_t atomic_compare_exchange64(atomic64_t volatile* pDest, atomic64_t exchange, atomic64_t comparand) {
CRNLIB_ASSERT((reinterpret_cast<ptr_bits_t>(pDest) & 7) == 0);
atomic64_t cur = *pDest;
if (cur == comparand)
*pDest = exchange;
return cur;
}
inline atomic32_t atomic_increment32(atomic32_t volatile *pDest)
{
CRNLIB_ASSERT((reinterpret_cast<ptr_bits_t>(pDest) & 3) == 0);
return (*pDest += 1);
}
inline atomic32_t atomic_increment32(atomic32_t volatile* pDest) {
CRNLIB_ASSERT((reinterpret_cast<ptr_bits_t>(pDest) & 3) == 0);
return (*pDest += 1);
}
inline atomic32_t atomic_decrement32(atomic32_t volatile *pDest)
{
CRNLIB_ASSERT((reinterpret_cast<ptr_bits_t>(pDest) & 3) == 0);
return (*pDest -= 1);
}
inline atomic32_t atomic_decrement32(atomic32_t volatile* pDest) {
CRNLIB_ASSERT((reinterpret_cast<ptr_bits_t>(pDest) & 3) == 0);
return (*pDest -= 1);
}
inline atomic32_t atomic_exchange32(atomic32_t volatile *pDest, atomic32_t val)
{
CRNLIB_ASSERT((reinterpret_cast<ptr_bits_t>(pDest) & 3) == 0);
atomic32_t cur = *pDest;
*pDest = val;
return cur;
}
inline atomic32_t atomic_exchange32(atomic32_t volatile* pDest, atomic32_t val) {
CRNLIB_ASSERT((reinterpret_cast<ptr_bits_t>(pDest) & 3) == 0);
atomic32_t cur = *pDest;
*pDest = val;
return cur;
}
inline atomic32_t atomic_add32(atomic32_t volatile *pDest, atomic32_t val)
{
CRNLIB_ASSERT((reinterpret_cast<ptr_bits_t>(pDest) & 3) == 0);
return (*pDest += val);
}
inline atomic32_t atomic_add32(atomic32_t volatile* pDest, atomic32_t val) {
CRNLIB_ASSERT((reinterpret_cast<ptr_bits_t>(pDest) & 3) == 0);
return (*pDest += val);
}
inline atomic32_t atomic_exchange_add32(atomic32_t volatile *pDest, atomic32_t val)
{
CRNLIB_ASSERT((reinterpret_cast<ptr_bits_t>(pDest) & 3) == 0);
atomic32_t cur = *pDest;
*pDest += val;
return cur;
}
inline atomic32_t atomic_exchange_add32(atomic32_t volatile* pDest, atomic32_t val) {
CRNLIB_ASSERT((reinterpret_cast<ptr_bits_t>(pDest) & 3) == 0);
atomic32_t cur = *pDest;
*pDest += val;
return cur;
}
#endif
} // namespace crnlib
} // namespace crnlib
#endif // CRN_ATOMICS_H
#endif // CRN_ATOMICS_H
+125 -143
View File
@@ -3,194 +3,176 @@
#pragma once
#include "crn_data_stream.h"
namespace crnlib
{
class buffer_stream : public data_stream
{
public:
buffer_stream() :
data_stream(),
m_pBuf(NULL),
m_size(0),
m_ofs(0)
{
}
namespace crnlib {
class buffer_stream : public data_stream {
public:
buffer_stream()
: data_stream(),
m_pBuf(NULL),
m_size(0),
m_ofs(0) {
}
buffer_stream(void* p, uint size) :
data_stream(),
m_pBuf(NULL),
m_size(0),
m_ofs(0)
{
open(p, size);
}
buffer_stream(void* p, uint size)
: data_stream(),
m_pBuf(NULL),
m_size(0),
m_ofs(0) {
open(p, size);
}
buffer_stream(const void* p, uint size) :
data_stream(),
m_pBuf(NULL),
m_size(0),
m_ofs(0)
{
open(p, size);
}
buffer_stream(const void* p, uint size)
: data_stream(),
m_pBuf(NULL),
m_size(0),
m_ofs(0) {
open(p, size);
}
virtual ~buffer_stream()
{
}
virtual ~buffer_stream() {
}
bool open(const void* p, uint size)
{
CRNLIB_ASSERT(p);
bool open(const void* p, uint size) {
CRNLIB_ASSERT(p);
close();
close();
if ((!p) || (!size))
return false;
if ((!p) || (!size))
return false;
m_opened = true;
m_pBuf = (uint8*)(p);
m_size = size;
m_ofs = 0;
m_attribs = cDataStreamSeekable | cDataStreamReadable;
return true;
}
m_opened = true;
m_pBuf = (uint8*)(p);
m_size = size;
m_ofs = 0;
m_attribs = cDataStreamSeekable | cDataStreamReadable;
return true;
}
bool open(void* p, uint size)
{
CRNLIB_ASSERT(p);
bool open(void* p, uint size) {
CRNLIB_ASSERT(p);
close();
close();
if ((!p) || (!size))
return false;
if ((!p) || (!size))
return false;
m_opened = true;
m_pBuf = static_cast<uint8*>(p);
m_size = size;
m_ofs = 0;
m_attribs = cDataStreamSeekable | cDataStreamWritable | cDataStreamReadable;
return true;
}
m_opened = true;
m_pBuf = static_cast<uint8*>(p);
m_size = size;
m_ofs = 0;
m_attribs = cDataStreamSeekable | cDataStreamWritable | cDataStreamReadable;
return true;
}
virtual bool close()
{
if (m_opened)
{
m_opened = false;
m_pBuf = NULL;
m_size = 0;
m_ofs = 0;
return true;
}
virtual bool close() {
if (m_opened) {
m_opened = false;
m_pBuf = NULL;
m_size = 0;
m_ofs = 0;
return true;
}
return false;
}
return false;
}
const void* get_buf() const { return m_pBuf; }
void* get_buf() { return m_pBuf; }
const void* get_buf() const { return m_pBuf; }
void* get_buf() { return m_pBuf; }
virtual const void* get_ptr() const { return m_pBuf; }
virtual const void* get_ptr() const { return m_pBuf; }
virtual uint read(void* pBuf, uint len)
{
CRNLIB_ASSERT(pBuf && (len <= 0x7FFFFFFF));
virtual uint read(void* pBuf, uint len) {
CRNLIB_ASSERT(pBuf && (len <= 0x7FFFFFFF));
if ((!m_opened) || (!is_readable()) || (!len))
return 0;
if ((!m_opened) || (!is_readable()) || (!len))
return 0;
CRNLIB_ASSERT(m_ofs <= m_size);
CRNLIB_ASSERT(m_ofs <= m_size);
uint bytes_left = m_size - m_ofs;
uint bytes_left = m_size - m_ofs;
len = math::minimum<uint>(len, bytes_left);
len = math::minimum<uint>(len, bytes_left);
if (len)
memcpy(pBuf, &m_pBuf[m_ofs], len);
if (len)
memcpy(pBuf, &m_pBuf[m_ofs], len);
m_ofs += len;
m_ofs += len;
return len;
}
return len;
}
virtual uint write(const void* pBuf, uint len)
{
CRNLIB_ASSERT(pBuf && (len <= 0x7FFFFFFF));
virtual uint write(const void* pBuf, uint len) {
CRNLIB_ASSERT(pBuf && (len <= 0x7FFFFFFF));
if ((!m_opened) || (!is_writable()) || (!len))
return 0;
if ((!m_opened) || (!is_writable()) || (!len))
return 0;
CRNLIB_ASSERT(m_ofs <= m_size);
CRNLIB_ASSERT(m_ofs <= m_size);
uint bytes_left = m_size - m_ofs;
uint bytes_left = m_size - m_ofs;
len = math::minimum<uint>(len, bytes_left);
len = math::minimum<uint>(len, bytes_left);
if (len)
memcpy(&m_pBuf[m_ofs], pBuf, len);
if (len)
memcpy(&m_pBuf[m_ofs], pBuf, len);
m_ofs += len;
m_ofs += len;
return len;
}
return len;
}
virtual bool flush()
{
if (!m_opened)
return false;
virtual bool flush() {
if (!m_opened)
return false;
return true;
}
return true;
}
virtual uint64 get_size()
{
if (!m_opened)
return 0;
virtual uint64 get_size() {
if (!m_opened)
return 0;
return m_size;
}
return m_size;
}
virtual uint64 get_remaining()
{
if (!m_opened)
return 0;
virtual uint64 get_remaining() {
if (!m_opened)
return 0;
CRNLIB_ASSERT(m_ofs <= m_size);
CRNLIB_ASSERT(m_ofs <= m_size);
return m_size - m_ofs;
}
return m_size - m_ofs;
}
virtual uint64 get_ofs()
{
if (!m_opened)
return 0;
virtual uint64 get_ofs() {
if (!m_opened)
return 0;
return m_ofs;
}
return m_ofs;
}
virtual bool seek(int64 ofs, bool relative)
{
if ((!m_opened) || (!is_seekable()))
return false;
virtual bool seek(int64 ofs, bool relative) {
if ((!m_opened) || (!is_seekable()))
return false;
int64 new_ofs = relative ? (m_ofs + ofs) : ofs;
int64 new_ofs = relative ? (m_ofs + ofs) : ofs;
if (new_ofs < 0)
return false;
else if (new_ofs > m_size)
return false;
if (new_ofs < 0)
return false;
else if (new_ofs > m_size)
return false;
m_ofs = static_cast<uint>(new_ofs);
m_ofs = static_cast<uint>(new_ofs);
post_seek();
post_seek();
return true;
}
return true;
}
private:
uint8* m_pBuf;
uint m_size;
uint m_ofs;
};
} // namespace crnlib
private:
uint8* m_pBuf;
uint m_size;
uint m_ofs;
};
} // namespace crnlib
+201 -227
View File
@@ -3,239 +3,213 @@
#pragma once
#include "crn_data_stream.h"
namespace crnlib
{
class cfile_stream : public data_stream
{
public:
cfile_stream() : data_stream(), m_pFile(NULL), m_size(0), m_ofs(0), m_has_ownership(false)
{
namespace crnlib {
class cfile_stream : public data_stream {
public:
cfile_stream()
: data_stream(), m_pFile(NULL), m_size(0), m_ofs(0), m_has_ownership(false) {
}
cfile_stream(FILE* pFile, const char* pFilename, uint attribs, bool has_ownership)
: data_stream(), m_pFile(NULL), m_size(0), m_ofs(0), m_has_ownership(false) {
open(pFile, pFilename, attribs, has_ownership);
}
cfile_stream(const char* pFilename, uint attribs = cDataStreamReadable | cDataStreamSeekable, bool open_existing = false)
: data_stream(), m_pFile(NULL), m_size(0), m_ofs(0), m_has_ownership(false) {
open(pFilename, attribs, open_existing);
}
virtual ~cfile_stream() {
close();
}
virtual bool close() {
clear_error();
if (m_opened) {
bool status = true;
if (m_has_ownership) {
if (EOF == fclose(m_pFile))
status = false;
}
cfile_stream(FILE* pFile, const char* pFilename, uint attribs, bool has_ownership) :
data_stream(), m_pFile(NULL), m_size(0), m_ofs(0), m_has_ownership(false)
{
open(pFile, pFilename, attribs, has_ownership);
m_pFile = NULL;
m_opened = false;
m_size = 0;
m_ofs = 0;
m_has_ownership = false;
return status;
}
return false;
}
bool open(FILE* pFile, const char* pFilename, uint attribs, bool has_ownership) {
CRNLIB_ASSERT(pFile);
CRNLIB_ASSERT(pFilename);
close();
set_name(pFilename);
m_pFile = pFile;
m_has_ownership = has_ownership;
m_attribs = static_cast<uint16>(attribs);
m_ofs = crn_ftell(m_pFile);
crn_fseek(m_pFile, 0, SEEK_END);
m_size = crn_ftell(m_pFile);
crn_fseek(m_pFile, m_ofs, SEEK_SET);
m_opened = true;
return true;
}
bool open(const char* pFilename, uint attribs = cDataStreamReadable | cDataStreamSeekable, bool open_existing = false) {
CRNLIB_ASSERT(pFilename);
close();
m_attribs = static_cast<uint16>(attribs);
const char* pMode;
if ((is_readable()) && (is_writable()))
pMode = open_existing ? "r+b" : "w+b";
else if (is_writable())
pMode = open_existing ? "ab" : "wb";
else if (is_readable())
pMode = "rb";
else {
set_error();
return false;
}
FILE* pFile = NULL;
crn_fopen(&pFile, pFilename, pMode);
m_has_ownership = true;
if (!pFile) {
set_error();
return false;
}
// TODO: Change stream class to support UCS2 filenames.
return open(pFile, pFilename, attribs, true);
}
FILE* get_file() const { return m_pFile; }
virtual uint read(void* pBuf, uint len) {
CRNLIB_ASSERT(pBuf && (len <= 0x7FFFFFFF));
if (!m_opened || (!is_readable()) || (!len))
return 0;
len = static_cast<uint>(math::minimum<uint64>(len, get_remaining()));
if (fread(pBuf, 1, len, m_pFile) != len) {
set_error();
return 0;
}
m_ofs += len;
return len;
}
virtual uint write(const void* pBuf, uint len) {
CRNLIB_ASSERT(pBuf && (len <= 0x7FFFFFFF));
if (!m_opened || (!is_writable()) || (!len))
return 0;
if (fwrite(pBuf, 1, len, m_pFile) != len) {
set_error();
return 0;
}
m_ofs += len;
m_size = math::maximum(m_size, m_ofs);
return len;
}
virtual bool flush() {
if ((!m_opened) || (!is_writable()))
return false;
if (EOF == fflush(m_pFile)) {
set_error();
return false;
}
return true;
}
virtual uint64 get_size() {
if (!m_opened)
return 0;
return m_size;
}
virtual uint64 get_remaining() {
if (!m_opened)
return 0;
CRNLIB_ASSERT(m_ofs <= m_size);
return m_size - m_ofs;
}
virtual uint64 get_ofs() {
if (!m_opened)
return 0;
return m_ofs;
}
virtual bool seek(int64 ofs, bool relative) {
if ((!m_opened) || (!is_seekable()))
return false;
int64 new_ofs = relative ? (m_ofs + ofs) : ofs;
if (new_ofs < 0)
return false;
else if (static_cast<uint64>(new_ofs) > m_size)
return false;
if (static_cast<uint64>(new_ofs) != m_ofs) {
if (crn_fseek(m_pFile, new_ofs, SEEK_SET) != 0) {
set_error();
return false;
}
cfile_stream(const char* pFilename, uint attribs = cDataStreamReadable | cDataStreamSeekable, bool open_existing = false) :
data_stream(), m_pFile(NULL), m_size(0), m_ofs(0), m_has_ownership(false)
{
open(pFilename, attribs, open_existing);
}
m_ofs = new_ofs;
}
virtual ~cfile_stream()
{
close();
}
return true;
}
virtual bool close()
{
clear_error();
static bool read_file_into_array(const char* pFilename, vector<uint8>& buf) {
cfile_stream in_stream(pFilename);
if (!in_stream.is_opened())
return false;
return in_stream.read_array(buf);
}
if (m_opened)
{
bool status = true;
if (m_has_ownership)
{
if (EOF == fclose(m_pFile))
status = false;
}
static bool write_array_to_file(const char* pFilename, const vector<uint8>& buf) {
cfile_stream out_stream(pFilename, cDataStreamWritable | cDataStreamSeekable);
if (!out_stream.is_opened())
return false;
return out_stream.write_array(buf);
}
m_pFile = NULL;
m_opened = false;
m_size = 0;
m_ofs = 0;
m_has_ownership = false;
private:
FILE* m_pFile;
uint64 m_size, m_ofs;
bool m_has_ownership;
};
return status;
}
return false;
}
bool open(FILE* pFile, const char* pFilename, uint attribs, bool has_ownership)
{
CRNLIB_ASSERT(pFile);
CRNLIB_ASSERT(pFilename);
close();
set_name(pFilename);
m_pFile = pFile;
m_has_ownership = has_ownership;
m_attribs = static_cast<uint16>(attribs);
m_ofs = crn_ftell(m_pFile);
crn_fseek(m_pFile, 0, SEEK_END);
m_size = crn_ftell(m_pFile);
crn_fseek(m_pFile, m_ofs, SEEK_SET);
m_opened = true;
return true;
}
bool open(const char* pFilename, uint attribs = cDataStreamReadable | cDataStreamSeekable, bool open_existing = false)
{
CRNLIB_ASSERT(pFilename);
close();
m_attribs = static_cast<uint16>(attribs);
const char* pMode;
if ((is_readable()) && (is_writable()))
pMode = open_existing ? "r+b" : "w+b";
else if (is_writable())
pMode = open_existing ? "ab" : "wb";
else if (is_readable())
pMode = "rb";
else
{
set_error();
return false;
}
FILE* pFile = NULL;
crn_fopen(&pFile, pFilename, pMode);
m_has_ownership = true;
if (!pFile)
{
set_error();
return false;
}
// TODO: Change stream class to support UCS2 filenames.
return open(pFile, pFilename, attribs, true);
}
FILE* get_file() const { return m_pFile; }
virtual uint read(void* pBuf, uint len)
{
CRNLIB_ASSERT(pBuf && (len <= 0x7FFFFFFF));
if (!m_opened || (!is_readable()) || (!len))
return 0;
len = static_cast<uint>(math::minimum<uint64>(len, get_remaining()));
if (fread(pBuf, 1, len, m_pFile) != len)
{
set_error();
return 0;
}
m_ofs += len;
return len;
}
virtual uint write(const void* pBuf, uint len)
{
CRNLIB_ASSERT(pBuf && (len <= 0x7FFFFFFF));
if (!m_opened || (!is_writable()) || (!len))
return 0;
if (fwrite(pBuf, 1, len, m_pFile) != len)
{
set_error();
return 0;
}
m_ofs += len;
m_size = math::maximum(m_size, m_ofs);
return len;
}
virtual bool flush()
{
if ((!m_opened) || (!is_writable()))
return false;
if (EOF == fflush(m_pFile))
{
set_error();
return false;
}
return true;
}
virtual uint64 get_size()
{
if (!m_opened)
return 0;
return m_size;
}
virtual uint64 get_remaining()
{
if (!m_opened)
return 0;
CRNLIB_ASSERT(m_ofs <= m_size);
return m_size - m_ofs;
}
virtual uint64 get_ofs()
{
if (!m_opened)
return 0;
return m_ofs;
}
virtual bool seek(int64 ofs, bool relative)
{
if ((!m_opened) || (!is_seekable()))
return false;
int64 new_ofs = relative ? (m_ofs + ofs) : ofs;
if (new_ofs < 0)
return false;
else if (static_cast<uint64>(new_ofs) > m_size)
return false;
if (static_cast<uint64>(new_ofs) != m_ofs)
{
if (crn_fseek(m_pFile, new_ofs, SEEK_SET) != 0)
{
set_error();
return false;
}
m_ofs = new_ofs;
}
return true;
}
static bool read_file_into_array(const char* pFilename, vector<uint8>& buf)
{
cfile_stream in_stream(pFilename);
if (!in_stream.is_opened())
return false;
return in_stream.read_array(buf);
}
static bool write_array_to_file(const char* pFilename, const vector<uint8>& buf)
{
cfile_stream out_stream(pFilename, cDataStreamWritable|cDataStreamSeekable);
if (!out_stream.is_opened())
return false;
return out_stream.write_array(buf);
}
private:
FILE* m_pFile;
uint64 m_size, m_ofs;
bool m_has_ownership;
};
} // namespace crnlib
} // namespace crnlib
+47 -52
View File
@@ -1,63 +1,58 @@
// File: crn_checksum.cpp
#include "crn_core.h"
namespace crnlib
{
// From the public domain stb.h header.
uint adler32(const void* pBuf, size_t buflen, uint adler32)
{
const uint8* buffer = static_cast<const uint8*>(pBuf);
const unsigned long ADLER_MOD = 65521;
unsigned long s1 = adler32 & 0xffff, s2 = adler32 >> 16;
size_t blocklen;
unsigned long i;
namespace crnlib {
// From the public domain stb.h header.
uint adler32(const void* pBuf, size_t buflen, uint adler32) {
const uint8* buffer = static_cast<const uint8*>(pBuf);
blocklen = buflen % 5552;
while (buflen) {
for (i=0; i + 7 < blocklen; i += 8) {
s1 += buffer[0], s2 += s1;
s1 += buffer[1], s2 += s1;
s1 += buffer[2], s2 += s1;
s1 += buffer[3], s2 += s1;
s1 += buffer[4], s2 += s1;
s1 += buffer[5], s2 += s1;
s1 += buffer[6], s2 += s1;
s1 += buffer[7], s2 += s1;
const unsigned long ADLER_MOD = 65521;
unsigned long s1 = adler32 & 0xffff, s2 = adler32 >> 16;
size_t blocklen;
unsigned long i;
buffer += 8;
}
blocklen = buflen % 5552;
while (buflen) {
for (i = 0; i + 7 < blocklen; i += 8) {
s1 += buffer[0], s2 += s1;
s1 += buffer[1], s2 += s1;
s1 += buffer[2], s2 += s1;
s1 += buffer[3], s2 += s1;
s1 += buffer[4], s2 += s1;
s1 += buffer[5], s2 += s1;
s1 += buffer[6], s2 += s1;
s1 += buffer[7], s2 += s1;
for (; i < blocklen; ++i)
s1 += *buffer++, s2 += s1;
buffer += 8;
}
s1 %= ADLER_MOD, s2 %= ADLER_MOD;
buflen -= blocklen;
blocklen = 5552;
}
return (s2 << 16) + s1;
}
uint16 crc16(const void* pBuf, size_t len, uint16 crc)
{
crc = ~crc;
for (; i < blocklen; ++i)
s1 += *buffer++, s2 += s1;
const uint8* p = reinterpret_cast<const uint8*>(pBuf);
while (len)
{
const uint16 q = *p++ ^ (crc >> 8);
crc <<= 8U;
uint16 r = (q >> 4) ^ q;
crc ^= r;
r <<= 5U;
crc ^= r;
r <<= 7U;
crc ^= r;
len--;
}
s1 %= ADLER_MOD, s2 %= ADLER_MOD;
buflen -= blocklen;
blocklen = 5552;
}
return (s2 << 16) + s1;
}
return static_cast<uint16>(~crc);
}
uint16 crc16(const void* pBuf, size_t len, uint16 crc) {
crc = ~crc;
} // namespace crnlib
const uint8* p = reinterpret_cast<const uint8*>(pBuf);
while (len) {
const uint16 q = *p++ ^ (crc >> 8);
crc <<= 8U;
uint16 r = (q >> 4) ^ q;
crc ^= r;
r <<= 5U;
crc ^= r;
r <<= 7U;
crc ^= r;
len--;
}
return static_cast<uint16>(~crc);
}
} // namespace crnlib
+8 -9
View File
@@ -1,13 +1,12 @@
// File: crn_checksum.h
#pragma once
namespace crnlib
{
const uint cInitAdler32 = 1U;
uint adler32(const void* pBuf, size_t buflen, uint adler32 = cInitAdler32);
// crc16() intended for small buffers - doesn't use an acceleration table.
const uint cInitCRC16 = 0;
uint16 crc16(const void* pBuf, size_t len, uint16 crc = cInitCRC16);
namespace crnlib {
const uint cInitAdler32 = 1U;
uint adler32(const void* pBuf, size_t buflen, uint adler32 = cInitAdler32);
// crc16() intended for small buffers - doesn't use an acceleration table.
const uint cInitCRC16 = 0;
uint16 crc16(const void* pBuf, size_t len, uint16 crc = cInitCRC16);
} // namespace crnlib
+532 -593
View File
File diff suppressed because it is too large Load Diff
+882 -976
View File
File diff suppressed because it is too large Load Diff
+86 -93
View File
@@ -6,114 +6,107 @@
#include "crn_winhdr.h"
#endif
namespace crnlib
{
void colorized_console::init()
{
console::init();
console::add_console_output_func(console_output_func, NULL);
}
namespace crnlib {
void colorized_console::init() {
console::init();
console::add_console_output_func(console_output_func, NULL);
}
void colorized_console::deinit()
{
console::remove_console_output_func(console_output_func);
console::deinit();
}
void colorized_console::deinit() {
console::remove_console_output_func(console_output_func);
console::deinit();
}
void colorized_console::tick()
{
}
void colorized_console::tick() {
}
#ifdef CRNLIB_USE_WIN32_API
bool colorized_console::console_output_func(eConsoleMessageType type, const char* pMsg, void* pData)
{
pData;
bool colorized_console::console_output_func(eConsoleMessageType type, const char* pMsg, void* pData) {
pData;
if (console::get_output_disabled())
return true;
if (console::get_output_disabled())
return true;
HANDLE cons = GetStdHandle(STD_OUTPUT_HANDLE);
HANDLE cons = GetStdHandle(STD_OUTPUT_HANDLE);
DWORD attr = FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE;
switch (type)
{
case cDebugConsoleMessage: attr = FOREGROUND_BLUE | FOREGROUND_INTENSITY; break;
case cMessageConsoleMessage: attr = FOREGROUND_GREEN | FOREGROUND_BLUE | FOREGROUND_INTENSITY; break;
case cWarningConsoleMessage: attr = FOREGROUND_GREEN | FOREGROUND_RED | FOREGROUND_INTENSITY; break;
case cErrorConsoleMessage: attr = FOREGROUND_RED | FOREGROUND_INTENSITY; break;
default: break;
}
DWORD attr = FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE;
switch (type) {
case cDebugConsoleMessage:
attr = FOREGROUND_BLUE | FOREGROUND_INTENSITY;
break;
case cMessageConsoleMessage:
attr = FOREGROUND_GREEN | FOREGROUND_BLUE | FOREGROUND_INTENSITY;
break;
case cWarningConsoleMessage:
attr = FOREGROUND_GREEN | FOREGROUND_RED | FOREGROUND_INTENSITY;
break;
case cErrorConsoleMessage:
attr = FOREGROUND_RED | FOREGROUND_INTENSITY;
break;
default:
break;
}
if (INVALID_HANDLE_VALUE != cons)
SetConsoleTextAttribute(cons, (WORD)attr);
if (INVALID_HANDLE_VALUE != cons)
SetConsoleTextAttribute(cons, (WORD)attr);
if ((console::get_prefixes()) && (console::get_at_beginning_of_line()))
{
switch (type)
{
case cDebugConsoleMessage:
printf("Debug: %s", pMsg);
break;
case cWarningConsoleMessage:
printf("Warning: %s", pMsg);
break;
case cErrorConsoleMessage:
printf("Error: %s", pMsg);
break;
default:
printf("%s", pMsg);
break;
}
}
else
{
printf("%s", pMsg);
}
if ((console::get_prefixes()) && (console::get_at_beginning_of_line())) {
switch (type) {
case cDebugConsoleMessage:
printf("Debug: %s", pMsg);
break;
case cWarningConsoleMessage:
printf("Warning: %s", pMsg);
break;
case cErrorConsoleMessage:
printf("Error: %s", pMsg);
break;
default:
printf("%s", pMsg);
break;
}
} else {
printf("%s", pMsg);
}
if (console::get_crlf())
printf("\n");
if (console::get_crlf())
printf("\n");
if (INVALID_HANDLE_VALUE != cons)
SetConsoleTextAttribute(cons, FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE);
if (INVALID_HANDLE_VALUE != cons)
SetConsoleTextAttribute(cons, FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE);
return true;
}
return true;
}
#else
bool colorized_console::console_output_func(eConsoleMessageType type, const char* pMsg, void* pData)
{
pData;
if (console::get_output_disabled())
return true;
bool colorized_console::console_output_func(eConsoleMessageType type, const char* pMsg, void* pData) {
pData;
if (console::get_output_disabled())
return true;
if ((console::get_prefixes()) && (console::get_at_beginning_of_line()))
{
switch (type)
{
case cDebugConsoleMessage:
printf("Debug: %s", pMsg);
break;
case cWarningConsoleMessage:
printf("Warning: %s", pMsg);
break;
case cErrorConsoleMessage:
printf("Error: %s", pMsg);
break;
default:
printf("%s", pMsg);
break;
}
}
else
{
printf("%s", pMsg);
}
if ((console::get_prefixes()) && (console::get_at_beginning_of_line())) {
switch (type) {
case cDebugConsoleMessage:
printf("Debug: %s", pMsg);
break;
case cWarningConsoleMessage:
printf("Warning: %s", pMsg);
break;
case cErrorConsoleMessage:
printf("Error: %s", pMsg);
break;
default:
printf("%s", pMsg);
break;
}
} else {
printf("%s", pMsg);
}
if (console::get_crlf())
printf("\n");
if (console::get_crlf())
printf("\n");
return true;
}
return true;
}
#endif
} // namespace crnlib
} // namespace crnlib
+10 -12
View File
@@ -3,17 +3,15 @@
#pragma once
#include "crn_console.h"
namespace crnlib
{
class colorized_console
{
public:
static void init();
static void deinit();
static void tick();
namespace crnlib {
class colorized_console {
public:
static void init();
static void deinit();
static void tick();
private:
static bool console_output_func(eConsoleMessageType type, const char* pMsg, void* pData);
};
private:
static bool console_output_func(eConsoleMessageType type, const char* pMsg, void* pData);
};
} // namespace crnlib
} // namespace crnlib
+320 -382
View File
@@ -6,467 +6,405 @@
#include "crn_cfile_stream.h"
#ifdef WIN32
#define CRNLIB_CMD_LINE_ALLOW_SLASH_PARAMS 1
#define CRNLIB_CMD_LINE_ALLOW_SLASH_PARAMS 1
#endif
#if CRNLIB_USE_WIN32_API
#include "crn_winhdr.h"
#endif
namespace crnlib
{
void get_command_line_as_single_string(dynamic_string& cmd_line, int argc, char *argv[])
{
argc, argv;
namespace crnlib {
void get_command_line_as_single_string(dynamic_string& cmd_line, int argc, char* argv[]) {
argc, argv;
#if CRNLIB_USE_WIN32_API
cmd_line.set(GetCommandLineA());
cmd_line.set(GetCommandLineA());
#else
cmd_line.clear();
for (int i = 0; i < argc; i++)
{
dynamic_string tmp(argv[i]);
if ((tmp.front() != '"') && (tmp.front() != '-') && (tmp.front() != '@'))
tmp = "\"" + tmp + "\"";
if (cmd_line.get_len())
cmd_line += " ";
cmd_line += tmp;
}
cmd_line.clear();
for (int i = 0; i < argc; i++) {
dynamic_string tmp(argv[i]);
if ((tmp.front() != '"') && (tmp.front() != '-') && (tmp.front() != '@'))
tmp = "\"" + tmp + "\"";
if (cmd_line.get_len())
cmd_line += " ";
cmd_line += tmp;
}
#endif
}
}
command_line_params::command_line_params()
{
}
command_line_params::command_line_params() {
}
void command_line_params::clear()
{
m_params.clear();
void command_line_params::clear() {
m_params.clear();
m_param_map.clear();
}
m_param_map.clear();
}
bool command_line_params::split_params(const char* p, dynamic_string_array& params)
{
bool within_param = false;
bool within_quote = false;
bool command_line_params::split_params(const char* p, dynamic_string_array& params) {
bool within_param = false;
bool within_quote = false;
uint ofs = 0;
dynamic_string str;
uint ofs = 0;
dynamic_string str;
while (p[ofs])
{
const char c = p[ofs];
while (p[ofs]) {
const char c = p[ofs];
if (within_param)
{
if (within_quote)
{
if (c == '"')
within_quote = false;
if (within_param) {
if (within_quote) {
if (c == '"')
within_quote = false;
str.append_char(c);
}
else if ((c == ' ') || (c == '\t'))
{
if (!str.is_empty())
{
params.push_back(str);
str.clear();
}
within_param = false;
}
else
{
if (c == '"')
within_quote = true;
str.append_char(c);
} else if ((c == ' ') || (c == '\t')) {
if (!str.is_empty()) {
params.push_back(str);
str.clear();
}
within_param = false;
} else {
if (c == '"')
within_quote = true;
str.append_char(c);
}
}
else if ((c != ' ') && (c != '\t'))
{
within_param = true;
if (c == '"')
within_quote = true;
str.append_char(c);
}
ofs++;
str.append_char(c);
}
} else if ((c != ' ') && (c != '\t')) {
within_param = true;
if (within_quote)
{
console::error("Unmatched quote in command line \"%s\"", p);
return false;
}
if (c == '"')
within_quote = true;
if (!str.is_empty())
params.push_back(str);
str.append_char(c);
}
return true;
}
ofs++;
}
bool command_line_params::load_string_file(const char* pFilename, dynamic_string_array& strings)
{
cfile_stream in_stream;
if (!in_stream.open(pFilename, cDataStreamReadable | cDataStreamSeekable))
{
console::error("Unable to open file \"%s\" for reading!", pFilename);
return false;
}
if (within_quote) {
console::error("Unmatched quote in command line \"%s\"", p);
return false;
}
dynamic_string ansi_str;
if (!str.is_empty())
params.push_back(str);
for ( ; ; )
{
if (!in_stream.read_line(ansi_str))
break;
return true;
}
ansi_str.trim();
if (ansi_str.is_empty())
continue;
bool command_line_params::load_string_file(const char* pFilename, dynamic_string_array& strings) {
cfile_stream in_stream;
if (!in_stream.open(pFilename, cDataStreamReadable | cDataStreamSeekable)) {
console::error("Unable to open file \"%s\" for reading!", pFilename);
return false;
}
strings.push_back(dynamic_string(ansi_str.get_ptr()));
}
dynamic_string ansi_str;
return true;
}
for (;;) {
if (!in_stream.read_line(ansi_str))
break;
bool command_line_params::parse(const dynamic_string_array& params, uint n, const param_desc* pParam_desc)
{
CRNLIB_ASSERT(n && pParam_desc);
ansi_str.trim();
if (ansi_str.is_empty())
continue;
m_params = params;
strings.push_back(dynamic_string(ansi_str.get_ptr()));
}
uint arg_index = 0;
while (arg_index < params.size())
{
const uint cur_arg_index = arg_index;
const dynamic_string& src_param = params[arg_index++];
return true;
}
if (src_param.is_empty())
continue;
bool command_line_params::parse(const dynamic_string_array& params, uint n, const param_desc* pParam_desc) {
CRNLIB_ASSERT(n && pParam_desc);
m_params = params;
uint arg_index = 0;
while (arg_index < params.size()) {
const uint cur_arg_index = arg_index;
const dynamic_string& src_param = params[arg_index++];
if (src_param.is_empty())
continue;
#if CRNLIB_CMD_LINE_ALLOW_SLASH_PARAMS
if ((src_param[0] == '/') || (src_param[0] == '-'))
if ((src_param[0] == '/') || (src_param[0] == '-'))
#else
if (src_param[0] == '-')
if (src_param[0] == '-')
#endif
{
if (src_param.get_len() < 2)
{
console::error("Invalid command line parameter: \"%s\"", src_param.get_ptr());
return false;
}
dynamic_string key_str(src_param);
key_str.right(1);
int modifier = 0;
char c = key_str[key_str.get_len() - 1];
if (c == '+')
modifier = 1;
else if (c == '-')
modifier = -1;
if (modifier)
key_str.left(key_str.get_len() - 1);
uint param_index;
for (param_index = 0; param_index < n; param_index++)
if (key_str == pParam_desc[param_index].m_pName)
break;
if (param_index == n)
{
console::error("Unrecognized command line parameter: \"%s\"", src_param.get_ptr());
return false;
}
const param_desc& desc = pParam_desc[param_index];
const uint cMaxValues = 16;
dynamic_string val_str[cMaxValues];
uint num_val_strs = 0;
if (desc.m_num_values)
{
CRNLIB_ASSERT(desc.m_num_values <= cMaxValues);
if ((arg_index + desc.m_num_values) > params.size())
{
console::error("Expected %u value(s) after command line parameter: \"%s\"", desc.m_num_values, src_param.get_ptr());
return false;
}
for (uint v = 0; v < desc.m_num_values; v++)
val_str[num_val_strs++] = params[arg_index++];
}
dynamic_string_array strings;
if ((desc.m_support_listing_file) && (val_str[0].get_len() >= 2) && (val_str[0][0] == '@'))
{
dynamic_string filename(val_str[0]);
filename.right(1);
filename.unquote();
if (!load_string_file(filename.get_ptr(), strings))
{
console::error("Failed loading listing file \"%s\"!", filename.get_ptr());
return false;
}
}
else
{
for (uint v = 0; v < num_val_strs; v++)
{
val_str[v].unquote();
strings.push_back(val_str[v]);
}
}
param_value pv;
pv.m_values.swap(strings);
pv.m_index = cur_arg_index;
pv.m_modifier = (int8)modifier;
m_param_map.insert(std::make_pair(key_str, pv));
}
else
{
param_value pv;
pv.m_values.push_back(src_param);
pv.m_values.back().unquote();
pv.m_index = cur_arg_index;
m_param_map.insert(std::make_pair(g_empty_dynamic_string, pv));
}
{
if (src_param.get_len() < 2) {
console::error("Invalid command line parameter: \"%s\"", src_param.get_ptr());
return false;
}
return true;
}
dynamic_string key_str(src_param);
bool command_line_params::parse(const char* pCmd_line, uint n, const param_desc* pParam_desc, bool skip_first_param)
{
CRNLIB_ASSERT(n && pParam_desc);
key_str.right(1);
dynamic_string_array p;
if (!split_params(pCmd_line, p))
return 0;
int modifier = 0;
char c = key_str[key_str.get_len() - 1];
if (c == '+')
modifier = 1;
else if (c == '-')
modifier = -1;
if (p.empty())
return 0;
if (modifier)
key_str.left(key_str.get_len() - 1);
if (skip_first_param)
p.erase(0U);
uint param_index;
for (param_index = 0; param_index < n; param_index++)
if (key_str == pParam_desc[param_index].m_pName)
break;
return parse(p, n, pParam_desc);
}
if (param_index == n) {
console::error("Unrecognized command line parameter: \"%s\"", src_param.get_ptr());
return false;
}
bool command_line_params::is_param(uint index) const
{
CRNLIB_ASSERT(index < m_params.size());
if (index >= m_params.size())
return false;
const param_desc& desc = pParam_desc[param_index];
const dynamic_string& w = m_params[index];
if (w.is_empty())
return false;
const uint cMaxValues = 16;
dynamic_string val_str[cMaxValues];
uint num_val_strs = 0;
if (desc.m_num_values) {
CRNLIB_ASSERT(desc.m_num_values <= cMaxValues);
if ((arg_index + desc.m_num_values) > params.size()) {
console::error("Expected %u value(s) after command line parameter: \"%s\"", desc.m_num_values, src_param.get_ptr());
return false;
}
for (uint v = 0; v < desc.m_num_values; v++)
val_str[num_val_strs++] = params[arg_index++];
}
dynamic_string_array strings;
if ((desc.m_support_listing_file) && (val_str[0].get_len() >= 2) && (val_str[0][0] == '@')) {
dynamic_string filename(val_str[0]);
filename.right(1);
filename.unquote();
if (!load_string_file(filename.get_ptr(), strings)) {
console::error("Failed loading listing file \"%s\"!", filename.get_ptr());
return false;
}
} else {
for (uint v = 0; v < num_val_strs; v++) {
val_str[v].unquote();
strings.push_back(val_str[v]);
}
}
param_value pv;
pv.m_values.swap(strings);
pv.m_index = cur_arg_index;
pv.m_modifier = (int8)modifier;
m_param_map.insert(std::make_pair(key_str, pv));
} else {
param_value pv;
pv.m_values.push_back(src_param);
pv.m_values.back().unquote();
pv.m_index = cur_arg_index;
m_param_map.insert(std::make_pair(g_empty_dynamic_string, pv));
}
}
return true;
}
bool command_line_params::parse(const char* pCmd_line, uint n, const param_desc* pParam_desc, bool skip_first_param) {
CRNLIB_ASSERT(n && pParam_desc);
dynamic_string_array p;
if (!split_params(pCmd_line, p))
return 0;
if (p.empty())
return 0;
if (skip_first_param)
p.erase(0U);
return parse(p, n, pParam_desc);
}
bool command_line_params::is_param(uint index) const {
CRNLIB_ASSERT(index < m_params.size());
if (index >= m_params.size())
return false;
const dynamic_string& w = m_params[index];
if (w.is_empty())
return false;
#if CRNLIB_CMD_LINE_ALLOW_SLASH_PARAMS
return (w.get_len() >= 2) && ((w[0] == '-') || (w[0] == '/'));
return (w.get_len() >= 2) && ((w[0] == '-') || (w[0] == '/'));
#else
return (w.get_len() >= 2) && (w[0] == '-');
return (w.get_len() >= 2) && (w[0] == '-');
#endif
}
}
uint command_line_params::find(uint num_keys, const char** ppKeys, crnlib::vector<param_map_const_iterator>* pIterators, crnlib::vector<uint>* pUnmatched_indices) const
{
CRNLIB_ASSERT(ppKeys);
uint command_line_params::find(uint num_keys, const char** ppKeys, crnlib::vector<param_map_const_iterator>* pIterators, crnlib::vector<uint>* pUnmatched_indices) const {
CRNLIB_ASSERT(ppKeys);
if (pUnmatched_indices)
{
pUnmatched_indices->resize(m_params.size());
for (uint i = 0; i < m_params.size(); i++)
(*pUnmatched_indices)[i] = i;
if (pUnmatched_indices) {
pUnmatched_indices->resize(m_params.size());
for (uint i = 0; i < m_params.size(); i++)
(*pUnmatched_indices)[i] = i;
}
uint n = 0;
for (uint i = 0; i < num_keys; i++) {
const char* pKey = ppKeys[i];
param_map_const_iterator begin, end;
find(pKey, begin, end);
while (begin != end) {
if (pIterators)
pIterators->push_back(begin);
if (pUnmatched_indices) {
int k = pUnmatched_indices->find(begin->second.m_index);
if (k >= 0)
pUnmatched_indices->erase_unordered(k);
}
uint n = 0;
for (uint i = 0; i < num_keys; i++)
{
const char* pKey = ppKeys[i];
n++;
begin++;
}
}
param_map_const_iterator begin, end;
find(pKey, begin, end);
return n;
}
while (begin != end)
{
if (pIterators)
pIterators->push_back(begin);
void command_line_params::find(const char* pKey, param_map_const_iterator& begin, param_map_const_iterator& end) const {
dynamic_string key(pKey);
begin = m_param_map.lower_bound(key);
end = m_param_map.upper_bound(key);
}
if (pUnmatched_indices)
{
int k = pUnmatched_indices->find(begin->second.m_index);
if (k >= 0)
pUnmatched_indices->erase_unordered(k);
}
uint command_line_params::get_count(const char* pKey) const {
param_map_const_iterator begin, end;
find(pKey, begin, end);
n++;
begin++;
}
}
uint n = 0;
return n;
}
while (begin != end) {
n++;
begin++;
}
void command_line_params::find(const char* pKey, param_map_const_iterator& begin, param_map_const_iterator& end) const
{
dynamic_string key(pKey);
begin = m_param_map.lower_bound(key);
end = m_param_map.upper_bound(key);
}
return n;
}
uint command_line_params::get_count(const char* pKey) const
{
param_map_const_iterator begin, end;
find(pKey, begin, end);
command_line_params::param_map_const_iterator command_line_params::get_param(const char* pKey, uint index) const {
param_map_const_iterator begin, end;
find(pKey, begin, end);
uint n = 0;
if (begin == end)
return m_param_map.end();
while (begin != end)
{
n++;
begin++;
}
uint n = 0;
return n;
}
while ((begin != end) && (n != index)) {
n++;
begin++;
}
command_line_params::param_map_const_iterator command_line_params::get_param(const char* pKey, uint index) const
{
param_map_const_iterator begin, end;
find(pKey, begin, end);
if (begin == end)
return m_param_map.end();
if (begin == end)
return m_param_map.end();
return begin;
}
uint n = 0;
bool command_line_params::has_value(const char* pKey, uint index) const {
return get_num_values(pKey, index) != 0;
}
while ((begin != end) && (n != index))
{
n++;
begin++;
}
uint command_line_params::get_num_values(const char* pKey, uint index) const {
param_map_const_iterator it = get_param(pKey, index);
if (begin == end)
return m_param_map.end();
if (it == end())
return 0;
return begin;
}
return it->second.m_values.size();
}
bool command_line_params::has_value(const char* pKey, uint index) const
{
return get_num_values(pKey, index) != 0;
}
bool command_line_params::get_value_as_bool(const char* pKey, uint index, bool def) const {
param_map_const_iterator it = get_param(pKey, index);
if (it == end())
return def;
uint command_line_params::get_num_values(const char* pKey, uint index) const
{
param_map_const_iterator it = get_param(pKey, index);
if (it->second.m_modifier)
return it->second.m_modifier > 0;
else
return true;
}
if (it == end())
return 0;
int command_line_params::get_value_as_int(const char* pKey, uint index, int def, int l, int h, uint value_index) const {
param_map_const_iterator it = get_param(pKey, index);
if ((it == end()) || (value_index >= it->second.m_values.size()))
return def;
return it->second.m_values.size();
}
int val;
const char* p = it->second.m_values[value_index].get_ptr();
if (!string_to_int(p, val)) {
crnlib::console::warning("Invalid value specified for parameter \"%s\", using default value of %i", pKey, def);
return def;
}
bool command_line_params::get_value_as_bool(const char* pKey, uint index, bool def) const
{
param_map_const_iterator it = get_param(pKey, index);
if (it == end())
return def;
if (val < l) {
crnlib::console::warning("Value %i for parameter \"%s\" is out of range, clamping to %i", val, pKey, l);
val = l;
} else if (val > h) {
crnlib::console::warning("Value %i for parameter \"%s\" is out of range, clamping to %i", val, pKey, h);
val = h;
}
if (it->second.m_modifier)
return it->second.m_modifier > 0;
else
return true;
}
return val;
}
int command_line_params::get_value_as_int(const char* pKey, uint index, int def, int l, int h, uint value_index) const
{
param_map_const_iterator it = get_param(pKey, index);
if ((it == end()) || (value_index >= it->second.m_values.size()))
return def;
float command_line_params::get_value_as_float(const char* pKey, uint index, float def, float l, float h, uint value_index) const {
param_map_const_iterator it = get_param(pKey, index);
if ((it == end()) || (value_index >= it->second.m_values.size()))
return def;
int val;
const char* p = it->second.m_values[value_index].get_ptr();
if (!string_to_int(p, val))
{
crnlib::console::warning("Invalid value specified for parameter \"%s\", using default value of %i", pKey, def);
return def;
}
float val;
const char* p = it->second.m_values[value_index].get_ptr();
if (!string_to_float(p, val)) {
crnlib::console::warning("Invalid value specified for float parameter \"%s\", using default value of %f", pKey, def);
return def;
}
if (val < l)
{
crnlib::console::warning("Value %i for parameter \"%s\" is out of range, clamping to %i", val, pKey, l);
val = l;
}
else if (val > h)
{
crnlib::console::warning("Value %i for parameter \"%s\" is out of range, clamping to %i", val, pKey, h);
val = h;
}
if (val < l) {
crnlib::console::warning("Value %f for parameter \"%s\" is out of range, clamping to %f", val, pKey, l);
val = l;
} else if (val > h) {
crnlib::console::warning("Value %f for parameter \"%s\" is out of range, clamping to %f", val, pKey, h);
val = h;
}
return val;
}
return val;
}
float command_line_params::get_value_as_float(const char* pKey, uint index, float def, float l, float h, uint value_index) const
{
param_map_const_iterator it = get_param(pKey, index);
if ((it == end()) || (value_index >= it->second.m_values.size()))
return def;
bool command_line_params::get_value_as_string(const char* pKey, uint index, dynamic_string& value, uint value_index) const {
param_map_const_iterator it = get_param(pKey, index);
if ((it == end()) || (value_index >= it->second.m_values.size())) {
value.empty();
return false;
}
float val;
const char* p = it->second.m_values[value_index].get_ptr();
if (!string_to_float(p, val))
{
crnlib::console::warning("Invalid value specified for float parameter \"%s\", using default value of %f", pKey, def);
return def;
}
value = it->second.m_values[value_index];
return true;
}
if (val < l)
{
crnlib::console::warning("Value %f for parameter \"%s\" is out of range, clamping to %f", val, pKey, l);
val = l;
}
else if (val > h)
{
crnlib::console::warning("Value %f for parameter \"%s\" is out of range, clamping to %f", val, pKey, h);
val = h;
}
const dynamic_string& command_line_params::get_value_as_string_or_empty(const char* pKey, uint index, uint value_index) const {
param_map_const_iterator it = get_param(pKey, index);
if ((it == end()) || (value_index >= it->second.m_values.size()))
return g_empty_dynamic_string;
return val;
}
bool command_line_params::get_value_as_string(const char* pKey, uint index, dynamic_string& value, uint value_index) const
{
param_map_const_iterator it = get_param(pKey, index);
if ((it == end()) || (value_index >= it->second.m_values.size()))
{
value.empty();
return false;
}
value = it->second.m_values[value_index];
return true;
}
const dynamic_string& command_line_params::get_value_as_string_or_empty(const char* pKey, uint index, uint value_index) const
{
param_map_const_iterator it = get_param(pKey, index);
if ((it == end()) || (value_index >= it->second.m_values.size()))
return g_empty_dynamic_string;
return it->second.m_values[value_index];
}
} // namespace crnlib
return it->second.m_values[value_index];
}
} // namespace crnlib
+51 -54
View File
@@ -4,83 +4,80 @@
#include "crn_value.h"
#include <map>
namespace crnlib
{
// Returns the command line passed to the app as a string.
// On systems where this isn't trivial, this function combines together the separate arguments, quoting and adding spaces as needed.
void get_command_line_as_single_string(dynamic_string& cmd_line, int argc, char *argv[]);
namespace crnlib {
// Returns the command line passed to the app as a string.
// On systems where this isn't trivial, this function combines together the separate arguments, quoting and adding spaces as needed.
void get_command_line_as_single_string(dynamic_string& cmd_line, int argc, char* argv[]);
class command_line_params
{
public:
struct param_value
{
inline param_value() : m_index(0), m_modifier(0) { }
class command_line_params {
public:
struct param_value {
inline param_value()
: m_index(0), m_modifier(0) {}
dynamic_string_array m_values;
uint m_index;
int8 m_modifier;
};
dynamic_string_array m_values;
uint m_index;
int8 m_modifier;
};
typedef std::multimap<dynamic_string, param_value> param_map;
typedef param_map::const_iterator param_map_const_iterator;
typedef param_map::iterator param_map_iterator;
typedef std::multimap<dynamic_string, param_value> param_map;
typedef param_map::const_iterator param_map_const_iterator;
typedef param_map::iterator param_map_iterator;
command_line_params();
command_line_params();
void clear();
void clear();
static bool split_params(const char* p, dynamic_string_array& params);
static bool split_params(const char* p, dynamic_string_array& params);
struct param_desc
{
const char* m_pName;
uint m_num_values;
bool m_support_listing_file;
};
struct param_desc {
const char* m_pName;
uint m_num_values;
bool m_support_listing_file;
};
bool parse(const dynamic_string_array& params, uint n, const param_desc* pParam_desc);
bool parse(const char* pCmd_line, uint n, const param_desc* pParam_desc, bool skip_first_param = true);
bool parse(const dynamic_string_array& params, uint n, const param_desc* pParam_desc);
bool parse(const char* pCmd_line, uint n, const param_desc* pParam_desc, bool skip_first_param = true);
const dynamic_string_array& get_array() const { return m_params; }
const dynamic_string_array& get_array() const { return m_params; }
bool is_param(uint index) const;
bool is_param(uint index) const;
const param_map& get_map() const { return m_param_map; }
const param_map& get_map() const { return m_param_map; }
uint get_num_params() const { return static_cast<uint>(m_param_map.size()); }
uint get_num_params() const { return static_cast<uint>(m_param_map.size()); }
param_map_const_iterator begin() const { return m_param_map.begin(); }
param_map_const_iterator end() const { return m_param_map.end(); }
param_map_const_iterator begin() const { return m_param_map.begin(); }
param_map_const_iterator end() const { return m_param_map.end(); }
uint find(uint num_keys, const char** ppKeys, crnlib::vector<param_map_const_iterator>* pIterators, crnlib::vector<uint>* pUnmatched_indices) const;
uint find(uint num_keys, const char** ppKeys, crnlib::vector<param_map_const_iterator>* pIterators, crnlib::vector<uint>* pUnmatched_indices) const;
void find(const char* pKey, param_map_const_iterator& begin, param_map_const_iterator& end) const;
void find(const char* pKey, param_map_const_iterator& begin, param_map_const_iterator& end) const;
uint get_count(const char* pKey) const;
uint get_count(const char* pKey) const;
// Returns end() if param cannot be found, or index is out of range.
param_map_const_iterator get_param(const char* pKey, uint index) const;
// Returns end() if param cannot be found, or index is out of range.
param_map_const_iterator get_param(const char* pKey, uint index) const;
bool has_key(const char* pKey) const { return get_param(pKey, 0) != end(); }
bool has_key(const char* pKey) const { return get_param(pKey, 0) != end(); }
bool has_value(const char* pKey, uint index) const;
uint get_num_values(const char* pKey, uint index) const;
bool has_value(const char* pKey, uint index) const;
uint get_num_values(const char* pKey, uint index) const;
bool get_value_as_bool(const char* pKey, uint index = 0, bool def = false) const;
bool get_value_as_bool(const char* pKey, uint index = 0, bool def = false) const;
int get_value_as_int(const char* pKey, uint index, int def, int l = INT_MIN, int h = INT_MAX, uint value_index = 0) const;
float get_value_as_float(const char* pKey, uint index, float def = 0.0f, float l = -math::cNearlyInfinite, float h = math::cNearlyInfinite, uint value_index = 0) const;
int get_value_as_int(const char* pKey, uint index, int def, int l = INT_MIN, int h = INT_MAX, uint value_index = 0) const;
float get_value_as_float(const char* pKey, uint index, float def = 0.0f, float l = -math::cNearlyInfinite, float h = math::cNearlyInfinite, uint value_index = 0) const;
bool get_value_as_string(const char* pKey, uint index, dynamic_string& value, uint value_index = 0) const;
const dynamic_string& get_value_as_string_or_empty(const char* pKey, uint index = 0, uint value_index = 0) const;
bool get_value_as_string(const char* pKey, uint index, dynamic_string& value, uint value_index = 0) const;
const dynamic_string& get_value_as_string_or_empty(const char* pKey, uint index = 0, uint value_index = 0) const;
private:
dynamic_string_array m_params;
private:
dynamic_string_array m_params;
param_map m_param_map;
param_map m_param_map;
static bool load_string_file(const char* pFilename, dynamic_string_array& strings);
};
static bool load_string_file(const char* pFilename, dynamic_string_array& strings);
};
} // namespace crnlib
} // namespace crnlib
+1522 -1717
View File
File diff suppressed because it is too large Load Diff
+120 -125
View File
@@ -13,169 +13,164 @@
#include "crn_image_utils.h"
#include "crn_texture_comp.h"
namespace crnlib
{
class crn_comp : public itexture_comp
{
CRNLIB_NO_COPY_OR_ASSIGNMENT_OP(crn_comp);
namespace crnlib {
class crn_comp : public itexture_comp {
CRNLIB_NO_COPY_OR_ASSIGNMENT_OP(crn_comp);
public:
crn_comp();
virtual ~crn_comp();
public:
crn_comp();
virtual ~crn_comp();
virtual const char *get_ext() const { return "CRN"; }
virtual const char* get_ext() const { return "CRN"; }
virtual bool compress_init(const crn_comp_params& params);
virtual bool compress_pass(const crn_comp_params& params, float *pEffective_bitrate);
virtual void compress_deinit();
virtual bool compress_init(const crn_comp_params& params);
virtual bool compress_pass(const crn_comp_params& params, float* pEffective_bitrate);
virtual void compress_deinit();
virtual const crnlib::vector<uint8>& get_comp_data() const { return m_comp_data; }
virtual crnlib::vector<uint8>& get_comp_data() { return m_comp_data; }
virtual const crnlib::vector<uint8>& get_comp_data() const { return m_comp_data; }
virtual crnlib::vector<uint8>& get_comp_data() { return m_comp_data; }
uint get_comp_data_size() const { return m_comp_data.size(); }
const uint8* get_comp_data_ptr() const { return m_comp_data.size() ? &m_comp_data[0] : NULL; }
uint get_comp_data_size() const { return m_comp_data.size(); }
const uint8* get_comp_data_ptr() const { return m_comp_data.size() ? &m_comp_data[0] : NULL; }
private:
task_pool m_task_pool;
const crn_comp_params* m_pParams;
private:
task_pool m_task_pool;
const crn_comp_params* m_pParams;
image_u8 m_images[cCRNMaxFaces][cCRNMaxLevels];
image_u8 m_images[cCRNMaxFaces][cCRNMaxLevels];
struct level_tag
{
uint m_width, m_height;
uint m_chunk_width, m_chunk_height;
uint m_group_index;
uint m_num_chunks;
uint m_first_chunk;
uint m_group_first_chunk;
} m_levels[cCRNMaxLevels];
struct level_tag {
uint m_width, m_height;
uint m_chunk_width, m_chunk_height;
uint m_group_index;
uint m_num_chunks;
uint m_first_chunk;
uint m_group_first_chunk;
} m_levels[cCRNMaxLevels];
struct mip_group
{
mip_group() : m_first_chunk(0), m_num_chunks(0) { }
struct mip_group {
mip_group()
: m_first_chunk(0), m_num_chunks(0) {}
uint m_first_chunk;
uint m_num_chunks;
};
crnlib::vector<mip_group> m_mip_groups;
uint m_first_chunk;
uint m_num_chunks;
};
crnlib::vector<mip_group> m_mip_groups;
enum comp
{
cColor,
cAlpha0,
cAlpha1,
cNumComps
};
enum comp {
cColor,
cAlpha0,
cAlpha1,
cNumComps
};
bool m_has_comp[cNumComps];
bool m_has_comp[cNumComps];
struct chunk_detail
{
chunk_detail() { utils::zero_object(*this); }
struct chunk_detail {
chunk_detail() { utils::zero_object(*this); }
uint m_first_endpoint_index;
uint m_first_selector_index;
};
typedef crnlib::vector<chunk_detail> chunk_detail_vec;
chunk_detail_vec m_chunk_details;
uint m_first_endpoint_index;
uint m_first_selector_index;
};
typedef crnlib::vector<chunk_detail> chunk_detail_vec;
chunk_detail_vec m_chunk_details;
crnlib::vector<uint> m_endpoint_indices[cNumComps];
crnlib::vector<uint> m_selector_indices[cNumComps];
crnlib::vector<uint> m_endpoint_indices[cNumComps];
crnlib::vector<uint> m_selector_indices[cNumComps];
uint m_total_chunks;
dxt_hc::pixel_chunk_vec m_chunks;
uint m_total_chunks;
dxt_hc::pixel_chunk_vec m_chunks;
crnd::crn_header m_crn_header;
crnlib::vector<uint8> m_comp_data;
crnd::crn_header m_crn_header;
crnlib::vector<uint8> m_comp_data;
dxt_hc m_hvq;
dxt_hc m_hvq;
symbol_histogram m_chunk_encoding_hist;
static_huffman_data_model m_chunk_encoding_dm;
symbol_histogram m_chunk_encoding_hist;
static_huffman_data_model m_chunk_encoding_dm;
symbol_histogram m_endpoint_index_hist[2];
static_huffman_data_model m_endpoint_index_dm[2]; // color, alpha
symbol_histogram m_endpoint_index_hist[2];
static_huffman_data_model m_endpoint_index_dm[2]; // color, alpha
symbol_histogram m_selector_index_hist[2];
static_huffman_data_model m_selector_index_dm[2]; // color, alpha
symbol_histogram m_selector_index_hist[2];
static_huffman_data_model m_selector_index_dm[2]; // color, alpha
crnlib::vector<uint8> m_packed_chunks[cCRNMaxLevels];
crnlib::vector<uint8> m_packed_data_models;
crnlib::vector<uint8> m_packed_color_endpoints;
crnlib::vector<uint8> m_packed_color_selectors;
crnlib::vector<uint8> m_packed_alpha_endpoints;
crnlib::vector<uint8> m_packed_alpha_selectors;
crnlib::vector<uint8> m_packed_chunks[cCRNMaxLevels];
crnlib::vector<uint8> m_packed_data_models;
crnlib::vector<uint8> m_packed_color_endpoints;
crnlib::vector<uint8> m_packed_color_selectors;
crnlib::vector<uint8> m_packed_alpha_endpoints;
crnlib::vector<uint8> m_packed_alpha_selectors;
void clear();
void clear();
void append_chunks(const image_u8& img, uint num_chunks_x, uint num_chunks_y, dxt_hc::pixel_chunk_vec& chunks, float weight);
void append_chunks(const image_u8& img, uint num_chunks_x, uint num_chunks_y, dxt_hc::pixel_chunk_vec& chunks, float weight);
static float color_endpoint_similarity_func(uint index_a, uint index_b, void* pContext);
static float alpha_endpoint_similarity_func(uint index_a, uint index_b, void* pContext);
void sort_color_endpoint_codebook(crnlib::vector<uint>& remapping, const crnlib::vector<uint>& endpoints);
void sort_alpha_endpoint_codebook(crnlib::vector<uint>& remapping, const crnlib::vector<uint>& endpoints);
static float color_endpoint_similarity_func(uint index_a, uint index_b, void* pContext);
static float alpha_endpoint_similarity_func(uint index_a, uint index_b, void* pContext);
void sort_color_endpoint_codebook(crnlib::vector<uint>& remapping, const crnlib::vector<uint>& endpoints);
void sort_alpha_endpoint_codebook(crnlib::vector<uint>& remapping, const crnlib::vector<uint>& endpoints);
bool pack_color_endpoints(crnlib::vector<uint8>& data, const crnlib::vector<uint>& remapping, const crnlib::vector<uint>& endpoint_indices, uint trial_index);
bool pack_alpha_endpoints(crnlib::vector<uint8>& data, const crnlib::vector<uint>& remapping, const crnlib::vector<uint>& endpoint_indices, uint trial_index);
bool pack_color_endpoints(crnlib::vector<uint8>& data, const crnlib::vector<uint>& remapping, const crnlib::vector<uint>& endpoint_indices, uint trial_index);
bool pack_alpha_endpoints(crnlib::vector<uint8>& data, const crnlib::vector<uint>& remapping, const crnlib::vector<uint>& endpoint_indices, uint trial_index);
static float color_selector_similarity_func(uint index_a, uint index_b, void* pContext);
static float alpha_selector_similarity_func(uint index_a, uint index_b, void* pContext);
void sort_selector_codebook(crnlib::vector<uint>& remapping, const crnlib::vector<dxt_hc::selectors>& selectors, const uint8* pTo_linear);
static float color_selector_similarity_func(uint index_a, uint index_b, void* pContext);
static float alpha_selector_similarity_func(uint index_a, uint index_b, void* pContext);
void sort_selector_codebook(crnlib::vector<uint>& remapping, const crnlib::vector<dxt_hc::selectors>& selectors, const uint8* pTo_linear);
bool pack_selectors(
crnlib::vector<uint8>& packed_data,
const crnlib::vector<uint>& selector_indices,
const crnlib::vector<dxt_hc::selectors>& selectors,
const crnlib::vector<uint>& remapping,
uint max_selector_value,
const uint8* pTo_linear,
uint trial_index);
bool pack_selectors(
crnlib::vector<uint8>& packed_data,
const crnlib::vector<uint>& selector_indices,
const crnlib::vector<dxt_hc::selectors>& selectors,
const crnlib::vector<uint>& remapping,
uint max_selector_value,
const uint8* pTo_linear,
uint trial_index);
bool alias_images();
void create_chunks();
bool quantize_chunks();
void create_chunk_indices();
bool alias_images();
void create_chunks();
bool quantize_chunks();
void create_chunk_indices();
bool pack_chunks(
uint first_chunk, uint num_chunks,
bool clear_histograms,
symbol_codec* pCodec,
const crnlib::vector<uint>* pColor_endpoint_remap,
const crnlib::vector<uint>* pColor_selector_remap,
const crnlib::vector<uint>* pAlpha_endpoint_remap,
const crnlib::vector<uint>* pAlpha_selector_remap);
bool pack_chunks(
uint first_chunk, uint num_chunks,
bool clear_histograms,
symbol_codec* pCodec,
const crnlib::vector<uint>* pColor_endpoint_remap,
const crnlib::vector<uint>* pColor_selector_remap,
const crnlib::vector<uint>* pAlpha_endpoint_remap,
const crnlib::vector<uint>* pAlpha_selector_remap);
bool pack_chunks_simulation(
uint first_chunk, uint num_chunks,
uint& total_bits,
const crnlib::vector<uint>* pColor_endpoint_remap,
const crnlib::vector<uint>* pColor_selector_remap,
const crnlib::vector<uint>* pAlpha_endpoint_remap,
const crnlib::vector<uint>* pAlpha_selector_remap);
bool pack_chunks_simulation(
uint first_chunk, uint num_chunks,
uint& total_bits,
const crnlib::vector<uint>* pColor_endpoint_remap,
const crnlib::vector<uint>* pColor_selector_remap,
const crnlib::vector<uint>* pAlpha_endpoint_remap,
const crnlib::vector<uint>* pAlpha_selector_remap);
void optimize_color_endpoint_codebook_task(uint64 data, void* pData_ptr);
bool optimize_color_endpoint_codebook(crnlib::vector<uint>& remapping);
void optimize_color_endpoint_codebook_task(uint64 data, void* pData_ptr);
bool optimize_color_endpoint_codebook(crnlib::vector<uint>& remapping);
void optimize_color_selector_codebook_task(uint64 data, void* pData_ptr);
bool optimize_color_selector_codebook(crnlib::vector<uint>& remapping);
void optimize_color_selector_codebook_task(uint64 data, void* pData_ptr);
bool optimize_color_selector_codebook(crnlib::vector<uint>& remapping);
void optimize_alpha_endpoint_codebook_task(uint64 data, void* pData_ptr);
bool optimize_alpha_endpoint_codebook(crnlib::vector<uint>& remapping);
void optimize_alpha_endpoint_codebook_task(uint64 data, void* pData_ptr);
bool optimize_alpha_endpoint_codebook(crnlib::vector<uint>& remapping);
void optimize_alpha_selector_codebook_task(uint64 data, void* pData_ptr);
bool optimize_alpha_selector_codebook(crnlib::vector<uint>& remapping);
void optimize_alpha_selector_codebook_task(uint64 data, void* pData_ptr);
bool optimize_alpha_selector_codebook(crnlib::vector<uint>& remapping);
bool create_comp_data();
bool create_comp_data();
bool pack_data_models();
bool pack_data_models();
bool update_progress(uint phase_index, uint subphase_index, uint subphase_total);
bool update_progress(uint phase_index, uint subphase_index, uint subphase_total);
bool compress_internal();
bool compress_internal();
static void append_vec(crnlib::vector<uint8>& a, const void* p, uint size);
static void append_vec(crnlib::vector<uint8>& a, const crnlib::vector<uint8>& b);
};
static void append_vec(crnlib::vector<uint8>& a, const void* p, uint size);
static void append_vec(crnlib::vector<uint8>& a, const crnlib::vector<uint8>& b);
};
} // namespace crnlib
} // namespace crnlib
+153 -175
View File
@@ -5,218 +5,196 @@
#include "crn_data_stream.h"
#include "crn_threading.h"
namespace crnlib
{
eConsoleMessageType console::m_default_category = cInfoConsoleMessage;
crnlib::vector<console::console_func> console::m_output_funcs;
bool console::m_crlf = true;
bool console::m_prefixes = true;
bool console::m_output_disabled;
data_stream* console::m_pLog_stream;
mutex* console::m_pMutex;
uint console::m_num_messages[cCMTTotal];
bool console::m_at_beginning_of_line = true;
namespace crnlib {
eConsoleMessageType console::m_default_category = cInfoConsoleMessage;
crnlib::vector<console::console_func> console::m_output_funcs;
bool console::m_crlf = true;
bool console::m_prefixes = true;
bool console::m_output_disabled;
data_stream* console::m_pLog_stream;
mutex* console::m_pMutex;
uint console::m_num_messages[cCMTTotal];
bool console::m_at_beginning_of_line = true;
const uint cConsoleBufSize = 4096;
const uint cConsoleBufSize = 4096;
void console::init()
{
if (!m_pMutex)
{
m_pMutex = crnlib_new<mutex>();
}
}
void console::init() {
if (!m_pMutex) {
m_pMutex = crnlib_new<mutex>();
}
}
void console::deinit()
{
if (m_pMutex)
{
crnlib_delete(m_pMutex);
m_pMutex = NULL;
}
}
void console::deinit() {
if (m_pMutex) {
crnlib_delete(m_pMutex);
m_pMutex = NULL;
}
}
void console::disable_crlf()
{
init();
void console::disable_crlf() {
init();
m_crlf = false;
}
m_crlf = false;
}
void console::enable_crlf()
{
init();
void console::enable_crlf() {
init();
m_crlf = true;
}
m_crlf = true;
}
void console::vprintf(eConsoleMessageType type, const char* p, va_list args)
{
init();
void console::vprintf(eConsoleMessageType type, const char* p, va_list args) {
init();
scoped_mutex lock(*m_pMutex);
scoped_mutex lock(*m_pMutex);
m_num_messages[type]++;
m_num_messages[type]++;
char buf[cConsoleBufSize];
vsprintf_s(buf, cConsoleBufSize, p, args);
char buf[cConsoleBufSize];
vsprintf_s(buf, cConsoleBufSize, p, args);
bool handled = false;
bool handled = false;
if (m_output_funcs.size())
{
for (uint i = 0; i < m_output_funcs.size(); i++)
if (m_output_funcs[i].m_func(type, buf, m_output_funcs[i].m_pData))
handled = true;
}
if (m_output_funcs.size()) {
for (uint i = 0; i < m_output_funcs.size(); i++)
if (m_output_funcs[i].m_func(type, buf, m_output_funcs[i].m_pData))
handled = true;
}
const char* pPrefix = NULL;
if ((m_prefixes) && (m_at_beginning_of_line))
{
switch (type)
{
case cDebugConsoleMessage: pPrefix = "Debug: "; break;
case cWarningConsoleMessage: pPrefix = "Warning: "; break;
case cErrorConsoleMessage: pPrefix = "Error: "; break;
default: break;
}
}
const char* pPrefix = NULL;
if ((m_prefixes) && (m_at_beginning_of_line)) {
switch (type) {
case cDebugConsoleMessage:
pPrefix = "Debug: ";
break;
case cWarningConsoleMessage:
pPrefix = "Warning: ";
break;
case cErrorConsoleMessage:
pPrefix = "Error: ";
break;
default:
break;
}
}
if ((!m_output_disabled) && (!handled))
{
if (pPrefix)
::printf("%s", pPrefix);
::printf(m_crlf ? "%s\n" : "%s", buf);
}
if ((!m_output_disabled) && (!handled)) {
if (pPrefix)
::printf("%s", pPrefix);
::printf(m_crlf ? "%s\n" : "%s", buf);
}
uint n = strlen(buf);
m_at_beginning_of_line = (m_crlf) || ((n) && (buf[n - 1] == '\n'));
uint n = strlen(buf);
m_at_beginning_of_line = (m_crlf) || ((n) && (buf[n - 1] == '\n'));
if ((type != cProgressConsoleMessage) && (m_pLog_stream))
{
// Yes this is bad.
dynamic_string tmp_buf(buf);
if ((type != cProgressConsoleMessage) && (m_pLog_stream)) {
// Yes this is bad.
dynamic_string tmp_buf(buf);
tmp_buf.translate_lf_to_crlf();
tmp_buf.translate_lf_to_crlf();
m_pLog_stream->printf(m_crlf ? "%s\r\n" : "%s", tmp_buf.get_ptr());
m_pLog_stream->flush();
}
}
m_pLog_stream->printf(m_crlf ? "%s\r\n" : "%s", tmp_buf.get_ptr());
m_pLog_stream->flush();
}
}
void console::printf(eConsoleMessageType type, const char* p, ...)
{
va_list args;
va_start(args, p);
vprintf(type, p, args);
va_end(args);
}
void console::printf(eConsoleMessageType type, const char* p, ...) {
va_list args;
va_start(args, p);
vprintf(type, p, args);
va_end(args);
}
void console::printf(const char* p, ...)
{
va_list args;
va_start(args, p);
vprintf(m_default_category, p, args);
va_end(args);
}
void console::printf(const char* p, ...) {
va_list args;
va_start(args, p);
vprintf(m_default_category, p, args);
va_end(args);
}
void console::set_default_category(eConsoleMessageType category)
{
init();
void console::set_default_category(eConsoleMessageType category) {
init();
m_default_category = category;
}
m_default_category = category;
}
eConsoleMessageType console::get_default_category()
{
init();
eConsoleMessageType console::get_default_category() {
init();
return m_default_category;
}
return m_default_category;
}
void console::add_console_output_func(console_output_func pFunc, void* pData)
{
init();
void console::add_console_output_func(console_output_func pFunc, void* pData) {
init();
scoped_mutex lock(*m_pMutex);
scoped_mutex lock(*m_pMutex);
m_output_funcs.push_back(console_func(pFunc, pData));
}
m_output_funcs.push_back(console_func(pFunc, pData));
}
void console::remove_console_output_func(console_output_func pFunc)
{
init();
void console::remove_console_output_func(console_output_func pFunc) {
init();
scoped_mutex lock(*m_pMutex);
scoped_mutex lock(*m_pMutex);
for (int i = m_output_funcs.size() - 1; i >= 0; i--)
{
if (m_output_funcs[i].m_func == pFunc)
{
m_output_funcs.erase(m_output_funcs.begin() + i);
}
}
for (int i = m_output_funcs.size() - 1; i >= 0; i--) {
if (m_output_funcs[i].m_func == pFunc) {
m_output_funcs.erase(m_output_funcs.begin() + i);
}
}
if (!m_output_funcs.size())
{
m_output_funcs.clear();
}
}
if (!m_output_funcs.size()) {
m_output_funcs.clear();
}
}
void console::progress(const char* p, ...)
{
va_list args;
va_start(args, p);
vprintf(cProgressConsoleMessage, p, args);
va_end(args);
}
void console::progress(const char* p, ...) {
va_list args;
va_start(args, p);
vprintf(cProgressConsoleMessage, p, args);
va_end(args);
}
void console::info(const char* p, ...)
{
va_list args;
va_start(args, p);
vprintf(cInfoConsoleMessage, p, args);
va_end(args);
}
void console::info(const char* p, ...) {
va_list args;
va_start(args, p);
vprintf(cInfoConsoleMessage, p, args);
va_end(args);
}
void console::message(const char* p, ...)
{
va_list args;
va_start(args, p);
vprintf(cMessageConsoleMessage, p, args);
va_end(args);
}
void console::message(const char* p, ...) {
va_list args;
va_start(args, p);
vprintf(cMessageConsoleMessage, p, args);
va_end(args);
}
void console::cons(const char* p, ...)
{
va_list args;
va_start(args, p);
vprintf(cConsoleConsoleMessage, p, args);
va_end(args);
}
void console::cons(const char* p, ...) {
va_list args;
va_start(args, p);
vprintf(cConsoleConsoleMessage, p, args);
va_end(args);
}
void console::debug(const char* p, ...)
{
va_list args;
va_start(args, p);
vprintf(cDebugConsoleMessage, p, args);
va_end(args);
}
void console::debug(const char* p, ...) {
va_list args;
va_start(args, p);
vprintf(cDebugConsoleMessage, p, args);
va_end(args);
}
void console::warning(const char* p, ...)
{
va_list args;
va_start(args, p);
vprintf(cWarningConsoleMessage, p, args);
va_end(args);
}
void console::warning(const char* p, ...) {
va_list args;
va_start(args, p);
vprintf(cWarningConsoleMessage, p, args);
va_end(args);
}
void console::error(const char* p, ...)
{
va_list args;
va_start(args, p);
vprintf(cErrorConsoleMessage, p, args);
va_end(args);
}
void console::error(const char* p, ...) {
va_list args;
va_start(args, p);
vprintf(cErrorConsoleMessage, p, args);
va_end(args);
}
} // namespace crnlib
} // namespace crnlib
+85 -92
View File
@@ -7,122 +7,115 @@
#include <tchar.h>
#include <conio.h>
#endif
namespace crnlib
{
class dynamic_string;
class data_stream;
class mutex;
namespace crnlib {
class dynamic_string;
class data_stream;
class mutex;
enum eConsoleMessageType
{
cDebugConsoleMessage, // debugging messages
cProgressConsoleMessage, // progress messages
cInfoConsoleMessage, // ordinary messages
cConsoleConsoleMessage, // user console output
cMessageConsoleMessage, // high importance messages
cWarningConsoleMessage, // warnings
cErrorConsoleMessage, // errors
enum eConsoleMessageType {
cDebugConsoleMessage, // debugging messages
cProgressConsoleMessage, // progress messages
cInfoConsoleMessage, // ordinary messages
cConsoleConsoleMessage, // user console output
cMessageConsoleMessage, // high importance messages
cWarningConsoleMessage, // warnings
cErrorConsoleMessage, // errors
cCMTTotal
};
cCMTTotal
};
typedef bool (*console_output_func)(eConsoleMessageType type, const char* pMsg, void* pData);
typedef bool (*console_output_func)(eConsoleMessageType type, const char* pMsg, void* pData);
class console
{
public:
static void init();
static void deinit();
class console {
public:
static void init();
static void deinit();
static bool is_initialized() { return m_pMutex != NULL; }
static bool is_initialized() { return m_pMutex != NULL; }
static void set_default_category(eConsoleMessageType category);
static eConsoleMessageType get_default_category();
static void set_default_category(eConsoleMessageType category);
static eConsoleMessageType get_default_category();
static void add_console_output_func(console_output_func pFunc, void* pData);
static void remove_console_output_func(console_output_func pFunc);
static void add_console_output_func(console_output_func pFunc, void* pData);
static void remove_console_output_func(console_output_func pFunc);
static void printf(const char* p, ...);
static void printf(const char* p, ...);
static void vprintf(eConsoleMessageType type, const char* p, va_list args);
static void printf(eConsoleMessageType type, const char* p, ...);
static void vprintf(eConsoleMessageType type, const char* p, va_list args);
static void printf(eConsoleMessageType type, const char* p, ...);
static void cons(const char* p, ...);
static void debug(const char* p, ...);
static void progress(const char* p, ...);
static void info(const char* p, ...);
static void message(const char* p, ...);
static void warning(const char* p, ...);
static void error(const char* p, ...);
static void cons(const char* p, ...);
static void debug(const char* p, ...);
static void progress(const char* p, ...);
static void info(const char* p, ...);
static void message(const char* p, ...);
static void warning(const char* p, ...);
static void error(const char* p, ...);
// FIXME: All console state is currently global!
static void disable_prefixes();
static void enable_prefixes();
static bool get_prefixes() { return m_prefixes; }
static bool get_at_beginning_of_line() { return m_at_beginning_of_line; }
// FIXME: All console state is currently global!
static void disable_prefixes();
static void enable_prefixes();
static bool get_prefixes() { return m_prefixes; }
static bool get_at_beginning_of_line() { return m_at_beginning_of_line; }
static void disable_crlf();
static void enable_crlf();
static bool get_crlf() { return m_crlf; }
static void disable_crlf();
static void enable_crlf();
static bool get_crlf() { return m_crlf; }
static void disable_output() { m_output_disabled = true; }
static void enable_output() { m_output_disabled = false; }
static bool get_output_disabled() { return m_output_disabled; }
static void disable_output() { m_output_disabled = true; }
static void enable_output() { m_output_disabled = false; }
static bool get_output_disabled() { return m_output_disabled; }
static void set_log_stream(data_stream* pStream) { m_pLog_stream = pStream; }
static data_stream* get_log_stream() { return m_pLog_stream; }
static void set_log_stream(data_stream* pStream) { m_pLog_stream = pStream; }
static data_stream* get_log_stream() { return m_pLog_stream; }
static uint get_num_messages(eConsoleMessageType type) { return m_num_messages[type]; }
static uint get_num_messages(eConsoleMessageType type) { return m_num_messages[type]; }
private:
static eConsoleMessageType m_default_category;
private:
static eConsoleMessageType m_default_category;
struct console_func
{
console_func(console_output_func func = NULL, void* pData = NULL) : m_func(func), m_pData(pData) { }
struct console_func {
console_func(console_output_func func = NULL, void* pData = NULL)
: m_func(func), m_pData(pData) {}
console_output_func m_func;
void* m_pData;
};
static crnlib::vector<console_func> m_output_funcs;
console_output_func m_func;
void* m_pData;
};
static crnlib::vector<console_func> m_output_funcs;
static bool m_crlf, m_prefixes, m_output_disabled;
static bool m_crlf, m_prefixes, m_output_disabled;
static data_stream* m_pLog_stream;
static data_stream* m_pLog_stream;
static mutex* m_pMutex;
static mutex* m_pMutex;
static uint m_num_messages[cCMTTotal];
static uint m_num_messages[cCMTTotal];
static bool m_at_beginning_of_line;
};
static bool m_at_beginning_of_line;
};
#if defined(WIN32)
inline int crn_getch()
{
return _getch();
}
inline int crn_getch() {
return _getch();
}
#elif defined(__GNUC__)
#include <termios.h>
#include <unistd.h>
inline int crn_getch()
{
struct termios oldt, newt;
int ch;
tcgetattr(STDIN_FILENO, &oldt);
newt = oldt;
newt.c_lflag &= ~(ICANON | ECHO);
tcsetattr(STDIN_FILENO, TCSANOW, &newt);
ch = getchar();
tcsetattr(STDIN_FILENO, TCSANOW, &oldt);
return ch;
}
#else
inline int crn_getch()
{
printf("crn_getch: Unimplemented");
return 0;
}
#include <termios.h>
#include <unistd.h>
inline int crn_getch() {
struct termios oldt, newt;
int ch;
tcgetattr(STDIN_FILENO, &oldt);
newt = oldt;
newt.c_lflag &= ~(ICANON | ECHO);
tcsetattr(STDIN_FILENO, TCSANOW, &newt);
ch = getchar();
tcsetattr(STDIN_FILENO, TCSANOW, &oldt);
return ch;
}
#else
inline int crn_getch() {
printf("crn_getch: Unimplemented");
return 0;
}
#endif
} // namespace crnlib
} // namespace crnlib
+4 -5
View File
@@ -6,9 +6,8 @@
#include "crn_winhdr.h"
#endif
namespace crnlib
{
const char *g_copyright_str = "Copyright (c) 2010-2016 Richard Geldreich, Jr. and Binomial LLC";
const char *g_sig_str = "C8cfRlaorj0wLtnMSxrBJxTC85rho2L9hUZKHcBL";
namespace crnlib {
const char* g_copyright_str = "Copyright (c) 2010-2016 Richard Geldreich, Jr. and Binomial LLC";
const char* g_sig_str = "C8cfRlaorj0wLtnMSxrBJxTC85rho2L9hUZKHcBL";
} // namespace crnlib
} // namespace crnlib
+116 -116
View File
@@ -3,124 +3,124 @@
#pragma once
#if defined(WIN32) && defined(_MSC_VER)
#pragma warning (disable: 4201) // nonstandard extension used : nameless struct/union
#pragma warning (disable: 4127) // conditional expression is constant
#pragma warning (disable: 4793) // function compiled as native
#pragma warning (disable: 4324) // structure was padded due to __declspec(align())
#pragma warning(disable : 4201) // nonstandard extension used : nameless struct/union
#pragma warning(disable : 4127) // conditional expression is constant
#pragma warning(disable : 4793) // function compiled as native
#pragma warning(disable : 4324) // structure was padded due to __declspec(align())
#endif
#if defined(WIN32) && !defined(CRNLIB_ANSI_CPLUSPLUS)
// MSVC or MinGW, x86 or x64, Win32 API's for threading and Win32 Interlocked API's or GCC built-ins for atomic ops.
#ifdef NDEBUG
// Ensure checked iterators are disabled. Note: Be sure anything else that links against this lib also #define's this stuff, or remove this crap!
#define _SECURE_SCL 0
#define _HAS_ITERATOR_DEBUGGING 0
#endif
#ifndef _DLL
// If we're using the DLL form of the run-time libs, we're also going to be enabling exceptions because we'll be building CLR apps.
// Otherwise, we disable exceptions for a small speed boost.
#define _HAS_EXCEPTIONS 0
#endif
#define NOMINMAX
// MSVC or MinGW, x86 or x64, Win32 API's for threading and Win32 Interlocked API's or GCC built-ins for atomic ops.
#ifdef NDEBUG
// Ensure checked iterators are disabled. Note: Be sure anything else that links against this lib also #define's this stuff, or remove this crap!
#define _SECURE_SCL 0
#define _HAS_ITERATOR_DEBUGGING 0
#endif
#ifndef _DLL
// If we're using the DLL form of the run-time libs, we're also going to be enabling exceptions because we'll be building CLR apps.
// Otherwise, we disable exceptions for a small speed boost.
#define _HAS_EXCEPTIONS 0
#endif
#define NOMINMAX
#define CRNLIB_USE_WIN32_API 1
#define CRNLIB_USE_WIN32_API 1
#if defined(__MINGW32__) || defined(__MINGW64__)
#define CRNLIB_USE_GCC_ATOMIC_BUILTINS 1
#else
#define CRNLIB_USE_WIN32_ATOMIC_FUNCTIONS 1
#endif
#define CRNLIB_PLATFORM_PC 1
#if defined(_WIN64) || defined(__MINGW64__) || defined(_LP64) || defined(__LP64__)
#define CRNLIB_PLATFORM_PC_X64 1
#define CRNLIB_64BIT_POINTERS 1
#define CRNLIB_CPU_HAS_64BIT_REGISTERS 1
#define CRNLIB_LITTLE_ENDIAN_CPU 1
#else
#define CRNLIB_PLATFORM_PC_X86 1
#define CRNLIB_64BIT_POINTERS 0
#define CRNLIB_CPU_HAS_64BIT_REGISTERS 0
#define CRNLIB_LITTLE_ENDIAN_CPU 1
#endif
#define CRNLIB_USE_UNALIGNED_INT_LOADS 1
#define CRNLIB_RESTRICT __restrict
#define CRNLIB_FORCE_INLINE __forceinline
#if defined(_MSC_VER) || defined(__MINGW32__) || defined(__MINGW64__)
#define CRNLIB_USE_MSVC_INTRINSICS 1
#endif
#define CRNLIB_INT64_FORMAT_SPECIFIER "%I64i"
#define CRNLIB_UINT64_FORMAT_SPECIFIER "%I64u"
#define CRNLIB_STDCALL __stdcall
#define CRNLIB_MEMORY_IMPORT_BARRIER
#define CRNLIB_MEMORY_EXPORT_BARRIER
#elif defined(__GNUC__) && !defined(CRNLIB_ANSI_CPLUSPLUS)
// GCC x86 or x64, pthreads for threading and GCC built-ins for atomic ops.
#define CRNLIB_PLATFORM_PC 1
#if defined(_WIN64) || defined(__MINGW64__) || defined(_LP64) || defined(__LP64__)
#define CRNLIB_PLATFORM_PC_X64 1
#define CRNLIB_64BIT_POINTERS 1
#define CRNLIB_CPU_HAS_64BIT_REGISTERS 1
#else
#define CRNLIB_PLATFORM_PC_X86 1
#define CRNLIB_64BIT_POINTERS 0
#define CRNLIB_CPU_HAS_64BIT_REGISTERS 0
#endif
#define CRNLIB_USE_UNALIGNED_INT_LOADS 1
#define CRNLIB_LITTLE_ENDIAN_CPU 1
#define CRNLIB_USE_PTHREADS_API 1
#define CRNLIB_USE_GCC_ATOMIC_BUILTINS 1
#define CRNLIB_RESTRICT
#define CRNLIB_FORCE_INLINE inline __attribute__((__always_inline__,__gnu_inline__))
#define CRNLIB_INT64_FORMAT_SPECIFIER "%lli"
#define CRNLIB_UINT64_FORMAT_SPECIFIER "%llu"
#define CRNLIB_STDCALL
#define CRNLIB_MEMORY_IMPORT_BARRIER
#define CRNLIB_MEMORY_EXPORT_BARRIER
#if defined(__MINGW32__) || defined(__MINGW64__)
#define CRNLIB_USE_GCC_ATOMIC_BUILTINS 1
#else
// Vanilla ANSI-C/C++
// No threading support, unaligned loads are NOT okay.
#if defined(_WIN64) || defined(__MINGW64__) || defined(_LP64) || defined(__LP64__)
#define CRNLIB_64BIT_POINTERS 1
#define CRNLIB_CPU_HAS_64BIT_REGISTERS 1
#else
#define CRNLIB_64BIT_POINTERS 0
#define CRNLIB_CPU_HAS_64BIT_REGISTERS 0
#endif
#define CRNLIB_USE_WIN32_ATOMIC_FUNCTIONS 1
#endif
#define CRNLIB_USE_UNALIGNED_INT_LOADS 0
#define CRNLIB_PLATFORM_PC 1
#if __BIG_ENDIAN__
#define CRNLIB_BIG_ENDIAN_CPU 1
#else
#define CRNLIB_LITTLE_ENDIAN_CPU 1
#endif
#if defined(_WIN64) || defined(__MINGW64__) || defined(_LP64) || defined(__LP64__)
#define CRNLIB_PLATFORM_PC_X64 1
#define CRNLIB_64BIT_POINTERS 1
#define CRNLIB_CPU_HAS_64BIT_REGISTERS 1
#define CRNLIB_LITTLE_ENDIAN_CPU 1
#else
#define CRNLIB_PLATFORM_PC_X86 1
#define CRNLIB_64BIT_POINTERS 0
#define CRNLIB_CPU_HAS_64BIT_REGISTERS 0
#define CRNLIB_LITTLE_ENDIAN_CPU 1
#endif
#define CRNLIB_USE_GCC_ATOMIC_BUILTINS 0
#define CRNLIB_USE_WIN32_ATOMIC_FUNCTIONS 0
#define CRNLIB_USE_UNALIGNED_INT_LOADS 1
#define CRNLIB_RESTRICT __restrict
#define CRNLIB_FORCE_INLINE __forceinline
#define CRNLIB_RESTRICT
#define CRNLIB_FORCE_INLINE inline
#if defined(_MSC_VER) || defined(__MINGW32__) || defined(__MINGW64__)
#define CRNLIB_USE_MSVC_INTRINSICS 1
#endif
#define CRNLIB_INT64_FORMAT_SPECIFIER "%I64i"
#define CRNLIB_UINT64_FORMAT_SPECIFIER "%I64u"
#define CRNLIB_INT64_FORMAT_SPECIFIER "%I64i"
#define CRNLIB_UINT64_FORMAT_SPECIFIER "%I64u"
#define CRNLIB_STDCALL
#define CRNLIB_MEMORY_IMPORT_BARRIER
#define CRNLIB_MEMORY_EXPORT_BARRIER
#define CRNLIB_STDCALL __stdcall
#define CRNLIB_MEMORY_IMPORT_BARRIER
#define CRNLIB_MEMORY_EXPORT_BARRIER
#elif defined(__GNUC__) && !defined(CRNLIB_ANSI_CPLUSPLUS)
// GCC x86 or x64, pthreads for threading and GCC built-ins for atomic ops.
#define CRNLIB_PLATFORM_PC 1
#if defined(_WIN64) || defined(__MINGW64__) || defined(_LP64) || defined(__LP64__)
#define CRNLIB_PLATFORM_PC_X64 1
#define CRNLIB_64BIT_POINTERS 1
#define CRNLIB_CPU_HAS_64BIT_REGISTERS 1
#else
#define CRNLIB_PLATFORM_PC_X86 1
#define CRNLIB_64BIT_POINTERS 0
#define CRNLIB_CPU_HAS_64BIT_REGISTERS 0
#endif
#define CRNLIB_USE_UNALIGNED_INT_LOADS 1
#define CRNLIB_LITTLE_ENDIAN_CPU 1
#define CRNLIB_USE_PTHREADS_API 1
#define CRNLIB_USE_GCC_ATOMIC_BUILTINS 1
#define CRNLIB_RESTRICT
#define CRNLIB_FORCE_INLINE inline __attribute__((__always_inline__, __gnu_inline__))
#define CRNLIB_INT64_FORMAT_SPECIFIER "%lli"
#define CRNLIB_UINT64_FORMAT_SPECIFIER "%llu"
#define CRNLIB_STDCALL
#define CRNLIB_MEMORY_IMPORT_BARRIER
#define CRNLIB_MEMORY_EXPORT_BARRIER
#else
// Vanilla ANSI-C/C++
// No threading support, unaligned loads are NOT okay.
#if defined(_WIN64) || defined(__MINGW64__) || defined(_LP64) || defined(__LP64__)
#define CRNLIB_64BIT_POINTERS 1
#define CRNLIB_CPU_HAS_64BIT_REGISTERS 1
#else
#define CRNLIB_64BIT_POINTERS 0
#define CRNLIB_CPU_HAS_64BIT_REGISTERS 0
#endif
#define CRNLIB_USE_UNALIGNED_INT_LOADS 0
#if __BIG_ENDIAN__
#define CRNLIB_BIG_ENDIAN_CPU 1
#else
#define CRNLIB_LITTLE_ENDIAN_CPU 1
#endif
#define CRNLIB_USE_GCC_ATOMIC_BUILTINS 0
#define CRNLIB_USE_WIN32_ATOMIC_FUNCTIONS 0
#define CRNLIB_RESTRICT
#define CRNLIB_FORCE_INLINE inline
#define CRNLIB_INT64_FORMAT_SPECIFIER "%I64i"
#define CRNLIB_UINT64_FORMAT_SPECIFIER "%I64u"
#define CRNLIB_STDCALL
#define CRNLIB_MEMORY_IMPORT_BARRIER
#define CRNLIB_MEMORY_EXPORT_BARRIER
#endif
#define CRNLIB_SLOW_STRING_LEN_CHECKS 1
@@ -139,11 +139,11 @@
#include <errno.h>
#ifdef min
#undef min
#undef min
#endif
#ifdef max
#undef max
#undef max
#endif
#define CRNLIB_FALSE (0)
@@ -151,17 +151,17 @@
#define CRNLIB_MAX_PATH (260)
#ifdef _DEBUG
#define CRNLIB_BUILD_DEBUG
#define CRNLIB_BUILD_DEBUG
#else
#define CRNLIB_BUILD_RELEASE
#define CRNLIB_BUILD_RELEASE
#ifndef NDEBUG
#define NDEBUG
#endif
#ifndef NDEBUG
#define NDEBUG
#endif
#ifdef DEBUG
#error DEBUG cannot be defined in CRNLIB_BUILD_RELEASE
#endif
#ifdef DEBUG
#error DEBUG cannot be defined in CRNLIB_BUILD_RELEASE
#endif
#endif
#include "crn_types.h"
+89 -103
View File
@@ -3,126 +3,112 @@
#include "crn_core.h"
#include "crn_data_stream.h"
namespace crnlib
{
data_stream::data_stream() :
m_attribs(0),
m_opened(false), m_error(false), m_got_cr(false)
{
}
namespace crnlib {
data_stream::data_stream()
: m_attribs(0),
m_opened(false),
m_error(false),
m_got_cr(false) {
}
data_stream::data_stream(const char* pName, uint attribs) :
m_name(pName),
data_stream::data_stream(const char* pName, uint attribs)
: m_name(pName),
m_attribs(static_cast<uint16>(attribs)),
m_opened(false), m_error(false), m_got_cr(false)
{
}
m_opened(false),
m_error(false),
m_got_cr(false) {
}
uint64 data_stream::skip(uint64 len)
{
uint64 total_bytes_read = 0;
uint64 data_stream::skip(uint64 len) {
uint64 total_bytes_read = 0;
const uint cBufSize = 1024;
uint8 buf[cBufSize];
const uint cBufSize = 1024;
uint8 buf[cBufSize];
while (len)
{
const uint64 bytes_to_read = math::minimum<uint64>(sizeof(buf), len);
const uint64 bytes_read = read(buf, static_cast<uint>(bytes_to_read));
total_bytes_read += bytes_read;
while (len) {
const uint64 bytes_to_read = math::minimum<uint64>(sizeof(buf), len);
const uint64 bytes_read = read(buf, static_cast<uint>(bytes_to_read));
total_bytes_read += bytes_read;
if (bytes_read != bytes_to_read)
break;
if (bytes_read != bytes_to_read)
break;
len -= bytes_read;
}
len -= bytes_read;
}
return total_bytes_read;
}
return total_bytes_read;
}
bool data_stream::read_line(dynamic_string& str)
{
str.empty();
bool data_stream::read_line(dynamic_string& str) {
str.empty();
for ( ; ; )
{
const int c = read_byte();
for (;;) {
const int c = read_byte();
const bool prev_got_cr = m_got_cr;
m_got_cr = false;
const bool prev_got_cr = m_got_cr;
m_got_cr = false;
if (c < 0)
{
if (!str.is_empty())
break;
return false;
}
else if ((26 == c) || (!c))
continue;
else if (13 == c)
{
m_got_cr = true;
break;
}
else if (10 == c)
{
if (prev_got_cr)
continue;
break;
}
str.append_char(static_cast<char>(c));
}
return true;
}
bool data_stream::printf(const char* p, ...)
{
va_list args;
va_start(args, p);
dynamic_string buf;
buf.format_args(p, args);
va_end(args);
return write(buf.get_ptr(), buf.get_len() * sizeof(char)) == buf.get_len() * sizeof(char);
}
bool data_stream::write_line(const dynamic_string& str)
{
if (c < 0) {
if (!str.is_empty())
return write(str.get_ptr(), str.get_len()) == str.get_len();
break;
return true;
}
return false;
} else if ((26 == c) || (!c))
continue;
else if (13 == c) {
m_got_cr = true;
break;
} else if (10 == c) {
if (prev_got_cr)
continue;
bool data_stream::read_array(vector<uint8>& buf)
{
if (buf.size() < get_remaining())
{
if (get_remaining() > 1024U*1024U*1024U)
return false;
break;
}
buf.resize((uint)get_remaining());
}
str.append_char(static_cast<char>(c));
}
if (!get_remaining())
{
buf.resize(0);
return true;
}
return true;
}
return read(&buf[0], buf.size()) == buf.size();
}
bool data_stream::printf(const char* p, ...) {
va_list args;
bool data_stream::write_array(const vector<uint8>& buf)
{
if (!buf.empty())
return write(&buf[0], buf.size()) == buf.size();
return true;
}
va_start(args, p);
dynamic_string buf;
buf.format_args(p, args);
va_end(args);
} // namespace crnlib
return write(buf.get_ptr(), buf.get_len() * sizeof(char)) == buf.get_len() * sizeof(char);
}
bool data_stream::write_line(const dynamic_string& str) {
if (!str.is_empty())
return write(str.get_ptr(), str.get_len()) == str.get_len();
return true;
}
bool data_stream::read_array(vector<uint8>& buf) {
if (buf.size() < get_remaining()) {
if (get_remaining() > 1024U * 1024U * 1024U)
return false;
buf.resize((uint)get_remaining());
}
if (!get_remaining()) {
buf.resize(0);
return true;
}
return read(&buf[0], buf.size()) == buf.size();
}
bool data_stream::write_array(const vector<uint8>& buf) {
if (!buf.empty())
return write(&buf[0], buf.size()) == buf.size();
return true;
}
} // namespace crnlib
+69 -60
View File
@@ -2,88 +2,97 @@
// See Copyright Notice and license at the end of inc/crnlib.h
#pragma once
namespace crnlib
{
enum data_stream_attribs
{
cDataStreamReadable = 1,
cDataStreamWritable = 2,
cDataStreamSeekable = 4
};
namespace crnlib {
enum data_stream_attribs {
cDataStreamReadable = 1,
cDataStreamWritable = 2,
cDataStreamSeekable = 4
};
const int64 DATA_STREAM_SIZE_UNKNOWN = cINT64_MAX;
const int64 DATA_STREAM_SIZE_INFINITE = cUINT64_MAX;
const int64 DATA_STREAM_SIZE_UNKNOWN = cINT64_MAX;
const int64 DATA_STREAM_SIZE_INFINITE = cUINT64_MAX;
class data_stream
{
data_stream(const data_stream&);
data_stream& operator= (const data_stream&);
class data_stream {
data_stream(const data_stream&);
data_stream& operator=(const data_stream&);
public:
data_stream();
data_stream(const char* pName, uint attribs);
public:
data_stream();
data_stream(const char* pName, uint attribs);
virtual ~data_stream() { }
virtual ~data_stream() {}
virtual data_stream *get_parent() { return NULL; }
virtual data_stream* get_parent() { return NULL; }
virtual bool close() { m_opened = false; m_error = false; m_got_cr = false; return true; }
virtual bool close() {
m_opened = false;
m_error = false;
m_got_cr = false;
return true;
}
typedef uint16 attribs_t;
inline attribs_t get_attribs() const { return m_attribs; }
typedef uint16 attribs_t;
inline attribs_t get_attribs() const { return m_attribs; }
inline bool is_opened() const { return m_opened; }
inline bool is_opened() const { return m_opened; }
inline bool is_readable() const { return utils::is_bit_set(m_attribs, cDataStreamReadable); }
inline bool is_writable() const { return utils::is_bit_set(m_attribs, cDataStreamWritable); }
inline bool is_seekable() const { return utils::is_bit_set(m_attribs, cDataStreamSeekable); }
inline bool is_readable() const { return utils::is_bit_set(m_attribs, cDataStreamReadable); }
inline bool is_writable() const { return utils::is_bit_set(m_attribs, cDataStreamWritable); }
inline bool is_seekable() const { return utils::is_bit_set(m_attribs, cDataStreamSeekable); }
inline bool get_error() const { return m_error; }
inline bool get_error() const { return m_error; }
inline const dynamic_string& get_name() const { return m_name; }
inline void set_name(const char* pName) { m_name.set(pName); }
inline const dynamic_string& get_name() const { return m_name; }
inline void set_name(const char* pName) { m_name.set(pName); }
virtual uint read(void* pBuf, uint len) = 0;
virtual uint64 skip(uint64 len);
virtual uint read(void* pBuf, uint len) = 0;
virtual uint64 skip(uint64 len);
virtual uint write(const void* pBuf, uint len) = 0;
virtual bool flush() = 0;
virtual uint write(const void* pBuf, uint len) = 0;
virtual bool flush() = 0;
virtual bool is_size_known() const { return true; }
virtual bool is_size_known() const { return true; }
// Returns DATA_STREAM_SIZE_UNKNOWN if size hasn't been determined yet, or DATA_STREAM_SIZE_INFINITE for infinite streams.
virtual uint64 get_size() = 0;
virtual uint64 get_remaining() = 0;
// Returns DATA_STREAM_SIZE_UNKNOWN if size hasn't been determined yet, or DATA_STREAM_SIZE_INFINITE for infinite streams.
virtual uint64 get_size() = 0;
virtual uint64 get_remaining() = 0;
virtual uint64 get_ofs() = 0;
virtual bool seek(int64 ofs, bool relative) = 0;
virtual uint64 get_ofs() = 0;
virtual bool seek(int64 ofs, bool relative) = 0;
virtual const void* get_ptr() const { return NULL; }
virtual const void* get_ptr() const { return NULL; }
inline int read_byte() { uint8 c; if (read(&c, 1) != 1) return -1; return c; }
inline bool write_byte(uint8 c) { return write(&c, 1) == 1; }
inline int read_byte() {
uint8 c;
if (read(&c, 1) != 1)
return -1;
return c;
}
inline bool write_byte(uint8 c) { return write(&c, 1) == 1; }
bool read_line(dynamic_string& str);
bool printf(const char* p, ...);
bool write_line(const dynamic_string& str);
bool write_bom() { uint16 bom = 0xFEFF; return write(&bom, sizeof(bom)) == sizeof(bom); }
bool read_line(dynamic_string& str);
bool printf(const char* p, ...);
bool write_line(const dynamic_string& str);
bool write_bom() {
uint16 bom = 0xFEFF;
return write(&bom, sizeof(bom)) == sizeof(bom);
}
bool read_array(vector<uint8>& buf);
bool write_array(const vector<uint8>& buf);
bool read_array(vector<uint8>& buf);
bool write_array(const vector<uint8>& buf);
protected:
dynamic_string m_name;
protected:
dynamic_string m_name;
attribs_t m_attribs;
bool m_opened : 1;
bool m_error : 1;
bool m_got_cr : 1;
attribs_t m_attribs;
bool m_opened : 1;
bool m_error : 1;
bool m_got_cr : 1;
inline void set_error() { m_error = true; }
inline void clear_error() { m_error = false; }
inline void set_error() { m_error = true; }
inline void clear_error() { m_error = false; }
inline void post_seek() { m_got_cr = false; }
};
} // namespace crnlib
inline void post_seek() { m_got_cr = false; }
};
} // namespace crnlib
+467 -440
View File
@@ -3,466 +3,493 @@
#pragma once
#include "crn_data_stream.h"
namespace crnlib
{
// Defaults to little endian mode.
class data_stream_serializer
{
public:
data_stream_serializer() : m_pStream(NULL), m_little_endian(true) { }
data_stream_serializer(data_stream* pStream) : m_pStream(pStream), m_little_endian(true) { }
data_stream_serializer(data_stream& stream) : m_pStream(&stream), m_little_endian(true) { }
data_stream_serializer(const data_stream_serializer& other) : m_pStream(other.m_pStream), m_little_endian(other.m_little_endian) { }
data_stream_serializer& operator= (const data_stream_serializer& rhs) { m_pStream = rhs.m_pStream; m_little_endian = rhs.m_little_endian; return *this; }
namespace crnlib {
// Defaults to little endian mode.
class data_stream_serializer {
public:
data_stream_serializer()
: m_pStream(NULL), m_little_endian(true) {}
data_stream_serializer(data_stream* pStream)
: m_pStream(pStream), m_little_endian(true) {}
data_stream_serializer(data_stream& stream)
: m_pStream(&stream), m_little_endian(true) {}
data_stream_serializer(const data_stream_serializer& other)
: m_pStream(other.m_pStream), m_little_endian(other.m_little_endian) {}
data_stream* get_stream() const { return m_pStream; }
void set_stream(data_stream* pStream) { m_pStream = pStream; }
data_stream_serializer& operator=(const data_stream_serializer& rhs) {
m_pStream = rhs.m_pStream;
m_little_endian = rhs.m_little_endian;
return *this;
}
const dynamic_string& get_name() const { return m_pStream ? m_pStream->get_name() : g_empty_dynamic_string; }
data_stream* get_stream() const { return m_pStream; }
void set_stream(data_stream* pStream) { m_pStream = pStream; }
bool get_error() { return m_pStream ? m_pStream->get_error() : false; }
bool get_little_endian() const { return m_little_endian; }
void set_little_endian(bool little_endian) { m_little_endian = little_endian; }
bool write(const void* pBuf, uint len)
{
return m_pStream->write(pBuf, len) == len;
}
bool read(void* pBuf, uint len)
{
return m_pStream->read(pBuf, len) == len;
}
// size = size of each element, count = number of elements, returns actual count of elements written
uint write(const void* pBuf, uint size, uint count)
{
uint actual_size = size * count;
if (!actual_size)
return 0;
uint n = m_pStream->write(pBuf, actual_size);
if (n == actual_size)
return count;
return n / size;
}
const dynamic_string& get_name() const { return m_pStream ? m_pStream->get_name() : g_empty_dynamic_string; }
// size = size of each element, count = number of elements, returns actual count of elements read
uint read(void* pBuf, uint size, uint count)
{
uint actual_size = size * count;
if (!actual_size)
return 0;
uint n = m_pStream->read(pBuf, actual_size);
if (n == actual_size)
return count;
return n / size;
}
bool write_chars(const char* pBuf, uint len)
{
return write(pBuf, len);
}
bool read_chars(char* pBuf, uint len)
{
return read(pBuf, len);
}
bool skip(uint len)
{
return m_pStream->skip(len) == len;
}
template<typename T>
bool write_object(const T& obj)
{
if (m_little_endian == c_crnlib_little_endian_platform)
return write(&obj, sizeof(obj));
else
{
uint8 buf[sizeof(T)];
uint buf_size = sizeof(T);
void* pBuf = buf;
utils::write_obj(obj, pBuf, buf_size, m_little_endian);
return write(buf, sizeof(T));
}
}
template<typename T>
bool read_object(T& obj)
{
if (m_little_endian == c_crnlib_little_endian_platform)
return read(&obj, sizeof(obj));
else
{
uint8 buf[sizeof(T)];
if (!read(buf, sizeof(T)))
return false;
uint buf_size = sizeof(T);
const void* pBuf = buf;
utils::read_obj(obj, pBuf, buf_size, m_little_endian);
return true;
}
}
template<typename T>
bool write_value(T value)
{
return write_object(value);
}
template<typename T>
T read_value(const T& on_error_value = T())
{
T result;
if (!read_object(result))
result = on_error_value;
return result;
}
template<typename T>
bool write_enum(T e)
{
int val = static_cast<int>(e);
return write_object(val);
}
bool get_error() { return m_pStream ? m_pStream->get_error() : false; }
template<typename T>
T read_enum()
{
return static_cast<T>(read_value<int>());
bool get_little_endian() const { return m_little_endian; }
void set_little_endian(bool little_endian) { m_little_endian = little_endian; }
bool write(const void* pBuf, uint len) {
return m_pStream->write(pBuf, len) == len;
}
bool read(void* pBuf, uint len) {
return m_pStream->read(pBuf, len) == len;
}
// size = size of each element, count = number of elements, returns actual count of elements written
uint write(const void* pBuf, uint size, uint count) {
uint actual_size = size * count;
if (!actual_size)
return 0;
uint n = m_pStream->write(pBuf, actual_size);
if (n == actual_size)
return count;
return n / size;
}
// size = size of each element, count = number of elements, returns actual count of elements read
uint read(void* pBuf, uint size, uint count) {
uint actual_size = size * count;
if (!actual_size)
return 0;
uint n = m_pStream->read(pBuf, actual_size);
if (n == actual_size)
return count;
return n / size;
}
bool write_chars(const char* pBuf, uint len) {
return write(pBuf, len);
}
bool read_chars(char* pBuf, uint len) {
return read(pBuf, len);
}
bool skip(uint len) {
return m_pStream->skip(len) == len;
}
template <typename T>
bool write_object(const T& obj) {
if (m_little_endian == c_crnlib_little_endian_platform)
return write(&obj, sizeof(obj));
else {
uint8 buf[sizeof(T)];
uint buf_size = sizeof(T);
void* pBuf = buf;
utils::write_obj(obj, pBuf, buf_size, m_little_endian);
return write(buf, sizeof(T));
}
}
template <typename T>
bool read_object(T& obj) {
if (m_little_endian == c_crnlib_little_endian_platform)
return read(&obj, sizeof(obj));
else {
uint8 buf[sizeof(T)];
if (!read(buf, sizeof(T)))
return false;
uint buf_size = sizeof(T);
const void* pBuf = buf;
utils::read_obj(obj, pBuf, buf_size, m_little_endian);
return true;
}
}
template <typename T>
bool write_value(T value) {
return write_object(value);
}
template <typename T>
T read_value(const T& on_error_value = T()) {
T result;
if (!read_object(result))
result = on_error_value;
return result;
}
template <typename T>
bool write_enum(T e) {
int val = static_cast<int>(e);
return write_object(val);
}
template <typename T>
T read_enum() {
return static_cast<T>(read_value<int>());
}
// Writes uint using a simple variable length code (VLC).
bool write_uint_vlc(uint val) {
do {
uint8 c = static_cast<uint8>(val) & 0x7F;
if (val <= 0x7F)
c |= 0x80;
if (!write_value(c))
return false;
val >>= 7;
} while (val);
return true;
}
// Reads uint using a simple variable length code (VLC).
bool read_uint_vlc(uint& val) {
val = 0;
uint shift = 0;
for (;;) {
if (shift >= 32)
return false;
uint8 c;
if (!read_object(c))
return false;
val |= ((c & 0x7F) << shift);
shift += 7;
if (c & 0x80)
break;
}
return true;
}
bool write_c_str(const char* p) {
uint len = static_cast<uint>(strlen(p));
if (!write_uint_vlc(len))
return false;
return write_chars(p, len);
}
bool read_c_str(char* pBuf, uint buf_size) {
uint len;
if (!read_uint_vlc(len))
return false;
if ((len + 1) > buf_size)
return false;
pBuf[len] = '\0';
return read_chars(pBuf, len);
}
bool write_string(const dynamic_string& str) {
if (!write_uint_vlc(str.get_len()))
return false;
return write_chars(str.get_ptr(), str.get_len());
}
bool read_string(dynamic_string& str) {
uint len;
if (!read_uint_vlc(len))
return false;
if (!str.set_len(len))
return false;
if (len) {
if (!read_chars(str.get_ptr_raw(), len))
return false;
if (memchr(str.get_ptr(), 0, len) != NULL) {
str.truncate(0);
return false;
}
// Writes uint using a simple variable length code (VLC).
bool write_uint_vlc(uint val)
{
do
{
uint8 c = static_cast<uint8>(val) & 0x7F;
if (val <= 0x7F)
c |= 0x80;
if (!write_value(c))
return false;
val >>= 7;
} while (val);
return true;
}
// Reads uint using a simple variable length code (VLC).
bool read_uint_vlc(uint& val)
{
val = 0;
uint shift = 0;
for ( ; ; )
{
if (shift >= 32)
return false;
uint8 c;
if (!read_object(c))
return false;
val |= ((c & 0x7F) << shift);
shift += 7;
if (c & 0x80)
break;
}
return true;
}
bool write_c_str(const char* p)
{
uint len = static_cast<uint>(strlen(p));
if (!write_uint_vlc(len))
}
return true;
}
template <typename T>
bool write_vector(const T& vec) {
if (!write_uint_vlc(vec.size()))
return false;
for (uint i = 0; i < vec.size(); i++) {
*this << vec[i];
if (get_error())
return false;
}
return true;
};
template <typename T>
bool read_vector(T& vec, uint num_expected = UINT_MAX) {
uint size;
if (!read_uint_vlc(size))
return false;
if ((size * sizeof(T::value_type)) >= 2U * 1024U * 1024U * 1024U)
return false;
if ((num_expected != UINT_MAX) && (size != num_expected))
return false;
vec.resize(size);
for (uint i = 0; i < vec.size(); i++) {
*this >> vec[i];
if (get_error())
return false;
}
return true;
}
bool read_entire_file(crnlib::vector<uint8>& buf) {
return m_pStream->read_array(buf);
}
bool write_entire_file(const crnlib::vector<uint8>& buf) {
return m_pStream->write_array(buf);
}
// Got this idea from the Molly Rocket forums.
// fmt may contain the characters "1", "2", or "4".
bool writef(char* fmt, ...) {
va_list v;
va_start(v, fmt);
while (*fmt) {
switch (*fmt++) {
case '1': {
const uint8 x = static_cast<uint8>(va_arg(v, uint));
if (!write_value(x))
return false;
return write_chars(p, len);
}
case '2': {
const uint16 x = static_cast<uint16>(va_arg(v, uint));
if (!write_value(x))
return false;
}
case '4': {
const uint32 x = static_cast<uint32>(va_arg(v, uint));
if (!write_value(x))
return false;
}
case ' ':
case ',': {
break;
}
default: {
CRNLIB_ASSERT(0);
return false;
}
}
bool read_c_str(char* pBuf, uint buf_size)
{
uint len;
if (!read_uint_vlc(len))
}
va_end(v);
return true;
}
// Got this idea from the Molly Rocket forums.
// fmt may contain the characters "1", "2", or "4".
bool readf(char* fmt, ...) {
va_list v;
va_start(v, fmt);
while (*fmt) {
switch (*fmt++) {
case '1': {
uint8* x = va_arg(v, uint8*);
CRNLIB_ASSERT(x);
if (!read_object(*x))
return false;
if ((len + 1) > buf_size)
}
case '2': {
uint16* x = va_arg(v, uint16*);
CRNLIB_ASSERT(x);
if (!read_object(*x))
return false;
pBuf[len] = '\0';
return read_chars(pBuf, len);
}
case '4': {
uint32* x = va_arg(v, uint32*);
CRNLIB_ASSERT(x);
if (!read_object(*x))
return false;
}
case ' ':
case ',': {
break;
}
default: {
CRNLIB_ASSERT(0);
return false;
}
}
bool write_string(const dynamic_string& str)
{
if (!write_uint_vlc(str.get_len()))
return false;
}
return write_chars(str.get_ptr(), str.get_len());
}
bool read_string(dynamic_string& str)
{
uint len;
if (!read_uint_vlc(len))
return false;
if (!str.set_len(len))
return false;
if (len)
{
if (!read_chars(str.get_ptr_raw(), len))
return false;
if (memchr(str.get_ptr(), 0, len) != NULL)
{
str.truncate(0);
return false;
}
}
return true;
}
template<typename T>
bool write_vector(const T& vec)
{
if (!write_uint_vlc(vec.size()))
return false;
for (uint i = 0; i < vec.size(); i++)
{
*this << vec[i];
if (get_error())
return false;
}
return true;
};
template<typename T>
bool read_vector(T& vec, uint num_expected = UINT_MAX)
{
uint size;
if (!read_uint_vlc(size))
return false;
if ((size * sizeof(T::value_type)) >= 2U*1024U*1024U*1024U)
return false;
if ((num_expected != UINT_MAX) && (size != num_expected))
return false;
vec.resize(size);
for (uint i = 0; i < vec.size(); i++)
{
*this >> vec[i];
if (get_error())
return false;
}
return true;
}
va_end(v);
return true;
}
bool read_entire_file(crnlib::vector<uint8>& buf)
{
return m_pStream->read_array(buf);
}
private:
data_stream* m_pStream;
bool write_entire_file(const crnlib::vector<uint8>& buf)
{
return m_pStream->write_array(buf);
}
// Got this idea from the Molly Rocket forums.
// fmt may contain the characters "1", "2", or "4".
bool writef(char *fmt, ...)
{
va_list v;
va_start(v, fmt);
while (*fmt)
{
switch (*fmt++)
{
case '1':
{
const uint8 x = static_cast<uint8>(va_arg(v, uint));
if (!write_value(x))
return false;
}
case '2':
{
const uint16 x = static_cast<uint16>(va_arg(v, uint));
if (!write_value(x))
return false;
}
case '4':
{
const uint32 x = static_cast<uint32>(va_arg(v, uint));
if (!write_value(x))
return false;
}
case ' ':
case ',':
{
break;
}
default:
{
CRNLIB_ASSERT(0);
return false;
}
}
}
va_end(v);
return true;
}
// Got this idea from the Molly Rocket forums.
// fmt may contain the characters "1", "2", or "4".
bool readf(char *fmt, ...)
{
va_list v;
va_start(v, fmt);
bool m_little_endian;
};
while (*fmt)
{
switch (*fmt++)
{
case '1':
{
uint8* x = va_arg(v, uint8*);
CRNLIB_ASSERT(x);
if (!read_object(*x))
return false;
}
case '2':
{
uint16* x = va_arg(v, uint16*);
CRNLIB_ASSERT(x);
if (!read_object(*x))
return false;
}
case '4':
{
uint32* x = va_arg(v, uint32*);
CRNLIB_ASSERT(x);
if (!read_object(*x))
return false;
}
case ' ':
case ',':
{
break;
}
default:
{
CRNLIB_ASSERT(0);
return false;
}
}
}
// Write operators
inline data_stream_serializer& operator<<(data_stream_serializer& serializer, bool val) {
serializer.write_value(val);
return serializer;
}
inline data_stream_serializer& operator<<(data_stream_serializer& serializer, int8 val) {
serializer.write_value(val);
return serializer;
}
inline data_stream_serializer& operator<<(data_stream_serializer& serializer, uint8 val) {
serializer.write_value(val);
return serializer;
}
inline data_stream_serializer& operator<<(data_stream_serializer& serializer, int16 val) {
serializer.write_value(val);
return serializer;
}
inline data_stream_serializer& operator<<(data_stream_serializer& serializer, uint16 val) {
serializer.write_value(val);
return serializer;
}
inline data_stream_serializer& operator<<(data_stream_serializer& serializer, int32 val) {
serializer.write_value(val);
return serializer;
}
inline data_stream_serializer& operator<<(data_stream_serializer& serializer, uint32 val) {
serializer.write_uint_vlc(val);
return serializer;
}
inline data_stream_serializer& operator<<(data_stream_serializer& serializer, int64 val) {
serializer.write_value(val);
return serializer;
}
inline data_stream_serializer& operator<<(data_stream_serializer& serializer, uint64 val) {
serializer.write_value(val);
return serializer;
}
inline data_stream_serializer& operator<<(data_stream_serializer& serializer, long val) {
serializer.write_value(val);
return serializer;
}
inline data_stream_serializer& operator<<(data_stream_serializer& serializer, unsigned long val) {
serializer.write_value(val);
return serializer;
}
inline data_stream_serializer& operator<<(data_stream_serializer& serializer, float val) {
serializer.write_value(val);
return serializer;
}
inline data_stream_serializer& operator<<(data_stream_serializer& serializer, double val) {
serializer.write_value(val);
return serializer;
}
inline data_stream_serializer& operator<<(data_stream_serializer& serializer, const char* p) {
serializer.write_c_str(p);
return serializer;
}
va_end(v);
return true;
}
private:
data_stream* m_pStream;
bool m_little_endian;
};
// Write operators
inline data_stream_serializer& operator<< (data_stream_serializer& serializer, bool val) { serializer.write_value(val); return serializer; }
inline data_stream_serializer& operator<< (data_stream_serializer& serializer, int8 val) { serializer.write_value(val); return serializer; }
inline data_stream_serializer& operator<< (data_stream_serializer& serializer, uint8 val) { serializer.write_value(val); return serializer; }
inline data_stream_serializer& operator<< (data_stream_serializer& serializer, int16 val) { serializer.write_value(val); return serializer; }
inline data_stream_serializer& operator<< (data_stream_serializer& serializer, uint16 val) { serializer.write_value(val); return serializer; }
inline data_stream_serializer& operator<< (data_stream_serializer& serializer, int32 val) { serializer.write_value(val); return serializer; }
inline data_stream_serializer& operator<< (data_stream_serializer& serializer, uint32 val) { serializer.write_uint_vlc(val); return serializer; }
inline data_stream_serializer& operator<< (data_stream_serializer& serializer, int64 val) { serializer.write_value(val); return serializer; }
inline data_stream_serializer& operator<< (data_stream_serializer& serializer, uint64 val) { serializer.write_value(val); return serializer; }
inline data_stream_serializer& operator<< (data_stream_serializer& serializer, long val) { serializer.write_value(val); return serializer; }
inline data_stream_serializer& operator<< (data_stream_serializer& serializer, unsigned long val) { serializer.write_value(val); return serializer; }
inline data_stream_serializer& operator<< (data_stream_serializer& serializer, float val) { serializer.write_value(val); return serializer; }
inline data_stream_serializer& operator<< (data_stream_serializer& serializer, double val) { serializer.write_value(val); return serializer; }
inline data_stream_serializer& operator<< (data_stream_serializer& serializer, const char* p) { serializer.write_c_str(p); return serializer; }
inline data_stream_serializer& operator<< (data_stream_serializer& serializer, const dynamic_string& str)
{
serializer.write_string(str);
return serializer;
}
template<typename T>
inline data_stream_serializer& operator<< (data_stream_serializer& serializer, const crnlib::vector<T>& vec)
{
serializer.write_vector(vec);
return serializer;
}
template<typename T>
inline data_stream_serializer& operator<< (data_stream_serializer& serializer, const T* p)
{
serializer.write_object(*p);
return serializer;
}
// Read operators
inline data_stream_serializer& operator>> (data_stream_serializer& serializer, bool& val) { serializer.read_object(val); return serializer; }
inline data_stream_serializer& operator>> (data_stream_serializer& serializer, int8& val) { serializer.read_object(val); return serializer; }
inline data_stream_serializer& operator>> (data_stream_serializer& serializer, uint8& val) { serializer.read_object(val); return serializer; }
inline data_stream_serializer& operator>> (data_stream_serializer& serializer, int16& val) { serializer.read_object(val); return serializer; }
inline data_stream_serializer& operator>> (data_stream_serializer& serializer, uint16& val) { serializer.read_object(val); return serializer; }
inline data_stream_serializer& operator>> (data_stream_serializer& serializer, int32& val) { serializer.read_object(val); return serializer; }
inline data_stream_serializer& operator>> (data_stream_serializer& serializer, uint32& val) { serializer.read_uint_vlc(val); return serializer; }
inline data_stream_serializer& operator>> (data_stream_serializer& serializer, int64& val) { serializer.read_object(val); return serializer; }
inline data_stream_serializer& operator>> (data_stream_serializer& serializer, uint64& val) { serializer.read_object(val); return serializer; }
inline data_stream_serializer& operator>> (data_stream_serializer& serializer, long& val) { serializer.read_object(val); return serializer; }
inline data_stream_serializer& operator>> (data_stream_serializer& serializer, unsigned long& val) { serializer.read_object(val); return serializer; }
inline data_stream_serializer& operator>> (data_stream_serializer& serializer, float& val) { serializer.read_object(val); return serializer; }
inline data_stream_serializer& operator>> (data_stream_serializer& serializer, double& val) { serializer.read_object(val); return serializer; }
inline data_stream_serializer& operator>> (data_stream_serializer& serializer, dynamic_string& str)
{
serializer.read_string(str);
return serializer;
}
template<typename T>
inline data_stream_serializer& operator>> (data_stream_serializer& serializer, crnlib::vector<T>& vec)
{
serializer.read_vector(vec);
return serializer;
}
template<typename T>
inline data_stream_serializer& operator>> (data_stream_serializer& serializer, T* p)
{
serializer.read_object(*p);
return serializer;
}
} // namespace crnlib
inline data_stream_serializer& operator<<(data_stream_serializer& serializer, const dynamic_string& str) {
serializer.write_string(str);
return serializer;
}
template <typename T>
inline data_stream_serializer& operator<<(data_stream_serializer& serializer, const crnlib::vector<T>& vec) {
serializer.write_vector(vec);
return serializer;
}
template <typename T>
inline data_stream_serializer& operator<<(data_stream_serializer& serializer, const T* p) {
serializer.write_object(*p);
return serializer;
}
// Read operators
inline data_stream_serializer& operator>>(data_stream_serializer& serializer, bool& val) {
serializer.read_object(val);
return serializer;
}
inline data_stream_serializer& operator>>(data_stream_serializer& serializer, int8& val) {
serializer.read_object(val);
return serializer;
}
inline data_stream_serializer& operator>>(data_stream_serializer& serializer, uint8& val) {
serializer.read_object(val);
return serializer;
}
inline data_stream_serializer& operator>>(data_stream_serializer& serializer, int16& val) {
serializer.read_object(val);
return serializer;
}
inline data_stream_serializer& operator>>(data_stream_serializer& serializer, uint16& val) {
serializer.read_object(val);
return serializer;
}
inline data_stream_serializer& operator>>(data_stream_serializer& serializer, int32& val) {
serializer.read_object(val);
return serializer;
}
inline data_stream_serializer& operator>>(data_stream_serializer& serializer, uint32& val) {
serializer.read_uint_vlc(val);
return serializer;
}
inline data_stream_serializer& operator>>(data_stream_serializer& serializer, int64& val) {
serializer.read_object(val);
return serializer;
}
inline data_stream_serializer& operator>>(data_stream_serializer& serializer, uint64& val) {
serializer.read_object(val);
return serializer;
}
inline data_stream_serializer& operator>>(data_stream_serializer& serializer, long& val) {
serializer.read_object(val);
return serializer;
}
inline data_stream_serializer& operator>>(data_stream_serializer& serializer, unsigned long& val) {
serializer.read_object(val);
return serializer;
}
inline data_stream_serializer& operator>>(data_stream_serializer& serializer, float& val) {
serializer.read_object(val);
return serializer;
}
inline data_stream_serializer& operator>>(data_stream_serializer& serializer, double& val) {
serializer.read_object(val);
return serializer;
}
inline data_stream_serializer& operator>>(data_stream_serializer& serializer, dynamic_string& str) {
serializer.read_string(str);
return serializer;
}
template <typename T>
inline data_stream_serializer& operator>>(data_stream_serializer& serializer, crnlib::vector<T>& vec) {
serializer.read_vector(vec);
return serializer;
}
template <typename T>
inline data_stream_serializer& operator>>(data_stream_serializer& serializer, T* p) {
serializer.read_object(*p);
return serializer;
}
} // namespace crnlib
+196 -228
View File
@@ -5,255 +5,223 @@
#include "crn_dynamic_stream.h"
#include "crn_lzma_codec.h"
namespace crnlib
{
dds_comp::dds_comp() :
m_pParams(NULL),
namespace crnlib {
dds_comp::dds_comp()
: m_pParams(NULL),
m_pixel_fmt(PIXEL_FMT_INVALID),
m_pQDXT_state(NULL)
{
}
m_pQDXT_state(NULL) {
}
dds_comp::~dds_comp()
{
crnlib_delete(m_pQDXT_state);
}
dds_comp::~dds_comp() {
crnlib_delete(m_pQDXT_state);
}
void dds_comp::clear()
{
m_src_tex.clear();
m_packed_tex.clear();
m_comp_data.clear();
m_pParams = NULL;
m_pixel_fmt = PIXEL_FMT_INVALID;
m_task_pool.deinit();
if (m_pQDXT_state)
{
crnlib_delete(m_pQDXT_state);
m_pQDXT_state = NULL;
void dds_comp::clear() {
m_src_tex.clear();
m_packed_tex.clear();
m_comp_data.clear();
m_pParams = NULL;
m_pixel_fmt = PIXEL_FMT_INVALID;
m_task_pool.deinit();
if (m_pQDXT_state) {
crnlib_delete(m_pQDXT_state);
m_pQDXT_state = NULL;
}
}
bool dds_comp::create_dds_tex(mipmapped_texture& dds_tex) {
image_u8 images[cCRNMaxFaces][cCRNMaxLevels];
bool has_alpha = false;
for (uint face_index = 0; face_index < m_pParams->m_faces; face_index++) {
for (uint level_index = 0; level_index < m_pParams->m_levels; level_index++) {
const uint width = math::maximum(1U, m_pParams->m_width >> level_index);
const uint height = math::maximum(1U, m_pParams->m_height >> level_index);
if (!m_pParams->m_pImages[face_index][level_index])
return false;
images[face_index][level_index].alias((color_quad_u8*)m_pParams->m_pImages[face_index][level_index], width, height);
if (!has_alpha)
has_alpha = image_utils::has_alpha(images[face_index][level_index]);
}
}
for (uint face_index = 0; face_index < m_pParams->m_faces; face_index++)
for (uint level_index = 0; level_index < m_pParams->m_levels; level_index++)
images[face_index][level_index].set_component_valid(3, has_alpha);
image_utils::conversion_type conv_type = image_utils::get_image_conversion_type_from_crn_format((crn_format)m_pParams->m_format);
if (conv_type != image_utils::cConversion_Invalid) {
for (uint face_index = 0; face_index < m_pParams->m_faces; face_index++) {
for (uint level_index = 0; level_index < m_pParams->m_levels; level_index++) {
image_u8 cooked_image(images[face_index][level_index]);
image_utils::convert_image(cooked_image, conv_type);
images[face_index][level_index].swap(cooked_image);
}
}
bool dds_comp::create_dds_tex(mipmapped_texture &dds_tex)
{
image_u8 images[cCRNMaxFaces][cCRNMaxLevels];
}
}
bool has_alpha = false;
for (uint face_index = 0; face_index < m_pParams->m_faces; face_index++)
{
for (uint level_index = 0; level_index < m_pParams->m_levels; level_index++)
{
const uint width = math::maximum(1U, m_pParams->m_width >> level_index);
const uint height = math::maximum(1U, m_pParams->m_height >> level_index);
face_vec faces(m_pParams->m_faces);
if (!m_pParams->m_pImages[face_index][level_index])
return false;
for (uint face_index = 0; face_index < m_pParams->m_faces; face_index++) {
for (uint level_index = 0; level_index < m_pParams->m_levels; level_index++) {
mip_level* pMip = crnlib_new<mip_level>();
images[face_index][level_index].alias((color_quad_u8*)m_pParams->m_pImages[face_index][level_index], width, height);
if (!has_alpha)
has_alpha = image_utils::has_alpha(images[face_index][level_index]);
}
}
for (uint face_index = 0; face_index < m_pParams->m_faces; face_index++)
for (uint level_index = 0; level_index < m_pParams->m_levels; level_index++)
images[face_index][level_index].set_component_valid(3, has_alpha);
image_u8* pImage = crnlib_new<image_u8>();
pImage->swap(images[face_index][level_index]);
pMip->assign(pImage);
image_utils::conversion_type conv_type = image_utils::get_image_conversion_type_from_crn_format((crn_format)m_pParams->m_format);
if (conv_type != image_utils::cConversion_Invalid)
{
for (uint face_index = 0; face_index < m_pParams->m_faces; face_index++)
{
for (uint level_index = 0; level_index < m_pParams->m_levels; level_index++)
{
image_u8 cooked_image(images[face_index][level_index]);
faces[face_index].push_back(pMip);
}
}
image_utils::convert_image(cooked_image, conv_type);
images[face_index][level_index].swap(cooked_image);
}
}
}
face_vec faces(m_pParams->m_faces);
for (uint face_index = 0; face_index < m_pParams->m_faces; face_index++)
{
for (uint level_index = 0; level_index < m_pParams->m_levels; level_index++)
{
mip_level *pMip = crnlib_new<mip_level>();
image_u8 *pImage = crnlib_new<image_u8>();
pImage->swap(images[face_index][level_index]);
pMip->assign(pImage);
faces[face_index].push_back(pMip);
}
}
dds_tex.assign(faces);
dds_tex.assign(faces);
#ifdef CRNLIB_BUILD_DEBUG
CRNLIB_ASSERT(dds_tex.check());
CRNLIB_ASSERT(dds_tex.check());
#endif
return true;
}
return true;
}
static bool progress_callback_func(uint percentage_complete, void* pUser_data_ptr)
{
const crn_comp_params& params = *(const crn_comp_params*)pUser_data_ptr;
return params.m_pProgress_func(0, 1, percentage_complete, 100, params.m_pProgress_func_data) != 0;
}
static bool progress_callback_func(uint percentage_complete, void* pUser_data_ptr) {
const crn_comp_params& params = *(const crn_comp_params*)pUser_data_ptr;
return params.m_pProgress_func(0, 1, percentage_complete, 100, params.m_pProgress_func_data) != 0;
}
static bool progress_callback_func_phase_0(uint percentage_complete, void* pUser_data_ptr)
{
const crn_comp_params& params = *(const crn_comp_params*)pUser_data_ptr;
return params.m_pProgress_func(0, 2, percentage_complete, 100, params.m_pProgress_func_data) != 0;
}
static bool progress_callback_func_phase_0(uint percentage_complete, void* pUser_data_ptr) {
const crn_comp_params& params = *(const crn_comp_params*)pUser_data_ptr;
return params.m_pProgress_func(0, 2, percentage_complete, 100, params.m_pProgress_func_data) != 0;
}
static bool progress_callback_func_phase_1(uint percentage_complete, void* pUser_data_ptr)
{
const crn_comp_params& params = *(const crn_comp_params*)pUser_data_ptr;
return params.m_pProgress_func(1, 2, percentage_complete, 100, params.m_pProgress_func_data) != 0;
}
static bool progress_callback_func_phase_1(uint percentage_complete, void* pUser_data_ptr) {
const crn_comp_params& params = *(const crn_comp_params*)pUser_data_ptr;
return params.m_pProgress_func(1, 2, percentage_complete, 100, params.m_pProgress_func_data) != 0;
}
bool dds_comp::convert_to_dxt(const crn_comp_params& params)
{
if ((params.m_quality_level == cCRNMaxQualityLevel) || (params.m_format == cCRNFmtDXT3))
{
m_packed_tex = m_src_tex;
if (!m_packed_tex.convert(m_pixel_fmt, false, m_pack_params))
return false;
}
else
{
const bool hierarchical = (params.m_flags & cCRNCompFlagHierarchical) != 0;
m_q1_params.m_quality_level = params.m_quality_level;
m_q1_params.m_hierarchical = hierarchical;
bool dds_comp::convert_to_dxt(const crn_comp_params& params) {
if ((params.m_quality_level == cCRNMaxQualityLevel) || (params.m_format == cCRNFmtDXT3)) {
m_packed_tex = m_src_tex;
if (!m_packed_tex.convert(m_pixel_fmt, false, m_pack_params))
return false;
} else {
const bool hierarchical = (params.m_flags & cCRNCompFlagHierarchical) != 0;
m_q5_params.m_quality_level = params.m_quality_level;
m_q5_params.m_hierarchical = hierarchical;
m_q1_params.m_quality_level = params.m_quality_level;
m_q1_params.m_hierarchical = hierarchical;
if (!m_pQDXT_state)
{
m_pQDXT_state = crnlib_new<mipmapped_texture::qdxt_state>(m_task_pool);
if (params.m_pProgress_func)
{
m_q1_params.m_pProgress_func = progress_callback_func_phase_0;
m_q1_params.m_pProgress_data = (void*)&params;
m_q5_params.m_pProgress_func = progress_callback_func_phase_0;
m_q5_params.m_pProgress_data = (void*)&params;
}
m_q5_params.m_quality_level = params.m_quality_level;
m_q5_params.m_hierarchical = hierarchical;
if (!m_src_tex.qdxt_pack_init(*m_pQDXT_state, m_packed_tex, m_q1_params, m_q5_params, m_pixel_fmt, false))
return false;
if (params.m_pProgress_func)
{
m_q1_params.m_pProgress_func = progress_callback_func_phase_1;
m_q5_params.m_pProgress_func = progress_callback_func_phase_1;
}
}
else
{
if (params.m_pProgress_func)
{
m_q1_params.m_pProgress_func = progress_callback_func;
m_q1_params.m_pProgress_data = (void*)&params;
m_q5_params.m_pProgress_func = progress_callback_func;
m_q5_params.m_pProgress_data = (void*)&params;
}
}
if (!m_pQDXT_state) {
m_pQDXT_state = crnlib_new<mipmapped_texture::qdxt_state>(m_task_pool);
if (!m_src_tex.qdxt_pack(*m_pQDXT_state, m_packed_tex, m_q1_params, m_q5_params))
return false;
}
return true;
}
bool dds_comp::compress_init(const crn_comp_params& params)
{
clear();
m_pParams = &params;
if ((math::minimum(m_pParams->m_width, m_pParams->m_height) < 1) || (math::maximum(m_pParams->m_width, m_pParams->m_height) > cCRNMaxLevelResolution))
return false;
if (math::minimum(m_pParams->m_faces, m_pParams->m_levels) < 1)
return false;
if (!create_dds_tex(m_src_tex))
return false;
m_pack_params.init(*m_pParams);
if (params.m_pProgress_func)
{
m_pack_params.m_pProgress_callback = progress_callback_func;
m_pack_params.m_pProgress_callback_user_data_ptr = (void*)&params;
}
m_pixel_fmt = pixel_format_helpers::convert_crn_format_to_pixel_format(static_cast<crn_format>(m_pParams->m_format));
if (m_pixel_fmt == PIXEL_FMT_INVALID)
return false;
if ((m_pixel_fmt == PIXEL_FMT_DXT1) && (m_src_tex.has_alpha()) && (m_pack_params.m_use_both_block_types) && (m_pParams->m_flags & cCRNCompFlagDXT1AForTransparency))
m_pixel_fmt = PIXEL_FMT_DXT1A;
if (!m_task_pool.init(m_pParams->m_num_helper_threads))
return false;
m_pack_params.m_pTask_pool = &m_task_pool;
const bool hierarchical = (params.m_flags & cCRNCompFlagHierarchical) != 0;
m_q1_params.init(m_pack_params, params.m_quality_level, hierarchical);
m_q5_params.init(m_pack_params, params.m_quality_level, hierarchical);
return true;
}
bool dds_comp::compress_pass(const crn_comp_params& params, float *pEffective_bitrate)
{
if (pEffective_bitrate) *pEffective_bitrate = 0.0f;
if (!m_pParams)
return false;
if (!convert_to_dxt(params))
return false;
dynamic_stream out_stream;
out_stream.reserve(512*1024);
data_stream_serializer serializer(out_stream);
if (!m_packed_tex.write_dds(serializer))
return false;
out_stream.reserve(0);
m_comp_data.swap(out_stream.get_buf());
if (pEffective_bitrate)
{
lzma_codec lossless_codec;
crnlib::vector<uint8> cmp_tex_bytes;
if (lossless_codec.pack(m_comp_data.get_ptr(), m_comp_data.size(), cmp_tex_bytes))
{
uint comp_size = cmp_tex_bytes.size();
if (comp_size)
{
*pEffective_bitrate = (comp_size * 8.0f) / m_src_tex.get_total_pixels_in_all_faces_and_mips();
}
}
if (params.m_pProgress_func) {
m_q1_params.m_pProgress_func = progress_callback_func_phase_0;
m_q1_params.m_pProgress_data = (void*)&params;
m_q5_params.m_pProgress_func = progress_callback_func_phase_0;
m_q5_params.m_pProgress_data = (void*)&params;
}
return true;
}
if (!m_src_tex.qdxt_pack_init(*m_pQDXT_state, m_packed_tex, m_q1_params, m_q5_params, m_pixel_fmt, false))
return false;
void dds_comp::compress_deinit()
{
clear();
}
if (params.m_pProgress_func) {
m_q1_params.m_pProgress_func = progress_callback_func_phase_1;
m_q5_params.m_pProgress_func = progress_callback_func_phase_1;
}
} else {
if (params.m_pProgress_func) {
m_q1_params.m_pProgress_func = progress_callback_func;
m_q1_params.m_pProgress_data = (void*)&params;
m_q5_params.m_pProgress_func = progress_callback_func;
m_q5_params.m_pProgress_data = (void*)&params;
}
}
} // namespace crnlib
if (!m_src_tex.qdxt_pack(*m_pQDXT_state, m_packed_tex, m_q1_params, m_q5_params))
return false;
}
return true;
}
bool dds_comp::compress_init(const crn_comp_params& params) {
clear();
m_pParams = &params;
if ((math::minimum(m_pParams->m_width, m_pParams->m_height) < 1) || (math::maximum(m_pParams->m_width, m_pParams->m_height) > cCRNMaxLevelResolution))
return false;
if (math::minimum(m_pParams->m_faces, m_pParams->m_levels) < 1)
return false;
if (!create_dds_tex(m_src_tex))
return false;
m_pack_params.init(*m_pParams);
if (params.m_pProgress_func) {
m_pack_params.m_pProgress_callback = progress_callback_func;
m_pack_params.m_pProgress_callback_user_data_ptr = (void*)&params;
}
m_pixel_fmt = pixel_format_helpers::convert_crn_format_to_pixel_format(static_cast<crn_format>(m_pParams->m_format));
if (m_pixel_fmt == PIXEL_FMT_INVALID)
return false;
if ((m_pixel_fmt == PIXEL_FMT_DXT1) && (m_src_tex.has_alpha()) && (m_pack_params.m_use_both_block_types) && (m_pParams->m_flags & cCRNCompFlagDXT1AForTransparency))
m_pixel_fmt = PIXEL_FMT_DXT1A;
if (!m_task_pool.init(m_pParams->m_num_helper_threads))
return false;
m_pack_params.m_pTask_pool = &m_task_pool;
const bool hierarchical = (params.m_flags & cCRNCompFlagHierarchical) != 0;
m_q1_params.init(m_pack_params, params.m_quality_level, hierarchical);
m_q5_params.init(m_pack_params, params.m_quality_level, hierarchical);
return true;
}
bool dds_comp::compress_pass(const crn_comp_params& params, float* pEffective_bitrate) {
if (pEffective_bitrate)
*pEffective_bitrate = 0.0f;
if (!m_pParams)
return false;
if (!convert_to_dxt(params))
return false;
dynamic_stream out_stream;
out_stream.reserve(512 * 1024);
data_stream_serializer serializer(out_stream);
if (!m_packed_tex.write_dds(serializer))
return false;
out_stream.reserve(0);
m_comp_data.swap(out_stream.get_buf());
if (pEffective_bitrate) {
lzma_codec lossless_codec;
crnlib::vector<uint8> cmp_tex_bytes;
if (lossless_codec.pack(m_comp_data.get_ptr(), m_comp_data.size(), cmp_tex_bytes)) {
uint comp_size = cmp_tex_bytes.size();
if (comp_size) {
*pEffective_bitrate = (comp_size * 8.0f) / m_src_tex.get_total_pixels_in_all_faces_and_mips();
}
}
}
return true;
}
void dds_comp::compress_deinit() {
clear();
}
} // namespace crnlib
+28 -30
View File
@@ -5,44 +5,42 @@
#include "crn_mipmapped_texture.h"
#include "crn_texture_comp.h"
namespace crnlib
{
class dds_comp : public itexture_comp
{
CRNLIB_NO_COPY_OR_ASSIGNMENT_OP(dds_comp);
namespace crnlib {
class dds_comp : public itexture_comp {
CRNLIB_NO_COPY_OR_ASSIGNMENT_OP(dds_comp);
public:
dds_comp();
virtual ~dds_comp();
public:
dds_comp();
virtual ~dds_comp();
virtual const char *get_ext() const { return "DDS"; }
virtual const char* get_ext() const { return "DDS"; }
virtual bool compress_init(const crn_comp_params& params);
virtual bool compress_pass(const crn_comp_params& params, float *pEffective_bitrate);
virtual void compress_deinit();
virtual bool compress_init(const crn_comp_params& params);
virtual bool compress_pass(const crn_comp_params& params, float* pEffective_bitrate);
virtual void compress_deinit();
virtual const crnlib::vector<uint8>& get_comp_data() const { return m_comp_data; }
virtual crnlib::vector<uint8>& get_comp_data() { return m_comp_data; }
virtual const crnlib::vector<uint8>& get_comp_data() const { return m_comp_data; }
virtual crnlib::vector<uint8>& get_comp_data() { return m_comp_data; }
private:
mipmapped_texture m_src_tex;
mipmapped_texture m_packed_tex;
private:
mipmapped_texture m_src_tex;
mipmapped_texture m_packed_tex;
crnlib::vector<uint8> m_comp_data;
crnlib::vector<uint8> m_comp_data;
const crn_comp_params* m_pParams;
const crn_comp_params* m_pParams;
pixel_format m_pixel_fmt;
dxt_image::pack_params m_pack_params;
pixel_format m_pixel_fmt;
dxt_image::pack_params m_pack_params;
task_pool m_task_pool;
qdxt1_params m_q1_params;
qdxt5_params m_q5_params;
mipmapped_texture::qdxt_state *m_pQDXT_state;
task_pool m_task_pool;
qdxt1_params m_q1_params;
qdxt5_params m_q5_params;
mipmapped_texture::qdxt_state* m_pQDXT_state;
void clear();
bool create_dds_tex(mipmapped_texture &dds_tex);
bool convert_to_dxt(const crn_comp_params& params);
};
void clear();
bool create_dds_tex(mipmapped_texture& dds_tex);
bool convert_to_dxt(const crn_comp_params& params);
};
} // namespace crnlib
} // namespace crnlib
+336 -359
View File
@@ -7,380 +7,357 @@
#include "crn_dxt_fast.h"
#include "crn_intersect.h"
namespace crnlib
{
const uint8 g_dxt5_from_linear[cDXT5SelectorValues] = { 0U, 2U, 3U, 4U, 5U, 6U, 7U, 1U };
const uint8 g_dxt5_to_linear[cDXT5SelectorValues] = { 0U, 7U, 1U, 2U, 3U, 4U, 5U, 6U };
namespace crnlib {
const uint8 g_dxt5_from_linear[cDXT5SelectorValues] = {0U, 2U, 3U, 4U, 5U, 6U, 7U, 1U};
const uint8 g_dxt5_to_linear[cDXT5SelectorValues] = {0U, 7U, 1U, 2U, 3U, 4U, 5U, 6U};
const uint8 g_dxt5_alpha6_to_linear[cDXT5SelectorValues] = { 0U, 5U, 1U, 2U, 3U, 4U, 0U, 0U };
const uint8 g_dxt5_alpha6_to_linear[cDXT5SelectorValues] = {0U, 5U, 1U, 2U, 3U, 4U, 0U, 0U};
const uint8 g_dxt1_from_linear[cDXT1SelectorValues] = { 0U, 2U, 3U, 1U };
const uint8 g_dxt1_to_linear[cDXT1SelectorValues] = { 0U, 3U, 1U, 2U };
const uint8 g_dxt1_from_linear[cDXT1SelectorValues] = {0U, 2U, 3U, 1U};
const uint8 g_dxt1_to_linear[cDXT1SelectorValues] = {0U, 3U, 1U, 2U};
const uint8 g_six_alpha_invert_table[cDXT5SelectorValues] = { 1, 0, 5, 4, 3, 2, 6, 7 };
const uint8 g_eight_alpha_invert_table[cDXT5SelectorValues] = { 1, 0, 7, 6, 5, 4, 3, 2 };
const uint8 g_six_alpha_invert_table[cDXT5SelectorValues] = {1, 0, 5, 4, 3, 2, 6, 7};
const uint8 g_eight_alpha_invert_table[cDXT5SelectorValues] = {1, 0, 7, 6, 5, 4, 3, 2};
const char* get_dxt_format_string(dxt_format fmt)
{
switch (fmt)
{
case cDXT1: return "DXT1";
case cDXT1A: return "DXT1A";
case cDXT3: return "DXT3";
case cDXT5: return "DXT5";
case cDXT5A: return "DXT5A";
case cDXN_XY: return "DXN_XY";
case cDXN_YX: return "DXN_YX";
case cETC1: return "ETC1";
default: break;
}
CRNLIB_ASSERT(false);
return "?";
}
const char* get_dxt_format_string(dxt_format fmt) {
switch (fmt) {
case cDXT1:
return "DXT1";
case cDXT1A:
return "DXT1A";
case cDXT3:
return "DXT3";
case cDXT5:
return "DXT5";
case cDXT5A:
return "DXT5A";
case cDXN_XY:
return "DXN_XY";
case cDXN_YX:
return "DXN_YX";
case cETC1:
return "ETC1";
default:
break;
}
CRNLIB_ASSERT(false);
return "?";
}
const char* get_dxt_compressor_name(crn_dxt_compressor_type c)
{
switch (c)
{
case cCRNDXTCompressorCRN: return "CRN";
case cCRNDXTCompressorCRNF: return "CRNF";
case cCRNDXTCompressorRYG: return "RYG";
const char* get_dxt_compressor_name(crn_dxt_compressor_type c) {
switch (c) {
case cCRNDXTCompressorCRN:
return "CRN";
case cCRNDXTCompressorCRNF:
return "CRNF";
case cCRNDXTCompressorRYG:
return "RYG";
#if CRNLIB_SUPPORT_ATI_COMPRESS
case cCRNDXTCompressorATI: return "ATI";
case cCRNDXTCompressorATI:
return "ATI";
#endif
default: break;
}
CRNLIB_ASSERT(false);
return "?";
}
uint get_dxt_format_bits_per_pixel(dxt_format fmt)
{
switch (fmt)
{
case cDXT1:
case cDXT1A:
case cDXT5A:
case cETC1:
return 4;
case cDXT3:
case cDXT5:
case cDXN_XY:
case cDXN_YX:
return 8;
default: break;
}
CRNLIB_ASSERT(false);
return 0;
}
bool get_dxt_format_has_alpha(dxt_format fmt)
{
switch (fmt)
{
case cDXT1A:
case cDXT3:
case cDXT5:
case cDXT5A:
return true;
default: break;
}
return false;
}
uint16 dxt1_block::pack_color(const color_quad_u8& color, bool scaled, uint bias)
{
uint r = color.r;
uint g = color.g;
uint b = color.b;
if (scaled)
{
r = (r * 31U + bias) / 255U;
g = (g * 63U + bias) / 255U;
b = (b * 31U + bias) / 255U;
}
r = math::minimum(r, 31U);
g = math::minimum(g, 63U);
b = math::minimum(b, 31U);
return static_cast<uint16>(b | (g << 5U) | (r << 11U));
}
uint16 dxt1_block::pack_color(uint r, uint g, uint b, bool scaled, uint bias)
{
return pack_color(color_quad_u8(r, g, b, 0), scaled, bias);
}
color_quad_u8 dxt1_block::unpack_color(uint16 packed_color, bool scaled, uint alpha)
{
uint b = packed_color & 31U;
uint g = (packed_color >> 5U) & 63U;
uint r = (packed_color >> 11U) & 31U;
if (scaled)
{
b = (b << 3U) | (b >> 2U);
g = (g << 2U) | (g >> 4U);
r = (r << 3U) | (r >> 2U);
}
return color_quad_u8(cNoClamp, r, g, b, math::minimum(alpha, 255U));
}
void dxt1_block::unpack_color(uint& r, uint& g, uint& b, uint16 packed_color, bool scaled)
{
color_quad_u8 c(unpack_color(packed_color, scaled, 0));
r = c.r;
g = c.g;
b = c.b;
}
void dxt1_block::get_block_colors_NV5x(color_quad_u8* pDst, uint16 packed_col0, uint16 packed_col1, bool color4)
{
color_quad_u8 col0(unpack_color(packed_col0, false));
color_quad_u8 col1(unpack_color(packed_col1, false));
pDst[0].r = (3 * col0.r * 22) / 8;
pDst[0].b = (3 * col0.b * 22) / 8;
pDst[0].g = (col0.g << 2) | (col0.g >> 4);
pDst[0].a = 0xFF;
pDst[1].r = (3 * col1.r * 22) / 8;
pDst[1].g = (col1.g << 2) | (col1.g >> 4);
pDst[1].b = (3 * col1.b * 22) / 8;
pDst[1].a = 0xFF;
int gdiff = pDst[1].g - pDst[0].g;
if (color4) //(packed_col0 > packed_col1)
{
pDst[2].r = static_cast<uint8>(((2 * col0.r + col1.r) * 22) / 8);
pDst[2].g = static_cast<uint8>((256 * pDst[0].g + gdiff/4 + 128 + gdiff * 80) / 256);
pDst[2].b = static_cast<uint8>(((2 * col0.b + col1.b) * 22) / 8);
pDst[2].a = 0xFF;
pDst[3].r = static_cast<uint8>(((2 * col1.r + col0.r) * 22) / 8);
pDst[3].g = static_cast<uint8>((256 * pDst[1].g - gdiff/4 + 128 - gdiff * 80) / 256);
pDst[3].b = static_cast<uint8>(((2 * col1.b + col0.b) * 22) / 8);
pDst[3].a = 0xFF;
}
else {
pDst[2].r = static_cast<uint8>(((col0.r + col1.r) * 33) / 8);
pDst[2].g = static_cast<uint8>((256 * pDst[0].g + gdiff/4 + 128 + gdiff * 128) / 256);
pDst[2].b = static_cast<uint8>(((col0.b + col1.b) * 33) / 8);
pDst[2].a = 0xFF;
pDst[3].r = 0x00;
pDst[3].g = 0x00;
pDst[3].b = 0x00;
pDst[3].a = 0x00;
}
}
uint dxt1_block::get_block_colors3(color_quad_u8* pDst, uint16 color0, uint16 color1)
{
color_quad_u8 c0(unpack_color(color0, true));
color_quad_u8 c1(unpack_color(color1, true));
pDst[0] = c0;
pDst[1] = c1;
pDst[2].set_noclamp_rgba( (c0.r + c1.r) >> 1U, (c0.g + c1.g) >> 1U, (c0.b + c1.b) >> 1U, 255U);
pDst[3].set_noclamp_rgba(0, 0, 0, 0);
return 3;
}
uint dxt1_block::get_block_colors4(color_quad_u8* pDst, uint16 color0, uint16 color1)
{
color_quad_u8 c0(unpack_color(color0, true));
color_quad_u8 c1(unpack_color(color1, true));
pDst[0] = c0;
pDst[1] = c1;
// The compiler changes the div3 into a mul by recip+shift.
pDst[2].set_noclamp_rgba( (c0.r * 2 + c1.r) / 3, (c0.g * 2 + c1.g) / 3, (c0.b * 2 + c1.b) / 3, 255U);
pDst[3].set_noclamp_rgba( (c1.r * 2 + c0.r) / 3, (c1.g * 2 + c0.g) / 3, (c1.b * 2 + c0.b) / 3, 255U);
default:
break;
}
CRNLIB_ASSERT(false);
return "?";
}
uint get_dxt_format_bits_per_pixel(dxt_format fmt) {
switch (fmt) {
case cDXT1:
case cDXT1A:
case cDXT5A:
case cETC1:
return 4;
}
uint dxt1_block::get_block_colors3_round(color_quad_u8* pDst, uint16 color0, uint16 color1)
{
color_quad_u8 c0(unpack_color(color0, true));
color_quad_u8 c1(unpack_color(color1, true));
pDst[0] = c0;
pDst[1] = c1;
pDst[2].set_noclamp_rgba( (c0.r + c1.r + 1) >> 1U, (c0.g + c1.g + 1) >> 1U, (c0.b + c1.b + 1) >> 1U, 255U);
pDst[3].set_noclamp_rgba(0, 0, 0, 0);
return 3;
}
uint dxt1_block::get_block_colors4_round(color_quad_u8* pDst, uint16 color0, uint16 color1)
{
color_quad_u8 c0(unpack_color(color0, true));
color_quad_u8 c1(unpack_color(color1, true));
pDst[0] = c0;
pDst[1] = c1;
// 12/14/08 - Supposed to round according to DX docs, but this conflicts with the OpenGL S3TC spec. ?
// The compiler changes the div3 into a mul by recip+shift.
pDst[2].set_noclamp_rgba( (c0.r * 2 + c1.r + 1) / 3, (c0.g * 2 + c1.g + 1) / 3, (c0.b * 2 + c1.b + 1) / 3, 255U);
pDst[3].set_noclamp_rgba( (c1.r * 2 + c0.r + 1) / 3, (c1.g * 2 + c0.g + 1) / 3, (c1.b * 2 + c0.b + 1) / 3, 255U);
return 4;
}
uint dxt1_block::get_block_colors(color_quad_u8* pDst, uint16 color0, uint16 color1)
{
if (color0 > color1)
return get_block_colors4(pDst, color0, color1);
else
return get_block_colors3(pDst, color0, color1);
}
uint dxt1_block::get_block_colors_round(color_quad_u8* pDst, uint16 color0, uint16 color1)
{
if (color0 > color1)
return get_block_colors4_round(pDst, color0, color1);
else
return get_block_colors3_round(pDst, color0, color1);
}
color_quad_u8 dxt1_block::unpack_endpoint(uint32 endpoints, uint index, bool scaled, uint alpha)
{
CRNLIB_ASSERT(index < 2);
return unpack_color( static_cast<uint16>((endpoints >> (index * 16U)) & 0xFFFFU), scaled, alpha );
}
uint dxt1_block::pack_endpoints(uint lo, uint hi)
{
CRNLIB_ASSERT((lo <= 0xFFFFU) && (hi <= 0xFFFFU));
return lo | (hi << 16U);
}
void dxt3_block::set_alpha(uint x, uint y, uint value, bool scaled)
{
CRNLIB_ASSERT((x < cDXTBlockSize) && (y < cDXTBlockSize));
if (scaled)
{
CRNLIB_ASSERT(value <= 0xFF);
value = (value * 15U + 128U) / 255U;
}
else
{
CRNLIB_ASSERT(value <= 0xF);
}
uint ofs = (y << 1U) + (x >> 1U);
uint c = m_alpha[ofs];
c &= ~(0xF << ((x & 1U) << 2U));
c |= (value << ((x & 1U) << 2U));
m_alpha[ofs] = static_cast<uint8>(c);
}
uint dxt3_block::get_alpha(uint x, uint y, bool scaled) const
{
CRNLIB_ASSERT((x < cDXTBlockSize) && (y < cDXTBlockSize));
uint value = m_alpha[(y << 1U) + (x >> 1U)];
if (x & 1)
value >>= 4;
value &= 0xF;
if (scaled)
value = (value << 4U) | value;
return value;
}
uint dxt5_block::get_block_values6(color_quad_u8* pDst, uint l, uint h)
{
pDst[0].a = static_cast<uint8>(l);
pDst[1].a = static_cast<uint8>(h);
pDst[2].a = static_cast<uint8>((l * 4 + h ) / 5);
pDst[3].a = static_cast<uint8>((l * 3 + h * 2) / 5);
pDst[4].a = static_cast<uint8>((l * 2 + h * 3) / 5);
pDst[5].a = static_cast<uint8>((l + h * 4) / 5);
pDst[6].a = 0;
pDst[7].a = 255;
return 6;
}
uint dxt5_block::get_block_values8(color_quad_u8* pDst, uint l, uint h)
{
pDst[0].a = static_cast<uint8>(l);
pDst[1].a = static_cast<uint8>(h);
pDst[2].a = static_cast<uint8>((l * 6 + h ) / 7);
pDst[3].a = static_cast<uint8>((l * 5 + h * 2) / 7);
pDst[4].a = static_cast<uint8>((l * 4 + h * 3) / 7);
pDst[5].a = static_cast<uint8>((l * 3 + h * 4) / 7);
pDst[6].a = static_cast<uint8>((l * 2 + h * 5) / 7);
pDst[7].a = static_cast<uint8>((l + h * 6) / 7);
case cDXT3:
case cDXT5:
case cDXN_XY:
case cDXN_YX:
return 8;
}
default:
break;
}
CRNLIB_ASSERT(false);
return 0;
}
uint dxt5_block::get_block_values(color_quad_u8* pDst, uint l, uint h)
{
if (l > h)
return get_block_values8(pDst, l, h);
else
return get_block_values6(pDst, l, h);
}
bool get_dxt_format_has_alpha(dxt_format fmt) {
switch (fmt) {
case cDXT1A:
case cDXT3:
case cDXT5:
case cDXT5A:
return true;
default:
break;
}
return false;
}
uint dxt5_block::get_block_values6(uint* pDst, uint l, uint h)
{
pDst[0] = l;
pDst[1] = h;
pDst[2] = (l * 4 + h ) / 5;
pDst[3] = (l * 3 + h * 2) / 5;
pDst[4] = (l * 2 + h * 3) / 5;
pDst[5] = (l + h * 4) / 5;
pDst[6] = 0;
pDst[7] = 255;
return 6;
}
uint16 dxt1_block::pack_color(const color_quad_u8& color, bool scaled, uint bias) {
uint r = color.r;
uint g = color.g;
uint b = color.b;
uint dxt5_block::get_block_values8(uint* pDst, uint l, uint h)
{
pDst[0] = l;
pDst[1] = h;
pDst[2] = (l * 6 + h ) / 7;
pDst[3] = (l * 5 + h * 2) / 7;
pDst[4] = (l * 4 + h * 3) / 7;
pDst[5] = (l * 3 + h * 4) / 7;
pDst[6] = (l * 2 + h * 5) / 7;
pDst[7] = (l + h * 6) / 7;
return 8;
}
if (scaled) {
r = (r * 31U + bias) / 255U;
g = (g * 63U + bias) / 255U;
b = (b * 31U + bias) / 255U;
}
uint dxt5_block::unpack_endpoint(uint packed, uint index)
{
CRNLIB_ASSERT(index < 2);
return (packed >> (8 * index)) & 0xFF;
}
r = math::minimum(r, 31U);
g = math::minimum(g, 63U);
b = math::minimum(b, 31U);
uint dxt5_block::pack_endpoints(uint lo, uint hi)
{
CRNLIB_ASSERT((lo <= 0xFF) && (hi <= 0xFF));
return lo | (hi << 8U);
}
return static_cast<uint16>(b | (g << 5U) | (r << 11U));
}
uint dxt5_block::get_block_values(uint* pDst, uint l, uint h)
{
if (l > h)
return get_block_values8(pDst, l, h);
else
return get_block_values6(pDst, l, h);
}
uint16 dxt1_block::pack_color(uint r, uint g, uint b, bool scaled, uint bias) {
return pack_color(color_quad_u8(r, g, b, 0), scaled, bias);
}
} // namespace crnlib
color_quad_u8 dxt1_block::unpack_color(uint16 packed_color, bool scaled, uint alpha) {
uint b = packed_color & 31U;
uint g = (packed_color >> 5U) & 63U;
uint r = (packed_color >> 11U) & 31U;
if (scaled) {
b = (b << 3U) | (b >> 2U);
g = (g << 2U) | (g >> 4U);
r = (r << 3U) | (r >> 2U);
}
return color_quad_u8(cNoClamp, r, g, b, math::minimum(alpha, 255U));
}
void dxt1_block::unpack_color(uint& r, uint& g, uint& b, uint16 packed_color, bool scaled) {
color_quad_u8 c(unpack_color(packed_color, scaled, 0));
r = c.r;
g = c.g;
b = c.b;
}
void dxt1_block::get_block_colors_NV5x(color_quad_u8* pDst, uint16 packed_col0, uint16 packed_col1, bool color4) {
color_quad_u8 col0(unpack_color(packed_col0, false));
color_quad_u8 col1(unpack_color(packed_col1, false));
pDst[0].r = (3 * col0.r * 22) / 8;
pDst[0].b = (3 * col0.b * 22) / 8;
pDst[0].g = (col0.g << 2) | (col0.g >> 4);
pDst[0].a = 0xFF;
pDst[1].r = (3 * col1.r * 22) / 8;
pDst[1].g = (col1.g << 2) | (col1.g >> 4);
pDst[1].b = (3 * col1.b * 22) / 8;
pDst[1].a = 0xFF;
int gdiff = pDst[1].g - pDst[0].g;
if (color4) //(packed_col0 > packed_col1)
{
pDst[2].r = static_cast<uint8>(((2 * col0.r + col1.r) * 22) / 8);
pDst[2].g = static_cast<uint8>((256 * pDst[0].g + gdiff / 4 + 128 + gdiff * 80) / 256);
pDst[2].b = static_cast<uint8>(((2 * col0.b + col1.b) * 22) / 8);
pDst[2].a = 0xFF;
pDst[3].r = static_cast<uint8>(((2 * col1.r + col0.r) * 22) / 8);
pDst[3].g = static_cast<uint8>((256 * pDst[1].g - gdiff / 4 + 128 - gdiff * 80) / 256);
pDst[3].b = static_cast<uint8>(((2 * col1.b + col0.b) * 22) / 8);
pDst[3].a = 0xFF;
} else {
pDst[2].r = static_cast<uint8>(((col0.r + col1.r) * 33) / 8);
pDst[2].g = static_cast<uint8>((256 * pDst[0].g + gdiff / 4 + 128 + gdiff * 128) / 256);
pDst[2].b = static_cast<uint8>(((col0.b + col1.b) * 33) / 8);
pDst[2].a = 0xFF;
pDst[3].r = 0x00;
pDst[3].g = 0x00;
pDst[3].b = 0x00;
pDst[3].a = 0x00;
}
}
uint dxt1_block::get_block_colors3(color_quad_u8* pDst, uint16 color0, uint16 color1) {
color_quad_u8 c0(unpack_color(color0, true));
color_quad_u8 c1(unpack_color(color1, true));
pDst[0] = c0;
pDst[1] = c1;
pDst[2].set_noclamp_rgba((c0.r + c1.r) >> 1U, (c0.g + c1.g) >> 1U, (c0.b + c1.b) >> 1U, 255U);
pDst[3].set_noclamp_rgba(0, 0, 0, 0);
return 3;
}
uint dxt1_block::get_block_colors4(color_quad_u8* pDst, uint16 color0, uint16 color1) {
color_quad_u8 c0(unpack_color(color0, true));
color_quad_u8 c1(unpack_color(color1, true));
pDst[0] = c0;
pDst[1] = c1;
// The compiler changes the div3 into a mul by recip+shift.
pDst[2].set_noclamp_rgba((c0.r * 2 + c1.r) / 3, (c0.g * 2 + c1.g) / 3, (c0.b * 2 + c1.b) / 3, 255U);
pDst[3].set_noclamp_rgba((c1.r * 2 + c0.r) / 3, (c1.g * 2 + c0.g) / 3, (c1.b * 2 + c0.b) / 3, 255U);
return 4;
}
uint dxt1_block::get_block_colors3_round(color_quad_u8* pDst, uint16 color0, uint16 color1) {
color_quad_u8 c0(unpack_color(color0, true));
color_quad_u8 c1(unpack_color(color1, true));
pDst[0] = c0;
pDst[1] = c1;
pDst[2].set_noclamp_rgba((c0.r + c1.r + 1) >> 1U, (c0.g + c1.g + 1) >> 1U, (c0.b + c1.b + 1) >> 1U, 255U);
pDst[3].set_noclamp_rgba(0, 0, 0, 0);
return 3;
}
uint dxt1_block::get_block_colors4_round(color_quad_u8* pDst, uint16 color0, uint16 color1) {
color_quad_u8 c0(unpack_color(color0, true));
color_quad_u8 c1(unpack_color(color1, true));
pDst[0] = c0;
pDst[1] = c1;
// 12/14/08 - Supposed to round according to DX docs, but this conflicts with the OpenGL S3TC spec. ?
// The compiler changes the div3 into a mul by recip+shift.
pDst[2].set_noclamp_rgba((c0.r * 2 + c1.r + 1) / 3, (c0.g * 2 + c1.g + 1) / 3, (c0.b * 2 + c1.b + 1) / 3, 255U);
pDst[3].set_noclamp_rgba((c1.r * 2 + c0.r + 1) / 3, (c1.g * 2 + c0.g + 1) / 3, (c1.b * 2 + c0.b + 1) / 3, 255U);
return 4;
}
uint dxt1_block::get_block_colors(color_quad_u8* pDst, uint16 color0, uint16 color1) {
if (color0 > color1)
return get_block_colors4(pDst, color0, color1);
else
return get_block_colors3(pDst, color0, color1);
}
uint dxt1_block::get_block_colors_round(color_quad_u8* pDst, uint16 color0, uint16 color1) {
if (color0 > color1)
return get_block_colors4_round(pDst, color0, color1);
else
return get_block_colors3_round(pDst, color0, color1);
}
color_quad_u8 dxt1_block::unpack_endpoint(uint32 endpoints, uint index, bool scaled, uint alpha) {
CRNLIB_ASSERT(index < 2);
return unpack_color(static_cast<uint16>((endpoints >> (index * 16U)) & 0xFFFFU), scaled, alpha);
}
uint dxt1_block::pack_endpoints(uint lo, uint hi) {
CRNLIB_ASSERT((lo <= 0xFFFFU) && (hi <= 0xFFFFU));
return lo | (hi << 16U);
}
void dxt3_block::set_alpha(uint x, uint y, uint value, bool scaled) {
CRNLIB_ASSERT((x < cDXTBlockSize) && (y < cDXTBlockSize));
if (scaled) {
CRNLIB_ASSERT(value <= 0xFF);
value = (value * 15U + 128U) / 255U;
} else {
CRNLIB_ASSERT(value <= 0xF);
}
uint ofs = (y << 1U) + (x >> 1U);
uint c = m_alpha[ofs];
c &= ~(0xF << ((x & 1U) << 2U));
c |= (value << ((x & 1U) << 2U));
m_alpha[ofs] = static_cast<uint8>(c);
}
uint dxt3_block::get_alpha(uint x, uint y, bool scaled) const {
CRNLIB_ASSERT((x < cDXTBlockSize) && (y < cDXTBlockSize));
uint value = m_alpha[(y << 1U) + (x >> 1U)];
if (x & 1)
value >>= 4;
value &= 0xF;
if (scaled)
value = (value << 4U) | value;
return value;
}
uint dxt5_block::get_block_values6(color_quad_u8* pDst, uint l, uint h) {
pDst[0].a = static_cast<uint8>(l);
pDst[1].a = static_cast<uint8>(h);
pDst[2].a = static_cast<uint8>((l * 4 + h) / 5);
pDst[3].a = static_cast<uint8>((l * 3 + h * 2) / 5);
pDst[4].a = static_cast<uint8>((l * 2 + h * 3) / 5);
pDst[5].a = static_cast<uint8>((l + h * 4) / 5);
pDst[6].a = 0;
pDst[7].a = 255;
return 6;
}
uint dxt5_block::get_block_values8(color_quad_u8* pDst, uint l, uint h) {
pDst[0].a = static_cast<uint8>(l);
pDst[1].a = static_cast<uint8>(h);
pDst[2].a = static_cast<uint8>((l * 6 + h) / 7);
pDst[3].a = static_cast<uint8>((l * 5 + h * 2) / 7);
pDst[4].a = static_cast<uint8>((l * 4 + h * 3) / 7);
pDst[5].a = static_cast<uint8>((l * 3 + h * 4) / 7);
pDst[6].a = static_cast<uint8>((l * 2 + h * 5) / 7);
pDst[7].a = static_cast<uint8>((l + h * 6) / 7);
return 8;
}
uint dxt5_block::get_block_values(color_quad_u8* pDst, uint l, uint h) {
if (l > h)
return get_block_values8(pDst, l, h);
else
return get_block_values6(pDst, l, h);
}
uint dxt5_block::get_block_values6(uint* pDst, uint l, uint h) {
pDst[0] = l;
pDst[1] = h;
pDst[2] = (l * 4 + h) / 5;
pDst[3] = (l * 3 + h * 2) / 5;
pDst[4] = (l * 2 + h * 3) / 5;
pDst[5] = (l + h * 4) / 5;
pDst[6] = 0;
pDst[7] = 255;
return 6;
}
uint dxt5_block::get_block_values8(uint* pDst, uint l, uint h) {
pDst[0] = l;
pDst[1] = h;
pDst[2] = (l * 6 + h) / 7;
pDst[3] = (l * 5 + h * 2) / 7;
pDst[4] = (l * 4 + h * 3) / 7;
pDst[5] = (l * 3 + h * 4) / 7;
pDst[6] = (l * 2 + h * 5) / 7;
pDst[7] = (l + h * 6) / 7;
return 8;
}
uint dxt5_block::unpack_endpoint(uint packed, uint index) {
CRNLIB_ASSERT(index < 2);
return (packed >> (8 * index)) & 0xFF;
}
uint dxt5_block::pack_endpoints(uint lo, uint hi) {
CRNLIB_ASSERT((lo <= 0xFF) && (hi <= 0xFF));
return lo | (hi << 8U);
}
uint dxt5_block::get_block_values(uint* pDst, uint l, uint h) {
if (l > h)
return get_block_values8(pDst, l, h);
else
return get_block_values6(pDst, l, h);
}
} // namespace crnlib
+266 -306
View File
@@ -11,351 +11,311 @@
#define CRNLIB_DXT_ALT_ROUNDING 1
namespace crnlib
{
enum dxt_constants
{
cDXT1BytesPerBlock = 8U,
cDXT5NBytesPerBlock = 16U,
namespace crnlib {
enum dxt_constants {
cDXT1BytesPerBlock = 8U,
cDXT5NBytesPerBlock = 16U,
cDXT5SelectorBits = 3U,
cDXT5SelectorValues = 1U << cDXT5SelectorBits,
cDXT5SelectorMask = cDXT5SelectorValues - 1U,
cDXT5SelectorBits = 3U,
cDXT5SelectorValues = 1U << cDXT5SelectorBits,
cDXT5SelectorMask = cDXT5SelectorValues - 1U,
cDXT1SelectorBits = 2U,
cDXT1SelectorValues = 1U << cDXT1SelectorBits,
cDXT1SelectorMask = cDXT1SelectorValues - 1U,
cDXT1SelectorBits = 2U,
cDXT1SelectorValues = 1U << cDXT1SelectorBits,
cDXT1SelectorMask = cDXT1SelectorValues - 1U,
cDXTBlockShift = 2U,
cDXTBlockSize = 1U << cDXTBlockShift
};
cDXTBlockShift = 2U,
cDXTBlockSize = 1U << cDXTBlockShift
};
enum dxt_format
{
cDXTInvalid = -1,
enum dxt_format {
cDXTInvalid = -1,
// cDXT1/1A must appear first!
cDXT1,
cDXT1A,
// cDXT1/1A must appear first!
cDXT1,
cDXT1A,
cDXT3,
cDXT5,
cDXT5A,
cDXT3,
cDXT5,
cDXT5A,
cDXN_XY, // inverted relative to standard ATI2, 360's DXN
cDXN_YX, // standard ATI2,
cDXN_XY, // inverted relative to standard ATI2, 360's DXN
cDXN_YX, // standard ATI2,
cETC1 // Ericsson texture compression (color only, 4x4 blocks, 4bpp, 64-bits/block)
};
cETC1 // Ericsson texture compression (color only, 4x4 blocks, 4bpp, 64-bits/block)
};
const float cDXT1MaxLinearValue = 3.0f;
const float cDXT1InvMaxLinearValue = 1.0f/3.0f;
const float cDXT1MaxLinearValue = 3.0f;
const float cDXT1InvMaxLinearValue = 1.0f / 3.0f;
const float cDXT5MaxLinearValue = 7.0f;
const float cDXT5InvMaxLinearValue = 1.0f/7.0f;
const float cDXT5MaxLinearValue = 7.0f;
const float cDXT5InvMaxLinearValue = 1.0f / 7.0f;
// Converts DXT1 raw color selector index to a linear value.
extern const uint8 g_dxt1_to_linear[cDXT1SelectorValues];
// Converts DXT1 raw color selector index to a linear value.
extern const uint8 g_dxt1_to_linear[cDXT1SelectorValues];
// Converts DXT5 raw alpha selector index to a linear value.
extern const uint8 g_dxt5_to_linear[cDXT5SelectorValues];
// Converts DXT5 raw alpha selector index to a linear value.
extern const uint8 g_dxt5_to_linear[cDXT5SelectorValues];
// Converts DXT1 linear color selector index to a raw value (inverse of g_dxt1_to_linear).
extern const uint8 g_dxt1_from_linear[cDXT1SelectorValues];
// Converts DXT1 linear color selector index to a raw value (inverse of g_dxt1_to_linear).
extern const uint8 g_dxt1_from_linear[cDXT1SelectorValues];
// Converts DXT5 linear alpha selector index to a raw value (inverse of g_dxt5_to_linear).
extern const uint8 g_dxt5_from_linear[cDXT5SelectorValues];
// Converts DXT5 linear alpha selector index to a raw value (inverse of g_dxt5_to_linear).
extern const uint8 g_dxt5_from_linear[cDXT5SelectorValues];
extern const uint8 g_dxt5_alpha6_to_linear[cDXT5SelectorValues];
extern const uint8 g_dxt5_alpha6_to_linear[cDXT5SelectorValues];
extern const uint8 g_six_alpha_invert_table[cDXT5SelectorValues];
extern const uint8 g_eight_alpha_invert_table[cDXT5SelectorValues];
extern const uint8 g_six_alpha_invert_table[cDXT5SelectorValues];
extern const uint8 g_eight_alpha_invert_table[cDXT5SelectorValues];
const char* get_dxt_format_string(dxt_format fmt);
uint get_dxt_format_bits_per_pixel(dxt_format fmt);
bool get_dxt_format_has_alpha(dxt_format fmt);
const char* get_dxt_format_string(dxt_format fmt);
uint get_dxt_format_bits_per_pixel(dxt_format fmt);
bool get_dxt_format_has_alpha(dxt_format fmt);
const char* get_dxt_quality_string(crn_dxt_quality q);
const char* get_dxt_quality_string(crn_dxt_quality q);
const char* get_dxt_compressor_name(crn_dxt_compressor_type c);
const char* get_dxt_compressor_name(crn_dxt_compressor_type c);
struct dxt1_block
{
uint8 m_low_color[2];
uint8 m_high_color[2];
struct dxt1_block {
uint8 m_low_color[2];
uint8 m_high_color[2];
enum { cNumSelectorBytes = 4 };
uint8 m_selectors[cNumSelectorBytes];
enum { cNumSelectorBytes = 4 };
uint8 m_selectors[cNumSelectorBytes];
inline void clear()
{
utils::zero_this(this);
inline void clear() {
utils::zero_this(this);
}
// These methods assume the in-memory rep is in LE byte order.
inline uint get_low_color() const {
return m_low_color[0] | (m_low_color[1] << 8U);
}
inline uint get_high_color() const {
return m_high_color[0] | (m_high_color[1] << 8U);
}
inline void set_low_color(uint16 c) {
m_low_color[0] = static_cast<uint8>(c & 0xFF);
m_low_color[1] = static_cast<uint8>((c >> 8) & 0xFF);
}
inline void set_high_color(uint16 c) {
m_high_color[0] = static_cast<uint8>(c & 0xFF);
m_high_color[1] = static_cast<uint8>((c >> 8) & 0xFF);
}
inline bool is_constant_color_block() const { return get_low_color() == get_high_color(); }
inline bool is_alpha_block() const { return get_low_color() <= get_high_color(); }
inline bool is_non_alpha_block() const { return !is_alpha_block(); }
inline uint get_selector(uint x, uint y) const {
CRNLIB_ASSERT((x < 4U) && (y < 4U));
return (m_selectors[y] >> (x * cDXT1SelectorBits)) & cDXT1SelectorMask;
}
inline void set_selector(uint x, uint y, uint val) {
CRNLIB_ASSERT((x < 4U) && (y < 4U) && (val < 4U));
m_selectors[y] &= (~(cDXT1SelectorMask << (x * cDXT1SelectorBits)));
m_selectors[y] |= (val << (x * cDXT1SelectorBits));
}
inline void flip_x(uint w = 4, uint h = 4) {
for (uint x = 0; x < (w / 2); x++) {
for (uint y = 0; y < h; y++) {
const uint c = get_selector(x, y);
set_selector(x, y, get_selector((w - 1) - x, y));
set_selector((w - 1) - x, y, c);
}
}
}
// These methods assume the in-memory rep is in LE byte order.
inline uint get_low_color() const
{
return m_low_color[0] | (m_low_color[1] << 8U);
inline void flip_y(uint w = 4, uint h = 4) {
for (uint y = 0; y < (h / 2); y++) {
for (uint x = 0; x < w; x++) {
const uint c = get_selector(x, y);
set_selector(x, y, get_selector(x, (h - 1) - y));
set_selector(x, (h - 1) - y, c);
}
}
}
inline uint get_high_color() const
{
return m_high_color[0] | (m_high_color[1] << 8U);
static uint16 pack_color(const color_quad_u8& color, bool scaled, uint bias = 127U);
static uint16 pack_color(uint r, uint g, uint b, bool scaled, uint bias = 127U);
static color_quad_u8 unpack_color(uint16 packed_color, bool scaled, uint alpha = 255U);
static void unpack_color(uint& r, uint& g, uint& b, uint16 packed_color, bool scaled);
static uint get_block_colors3(color_quad_u8* pDst, uint16 color0, uint16 color1);
static uint get_block_colors3_round(color_quad_u8* pDst, uint16 color0, uint16 color1);
static uint get_block_colors4(color_quad_u8* pDst, uint16 color0, uint16 color1);
static uint get_block_colors4_round(color_quad_u8* pDst, uint16 color0, uint16 color1);
// pDst must point to an array at least cDXT1SelectorValues long.
static uint get_block_colors(color_quad_u8* pDst, uint16 color0, uint16 color1);
static uint get_block_colors_round(color_quad_u8* pDst, uint16 color0, uint16 color1);
static color_quad_u8 unpack_endpoint(uint32 endpoints, uint index, bool scaled, uint alpha = 255U);
static uint pack_endpoints(uint lo, uint hi);
static void get_block_colors_NV5x(color_quad_u8* pDst, uint16 packed_col0, uint16 packed_col1, bool color4);
};
CRNLIB_DEFINE_BITWISE_COPYABLE(dxt1_block);
struct dxt3_block {
enum { cNumAlphaBytes = 8 };
uint8 m_alpha[cNumAlphaBytes];
void set_alpha(uint x, uint y, uint value, bool scaled);
uint get_alpha(uint x, uint y, bool scaled) const;
inline void flip_x(uint w = 4, uint h = 4) {
for (uint x = 0; x < (w / 2); x++) {
for (uint y = 0; y < h; y++) {
const uint c = get_alpha(x, y, false);
set_alpha(x, y, get_alpha((w - 1) - x, y, false), false);
set_alpha((w - 1) - x, y, c, false);
}
}
}
inline void set_low_color(uint16 c)
{
m_low_color[0] = static_cast<uint8>(c & 0xFF);
m_low_color[1] = static_cast<uint8>((c >> 8) & 0xFF);
inline void flip_y(uint w = 4, uint h = 4) {
for (uint y = 0; y < (h / 2); y++) {
for (uint x = 0; x < w; x++) {
const uint c = get_alpha(x, y, false);
set_alpha(x, y, get_alpha(x, (h - 1) - y, false), false);
set_alpha(x, (h - 1) - y, c, false);
}
}
}
};
inline void set_high_color(uint16 c)
{
m_high_color[0] = static_cast<uint8>(c & 0xFF);
m_high_color[1] = static_cast<uint8>((c >> 8) & 0xFF);
CRNLIB_DEFINE_BITWISE_COPYABLE(dxt3_block);
struct dxt5_block {
uint8 m_endpoints[2];
enum { cNumSelectorBytes = 6 };
uint8 m_selectors[cNumSelectorBytes];
inline void clear() {
utils::zero_this(this);
}
inline uint get_low_alpha() const {
return m_endpoints[0];
}
inline uint get_high_alpha() const {
return m_endpoints[1];
}
inline void set_low_alpha(uint i) {
CRNLIB_ASSERT(i <= cUINT8_MAX);
m_endpoints[0] = static_cast<uint8>(i);
}
inline void set_high_alpha(uint i) {
CRNLIB_ASSERT(i <= cUINT8_MAX);
m_endpoints[1] = static_cast<uint8>(i);
}
inline bool is_alpha6_block() const { return get_low_alpha() <= get_high_alpha(); }
uint get_endpoints_as_word() const { return m_endpoints[0] | (m_endpoints[1] << 8); }
uint get_selectors_as_word(uint index) {
CRNLIB_ASSERT(index < 3);
return m_selectors[index * 2] | (m_selectors[index * 2 + 1] << 8);
}
inline uint get_selector(uint x, uint y) const {
CRNLIB_ASSERT((x < 4U) && (y < 4U));
uint selector_index = (y * 4) + x;
uint bit_index = selector_index * cDXT5SelectorBits;
uint byte_index = bit_index >> 3;
uint bit_ofs = bit_index & 7;
uint v = m_selectors[byte_index];
if (byte_index < (cNumSelectorBytes - 1))
v |= (m_selectors[byte_index + 1] << 8);
return (v >> bit_ofs) & 7;
}
inline void set_selector(uint x, uint y, uint val) {
CRNLIB_ASSERT((x < 4U) && (y < 4U) && (val < 8U));
uint selector_index = (y * 4) + x;
uint bit_index = selector_index * cDXT5SelectorBits;
uint byte_index = bit_index >> 3;
uint bit_ofs = bit_index & 7;
uint v = m_selectors[byte_index];
if (byte_index < (cNumSelectorBytes - 1))
v |= (m_selectors[byte_index + 1] << 8);
v &= (~(7 << bit_ofs));
v |= (val << bit_ofs);
m_selectors[byte_index] = static_cast<uint8>(v);
if (byte_index < (cNumSelectorBytes - 1))
m_selectors[byte_index + 1] = static_cast<uint8>(v >> 8);
}
inline void flip_x(uint w = 4, uint h = 4) {
for (uint x = 0; x < (w / 2); x++) {
for (uint y = 0; y < h; y++) {
const uint c = get_selector(x, y);
set_selector(x, y, get_selector((w - 1) - x, y));
set_selector((w - 1) - x, y, c);
}
}
}
inline bool is_constant_color_block() const { return get_low_color() == get_high_color(); }
inline bool is_alpha_block() const { return get_low_color() <= get_high_color(); }
inline bool is_non_alpha_block() const { return !is_alpha_block(); }
inline uint get_selector(uint x, uint y) const
{
CRNLIB_ASSERT((x < 4U) && (y < 4U));
return (m_selectors[y] >> (x * cDXT1SelectorBits)) & cDXT1SelectorMask;
inline void flip_y(uint w = 4, uint h = 4) {
for (uint y = 0; y < (h / 2); y++) {
for (uint x = 0; x < w; x++) {
const uint c = get_selector(x, y);
set_selector(x, y, get_selector(x, (h - 1) - y));
set_selector(x, (h - 1) - y, c);
}
}
}
inline void set_selector(uint x, uint y, uint val)
{
CRNLIB_ASSERT((x < 4U) && (y < 4U) && (val < 4U));
enum { cMaxSelectorValues = 8 };
m_selectors[y] &= (~(cDXT1SelectorMask << (x * cDXT1SelectorBits)));
m_selectors[y] |= (val << (x * cDXT1SelectorBits));
}
// Results written to alpha channel.
static uint get_block_values6(color_quad_u8* pDst, uint l, uint h);
static uint get_block_values8(color_quad_u8* pDst, uint l, uint h);
static uint get_block_values(color_quad_u8* pDst, uint l, uint h);
inline void flip_x(uint w = 4, uint h = 4)
{
for (uint x = 0; x < (w / 2); x++)
{
for (uint y = 0; y < h; y++)
{
const uint c = get_selector(x, y);
set_selector(x, y, get_selector((w - 1) - x, y));
set_selector((w - 1) - x, y, c);
}
}
}
static uint get_block_values6(uint* pDst, uint l, uint h);
static uint get_block_values8(uint* pDst, uint l, uint h);
// pDst must point to an array at least cDXT5SelectorValues long.
static uint get_block_values(uint* pDst, uint l, uint h);
inline void flip_y(uint w = 4, uint h = 4)
{
for (uint y = 0; y < (h / 2); y++)
{
for (uint x = 0; x < w; x++)
{
const uint c = get_selector(x, y);
set_selector(x, y, get_selector(x, (h - 1) - y));
set_selector(x, (h - 1) - y, c);
}
}
}
static uint16 pack_color(const color_quad_u8& color, bool scaled, uint bias = 127U);
static uint16 pack_color(uint r, uint g, uint b, bool scaled, uint bias = 127U);
static uint unpack_endpoint(uint packed, uint index);
static uint pack_endpoints(uint lo, uint hi);
};
static color_quad_u8 unpack_color(uint16 packed_color, bool scaled, uint alpha = 255U);
static void unpack_color(uint& r, uint& g, uint& b, uint16 packed_color, bool scaled);
CRNLIB_DEFINE_BITWISE_COPYABLE(dxt5_block);
static uint get_block_colors3(color_quad_u8* pDst, uint16 color0, uint16 color1);
static uint get_block_colors3_round(color_quad_u8* pDst, uint16 color0, uint16 color1);
static uint get_block_colors4(color_quad_u8* pDst, uint16 color0, uint16 color1);
static uint get_block_colors4_round(color_quad_u8* pDst, uint16 color0, uint16 color1);
// pDst must point to an array at least cDXT1SelectorValues long.
static uint get_block_colors(color_quad_u8* pDst, uint16 color0, uint16 color1);
static uint get_block_colors_round(color_quad_u8* pDst, uint16 color0, uint16 color1);
static color_quad_u8 unpack_endpoint(uint32 endpoints, uint index, bool scaled, uint alpha = 255U);
static uint pack_endpoints(uint lo, uint hi);
static void get_block_colors_NV5x(color_quad_u8* pDst, uint16 packed_col0, uint16 packed_col1, bool color4);
};
CRNLIB_DEFINE_BITWISE_COPYABLE(dxt1_block);
struct dxt3_block
{
enum { cNumAlphaBytes = 8 };
uint8 m_alpha[cNumAlphaBytes];
void set_alpha(uint x, uint y, uint value, bool scaled);
uint get_alpha(uint x, uint y, bool scaled) const;
inline void flip_x(uint w = 4, uint h = 4)
{
for (uint x = 0; x < (w / 2); x++)
{
for (uint y = 0; y < h; y++)
{
const uint c = get_alpha(x, y, false);
set_alpha(x, y, get_alpha((w - 1) - x, y, false), false);
set_alpha((w - 1) - x, y, c, false);
}
}
}
inline void flip_y(uint w = 4, uint h = 4)
{
for (uint y = 0; y < (h / 2); y++)
{
for (uint x = 0; x < w; x++)
{
const uint c = get_alpha(x, y, false);
set_alpha(x, y, get_alpha(x, (h - 1) - y, false), false);
set_alpha(x, (h - 1) - y, c, false);
}
}
}
};
CRNLIB_DEFINE_BITWISE_COPYABLE(dxt3_block);
struct dxt5_block
{
uint8 m_endpoints[2];
enum { cNumSelectorBytes = 6 };
uint8 m_selectors[cNumSelectorBytes];
inline void clear()
{
utils::zero_this(this);
}
inline uint get_low_alpha() const
{
return m_endpoints[0];
}
inline uint get_high_alpha() const
{
return m_endpoints[1];
}
inline void set_low_alpha(uint i)
{
CRNLIB_ASSERT(i <= cUINT8_MAX);
m_endpoints[0] = static_cast<uint8>(i);
}
inline void set_high_alpha(uint i)
{
CRNLIB_ASSERT(i <= cUINT8_MAX);
m_endpoints[1] = static_cast<uint8>(i);
}
inline bool is_alpha6_block() const { return get_low_alpha() <= get_high_alpha(); }
uint get_endpoints_as_word() const { return m_endpoints[0] | (m_endpoints[1] << 8); }
uint get_selectors_as_word(uint index) { CRNLIB_ASSERT(index < 3); return m_selectors[index * 2] | (m_selectors[index * 2 + 1] << 8); }
inline uint get_selector(uint x, uint y) const
{
CRNLIB_ASSERT((x < 4U) && (y < 4U));
uint selector_index = (y * 4) + x;
uint bit_index = selector_index * cDXT5SelectorBits;
uint byte_index = bit_index >> 3;
uint bit_ofs = bit_index & 7;
uint v = m_selectors[byte_index];
if (byte_index < (cNumSelectorBytes - 1))
v |= (m_selectors[byte_index + 1] << 8);
return (v >> bit_ofs) & 7;
}
inline void set_selector(uint x, uint y, uint val)
{
CRNLIB_ASSERT((x < 4U) && (y < 4U) && (val < 8U));
uint selector_index = (y * 4) + x;
uint bit_index = selector_index * cDXT5SelectorBits;
uint byte_index = bit_index >> 3;
uint bit_ofs = bit_index & 7;
uint v = m_selectors[byte_index];
if (byte_index < (cNumSelectorBytes - 1))
v |= (m_selectors[byte_index + 1] << 8);
v &= (~(7 << bit_ofs));
v |= (val << bit_ofs);
m_selectors[byte_index] = static_cast<uint8>(v);
if (byte_index < (cNumSelectorBytes - 1))
m_selectors[byte_index + 1] = static_cast<uint8>(v >> 8);
}
inline void flip_x(uint w = 4, uint h = 4)
{
for (uint x = 0; x < (w / 2); x++)
{
for (uint y = 0; y < h; y++)
{
const uint c = get_selector(x, y);
set_selector(x, y, get_selector((w - 1) - x, y));
set_selector((w - 1) - x, y, c);
}
}
}
inline void flip_y(uint w = 4, uint h = 4)
{
for (uint y = 0; y < (h / 2); y++)
{
for (uint x = 0; x < w; x++)
{
const uint c = get_selector(x, y);
set_selector(x, y, get_selector(x, (h - 1) - y));
set_selector(x, (h - 1) - y, c);
}
}
}
enum { cMaxSelectorValues = 8 };
// Results written to alpha channel.
static uint get_block_values6(color_quad_u8* pDst, uint l, uint h);
static uint get_block_values8(color_quad_u8* pDst, uint l, uint h);
static uint get_block_values(color_quad_u8* pDst, uint l, uint h);
static uint get_block_values6(uint* pDst, uint l, uint h);
static uint get_block_values8(uint* pDst, uint l, uint h);
// pDst must point to an array at least cDXT5SelectorValues long.
static uint get_block_values(uint* pDst, uint l, uint h);
static uint unpack_endpoint(uint packed, uint index);
static uint pack_endpoints(uint lo, uint hi);
};
CRNLIB_DEFINE_BITWISE_COPYABLE(dxt5_block);
struct dxt_pixel_block
{
color_quad_u8 m_pixels[cDXTBlockSize][cDXTBlockSize]; // [y][x]
inline void clear()
{
utils::zero_object(*this);
}
};
CRNLIB_DEFINE_BITWISE_COPYABLE(dxt_pixel_block);
} // namespace crnlib
struct dxt_pixel_block {
color_quad_u8 m_pixels[cDXTBlockSize][cDXTBlockSize]; // [y][x]
inline void clear() {
utils::zero_object(*this);
}
};
CRNLIB_DEFINE_BITWISE_COPYABLE(dxt_pixel_block);
} // namespace crnlib
+1711 -1892
View File
File diff suppressed because it is too large Load Diff
+318 -340
View File
@@ -3,350 +3,328 @@
#pragma once
#include "crn_dxt.h"
namespace crnlib
{
struct dxt1_solution_coordinates
{
inline dxt1_solution_coordinates() : m_low_color(0), m_high_color(0){ }
namespace crnlib {
struct dxt1_solution_coordinates {
inline dxt1_solution_coordinates()
: m_low_color(0), m_high_color(0) {}
inline dxt1_solution_coordinates(uint16 l, uint16 h) : m_low_color(l), m_high_color(h) { }
inline dxt1_solution_coordinates(uint16 l, uint16 h)
: m_low_color(l), m_high_color(h) {}
inline dxt1_solution_coordinates(const color_quad_u8& l, const color_quad_u8& h, bool scaled = true) :
m_low_color(dxt1_block::pack_color(l, scaled)),
m_high_color(dxt1_block::pack_color(h, scaled))
{
}
inline dxt1_solution_coordinates(const color_quad_u8& l, const color_quad_u8& h, bool scaled = true)
: m_low_color(dxt1_block::pack_color(l, scaled)),
m_high_color(dxt1_block::pack_color(h, scaled)) {
}
inline dxt1_solution_coordinates(vec3F nl, vec3F nh)
{
inline dxt1_solution_coordinates(vec3F nl, vec3F nh) {
#if CRNLIB_DXT_ALT_ROUNDING
// Umm, wtf?
nl.clamp(0.0f, .999f);
nh.clamp(0.0f, .999f);
color_quad_u8 l( (int)floor(nl[0] * 32.0f), (int)floor(nl[1] * 64.0f), (int)floor(nl[2] * 32.0f), 255);
color_quad_u8 h( (int)floor(nh[0] * 32.0f), (int)floor(nh[1] * 64.0f), (int)floor(nh[2] * 32.0f), 255);
// Umm, wtf?
nl.clamp(0.0f, .999f);
nh.clamp(0.0f, .999f);
color_quad_u8 l((int)floor(nl[0] * 32.0f), (int)floor(nl[1] * 64.0f), (int)floor(nl[2] * 32.0f), 255);
color_quad_u8 h((int)floor(nh[0] * 32.0f), (int)floor(nh[1] * 64.0f), (int)floor(nh[2] * 32.0f), 255);
#else
// Fixes the bins
color_quad_u8 l( (int)floor(.5f + nl[0] * 31.0f), (int)floor(.5f + nl[1] * 63.0f), (int)floor(.5f + nl[2] * 31.0f), 255);
color_quad_u8 h( (int)floor(.5f + nh[0] * 31.0f), (int)floor(.5f + nh[1] * 63.0f), (int)floor(.5f + nh[2] * 31.0f), 255);
// Fixes the bins
color_quad_u8 l((int)floor(.5f + nl[0] * 31.0f), (int)floor(.5f + nl[1] * 63.0f), (int)floor(.5f + nl[2] * 31.0f), 255);
color_quad_u8 h((int)floor(.5f + nh[0] * 31.0f), (int)floor(.5f + nh[1] * 63.0f), (int)floor(.5f + nh[2] * 31.0f), 255);
#endif
m_low_color = dxt1_block::pack_color(l, false);
m_high_color = dxt1_block::pack_color(h, false);
}
uint16 m_low_color;
uint16 m_high_color;
inline void clear()
{
m_low_color = 0;
m_high_color = 0;
}
inline dxt1_solution_coordinates& canonicalize()
{
if (m_low_color < m_high_color)
utils::swap(m_low_color, m_high_color);
return *this;
}
inline operator size_t() const { return fast_hash(this, sizeof(*this)); }
inline bool operator== (const dxt1_solution_coordinates& other) const
{
uint16 l0 = math::minimum(m_low_color, m_high_color);
uint16 h0 = math::maximum(m_low_color, m_high_color);
uint16 l1 = math::minimum(other.m_low_color, other.m_high_color);
uint16 h1 = math::maximum(other.m_low_color, other.m_high_color);
return (l0 == l1) && (h0 == h1);
}
inline bool operator!= (const dxt1_solution_coordinates& other) const
{
return !(*this == other);
}
inline bool operator< (const dxt1_solution_coordinates& other) const
{
uint16 l0 = math::minimum(m_low_color, m_high_color);
uint16 h0 = math::maximum(m_low_color, m_high_color);
uint16 l1 = math::minimum(other.m_low_color, other.m_high_color);
uint16 h1 = math::maximum(other.m_low_color, other.m_high_color);
if (l0 < l1)
return true;
else if (l0 == l1)
{
if (h0 < h1)
return true;
}
return false;
}
};
typedef crnlib::vector<dxt1_solution_coordinates> dxt1_solution_coordinates_vec;
CRNLIB_DEFINE_BITWISE_COPYABLE(dxt1_solution_coordinates);
struct unique_color
{
inline unique_color() { }
inline unique_color(const color_quad_u8& color, uint weight) : m_color(color), m_weight(weight) { }
color_quad_u8 m_color;
uint m_weight;
inline bool operator< (const unique_color& c) const
{
return *reinterpret_cast<const uint32*>(&m_color) < *reinterpret_cast<const uint32*>(&c.m_color);
}
inline bool operator== (const unique_color& c) const
{
return *reinterpret_cast<const uint32*>(&m_color) == *reinterpret_cast<const uint32*>(&c.m_color);
}
};
CRNLIB_DEFINE_BITWISE_COPYABLE(unique_color);
class dxt1_endpoint_optimizer
{
public:
dxt1_endpoint_optimizer();
struct params
{
params() :
m_block_index(0),
m_pPixels(NULL),
m_num_pixels(0),
m_dxt1a_alpha_threshold(128U),
m_quality(cCRNDXTQualityUber),
m_pixels_have_alpha(false),
m_use_alpha_blocks(true),
m_perceptual(true),
m_grayscale_sampling(false),
m_endpoint_caching(true),
m_use_transparent_indices_for_black(false),
m_force_alpha_blocks(false)
{
m_color_weights[0] = 1;
m_color_weights[1] = 1;
m_color_weights[2] = 1;
}
uint m_block_index;
const color_quad_u8* m_pPixels;
uint m_num_pixels;
uint m_dxt1a_alpha_threshold;
crn_dxt_quality m_quality;
bool m_pixels_have_alpha;
bool m_use_alpha_blocks;
bool m_perceptual;
bool m_grayscale_sampling;
bool m_endpoint_caching;
bool m_use_transparent_indices_for_black;
bool m_force_alpha_blocks;
int m_color_weights[3];
};
struct results
{
inline results() : m_pSelectors(NULL) { }
uint64 m_error;
uint16 m_low_color;
uint16 m_high_color;
uint8* m_pSelectors;
bool m_alpha_block;
};
struct solution
{
solution() { }
solution(const solution& other)
{
m_results = other.m_results;
m_selectors = other.m_selectors;
m_results.m_pSelectors = m_selectors.begin();
}
solution& operator= (const solution& rhs)
{
if (this == &rhs)
return *this;
m_results = rhs.m_results;
m_selectors = rhs.m_selectors;
m_results.m_pSelectors = m_selectors.begin();
return *this;
}
results m_results;
crnlib::vector<uint8> m_selectors;
inline bool operator< (const solution& other) const
{
return m_results.m_error < other.m_results.m_error;
}
static inline bool coords_equal(const solution& lhs, const solution& rhs)
{
return (lhs.m_results.m_low_color == rhs.m_results.m_low_color) && (lhs.m_results.m_high_color == rhs.m_results.m_high_color);
}
};
typedef crnlib::vector<solution> solution_vec;
bool compute(const params& p, results& r, solution_vec* pSolutions = NULL);
private:
const params* m_pParams;
results* m_pResults;
solution_vec* m_pSolutions;
bool m_perceptual;
bool m_has_color_weighting;
typedef crnlib::vector<unique_color> unique_color_vec;
//typedef crnlib::hash_map<uint32, uint32, bit_hasher<uint32> > unique_color_hash_map;
typedef crnlib::hash_map<uint32, uint32> unique_color_hash_map;
unique_color_hash_map m_unique_color_hash_map;
unique_color_vec m_unique_colors; // excludes transparent colors!
unique_color_vec m_temp_unique_colors;
uint m_total_unique_color_weight;
bool m_has_transparent_pixels;
vec3F_array m_norm_unique_colors;
vec3F m_mean_norm_color;
vec3F_array m_norm_unique_colors_weighted;
vec3F m_mean_norm_color_weighted;
vec3F m_principle_axis;
bool m_all_pixels_grayscale;
crnlib::vector<uint16> m_unique_packed_colors;
crnlib::vector<uint8> m_trial_selectors;
crnlib::vector<vec3F> m_low_coords;
crnlib::vector<vec3F> m_high_coords;
enum { cMaxPrevResults = 4 };
dxt1_solution_coordinates m_prev_results[cMaxPrevResults];
uint m_num_prev_results;
crnlib::vector<vec3I> m_lo_cells;
crnlib::vector<vec3I> m_hi_cells;
uint m_total_evals;
struct potential_solution
{
potential_solution() : m_coords(), m_error(cUINT64_MAX), m_alpha_block(false), m_valid(false)
{
}
dxt1_solution_coordinates m_coords;
crnlib::vector<uint8> m_selectors;
uint64 m_error;
bool m_alpha_block;
bool m_valid;
void clear()
{
m_coords.clear();
m_selectors.resize(0);
m_error = cUINT64_MAX;
m_alpha_block = false;
m_valid = false;
}
bool are_selectors_all_equal() const
{
if (m_selectors.empty())
return false;
const uint s = m_selectors[0];
for (uint i = 1; i < m_selectors.size(); i++)
if (m_selectors[i] != s)
return false;
return true;
}
};
potential_solution m_trial_solution;
potential_solution m_best_solution;
typedef crnlib::hash_map<uint, empty_type> solution_hash_map;
solution_hash_map m_solutions_tried;
bool refine_solution(int refinement_level = 0);
bool evaluate_solution(
const dxt1_solution_coordinates& coords,
bool early_out,
potential_solution* pBest_solution,
bool alternate_rounding = false);
bool evaluate_solution_uber(
potential_solution& solution,
const dxt1_solution_coordinates& coords,
bool early_out,
potential_solution* pBest_solution,
bool alternate_rounding = false);
bool evaluate_solution_fast(
potential_solution& solution,
const dxt1_solution_coordinates& coords,
bool early_out,
potential_solution* pBest_solution,
bool alternate_rounding = false);
void clear();
void find_unique_colors();
bool handle_all_transparent_block();
bool handle_solid_block();
bool handle_multicolor_block();
bool handle_grayscale_block();
void compute_pca(vec3F& axis, const vec3F_array& norm_colors, const vec3F& def);
void compute_vectors(const vec3F& perceptual_weights);
void return_solution(results& results, const potential_solution& solution);
void try_combinatorial_encoding();
void optimize_endpoint_comps();
bool optimize_endpoints(vec3F& low_color, vec3F& high_color);
bool try_alpha_as_black_optimization();
bool try_average_block_as_solid();
bool try_median4(const vec3F& low_color, const vec3F& high_color);
bool compute_internal(const params& p, results& r, solution_vec* pSolutions);
unique_color lerp_color(const color_quad_u8& a, const color_quad_u8& b, float f, int rounding = 1);
inline uint color_distance(bool perceptual, const color_quad_u8& e1, const color_quad_u8& e2, bool alpha);
static inline vec3F unpack_to_vec3F_raw(uint16 packed_color);
static inline vec3F unpack_to_vec3F(uint16 packed_color);
};
inline void swap(dxt1_endpoint_optimizer::solution& a, dxt1_endpoint_optimizer::solution& b)
{
std::swap(a.m_results, b.m_results);
a.m_selectors.swap(b.m_selectors);
}
} // namespace crnlib
m_low_color = dxt1_block::pack_color(l, false);
m_high_color = dxt1_block::pack_color(h, false);
}
uint16 m_low_color;
uint16 m_high_color;
inline void clear() {
m_low_color = 0;
m_high_color = 0;
}
inline dxt1_solution_coordinates& canonicalize() {
if (m_low_color < m_high_color)
utils::swap(m_low_color, m_high_color);
return *this;
}
inline operator size_t() const { return fast_hash(this, sizeof(*this)); }
inline bool operator==(const dxt1_solution_coordinates& other) const {
uint16 l0 = math::minimum(m_low_color, m_high_color);
uint16 h0 = math::maximum(m_low_color, m_high_color);
uint16 l1 = math::minimum(other.m_low_color, other.m_high_color);
uint16 h1 = math::maximum(other.m_low_color, other.m_high_color);
return (l0 == l1) && (h0 == h1);
}
inline bool operator!=(const dxt1_solution_coordinates& other) const {
return !(*this == other);
}
inline bool operator<(const dxt1_solution_coordinates& other) const {
uint16 l0 = math::minimum(m_low_color, m_high_color);
uint16 h0 = math::maximum(m_low_color, m_high_color);
uint16 l1 = math::minimum(other.m_low_color, other.m_high_color);
uint16 h1 = math::maximum(other.m_low_color, other.m_high_color);
if (l0 < l1)
return true;
else if (l0 == l1) {
if (h0 < h1)
return true;
}
return false;
}
};
typedef crnlib::vector<dxt1_solution_coordinates> dxt1_solution_coordinates_vec;
CRNLIB_DEFINE_BITWISE_COPYABLE(dxt1_solution_coordinates);
struct unique_color {
inline unique_color() {}
inline unique_color(const color_quad_u8& color, uint weight)
: m_color(color), m_weight(weight) {}
color_quad_u8 m_color;
uint m_weight;
inline bool operator<(const unique_color& c) const {
return *reinterpret_cast<const uint32*>(&m_color) < *reinterpret_cast<const uint32*>(&c.m_color);
}
inline bool operator==(const unique_color& c) const {
return *reinterpret_cast<const uint32*>(&m_color) == *reinterpret_cast<const uint32*>(&c.m_color);
}
};
CRNLIB_DEFINE_BITWISE_COPYABLE(unique_color);
class dxt1_endpoint_optimizer {
public:
dxt1_endpoint_optimizer();
struct params {
params()
: m_block_index(0),
m_pPixels(NULL),
m_num_pixels(0),
m_dxt1a_alpha_threshold(128U),
m_quality(cCRNDXTQualityUber),
m_pixels_have_alpha(false),
m_use_alpha_blocks(true),
m_perceptual(true),
m_grayscale_sampling(false),
m_endpoint_caching(true),
m_use_transparent_indices_for_black(false),
m_force_alpha_blocks(false) {
m_color_weights[0] = 1;
m_color_weights[1] = 1;
m_color_weights[2] = 1;
}
uint m_block_index;
const color_quad_u8* m_pPixels;
uint m_num_pixels;
uint m_dxt1a_alpha_threshold;
crn_dxt_quality m_quality;
bool m_pixels_have_alpha;
bool m_use_alpha_blocks;
bool m_perceptual;
bool m_grayscale_sampling;
bool m_endpoint_caching;
bool m_use_transparent_indices_for_black;
bool m_force_alpha_blocks;
int m_color_weights[3];
};
struct results {
inline results()
: m_pSelectors(NULL) {}
uint64 m_error;
uint16 m_low_color;
uint16 m_high_color;
uint8* m_pSelectors;
bool m_alpha_block;
};
struct solution {
solution() {}
solution(const solution& other) {
m_results = other.m_results;
m_selectors = other.m_selectors;
m_results.m_pSelectors = m_selectors.begin();
}
solution& operator=(const solution& rhs) {
if (this == &rhs)
return *this;
m_results = rhs.m_results;
m_selectors = rhs.m_selectors;
m_results.m_pSelectors = m_selectors.begin();
return *this;
}
results m_results;
crnlib::vector<uint8> m_selectors;
inline bool operator<(const solution& other) const {
return m_results.m_error < other.m_results.m_error;
}
static inline bool coords_equal(const solution& lhs, const solution& rhs) {
return (lhs.m_results.m_low_color == rhs.m_results.m_low_color) && (lhs.m_results.m_high_color == rhs.m_results.m_high_color);
}
};
typedef crnlib::vector<solution> solution_vec;
bool compute(const params& p, results& r, solution_vec* pSolutions = NULL);
private:
const params* m_pParams;
results* m_pResults;
solution_vec* m_pSolutions;
bool m_perceptual;
bool m_has_color_weighting;
typedef crnlib::vector<unique_color> unique_color_vec;
//typedef crnlib::hash_map<uint32, uint32, bit_hasher<uint32> > unique_color_hash_map;
typedef crnlib::hash_map<uint32, uint32> unique_color_hash_map;
unique_color_hash_map m_unique_color_hash_map;
unique_color_vec m_unique_colors; // excludes transparent colors!
unique_color_vec m_temp_unique_colors;
uint m_total_unique_color_weight;
bool m_has_transparent_pixels;
vec3F_array m_norm_unique_colors;
vec3F m_mean_norm_color;
vec3F_array m_norm_unique_colors_weighted;
vec3F m_mean_norm_color_weighted;
vec3F m_principle_axis;
bool m_all_pixels_grayscale;
crnlib::vector<uint16> m_unique_packed_colors;
crnlib::vector<uint8> m_trial_selectors;
crnlib::vector<vec3F> m_low_coords;
crnlib::vector<vec3F> m_high_coords;
enum { cMaxPrevResults = 4 };
dxt1_solution_coordinates m_prev_results[cMaxPrevResults];
uint m_num_prev_results;
crnlib::vector<vec3I> m_lo_cells;
crnlib::vector<vec3I> m_hi_cells;
uint m_total_evals;
struct potential_solution {
potential_solution()
: m_coords(), m_error(cUINT64_MAX), m_alpha_block(false), m_valid(false) {
}
dxt1_solution_coordinates m_coords;
crnlib::vector<uint8> m_selectors;
uint64 m_error;
bool m_alpha_block;
bool m_valid;
void clear() {
m_coords.clear();
m_selectors.resize(0);
m_error = cUINT64_MAX;
m_alpha_block = false;
m_valid = false;
}
bool are_selectors_all_equal() const {
if (m_selectors.empty())
return false;
const uint s = m_selectors[0];
for (uint i = 1; i < m_selectors.size(); i++)
if (m_selectors[i] != s)
return false;
return true;
}
};
potential_solution m_trial_solution;
potential_solution m_best_solution;
typedef crnlib::hash_map<uint, empty_type> solution_hash_map;
solution_hash_map m_solutions_tried;
bool refine_solution(int refinement_level = 0);
bool evaluate_solution(
const dxt1_solution_coordinates& coords,
bool early_out,
potential_solution* pBest_solution,
bool alternate_rounding = false);
bool evaluate_solution_uber(
potential_solution& solution,
const dxt1_solution_coordinates& coords,
bool early_out,
potential_solution* pBest_solution,
bool alternate_rounding = false);
bool evaluate_solution_fast(
potential_solution& solution,
const dxt1_solution_coordinates& coords,
bool early_out,
potential_solution* pBest_solution,
bool alternate_rounding = false);
void clear();
void find_unique_colors();
bool handle_all_transparent_block();
bool handle_solid_block();
bool handle_multicolor_block();
bool handle_grayscale_block();
void compute_pca(vec3F& axis, const vec3F_array& norm_colors, const vec3F& def);
void compute_vectors(const vec3F& perceptual_weights);
void return_solution(results& results, const potential_solution& solution);
void try_combinatorial_encoding();
void optimize_endpoint_comps();
bool optimize_endpoints(vec3F& low_color, vec3F& high_color);
bool try_alpha_as_black_optimization();
bool try_average_block_as_solid();
bool try_median4(const vec3F& low_color, const vec3F& high_color);
bool compute_internal(const params& p, results& r, solution_vec* pSolutions);
unique_color lerp_color(const color_quad_u8& a, const color_quad_u8& b, float f, int rounding = 1);
inline uint color_distance(bool perceptual, const color_quad_u8& e1, const color_quad_u8& e2, bool alpha);
static inline vec3F unpack_to_vec3F_raw(uint16 packed_color);
static inline vec3F unpack_to_vec3F(uint16 packed_color);
};
inline void swap(dxt1_endpoint_optimizer::solution& a, dxt1_endpoint_optimizer::solution& b) {
std::swap(a.m_results, b.m_results);
a.m_selectors.swap(b.m_selectors);
}
} // namespace crnlib
+160 -184
View File
@@ -6,204 +6,180 @@
#include "crn_dxt_fast.h"
#include "crn_intersect.h"
namespace crnlib
{
dxt5_endpoint_optimizer::dxt5_endpoint_optimizer() :
m_pParams(NULL),
m_pResults(NULL)
{
m_unique_values.reserve(16);
m_unique_value_weights.reserve(16);
}
namespace crnlib {
dxt5_endpoint_optimizer::dxt5_endpoint_optimizer()
: m_pParams(NULL),
m_pResults(NULL) {
m_unique_values.reserve(16);
m_unique_value_weights.reserve(16);
}
bool dxt5_endpoint_optimizer::compute(const params& p, results& r)
{
m_pParams = &p;
m_pResults = &r;
bool dxt5_endpoint_optimizer::compute(const params& p, results& r) {
m_pParams = &p;
m_pResults = &r;
if ((!p.m_num_pixels) || (!p.m_pPixels))
return false;
if ((!p.m_num_pixels) || (!p.m_pPixels))
return false;
m_unique_values.resize(0);
m_unique_value_weights.resize(0);
m_unique_values.resize(0);
m_unique_value_weights.resize(0);
for (uint i = 0; i < 256; i++)
m_unique_value_map[i] = -1;
for (uint i = 0; i < 256; i++)
m_unique_value_map[i] = -1;
for (uint i = 0; i < p.m_num_pixels; i++)
{
uint alpha = p.m_pPixels[i][p.m_comp_index];
for (uint i = 0; i < p.m_num_pixels; i++) {
uint alpha = p.m_pPixels[i][p.m_comp_index];
int index = m_unique_value_map[alpha];
int index = m_unique_value_map[alpha];
if (index == -1)
{
index = m_unique_values.size();
if (index == -1) {
index = m_unique_values.size();
m_unique_value_map[alpha] = index;
m_unique_value_map[alpha] = index;
m_unique_values.push_back(static_cast<uint8>(alpha));
m_unique_value_weights.push_back(0);
}
m_unique_values.push_back(static_cast<uint8>(alpha));
m_unique_value_weights.push_back(0);
}
m_unique_value_weights[index]++;
}
m_unique_value_weights[index]++;
}
if (m_unique_values.size() == 1)
{
r.m_block_type = 0;
r.m_error = 0;
r.m_first_endpoint = m_unique_values[0];
r.m_second_endpoint = m_unique_values[0];
memset(r.m_pSelectors, 0, p.m_num_pixels);
return true;
if (m_unique_values.size() == 1) {
r.m_block_type = 0;
r.m_error = 0;
r.m_first_endpoint = m_unique_values[0];
r.m_second_endpoint = m_unique_values[0];
memset(r.m_pSelectors, 0, p.m_num_pixels);
return true;
}
m_trial_selectors.resize(m_unique_values.size());
m_best_selectors.resize(m_unique_values.size());
r.m_error = cUINT64_MAX;
for (uint i = 0; i < m_unique_values.size() - 1; i++) {
const uint low_endpoint = m_unique_values[i];
for (uint j = i + 1; j < m_unique_values.size(); j++) {
const uint high_endpoint = m_unique_values[j];
evaluate_solution(low_endpoint, high_endpoint);
}
}
if ((m_pParams->m_quality >= cCRNDXTQualityBetter) && (m_pResults->m_error)) {
m_flags.resize(256 * 256);
m_flags.clear_all_bits();
const int cProbeAmount = (m_pParams->m_quality == cCRNDXTQualityUber) ? 16 : 8;
for (int l_delta = -cProbeAmount; l_delta <= cProbeAmount; l_delta++) {
const int l = m_pResults->m_first_endpoint + l_delta;
if (l < 0)
continue;
else if (l > 255)
break;
const uint bit_index = l * 256;
for (int h_delta = -cProbeAmount; h_delta <= cProbeAmount; h_delta++) {
const int h = m_pResults->m_second_endpoint + h_delta;
if (h < 0)
continue;
else if (h > 255)
break;
//if (m_flags.get_bit(bit_index + h))
// continue;
if ((m_flags.get_bit(bit_index + h)) || (m_flags.get_bit(h * 256 + l)))
continue;
m_flags.set_bit(bit_index + h);
evaluate_solution(static_cast<uint>(l), static_cast<uint>(h));
}
}
}
if (m_pResults->m_first_endpoint == m_pResults->m_second_endpoint) {
for (uint i = 0; i < m_best_selectors.size(); i++)
m_best_selectors[i] = 0;
} else if (m_pResults->m_block_type) {
//if (l > h)
// eight alpha
// else
// six alpha
if (m_pResults->m_first_endpoint > m_pResults->m_second_endpoint) {
utils::swap(m_pResults->m_first_endpoint, m_pResults->m_second_endpoint);
for (uint i = 0; i < m_best_selectors.size(); i++)
m_best_selectors[i] = g_six_alpha_invert_table[m_best_selectors[i]];
}
} else if (!(m_pResults->m_first_endpoint > m_pResults->m_second_endpoint)) {
utils::swap(m_pResults->m_first_endpoint, m_pResults->m_second_endpoint);
for (uint i = 0; i < m_best_selectors.size(); i++)
m_best_selectors[i] = g_eight_alpha_invert_table[m_best_selectors[i]];
}
for (uint i = 0; i < m_pParams->m_num_pixels; i++) {
uint alpha = m_pParams->m_pPixels[i][m_pParams->m_comp_index];
int index = m_unique_value_map[alpha];
m_pResults->m_pSelectors[i] = m_best_selectors[index];
}
return true;
}
void dxt5_endpoint_optimizer::evaluate_solution(uint low_endpoint, uint high_endpoint) {
for (uint block_type = 0; block_type < (m_pParams->m_use_both_block_types ? 2U : 1U); block_type++) {
uint selector_values[8];
if (!block_type)
dxt5_block::get_block_values8(selector_values, low_endpoint, high_endpoint);
else
dxt5_block::get_block_values6(selector_values, low_endpoint, high_endpoint);
uint64 trial_error = 0;
for (uint i = 0; i < m_unique_values.size(); i++) {
const uint val = m_unique_values[i];
const uint weight = m_unique_value_weights[i];
uint best_selector_error = UINT_MAX;
uint best_selector = 0;
for (uint j = 0; j < 8; j++) {
int selector_error = val - selector_values[j];
selector_error = selector_error * selector_error * (int)weight;
if (static_cast<uint>(selector_error) < best_selector_error) {
best_selector_error = selector_error;
best_selector = j;
if (!best_selector_error)
break;
}
}
m_trial_selectors.resize(m_unique_values.size());
m_best_selectors.resize(m_unique_values.size());
m_trial_selectors[i] = static_cast<uint8>(best_selector);
trial_error += best_selector_error;
r.m_error = cUINT64_MAX;
if (trial_error > m_pResults->m_error)
break;
}
for (uint i = 0; i < m_unique_values.size() - 1; i++)
{
const uint low_endpoint = m_unique_values[i];
if (trial_error < m_pResults->m_error) {
m_pResults->m_error = trial_error;
m_pResults->m_first_endpoint = static_cast<uint8>(low_endpoint);
m_pResults->m_second_endpoint = static_cast<uint8>(high_endpoint);
m_pResults->m_block_type = static_cast<uint8>(block_type);
m_best_selectors.swap(m_trial_selectors);
for (uint j = i + 1; j < m_unique_values.size(); j++)
{
const uint high_endpoint = m_unique_values[j];
if (!trial_error)
break;
}
}
}
evaluate_solution(low_endpoint, high_endpoint);
}
}
if ((m_pParams->m_quality >= cCRNDXTQualityBetter) && (m_pResults->m_error))
{
m_flags.resize(256 * 256);
m_flags.clear_all_bits();
const int cProbeAmount = (m_pParams->m_quality == cCRNDXTQualityUber) ? 16 : 8;
for (int l_delta = -cProbeAmount; l_delta <= cProbeAmount; l_delta++)
{
const int l = m_pResults->m_first_endpoint + l_delta;
if (l < 0)
continue;
else if (l > 255)
break;
const uint bit_index = l * 256;
for (int h_delta = -cProbeAmount; h_delta <= cProbeAmount; h_delta++)
{
const int h = m_pResults->m_second_endpoint + h_delta;
if (h < 0)
continue;
else if (h > 255)
break;
//if (m_flags.get_bit(bit_index + h))
// continue;
if ((m_flags.get_bit(bit_index + h)) || (m_flags.get_bit(h * 256 + l)))
continue;
m_flags.set_bit(bit_index + h);
evaluate_solution(static_cast<uint>(l), static_cast<uint>(h));
}
}
}
if (m_pResults->m_first_endpoint == m_pResults->m_second_endpoint)
{
for (uint i = 0; i < m_best_selectors.size(); i++)
m_best_selectors[i] = 0;
}
else if (m_pResults->m_block_type)
{
//if (l > h)
// eight alpha
// else
// six alpha
if (m_pResults->m_first_endpoint > m_pResults->m_second_endpoint)
{
utils::swap(m_pResults->m_first_endpoint, m_pResults->m_second_endpoint);
for (uint i = 0; i < m_best_selectors.size(); i++)
m_best_selectors[i] = g_six_alpha_invert_table[m_best_selectors[i]];
}
}
else if (!(m_pResults->m_first_endpoint > m_pResults->m_second_endpoint))
{
utils::swap(m_pResults->m_first_endpoint, m_pResults->m_second_endpoint);
for (uint i = 0; i < m_best_selectors.size(); i++)
m_best_selectors[i] = g_eight_alpha_invert_table[m_best_selectors[i]];
}
for (uint i = 0; i < m_pParams->m_num_pixels; i++)
{
uint alpha = m_pParams->m_pPixels[i][m_pParams->m_comp_index];
int index = m_unique_value_map[alpha];
m_pResults->m_pSelectors[i] = m_best_selectors[index];
}
return true;
}
void dxt5_endpoint_optimizer::evaluate_solution(uint low_endpoint, uint high_endpoint)
{
for (uint block_type = 0; block_type < (m_pParams->m_use_both_block_types ? 2U : 1U); block_type++)
{
uint selector_values[8];
if (!block_type)
dxt5_block::get_block_values8(selector_values, low_endpoint, high_endpoint);
else
dxt5_block::get_block_values6(selector_values, low_endpoint, high_endpoint);
uint64 trial_error = 0;
for (uint i = 0; i < m_unique_values.size(); i++)
{
const uint val = m_unique_values[i];
const uint weight = m_unique_value_weights[i];
uint best_selector_error = UINT_MAX;
uint best_selector = 0;
for (uint j = 0; j < 8; j++)
{
int selector_error = val - selector_values[j];
selector_error = selector_error * selector_error * (int)weight;
if (static_cast<uint>(selector_error) < best_selector_error)
{
best_selector_error = selector_error;
best_selector = j;
if (!best_selector_error)
break;
}
}
m_trial_selectors[i] = static_cast<uint8>(best_selector);
trial_error += best_selector_error;
if (trial_error > m_pResults->m_error)
break;
}
if (trial_error < m_pResults->m_error)
{
m_pResults->m_error = trial_error;
m_pResults->m_first_endpoint = static_cast<uint8>(low_endpoint);
m_pResults->m_second_endpoint = static_cast<uint8>(high_endpoint);
m_pResults->m_block_type = static_cast<uint8>(block_type);
m_best_selectors.swap(m_trial_selectors);
if (!trial_error)
break;
}
}
}
} // namespace crnlib
} // namespace crnlib
+40 -45
View File
@@ -3,64 +3,59 @@
#pragma once
#include "crn_dxt.h"
namespace crnlib
{
class dxt5_endpoint_optimizer
{
public:
dxt5_endpoint_optimizer();
namespace crnlib {
class dxt5_endpoint_optimizer {
public:
dxt5_endpoint_optimizer();
struct params
{
params() :
m_block_index(0),
m_pPixels(NULL),
m_num_pixels(0),
m_comp_index(3),
m_quality(cCRNDXTQualityUber),
m_use_both_block_types(true)
{
}
struct params {
params()
: m_block_index(0),
m_pPixels(NULL),
m_num_pixels(0),
m_comp_index(3),
m_quality(cCRNDXTQualityUber),
m_use_both_block_types(true) {
}
uint m_block_index;
uint m_block_index;
const color_quad_u8* m_pPixels;
uint m_num_pixels;
uint m_comp_index;
const color_quad_u8* m_pPixels;
uint m_num_pixels;
uint m_comp_index;
crn_dxt_quality m_quality;
crn_dxt_quality m_quality;
bool m_use_both_block_types;
};
bool m_use_both_block_types;
};
struct results
{
uint8* m_pSelectors;
struct results {
uint8* m_pSelectors;
uint64 m_error;
uint64 m_error;
uint8 m_first_endpoint;
uint8 m_second_endpoint;
uint8 m_first_endpoint;
uint8 m_second_endpoint;
uint8 m_block_type; // 1 if 6-alpha, otherwise 8-alpha
};
uint8 m_block_type; // 1 if 6-alpha, otherwise 8-alpha
};
bool compute(const params& p, results& r);
bool compute(const params& p, results& r);
private:
const params* m_pParams;
results* m_pResults;
private:
const params* m_pParams;
results* m_pResults;
crnlib::vector<uint8> m_unique_values;
crnlib::vector<uint> m_unique_value_weights;
crnlib::vector<uint8> m_unique_values;
crnlib::vector<uint> m_unique_value_weights;
crnlib::vector<uint8> m_trial_selectors;
crnlib::vector<uint8> m_best_selectors;
int m_unique_value_map[256];
crnlib::vector<uint8> m_trial_selectors;
crnlib::vector<uint8> m_best_selectors;
int m_unique_value_map[256];
sparse_bit_array m_flags;
sparse_bit_array m_flags;
void evaluate_solution(uint low_endpoint, uint high_endpoint);
};
void evaluate_solution(uint low_endpoint, uint high_endpoint);
};
} // namespace crnlib
} // namespace crnlib
+279 -313
View File
@@ -4,359 +4,325 @@
#include "crn_dxt_endpoint_refiner.h"
#include "crn_dxt1.h"
namespace crnlib
{
dxt_endpoint_refiner::dxt_endpoint_refiner() :
m_pParams(NULL),
m_pResults(NULL)
{
}
namespace crnlib {
dxt_endpoint_refiner::dxt_endpoint_refiner()
: m_pParams(NULL),
m_pResults(NULL) {
}
bool dxt_endpoint_refiner::refine(const params& p, results& r)
{
if (!p.m_num_pixels)
return false;
bool dxt_endpoint_refiner::refine(const params& p, results& r) {
if (!p.m_num_pixels)
return false;
m_pParams = &p;
m_pResults = &r;
m_pParams = &p;
m_pResults = &r;
r.m_error = cUINT64_MAX;
r.m_low_color = 0;
r.m_high_color = 0;
r.m_error = cUINT64_MAX;
r.m_low_color = 0;
r.m_high_color = 0;
double alpha2_sum = 0.0f;
double beta2_sum = 0.0f;
double alphabeta_sum = 0.0f;
double alpha2_sum = 0.0f;
double beta2_sum = 0.0f;
double alphabeta_sum = 0.0f;
vec<3, double> alphax_sum( 0.0f );
vec<3, double> betax_sum( 0.0f );
vec<3, double> alphax_sum(0.0f);
vec<3, double> betax_sum(0.0f);
vec<3, double> first_color( 0.0f );
vec<3, double> first_color(0.0f);
// This linear solver is from Squish.
for( uint i = 0; i < p.m_num_pixels; ++i )
{
uint8 c = p.m_pSelectors[i];
// This linear solver is from Squish.
for (uint i = 0; i < p.m_num_pixels; ++i) {
uint8 c = p.m_pSelectors[i];
double k;
if (p.m_dxt1_selectors)
k = g_dxt1_to_linear[c] * 1.0f/3.0f;
else
k = g_dxt5_to_linear[c] * 1.0f/7.0f;
double k;
if (p.m_dxt1_selectors)
k = g_dxt1_to_linear[c] * 1.0f / 3.0f;
else
k = g_dxt5_to_linear[c] * 1.0f / 7.0f;
double alpha = 1.0f - k;
double beta = k;
double alpha = 1.0f - k;
double beta = k;
vec<3, double> x;
vec<3, double> x;
if (p.m_dxt1_selectors)
x.set( p.m_pPixels[i][0] * 1.0f/255.0f, p.m_pPixels[i][1] * 1.0f/255.0f, p.m_pPixels[i][2] * 1.0f/255.0f );
else
x.set( p.m_pPixels[i][p.m_alpha_comp_index]/255.0f );
if (p.m_dxt1_selectors)
x.set(p.m_pPixels[i][0] * 1.0f / 255.0f, p.m_pPixels[i][1] * 1.0f / 255.0f, p.m_pPixels[i][2] * 1.0f / 255.0f);
else
x.set(p.m_pPixels[i][p.m_alpha_comp_index] / 255.0f);
if (!i)
first_color = x;
if (!i)
first_color = x;
alpha2_sum += alpha*alpha;
beta2_sum += beta*beta;
alphabeta_sum += alpha*beta;
alphax_sum += alpha*x;
betax_sum += beta*x;
}
alpha2_sum += alpha * alpha;
beta2_sum += beta * beta;
alphabeta_sum += alpha * beta;
alphax_sum += alpha * x;
betax_sum += beta * x;
}
// zero where non-determinate
vec<3, double> a, b;
if( beta2_sum == 0.0f )
{
a = alphax_sum / alpha2_sum;
b.clear();
}
else if( alpha2_sum == 0.0f )
{
a.clear();
b = betax_sum / beta2_sum;
}
else
{
double factor = alpha2_sum*beta2_sum - alphabeta_sum*alphabeta_sum;
if (factor != 0.0f)
{
a = ( alphax_sum*beta2_sum - betax_sum*alphabeta_sum ) / factor;
b = ( betax_sum*alpha2_sum - alphax_sum*alphabeta_sum ) / factor;
}
else
{
a = first_color;
b = first_color;
}
}
// zero where non-determinate
vec<3, double> a, b;
if (beta2_sum == 0.0f) {
a = alphax_sum / alpha2_sum;
b.clear();
} else if (alpha2_sum == 0.0f) {
a.clear();
b = betax_sum / beta2_sum;
} else {
double factor = alpha2_sum * beta2_sum - alphabeta_sum * alphabeta_sum;
if (factor != 0.0f) {
a = (alphax_sum * beta2_sum - betax_sum * alphabeta_sum) / factor;
b = (betax_sum * alpha2_sum - alphax_sum * alphabeta_sum) / factor;
} else {
a = first_color;
b = first_color;
}
}
vec3F l(0.0f), h(0.0f);
l = a;
h = b;
vec3F l(0.0f), h(0.0f);
l = a;
h = b;
l.clamp(0.0f, 1.0f);
h.clamp(0.0f, 1.0f);
l.clamp(0.0f, 1.0f);
h.clamp(0.0f, 1.0f);
if (p.m_dxt1_selectors)
optimize_dxt1(l, h);
else
optimize_dxt5(l, h);
if (p.m_dxt1_selectors)
optimize_dxt1(l, h);
else
optimize_dxt5(l, h);
//if (r.m_low_color < r.m_high_color)
// utils::swap(r.m_low_color, r.m_high_color);
//if (r.m_low_color < r.m_high_color)
// utils::swap(r.m_low_color, r.m_high_color);
return r.m_error < p.m_error_to_beat;
}
return r.m_error < p.m_error_to_beat;
}
void dxt_endpoint_refiner::optimize_dxt5(vec3F low_color, vec3F high_color)
{
float nl = low_color[0];
float nh = high_color[0];
void dxt_endpoint_refiner::optimize_dxt5(vec3F low_color, vec3F high_color) {
float nl = low_color[0];
float nh = high_color[0];
#if CRNLIB_DXT_ALT_ROUNDING
nl = math::clamp(nl, 0.0f, .999f);
nh = math::clamp(nh, 0.0f, .999f);
uint il = (int)floor(nl * 256.0f);
uint ih = (int)floor(nh * 256.0f);
nl = math::clamp(nl, 0.0f, .999f);
nh = math::clamp(nh, 0.0f, .999f);
uint il = (int)floor(nl * 256.0f);
uint ih = (int)floor(nh * 256.0f);
#else
uint il = (int)floor(.5f + math::clamp(nl, 0.0f, 1.0f) * 255.0f);
uint ih = (int)floor(.5f + math::clamp(nh, 0.0f, 1.0f) * 255.0f);
uint il = (int)floor(.5f + math::clamp(nl, 0.0f, 1.0f) * 255.0f);
uint ih = (int)floor(.5f + math::clamp(nh, 0.0f, 1.0f) * 255.0f);
#endif
crnlib::vector<uint> trial_solutions;
trial_solutions.reserve(256);
trial_solutions.push_back(il | (ih << 8));
crnlib::vector<uint> trial_solutions;
trial_solutions.reserve(256);
trial_solutions.push_back(il | (ih << 8));
sparse_bit_array flags;
flags.resize(256 * 256);
sparse_bit_array flags;
flags.resize(256 * 256);
flags.set_bit((il * 256) + ih);
flags.set_bit((il * 256) + ih);
const int cProbeAmount = 11;
const int cProbeAmount = 11;
for (int l_delta = -cProbeAmount; l_delta <= cProbeAmount; l_delta++)
{
const int l = il + l_delta;
if (l < 0)
continue;
else if (l > 255)
break;
for (int l_delta = -cProbeAmount; l_delta <= cProbeAmount; l_delta++) {
const int l = il + l_delta;
if (l < 0)
continue;
else if (l > 255)
break;
const uint bit_index = l * 256;
const uint bit_index = l * 256;
for (int h_delta = -cProbeAmount; h_delta <= cProbeAmount; h_delta++)
{
const int h = ih + h_delta;
if (h < 0)
continue;
else if (h > 255)
break;
for (int h_delta = -cProbeAmount; h_delta <= cProbeAmount; h_delta++) {
const int h = ih + h_delta;
if (h < 0)
continue;
else if (h > 255)
break;
if ((flags.get_bit(bit_index + h)) || (flags.get_bit(h * 256 + l)))
continue;
if ((flags.get_bit(bit_index + h)) || (flags.get_bit(h * 256 + l)))
continue;
flags.set_bit(bit_index + h);
flags.set_bit(bit_index + h);
trial_solutions.push_back(l | (h << 8));
}
trial_solutions.push_back(l | (h << 8));
}
}
for (uint trial = 0; trial < trial_solutions.size(); trial++) {
uint l = trial_solutions[trial] & 0xFF;
uint h = trial_solutions[trial] >> 8;
if (l == h) {
if (h)
h--;
else
l++;
} else if (l < h) {
utils::swap(l, h);
}
CRNLIB_ASSERT(l > h);
uint values[cDXT5SelectorValues];
dxt5_block::get_block_values8(values, l, h);
uint total_error = 0;
for (uint j = 0; j < m_pParams->m_num_pixels; j++) {
int p = m_pParams->m_pPixels[j][m_pParams->m_alpha_comp_index];
int c = values[m_pParams->m_pSelectors[j]];
int error = p - c;
error *= error;
total_error += error;
if (total_error > m_pResults->m_error)
break;
}
if (total_error < m_pResults->m_error) {
m_pResults->m_error = total_error;
m_pResults->m_low_color = static_cast<uint16>(l);
m_pResults->m_high_color = static_cast<uint16>(h);
if (m_pResults->m_error == 0)
return;
}
}
}
void dxt_endpoint_refiner::optimize_dxt1(vec3F low_color, vec3F high_color) {
uint selector_hist[4];
utils::zero_object(selector_hist);
for (uint i = 0; i < m_pParams->m_num_pixels; i++)
selector_hist[m_pParams->m_pSelectors[i]]++;
dxt1_solution_coordinates c(low_color, high_color);
for (uint pass = 0; pass < 8; pass++) {
const uint64 initial_error = m_pResults->m_error;
dxt1_solution_coordinates_vec coords_to_try;
coords_to_try.resize(0);
color_quad_u8 lc(dxt1_block::unpack_color(c.m_low_color, false));
color_quad_u8 hc(dxt1_block::unpack_color(c.m_high_color, false));
for (int i = 0; i < 27; i++) {
if (13 == i)
continue;
const int ir = (i % 3) - 1;
const int ig = ((i / 3) % 3) - 1;
const int ib = ((i / 9) % 3) - 1;
int r = lc.r + ir;
int g = lc.g + ig;
int b = lc.b + ib;
if ((r < 0) || (r > 31) || (g < 0) || (g > 63) || (b < 0) || (b > 31))
continue;
coords_to_try.push_back(
dxt1_solution_coordinates(dxt1_block::pack_color(r, g, b, false), c.m_high_color));
}
for (int i = 0; i < 27; i++) {
if (13 == i)
continue;
const int ir = (i % 3) - 1;
const int ig = ((i / 3) % 3) - 1;
const int ib = ((i / 9) % 3) - 1;
int r = hc.r + ir;
int g = hc.g + ig;
int b = hc.b + ib;
if ((r < 0) || (r > 31) || (g < 0) || (g > 63) || (b < 0) || (b > 31))
continue;
coords_to_try.push_back(dxt1_solution_coordinates(c.m_low_color, dxt1_block::pack_color(r, g, b, false)));
}
std::sort(coords_to_try.begin(), coords_to_try.end());
dxt1_solution_coordinates_vec::const_iterator p_last = std::unique(coords_to_try.begin(), coords_to_try.end());
uint num_coords_to_try = (uint)(p_last - coords_to_try.begin());
for (uint i = 0; i < num_coords_to_try; i++) {
color_quad_u8 block_colors[4];
uint16 l = coords_to_try[i].m_low_color;
uint16 h = coords_to_try[i].m_high_color;
if (l < h)
utils::swap(l, h);
else if (l == h) {
color_quad_u8 lc(dxt1_block::unpack_color(l, false));
color_quad_u8 hc(dxt1_block::unpack_color(h, false));
bool retry = false;
if ((selector_hist[0] + selector_hist[2]) > (selector_hist[1] + selector_hist[3])) {
// l affects the output more than h, so muck with h
if (hc[2] != 0)
hc[2]--;
else if (hc[0] != 0)
hc[0]--;
else if (hc[1] != 0)
hc[1]--;
else
retry = true;
} else {
// h affects the output more than l, so muck with l
if (lc[2] != 31)
lc[2]++;
else if (lc[0] != 31)
lc[0]++;
else if (lc[1] != 63)
lc[1]++;
else
retry = true;
}
if (retry) {
if (l == 0)
l++;
else
h--;
} else {
l = dxt1_block::pack_color(lc, false);
h = dxt1_block::pack_color(hc, false);
}
CRNLIB_ASSERT(l > h);
}
for (uint trial = 0; trial < trial_solutions.size(); trial++)
{
uint l = trial_solutions[trial] & 0xFF;
uint h = trial_solutions[trial] >> 8;
dxt1_block::get_block_colors4(block_colors, l, h);
if (l == h)
{
if (h)
h--;
else
l++;
}
else if (l < h)
{
utils::swap(l, h);
}
uint total_error = 0;
CRNLIB_ASSERT(l > h);
for (uint j = 0; j < m_pParams->m_num_pixels; j++) {
const color_quad_u8& c = block_colors[m_pParams->m_pSelectors[j]];
total_error += color::color_distance(m_pParams->m_perceptual, c, m_pParams->m_pPixels[j], false);
uint values[cDXT5SelectorValues];
dxt5_block::get_block_values8(values, l, h);
uint total_error = 0;
for (uint j = 0; j < m_pParams->m_num_pixels; j++)
{
int p = m_pParams->m_pPixels[j][m_pParams->m_alpha_comp_index];
int c = values[m_pParams->m_pSelectors[j]];
int error = p - c;
error *= error;
total_error += error;
if (total_error > m_pResults->m_error)
break;
}
if (total_error < m_pResults->m_error)
{
m_pResults->m_error = total_error;
m_pResults->m_low_color = static_cast<uint16>(l);
m_pResults->m_high_color = static_cast<uint16>(h);
if (m_pResults->m_error == 0)
return;
}
}
}
void dxt_endpoint_refiner::optimize_dxt1(vec3F low_color, vec3F high_color)
{
uint selector_hist[4];
utils::zero_object(selector_hist);
for (uint i = 0; i < m_pParams->m_num_pixels; i++)
selector_hist[m_pParams->m_pSelectors[i]]++;
dxt1_solution_coordinates c(low_color, high_color);
for (uint pass = 0; pass < 8; pass++)
{
const uint64 initial_error = m_pResults->m_error;
dxt1_solution_coordinates_vec coords_to_try;
coords_to_try.resize(0);
color_quad_u8 lc(dxt1_block::unpack_color(c.m_low_color, false));
color_quad_u8 hc(dxt1_block::unpack_color(c.m_high_color, false));
for (int i = 0; i < 27; i++)
{
if (13 == i) continue;
const int ir = (i % 3) - 1;
const int ig = ((i / 3) % 3) - 1;
const int ib = ((i / 9) % 3) - 1;
int r = lc.r + ir;
int g = lc.g + ig;
int b = lc.b + ib;
if ((r < 0) || (r > 31)|| (g < 0) || (g > 63) || (b < 0) || (b > 31)) continue;
coords_to_try.push_back(
dxt1_solution_coordinates(dxt1_block::pack_color(r, g, b, false), c.m_high_color)
);
}
for (int i = 0; i < 27; i++)
{
if (13 == i) continue;
const int ir = (i % 3) - 1;
const int ig = ((i / 3) % 3) - 1;
const int ib = ((i / 9) % 3) - 1;
int r = hc.r + ir;
int g = hc.g + ig;
int b = hc.b + ib;
if ((r < 0) || (r > 31)|| (g < 0) || (g > 63) || (b < 0) || (b > 31)) continue;
coords_to_try.push_back(dxt1_solution_coordinates(c.m_low_color, dxt1_block::pack_color(r, g, b, false)));
}
std::sort(coords_to_try.begin(), coords_to_try.end());
dxt1_solution_coordinates_vec::const_iterator p_last = std::unique(coords_to_try.begin(), coords_to_try.end());
uint num_coords_to_try = (uint)(p_last - coords_to_try.begin());
for (uint i = 0; i < num_coords_to_try; i++)
{
color_quad_u8 block_colors[4];
uint16 l = coords_to_try[i].m_low_color;
uint16 h = coords_to_try[i].m_high_color;
if (l < h)
utils::swap(l, h);
else if (l == h)
{
color_quad_u8 lc(dxt1_block::unpack_color(l, false));
color_quad_u8 hc(dxt1_block::unpack_color(h, false));
bool retry = false;
if ((selector_hist[0] + selector_hist[2]) > (selector_hist[1] + selector_hist[3]))
{
// l affects the output more than h, so muck with h
if (hc[2] != 0)
hc[2]--;
else if (hc[0] != 0)
hc[0]--;
else if (hc[1] != 0)
hc[1]--;
else
retry = true;
}
else
{
// h affects the output more than l, so muck with l
if (lc[2] != 31)
lc[2]++;
else if (lc[0] != 31)
lc[0]++;
else if (lc[1] != 63)
lc[1]++;
else
retry = true;
}
if (retry)
{
if (l == 0)
l++;
else
h--;
}
else
{
l = dxt1_block::pack_color(lc, false);
h = dxt1_block::pack_color(hc, false);
}
CRNLIB_ASSERT(l > h);
}
dxt1_block::get_block_colors4(block_colors, l, h);
uint total_error = 0;
for (uint j = 0; j < m_pParams->m_num_pixels; j++)
{
const color_quad_u8& c = block_colors[m_pParams->m_pSelectors[j]];
total_error += color::color_distance(m_pParams->m_perceptual, c, m_pParams->m_pPixels[j], false);
if (total_error > m_pResults->m_error)
break;
}
if (total_error < m_pResults->m_error)
{
m_pResults->m_error = total_error;
m_pResults->m_low_color = l;
m_pResults->m_high_color = h;
CRNLIB_ASSERT(l > h);
if (m_pResults->m_error == 0)
return;
}
}
if (m_pResults->m_error == initial_error)
break;
c.m_low_color = m_pResults->m_low_color;
c.m_high_color = m_pResults->m_high_color;
if (total_error > m_pResults->m_error)
break;
}
}
if (total_error < m_pResults->m_error) {
m_pResults->m_error = total_error;
m_pResults->m_low_color = l;
m_pResults->m_high_color = h;
CRNLIB_ASSERT(l > h);
if (m_pResults->m_error == 0)
return;
}
}
} // namespace crnlib
if (m_pResults->m_error == initial_error)
break;
c.m_low_color = m_pResults->m_low_color;
c.m_high_color = m_pResults->m_high_color;
}
}
} // namespace crnlib
+40 -45
View File
@@ -3,60 +3,55 @@
#pragma once
#include "crn_dxt.h"
namespace crnlib
{
// TODO: Experimental/Not fully implemented
class dxt_endpoint_refiner
{
public:
dxt_endpoint_refiner();
namespace crnlib {
// TODO: Experimental/Not fully implemented
class dxt_endpoint_refiner {
public:
dxt_endpoint_refiner();
struct params
{
params() :
m_block_index(0),
m_pPixels(NULL),
m_num_pixels(0),
m_pSelectors(NULL),
m_alpha_comp_index(0),
m_error_to_beat(cUINT64_MAX),
m_dxt1_selectors(true),
m_perceptual(true),
m_highest_quality(true)
{
}
struct params {
params()
: m_block_index(0),
m_pPixels(NULL),
m_num_pixels(0),
m_pSelectors(NULL),
m_alpha_comp_index(0),
m_error_to_beat(cUINT64_MAX),
m_dxt1_selectors(true),
m_perceptual(true),
m_highest_quality(true) {
}
uint m_block_index;
uint m_block_index;
const color_quad_u8* m_pPixels;
uint m_num_pixels;
const color_quad_u8* m_pPixels;
uint m_num_pixels;
const uint8* m_pSelectors;
const uint8* m_pSelectors;
uint m_alpha_comp_index;
uint m_alpha_comp_index;
uint64 m_error_to_beat;
uint64 m_error_to_beat;
bool m_dxt1_selectors;
bool m_perceptual;
bool m_highest_quality;
};
bool m_dxt1_selectors;
bool m_perceptual;
bool m_highest_quality;
};
struct results
{
uint16 m_low_color;
uint16 m_high_color;
uint64 m_error;
};
struct results {
uint16 m_low_color;
uint16 m_high_color;
uint64 m_error;
};
bool refine(const params& p, results& r);
bool refine(const params& p, results& r);
private:
const params* m_pParams;
results* m_pResults;
private:
const params* m_pParams;
results* m_pResults;
void optimize_dxt1(vec3F low_color, vec3F high_color);
void optimize_dxt5(vec3F low_color, vec3F high_color);
};
void optimize_dxt1(vec3F low_color, vec3F high_color);
void optimize_dxt5(vec3F low_color, vec3F high_color);
};
} // namespace crnlib
} // namespace crnlib
+773 -853
View File
File diff suppressed because it is too large Load Diff
+12 -14
View File
@@ -4,18 +4,16 @@
#include "crn_color.h"
#include "crn_dxt.h"
namespace crnlib
{
namespace dxt_fast
{
void compress_color_block(uint n, const color_quad_u8* block, uint& low16, uint& high16, uint8* pSelectors, bool refine = false);
void compress_color_block(dxt1_block* pDXT1_block, const color_quad_u8* pBlock, bool refine = false);
void compress_alpha_block(uint n, const color_quad_u8* block, uint& low8, uint& high8, uint8* pSelectors, uint comp_index);
void compress_alpha_block(dxt5_block* pDXT5_block, const color_quad_u8* pBlock, uint comp_index);
void find_representative_colors(uint n, const color_quad_u8* pBlock, color_quad_u8& lo, color_quad_u8& hi);
} // namespace dxt_fast
namespace crnlib {
namespace dxt_fast {
void compress_color_block(uint n, const color_quad_u8* block, uint& low16, uint& high16, uint8* pSelectors, bool refine = false);
void compress_color_block(dxt1_block* pDXT1_block, const color_quad_u8* pBlock, bool refine = false);
} // namespace crnlib
void compress_alpha_block(uint n, const color_quad_u8* block, uint& low8, uint& high8, uint8* pSelectors, uint comp_index);
void compress_alpha_block(dxt5_block* pDXT5_block, const color_quad_u8* pBlock, uint comp_index);
void find_representative_colors(uint n, const color_quad_u8* pBlock, color_quad_u8& lo, color_quad_u8& hi);
} // namespace dxt_fast
} // namespace crnlib
+2003 -2259
View File
File diff suppressed because it is too large Load Diff
+358 -370
View File
@@ -14,426 +14,414 @@
#define CRN_NO_FUNCTION_DEFINITIONS
#include "../inc/crnlib.h"
namespace crnlib
{
const uint cTotalCompressionPhases = 25;
class dxt_hc
{
public:
dxt_hc();
~dxt_hc();
struct pixel_chunk
{
pixel_chunk() { clear(); }
dxt_pixel_block m_blocks[cChunkBlockHeight][cChunkBlockWidth];
const color_quad_u8& operator() (uint cx, uint cy) const
{
CRNLIB_ASSERT((cx < cChunkPixelWidth) && (cy < cChunkPixelHeight));
return m_blocks[cy >> cBlockPixelHeightShift][cx >> cBlockPixelWidthShift].m_pixels
[cy & (cBlockPixelHeight - 1)][cx & (cBlockPixelWidth - 1)];
}
color_quad_u8& operator() (uint cx, uint cy)
{
CRNLIB_ASSERT((cx < cChunkPixelWidth) && (cy < cChunkPixelHeight));
return m_blocks[cy >> cBlockPixelHeightShift][cx >> cBlockPixelWidthShift].m_pixels
[cy & (cBlockPixelHeight - 1)][cx & (cBlockPixelWidth - 1)];
}
inline void clear()
{
utils::zero_object(*this);
m_weight = 1.0f;
}
float m_weight;
};
typedef crnlib::vector<pixel_chunk> pixel_chunk_vec;
struct params
{
params() :
m_color_endpoint_codebook_size(3072),
m_color_selector_codebook_size(3072),
m_alpha_endpoint_codebook_size(3072),
m_alpha_selector_codebook_size(3072),
m_adaptive_tile_color_psnr_derating(2.0f), // was 3.4f
m_adaptive_tile_alpha_psnr_derating(2.0f),
m_adaptive_tile_color_alpha_weighting_ratio(3.0f),
m_num_levels(0),
m_format(cDXT1),
m_hierarchical(true),
m_perceptual(true),
m_debugging(false),
m_pProgress_func(NULL),
m_pProgress_func_data(NULL)
{
m_alpha_component_indices[0] = 3;
m_alpha_component_indices[1] = 0;
for (uint i = 0; i < cCRNMaxLevels; i++)
{
m_levels[i].m_first_chunk = 0;
m_levels[i].m_num_chunks = 0;
}
}
// Valid range for codebook sizes: [32,8192] (non-power of two values are okay)
uint m_color_endpoint_codebook_size;
uint m_color_selector_codebook_size;
uint m_alpha_endpoint_codebook_size;
uint m_alpha_selector_codebook_size;
// Higher values cause fewer 8x4, 4x8, and 4x4 blocks to be utilized less often (lower quality/smaller files).
// Lower values cause the encoder to use large tiles less often (better quality/larger files).
// Valid range: [0.0,100.0].
// A value of 0 will cause the encoder to only use tiles larger than 4x4 if doing so would incur to quality loss.
float m_adaptive_tile_color_psnr_derating;
float m_adaptive_tile_alpha_psnr_derating;
float m_adaptive_tile_color_alpha_weighting_ratio;
uint m_alpha_component_indices[2];
struct miplevel_desc
{
uint m_first_chunk;
uint m_num_chunks;
};
// The mip level data is optional!
miplevel_desc m_levels[cCRNMaxLevels];
uint m_num_levels;
dxt_format m_format;
// If m_hierarchical is false, only 4x4 blocks will be used by the encoder (leading to higher quality/larger files).
bool m_hierarchical;
// If m_perceptual is true, perceptual color metrics will be used by the encoder.
bool m_perceptual;
bool m_debugging;
crn_progress_callback_func m_pProgress_func;
void* m_pProgress_func_data;
};
void clear();
// Main compression function
bool compress(const params& p, uint num_chunks, const pixel_chunk* pChunks, task_pool& task_pool);
// Output accessors
inline uint get_num_chunks() const { return m_num_chunks; }
struct chunk_encoding
{
chunk_encoding() { utils::zero_object(*this); };
// Index into g_chunk_encodings.
uint8 m_encoding_index;
// Number of tiles, endpoint indices.
uint8 m_num_tiles;
// Color, alpha0, alpha1
enum { cColorIndex = 0, cAlpha0Index = 1, cAlpha1Index = 2 };
uint16 m_endpoint_indices[3][cChunkMaxTiles];
uint16 m_selector_indices[3][cChunkBlockHeight][cChunkBlockWidth]; // [block_y][block_x]
};
namespace crnlib {
const uint cTotalCompressionPhases = 25;
typedef crnlib::vector<chunk_encoding> chunk_encoding_vec;
class dxt_hc {
public:
dxt_hc();
~dxt_hc();
inline const chunk_encoding& get_chunk_encoding(uint chunk_index) const { return m_chunk_encoding[chunk_index]; }
inline const chunk_encoding_vec& get_chunk_encoding_vec() const { return m_chunk_encoding; }
struct pixel_chunk {
pixel_chunk() { clear(); }
struct selectors
{
selectors() { utils::zero_object(*this); }
dxt_pixel_block m_blocks[cChunkBlockHeight][cChunkBlockWidth];
uint8 m_selectors[cBlockPixelHeight][cBlockPixelWidth];
const color_quad_u8& operator()(uint cx, uint cy) const {
CRNLIB_ASSERT((cx < cChunkPixelWidth) && (cy < cChunkPixelHeight));
uint8 get_by_index(uint i) const { CRNLIB_ASSERT(i < (cBlockPixelWidth * cBlockPixelHeight)); const uint8* p = (const uint8*)m_selectors; return *(p + i); }
void set_by_index(uint i, uint v) { CRNLIB_ASSERT(i < (cBlockPixelWidth * cBlockPixelHeight)); uint8* p = (uint8*)m_selectors; *(p + i) = static_cast<uint8>(v); }
};
typedef crnlib::vector<selectors> selectors_vec;
return m_blocks[cy >> cBlockPixelHeightShift][cx >> cBlockPixelWidthShift].m_pixels
[cy & (cBlockPixelHeight - 1)][cx & (cBlockPixelWidth - 1)];
}
// Color endpoints
inline uint get_color_endpoint_codebook_size() const { return m_color_endpoints.size(); }
inline uint get_color_endpoint(uint codebook_index) const { return m_color_endpoints[codebook_index]; }
const crnlib::vector<uint>& get_color_endpoint_vec() const { return m_color_endpoints; }
color_quad_u8& operator()(uint cx, uint cy) {
CRNLIB_ASSERT((cx < cChunkPixelWidth) && (cy < cChunkPixelHeight));
// Color selectors
uint get_color_selector_codebook_size() const { return m_color_selectors.size(); }
const selectors& get_color_selectors(uint codebook_index) const { return m_color_selectors[codebook_index]; }
const crnlib::vector<selectors>& get_color_selectors_vec() const { return m_color_selectors; }
return m_blocks[cy >> cBlockPixelHeightShift][cx >> cBlockPixelWidthShift].m_pixels
[cy & (cBlockPixelHeight - 1)][cx & (cBlockPixelWidth - 1)];
}
// Alpha endpoints
inline uint get_alpha_endpoint_codebook_size() const { return m_alpha_endpoints.size(); }
inline uint get_alpha_endpoint(uint codebook_index) const { return m_alpha_endpoints[codebook_index]; }
const crnlib::vector<uint>& get_alpha_endpoint_vec() const { return m_alpha_endpoints; }
inline void clear() {
utils::zero_object(*this);
m_weight = 1.0f;
}
// Alpha selectors
uint get_alpha_selector_codebook_size() const { return m_alpha_selectors.size(); }
const selectors& get_alpha_selectors(uint codebook_index) const { return m_alpha_selectors[codebook_index]; }
const crnlib::vector<selectors>& get_alpha_selectors_vec() const { return m_alpha_selectors; }
float m_weight;
};
// Debug images
const pixel_chunk_vec& get_compressed_chunk_pixels() const { return m_dbg_chunk_pixels; }
const pixel_chunk_vec& get_compressed_chunk_pixels_tile_vis() const { return m_dbg_chunk_pixels_tile_vis; }
const pixel_chunk_vec& get_compressed_chunk_pixels_color_quantized() const { return m_dbg_chunk_pixels_color_quantized; }
const pixel_chunk_vec& get_compressed_chunk_pixels_alpha_quantized() const { return m_dbg_chunk_pixels_alpha_quantized; }
const pixel_chunk_vec& get_compressed_chunk_pixels_final() const { return m_dbg_chunk_pixels_final; }
typedef crnlib::vector<pixel_chunk> pixel_chunk_vec;
const pixel_chunk_vec& get_compressed_chunk_pixels_orig_color_selectors() const { return m_dbg_chunk_pixels_orig_color_selectors; }
const pixel_chunk_vec& get_compressed_chunk_pixels_quantized_color_selectors() const { return m_dbg_chunk_pixels_quantized_color_selectors; }
const pixel_chunk_vec& get_compressed_chunk_pixels_final_color_selectors() const { return m_dbg_chunk_pixels_final_color_selectors; }
struct params {
params()
: m_color_endpoint_codebook_size(3072),
m_color_selector_codebook_size(3072),
m_alpha_endpoint_codebook_size(3072),
m_alpha_selector_codebook_size(3072),
m_adaptive_tile_color_psnr_derating(2.0f), // was 3.4f
m_adaptive_tile_alpha_psnr_derating(2.0f),
m_adaptive_tile_color_alpha_weighting_ratio(3.0f),
m_num_levels(0),
m_format(cDXT1),
m_hierarchical(true),
m_perceptual(true),
m_debugging(false),
m_pProgress_func(NULL),
m_pProgress_func_data(NULL) {
m_alpha_component_indices[0] = 3;
m_alpha_component_indices[1] = 0;
for (uint i = 0; i < cCRNMaxLevels; i++) {
m_levels[i].m_first_chunk = 0;
m_levels[i].m_num_chunks = 0;
}
}
// Valid range for codebook sizes: [32,8192] (non-power of two values are okay)
uint m_color_endpoint_codebook_size;
uint m_color_selector_codebook_size;
uint m_alpha_endpoint_codebook_size;
uint m_alpha_selector_codebook_size;
// Higher values cause fewer 8x4, 4x8, and 4x4 blocks to be utilized less often (lower quality/smaller files).
// Lower values cause the encoder to use large tiles less often (better quality/larger files).
// Valid range: [0.0,100.0].
// A value of 0 will cause the encoder to only use tiles larger than 4x4 if doing so would incur to quality loss.
float m_adaptive_tile_color_psnr_derating;
float m_adaptive_tile_alpha_psnr_derating;
float m_adaptive_tile_color_alpha_weighting_ratio;
uint m_alpha_component_indices[2];
struct miplevel_desc {
uint m_first_chunk;
uint m_num_chunks;
};
// The mip level data is optional!
miplevel_desc m_levels[cCRNMaxLevels];
uint m_num_levels;
dxt_format m_format;
// If m_hierarchical is false, only 4x4 blocks will be used by the encoder (leading to higher quality/larger files).
bool m_hierarchical;
// If m_perceptual is true, perceptual color metrics will be used by the encoder.
bool m_perceptual;
bool m_debugging;
crn_progress_callback_func m_pProgress_func;
void* m_pProgress_func_data;
};
void clear();
// Main compression function
bool compress(const params& p, uint num_chunks, const pixel_chunk* pChunks, task_pool& task_pool);
const pixel_chunk_vec& get_compressed_chunk_pixels_orig_alpha_selectors() const { return m_dbg_chunk_pixels_orig_alpha_selectors; }
const pixel_chunk_vec& get_compressed_chunk_pixels_quantized_alpha_selectors() const { return m_dbg_chunk_pixels_quantized_alpha_selectors; }
const pixel_chunk_vec& get_compressed_chunk_pixels_final_alpha_selectors() const { return m_dbg_chunk_pixels_final_alpha_selectors; }
// Output accessors
inline uint get_num_chunks() const { return m_num_chunks; }
struct chunk_encoding {
chunk_encoding() { utils::zero_object(*this); };
// Index into g_chunk_encodings.
uint8 m_encoding_index;
// Number of tiles, endpoint indices.
uint8 m_num_tiles;
// Color, alpha0, alpha1
enum { cColorIndex = 0,
cAlpha0Index = 1,
cAlpha1Index = 2 };
uint16 m_endpoint_indices[3][cChunkMaxTiles];
uint16 m_selector_indices[3][cChunkBlockHeight][cChunkBlockWidth]; // [block_y][block_x]
};
typedef crnlib::vector<chunk_encoding> chunk_encoding_vec;
inline const chunk_encoding& get_chunk_encoding(uint chunk_index) const { return m_chunk_encoding[chunk_index]; }
inline const chunk_encoding_vec& get_chunk_encoding_vec() const { return m_chunk_encoding; }
static void create_debug_image_from_chunks(uint num_chunks_x, uint num_chunks_y, const pixel_chunk_vec& chunks, const chunk_encoding_vec *pChunk_encodings, image_u8& img, bool serpentine_scan, int comp_index = -1);
struct selectors {
selectors() { utils::zero_object(*this); }
private:
params m_params;
uint8 m_selectors[cBlockPixelHeight][cBlockPixelWidth];
uint8 get_by_index(uint i) const {
CRNLIB_ASSERT(i < (cBlockPixelWidth * cBlockPixelHeight));
const uint8* p = (const uint8*)m_selectors;
return *(p + i);
}
void set_by_index(uint i, uint v) {
CRNLIB_ASSERT(i < (cBlockPixelWidth * cBlockPixelHeight));
uint8* p = (uint8*)m_selectors;
*(p + i) = static_cast<uint8>(v);
}
};
typedef crnlib::vector<selectors> selectors_vec;
uint m_num_chunks;
const pixel_chunk* m_pChunks;
// Color endpoints
inline uint get_color_endpoint_codebook_size() const { return m_color_endpoints.size(); }
inline uint get_color_endpoint(uint codebook_index) const { return m_color_endpoints[codebook_index]; }
const crnlib::vector<uint>& get_color_endpoint_vec() const { return m_color_endpoints; }
chunk_encoding_vec m_chunk_encoding;
// Color selectors
uint get_color_selector_codebook_size() const { return m_color_selectors.size(); }
const selectors& get_color_selectors(uint codebook_index) const { return m_color_selectors[codebook_index]; }
const crnlib::vector<selectors>& get_color_selectors_vec() const { return m_color_selectors; }
uint m_num_alpha_blocks; // 0, 1, or 2
bool m_has_color_blocks;
bool m_has_alpha0_blocks;
bool m_has_alpha1_blocks;
// Alpha endpoints
inline uint get_alpha_endpoint_codebook_size() const { return m_alpha_endpoints.size(); }
inline uint get_alpha_endpoint(uint codebook_index) const { return m_alpha_endpoints[codebook_index]; }
const crnlib::vector<uint>& get_alpha_endpoint_vec() const { return m_alpha_endpoints; }
struct compressed_tile
{
uint m_endpoint_cluster_index;
uint m_first_endpoint;
uint m_second_endpoint;
// Alpha selectors
uint get_alpha_selector_codebook_size() const { return m_alpha_selectors.size(); }
const selectors& get_alpha_selectors(uint codebook_index) const { return m_alpha_selectors[codebook_index]; }
const crnlib::vector<selectors>& get_alpha_selectors_vec() const { return m_alpha_selectors; }
uint8 m_selectors[cChunkPixelWidth * cChunkPixelHeight];
// Debug images
const pixel_chunk_vec& get_compressed_chunk_pixels() const { return m_dbg_chunk_pixels; }
const pixel_chunk_vec& get_compressed_chunk_pixels_tile_vis() const { return m_dbg_chunk_pixels_tile_vis; }
const pixel_chunk_vec& get_compressed_chunk_pixels_color_quantized() const { return m_dbg_chunk_pixels_color_quantized; }
const pixel_chunk_vec& get_compressed_chunk_pixels_alpha_quantized() const { return m_dbg_chunk_pixels_alpha_quantized; }
const pixel_chunk_vec& get_compressed_chunk_pixels_final() const { return m_dbg_chunk_pixels_final; }
void set_selector(uint x, uint y, uint s)
{
CRNLIB_ASSERT((x < m_pixel_width) && (y < m_pixel_height));
m_selectors[x + y * m_pixel_width] = static_cast<uint8>(s);
}
const pixel_chunk_vec& get_compressed_chunk_pixels_orig_color_selectors() const { return m_dbg_chunk_pixels_orig_color_selectors; }
const pixel_chunk_vec& get_compressed_chunk_pixels_quantized_color_selectors() const { return m_dbg_chunk_pixels_quantized_color_selectors; }
const pixel_chunk_vec& get_compressed_chunk_pixels_final_color_selectors() const { return m_dbg_chunk_pixels_final_color_selectors; }
uint get_selector(uint x, uint y) const
{
CRNLIB_ASSERT((x < m_pixel_width) && (y < m_pixel_height));
return m_selectors[x + y * m_pixel_width];
}
const pixel_chunk_vec& get_compressed_chunk_pixels_orig_alpha_selectors() const { return m_dbg_chunk_pixels_orig_alpha_selectors; }
const pixel_chunk_vec& get_compressed_chunk_pixels_quantized_alpha_selectors() const { return m_dbg_chunk_pixels_quantized_alpha_selectors; }
const pixel_chunk_vec& get_compressed_chunk_pixels_final_alpha_selectors() const { return m_dbg_chunk_pixels_final_alpha_selectors; }
uint8 m_pixel_width;
uint8 m_pixel_height;
static void create_debug_image_from_chunks(uint num_chunks_x, uint num_chunks_y, const pixel_chunk_vec& chunks, const chunk_encoding_vec* pChunk_encodings, image_u8& img, bool serpentine_scan, int comp_index = -1);
uint8 m_layout_index;
private:
params m_params;
bool m_alpha_encoding;
};
uint m_num_chunks;
const pixel_chunk* m_pChunks;
struct compressed_chunk
{
compressed_chunk() { utils::zero_object(*this); }
chunk_encoding_vec m_chunk_encoding;
uint8 m_encoding_index;
uint m_num_alpha_blocks; // 0, 1, or 2
bool m_has_color_blocks;
bool m_has_alpha0_blocks;
bool m_has_alpha1_blocks;
uint8 m_num_tiles;
struct compressed_tile {
uint m_endpoint_cluster_index;
uint m_first_endpoint;
uint m_second_endpoint;
compressed_tile m_tiles[cChunkMaxTiles];
compressed_tile m_quantized_tiles[cChunkMaxTiles];
uint8 m_selectors[cChunkPixelWidth * cChunkPixelHeight];
uint16 m_endpoint_cluster_index[cChunkMaxTiles];
uint16 m_selector_cluster_index[cChunkBlockHeight][cChunkBlockWidth];
};
void set_selector(uint x, uint y, uint s) {
CRNLIB_ASSERT((x < m_pixel_width) && (y < m_pixel_height));
m_selectors[x + y * m_pixel_width] = static_cast<uint8>(s);
}
typedef crnlib::vector<compressed_chunk> compressed_chunk_vec;
enum
{
cColorChunks = 0,
cAlpha0Chunks = 1,
cAlpha1Chunks = 2,
uint get_selector(uint x, uint y) const {
CRNLIB_ASSERT((x < m_pixel_width) && (y < m_pixel_height));
return m_selectors[x + y * m_pixel_width];
}
cNumCompressedChunkVecs = 3
};
compressed_chunk_vec m_compressed_chunks[cNumCompressedChunkVecs];
uint8 m_pixel_width;
uint8 m_pixel_height;
volatile atomic32_t m_encoding_hist[cNumChunkEncodings];
uint8 m_layout_index;
atomic32_t m_total_tiles;
bool m_alpha_encoding;
};
void compress_dxt1_block(
dxt1_endpoint_optimizer::results& results,
uint chunk_index, const image_u8& chunk, uint x_ofs, uint y_ofs, uint width, uint height,
uint8* pSelectors);
struct compressed_chunk {
compressed_chunk() { utils::zero_object(*this); }
void compress_dxt5_block(
dxt5_endpoint_optimizer::results& results,
uint chunk_index, const image_u8& chunk, uint x_ofs, uint y_ofs, uint width, uint height, uint component_index,
uint8* pAlpha_selectors);
uint8 m_encoding_index;
void determine_compressed_chunks_task(uint64 data, void* pData_ptr);
bool determine_compressed_chunks();
uint8 m_num_tiles;
struct tile_cluster
{
tile_cluster() : m_first_endpoint(0), m_second_endpoint(0), m_error(0), m_alpha_encoding(false) { }
compressed_tile m_tiles[cChunkMaxTiles];
compressed_tile m_quantized_tiles[cChunkMaxTiles];
// first = chunk, second = tile
// if an alpha tile, second's upper 16 bits contains the alpha index (0 or 1)
crnlib::vector< std::pair<uint, uint> > m_tiles;
uint16 m_endpoint_cluster_index[cChunkMaxTiles];
uint16 m_selector_cluster_index[cChunkBlockHeight][cChunkBlockWidth];
};
uint m_first_endpoint;
uint m_second_endpoint;
uint64 m_error;
typedef crnlib::vector<compressed_chunk> compressed_chunk_vec;
enum {
cColorChunks = 0,
cAlpha0Chunks = 1,
cAlpha1Chunks = 2,
bool m_alpha_encoding;
};
cNumCompressedChunkVecs = 3
};
compressed_chunk_vec m_compressed_chunks[cNumCompressedChunkVecs];
typedef crnlib::vector<tile_cluster> tile_cluster_vec;
volatile atomic32_t m_encoding_hist[cNumChunkEncodings];
tile_cluster_vec m_color_clusters;
tile_cluster_vec m_alpha_clusters;
atomic32_t m_total_tiles;
selectors_vec m_color_selectors;
selectors_vec m_alpha_selectors;
void compress_dxt1_block(
dxt1_endpoint_optimizer::results& results,
uint chunk_index, const image_u8& chunk, uint x_ofs, uint y_ofs, uint width, uint height,
uint8* pSelectors);
// For each selector, this array indicates every chunk/tile/tile block that use this color selector.
struct block_id
{
block_id() { utils::zero_object(*this); }
void compress_dxt5_block(
dxt5_endpoint_optimizer::results& results,
uint chunk_index, const image_u8& chunk, uint x_ofs, uint y_ofs, uint width, uint height, uint component_index,
uint8* pAlpha_selectors);
block_id(uint chunk_index, uint alpha_index, uint tile_index, uint block_x, uint block_y) :
m_chunk_index(chunk_index), m_alpha_index((uint8)alpha_index), m_tile_index((uint8)tile_index), m_block_x((uint8)block_x), m_block_y((uint8)block_y) { }
void determine_compressed_chunks_task(uint64 data, void* pData_ptr);
bool determine_compressed_chunks();
uint m_chunk_index;
uint8 m_alpha_index;
uint8 m_tile_index;
uint8 m_block_x;
uint8 m_block_y;
};
struct tile_cluster {
tile_cluster()
: m_first_endpoint(0), m_second_endpoint(0), m_error(0), m_alpha_encoding(false) {}
typedef crnlib::vector< crnlib::vector< block_id > > chunk_blocks_using_selectors_vec;
chunk_blocks_using_selectors_vec m_chunk_blocks_using_color_selectors;
chunk_blocks_using_selectors_vec m_chunk_blocks_using_alpha_selectors; // second's upper 16 bits contain alpha index!
// first = chunk, second = tile
// if an alpha tile, second's upper 16 bits contains the alpha index (0 or 1)
crnlib::vector<std::pair<uint, uint> > m_tiles;
crnlib::vector<uint> m_color_endpoints; // not valid until end, only for user access
crnlib::vector<uint> m_alpha_endpoints; // not valid until end, only for user access
uint m_first_endpoint;
uint m_second_endpoint;
uint64 m_error;
// Debugging
pixel_chunk_vec m_dbg_chunk_pixels;
pixel_chunk_vec m_dbg_chunk_pixels_tile_vis;
pixel_chunk_vec m_dbg_chunk_pixels_color_quantized;
pixel_chunk_vec m_dbg_chunk_pixels_alpha_quantized;
bool m_alpha_encoding;
};
pixel_chunk_vec m_dbg_chunk_pixels_orig_color_selectors;
pixel_chunk_vec m_dbg_chunk_pixels_quantized_color_selectors;
pixel_chunk_vec m_dbg_chunk_pixels_final_color_selectors;
typedef crnlib::vector<tile_cluster> tile_cluster_vec;
pixel_chunk_vec m_dbg_chunk_pixels_orig_alpha_selectors;
pixel_chunk_vec m_dbg_chunk_pixels_quantized_alpha_selectors;
pixel_chunk_vec m_dbg_chunk_pixels_final_alpha_selectors;
tile_cluster_vec m_color_clusters;
tile_cluster_vec m_alpha_clusters;
pixel_chunk_vec m_dbg_chunk_pixels_final;
selectors_vec m_color_selectors;
selectors_vec m_alpha_selectors;
crn_thread_id_t m_main_thread_id;
bool m_canceled;
task_pool* m_pTask_pool;
int m_prev_phase_index;
int m_prev_percentage_complete;
typedef vec<6, float> vec6F;
typedef vec<16, float> vec16F;
typedef tree_clusterizer<vec2F> vec2F_tree_vq;
typedef tree_clusterizer<vec6F> vec6F_tree_vq;
typedef tree_clusterizer<vec16F> vec16F_tree_vq;
struct assign_color_endpoint_clusters_state
{
CRNLIB_NO_COPY_OR_ASSIGNMENT_OP(assign_color_endpoint_clusters_state);
assign_color_endpoint_clusters_state(vec6F_tree_vq& vq, crnlib::vector< crnlib::vector<vec6F> >& training_vecs) :
m_vq(vq), m_training_vecs(training_vecs) { }
vec6F_tree_vq& m_vq;
crnlib::vector< crnlib::vector<vec6F> >& m_training_vecs;
};
struct create_selector_codebook_state
{
CRNLIB_NO_COPY_OR_ASSIGNMENT_OP(create_selector_codebook_state);
create_selector_codebook_state(dxt_hc& hc, bool alpha_blocks, uint comp_index_start, uint comp_index_end, vec16F_tree_vq& selector_vq, chunk_blocks_using_selectors_vec& chunk_blocks_using_selectors, selectors_vec& selectors_cb) :
m_hc(hc),
m_alpha_blocks(alpha_blocks),
m_comp_index_start(comp_index_start),
m_comp_index_end(comp_index_end),
m_selector_vq(selector_vq),
m_chunk_blocks_using_selectors(chunk_blocks_using_selectors),
m_selectors_cb(selectors_cb)
{
}
dxt_hc& m_hc;
bool m_alpha_blocks;
uint m_comp_index_start;
uint m_comp_index_end;
vec16F_tree_vq& m_selector_vq;
chunk_blocks_using_selectors_vec& m_chunk_blocks_using_selectors;
selectors_vec& m_selectors_cb;
mutable spinlock m_chunk_blocks_using_selectors_lock;
};
void assign_color_endpoint_clusters_task(uint64 data, void* pData_ptr);
bool determine_color_endpoint_clusters();
struct determine_alpha_endpoint_clusters_state
{
vec2F_tree_vq m_vq;
crnlib::vector< crnlib::vector<vec2F> > m_training_vecs[2];
};
void determine_alpha_endpoint_clusters_task(uint64 data, void* pData_ptr);
bool determine_alpha_endpoint_clusters();
void determine_color_endpoint_codebook_task(uint64 data, void* pData_ptr);
bool determine_color_endpoint_codebook();
void determine_alpha_endpoint_codebook_task(uint64 data, void* pData_ptr);
bool determine_alpha_endpoint_codebook();
void create_quantized_debug_images();
void create_selector_codebook_task(uint64 data, void* pData_ptr);
bool create_selector_codebook(bool alpha_blocks);
bool refine_quantized_color_endpoints();
bool refine_quantized_color_selectors();
bool refine_quantized_alpha_endpoints();
bool refine_quantized_alpha_selectors();
void create_final_debug_image();
bool create_chunk_encodings();
bool update_progress(uint phase_index, uint subphase_index, uint subphase_total);
bool compress_internal(const params& p, uint num_chunks, const pixel_chunk* pChunks);
};
CRNLIB_DEFINE_BITWISE_COPYABLE(dxt_hc::pixel_chunk);
CRNLIB_DEFINE_BITWISE_COPYABLE(dxt_hc::chunk_encoding);
CRNLIB_DEFINE_BITWISE_COPYABLE(dxt_hc::selectors);
} // namespace crnlib
// For each selector, this array indicates every chunk/tile/tile block that use this color selector.
struct block_id {
block_id() { utils::zero_object(*this); }
block_id(uint chunk_index, uint alpha_index, uint tile_index, uint block_x, uint block_y)
: m_chunk_index(chunk_index), m_alpha_index((uint8)alpha_index), m_tile_index((uint8)tile_index), m_block_x((uint8)block_x), m_block_y((uint8)block_y) {}
uint m_chunk_index;
uint8 m_alpha_index;
uint8 m_tile_index;
uint8 m_block_x;
uint8 m_block_y;
};
typedef crnlib::vector<crnlib::vector<block_id> > chunk_blocks_using_selectors_vec;
chunk_blocks_using_selectors_vec m_chunk_blocks_using_color_selectors;
chunk_blocks_using_selectors_vec m_chunk_blocks_using_alpha_selectors; // second's upper 16 bits contain alpha index!
crnlib::vector<uint> m_color_endpoints; // not valid until end, only for user access
crnlib::vector<uint> m_alpha_endpoints; // not valid until end, only for user access
// Debugging
pixel_chunk_vec m_dbg_chunk_pixels;
pixel_chunk_vec m_dbg_chunk_pixels_tile_vis;
pixel_chunk_vec m_dbg_chunk_pixels_color_quantized;
pixel_chunk_vec m_dbg_chunk_pixels_alpha_quantized;
pixel_chunk_vec m_dbg_chunk_pixels_orig_color_selectors;
pixel_chunk_vec m_dbg_chunk_pixels_quantized_color_selectors;
pixel_chunk_vec m_dbg_chunk_pixels_final_color_selectors;
pixel_chunk_vec m_dbg_chunk_pixels_orig_alpha_selectors;
pixel_chunk_vec m_dbg_chunk_pixels_quantized_alpha_selectors;
pixel_chunk_vec m_dbg_chunk_pixels_final_alpha_selectors;
pixel_chunk_vec m_dbg_chunk_pixels_final;
crn_thread_id_t m_main_thread_id;
bool m_canceled;
task_pool* m_pTask_pool;
int m_prev_phase_index;
int m_prev_percentage_complete;
typedef vec<6, float> vec6F;
typedef vec<16, float> vec16F;
typedef tree_clusterizer<vec2F> vec2F_tree_vq;
typedef tree_clusterizer<vec6F> vec6F_tree_vq;
typedef tree_clusterizer<vec16F> vec16F_tree_vq;
struct assign_color_endpoint_clusters_state {
CRNLIB_NO_COPY_OR_ASSIGNMENT_OP(assign_color_endpoint_clusters_state);
assign_color_endpoint_clusters_state(vec6F_tree_vq& vq, crnlib::vector<crnlib::vector<vec6F> >& training_vecs)
: m_vq(vq), m_training_vecs(training_vecs) {}
vec6F_tree_vq& m_vq;
crnlib::vector<crnlib::vector<vec6F> >& m_training_vecs;
};
struct create_selector_codebook_state {
CRNLIB_NO_COPY_OR_ASSIGNMENT_OP(create_selector_codebook_state);
create_selector_codebook_state(dxt_hc& hc, bool alpha_blocks, uint comp_index_start, uint comp_index_end, vec16F_tree_vq& selector_vq, chunk_blocks_using_selectors_vec& chunk_blocks_using_selectors, selectors_vec& selectors_cb)
: m_hc(hc),
m_alpha_blocks(alpha_blocks),
m_comp_index_start(comp_index_start),
m_comp_index_end(comp_index_end),
m_selector_vq(selector_vq),
m_chunk_blocks_using_selectors(chunk_blocks_using_selectors),
m_selectors_cb(selectors_cb) {
}
dxt_hc& m_hc;
bool m_alpha_blocks;
uint m_comp_index_start;
uint m_comp_index_end;
vec16F_tree_vq& m_selector_vq;
chunk_blocks_using_selectors_vec& m_chunk_blocks_using_selectors;
selectors_vec& m_selectors_cb;
mutable spinlock m_chunk_blocks_using_selectors_lock;
};
void assign_color_endpoint_clusters_task(uint64 data, void* pData_ptr);
bool determine_color_endpoint_clusters();
struct determine_alpha_endpoint_clusters_state {
vec2F_tree_vq m_vq;
crnlib::vector<crnlib::vector<vec2F> > m_training_vecs[2];
};
void determine_alpha_endpoint_clusters_task(uint64 data, void* pData_ptr);
bool determine_alpha_endpoint_clusters();
void determine_color_endpoint_codebook_task(uint64 data, void* pData_ptr);
bool determine_color_endpoint_codebook();
void determine_alpha_endpoint_codebook_task(uint64 data, void* pData_ptr);
bool determine_alpha_endpoint_codebook();
void create_quantized_debug_images();
void create_selector_codebook_task(uint64 data, void* pData_ptr);
bool create_selector_codebook(bool alpha_blocks);
bool refine_quantized_color_endpoints();
bool refine_quantized_color_selectors();
bool refine_quantized_alpha_endpoints();
bool refine_quantized_alpha_selectors();
void create_final_debug_image();
bool create_chunk_encodings();
bool update_progress(uint phase_index, uint subphase_index, uint subphase_total);
bool compress_internal(const params& p, uint num_chunks, const pixel_chunk* pChunks);
};
CRNLIB_DEFINE_BITWISE_COPYABLE(dxt_hc::pixel_chunk);
CRNLIB_DEFINE_BITWISE_COPYABLE(dxt_hc::chunk_encoding);
CRNLIB_DEFINE_BITWISE_COPYABLE(dxt_hc::selectors);
} // namespace crnlib
+27 -33
View File
@@ -3,45 +3,39 @@
#include "crn_core.h"
#include "crn_dxt_hc_common.h"
namespace crnlib
{
chunk_encoding_desc g_chunk_encodings[cNumChunkEncodings] =
{
{ 1, { { 0, 0, 8, 8, 0 } } },
namespace crnlib {
chunk_encoding_desc g_chunk_encodings[cNumChunkEncodings] =
{
{1, {{0, 0, 8, 8, 0}}},
{ 2, { { 0, 0, 8, 4, 1 }, { 0, 4, 8, 4, 2 } } },
{ 2, { { 0, 0, 4, 8, 3 }, { 4, 0, 4, 8, 4 } } },
{2, {{0, 0, 8, 4, 1}, {0, 4, 8, 4, 2}}},
{2, {{0, 0, 4, 8, 3}, {4, 0, 4, 8, 4}}},
{ 3, { { 0, 0, 8, 4, 1 }, { 0, 4, 4, 4, 7 }, { 4, 4, 4, 4, 8 } } },
{ 3, { { 0, 4, 8, 4, 2 }, { 0, 0, 4, 4, 5 }, { 4, 0, 4, 4, 6 } } },
{3, {{0, 0, 8, 4, 1}, {0, 4, 4, 4, 7}, {4, 4, 4, 4, 8}}},
{3, {{0, 4, 8, 4, 2}, {0, 0, 4, 4, 5}, {4, 0, 4, 4, 6}}},
{ 3, { { 0, 0, 4, 8, 3 }, { 4, 0, 4, 4, 6 }, { 4, 4, 4, 4, 8 } } },
{ 3, { { 4, 0, 4, 8, 4 }, { 0, 0, 4, 4, 5 }, { 0, 4, 4, 4, 7 } } },
{3, {{0, 0, 4, 8, 3}, {4, 0, 4, 4, 6}, {4, 4, 4, 4, 8}}},
{3, {{4, 0, 4, 8, 4}, {0, 0, 4, 4, 5}, {0, 4, 4, 4, 7}}},
{ 4, { { 0, 0, 4, 4, 5 }, { 4, 0, 4, 4, 6 }, { 0, 4, 4, 4, 7 }, { 4, 4, 4, 4, 8 } } }
};
{4, {{0, 0, 4, 4, 5}, {4, 0, 4, 4, 6}, {0, 4, 4, 4, 7}, {4, 4, 4, 4, 8}}}};
chunk_tile_desc g_chunk_tile_layouts[cNumChunkTileLayouts] =
{
// 2x2
{ 0, 0, 8, 8, 0 },
chunk_tile_desc g_chunk_tile_layouts[cNumChunkTileLayouts] =
{
// 2x2
{0, 0, 8, 8, 0},
// 2x1
{ 0, 0, 8, 4, 1 },
{ 0, 4, 8, 4, 2 },
// 1x2
{ 0, 0, 4, 8, 3 },
{ 4, 0, 4, 8, 4 },
// 1x1
{ 0, 0, 4, 4, 5 },
{ 4, 0, 4, 4, 6 },
{ 0, 4, 4, 4, 7 },
{ 4, 4, 4, 4, 8 }
};
} // namespace crnlib
// 2x1
{0, 0, 8, 4, 1},
{0, 4, 8, 4, 2},
// 1x2
{0, 0, 4, 8, 3},
{4, 0, 4, 8, 4},
// 1x1
{0, 0, 4, 4, 5},
{4, 0, 4, 4, 6},
{0, 4, 4, 4, 7},
{4, 4, 4, 4, 8}};
} // namespace crnlib
+29 -32
View File
@@ -2,42 +2,39 @@
// See Copyright Notice and license at the end of inc/crnlib.h
#pragma once
namespace crnlib
{
struct chunk_tile_desc
{
// These values are in pixels, and always a multiple of cBlockPixelWidth/cBlockPixelHeight.
uint m_x_ofs;
uint m_y_ofs;
uint m_width;
uint m_height;
uint m_layout_index;
};
namespace crnlib {
struct chunk_tile_desc {
// These values are in pixels, and always a multiple of cBlockPixelWidth/cBlockPixelHeight.
uint m_x_ofs;
uint m_y_ofs;
uint m_width;
uint m_height;
uint m_layout_index;
};
struct chunk_encoding_desc
{
uint m_num_tiles;
chunk_tile_desc m_tiles[4];
};
struct chunk_encoding_desc {
uint m_num_tiles;
chunk_tile_desc m_tiles[4];
};
const uint cChunkPixelWidth = 8;
const uint cChunkPixelHeight = 8;
const uint cChunkBlockWidth = 2;
const uint cChunkBlockHeight = 2;
const uint cChunkPixelWidth = 8;
const uint cChunkPixelHeight = 8;
const uint cChunkBlockWidth = 2;
const uint cChunkBlockHeight = 2;
const uint cChunkMaxTiles = 4;
const uint cChunkMaxTiles = 4;
const uint cBlockPixelWidthShift = 2;
const uint cBlockPixelHeightShift = 2;
const uint cBlockPixelWidthShift = 2;
const uint cBlockPixelHeightShift = 2;
const uint cBlockPixelWidth = 4;
const uint cBlockPixelHeight = 4;
const uint cBlockPixelWidth = 4;
const uint cBlockPixelHeight = 4;
const uint cNumChunkEncodings = 8;
extern chunk_encoding_desc g_chunk_encodings[cNumChunkEncodings];
const uint cNumChunkEncodings = 8;
extern chunk_encoding_desc g_chunk_encodings[cNumChunkEncodings];
const uint cNumChunkTileLayouts = 9;
const uint cFirst4x4ChunkTileLayout = 5;
extern chunk_tile_desc g_chunk_tile_layouts[cNumChunkTileLayouts];
} // namespace crnlib
const uint cNumChunkTileLayouts = 9;
const uint cFirst4x4ChunkTileLayout = 5;
extern chunk_tile_desc g_chunk_tile_layouts[cNumChunkTileLayouts];
} // namespace crnlib
+1446 -1565
View File
File diff suppressed because it is too large Load Diff
+230 -220
View File
@@ -11,238 +11,248 @@
#define CRNLIB_SUPPORT_ATI_COMPRESS 0
namespace crnlib
{
class task_pool;
namespace crnlib {
class task_pool;
class dxt_image
{
public:
dxt_image();
dxt_image(const dxt_image& other);
dxt_image& operator= (const dxt_image& rhs);
void clear();
class dxt_image {
public:
dxt_image();
dxt_image(const dxt_image& other);
dxt_image& operator=(const dxt_image& rhs);
inline bool is_valid() const { return m_blocks_x > 0; }
uint get_width() const { return m_width; }
uint get_height() const { return m_height; }
uint get_blocks_x() const { return m_blocks_x; }
uint get_blocks_y() const { return m_blocks_y; }
uint get_total_blocks() const { return m_blocks_x * m_blocks_y; }
uint get_elements_per_block() const { return m_num_elements_per_block; }
uint get_bytes_per_block() const { return m_bytes_per_block; }
dxt_format get_format() const { return m_format; }
bool has_color() const { return (m_format == cDXT1) || (m_format == cDXT1A) || (m_format == cDXT3) || (m_format == cDXT5) || (m_format == cETC1); }
// Will be pretty slow if the image is DXT1, as this method scans for alpha blocks/selectors.
bool has_alpha() const;
enum element_type
{
cUnused = 0,
cColorDXT1, // DXT1 color block
cAlphaDXT3, // DXT3 alpha block (only)
cAlphaDXT5, // DXT5 alpha block (only)
void clear();
cColorETC1, // ETC1 color block
};
element_type get_element_type(uint element_index) const { CRNLIB_ASSERT(element_index < m_num_elements_per_block); return m_element_type[element_index]; }
//Returns -1 for RGB, or [0,3]
int8 get_element_component_index(uint element_index) const { CRNLIB_ASSERT(element_index < m_num_elements_per_block); return m_element_component_index[element_index]; }
struct element
{
uint8 m_bytes[8];
uint get_le_word(uint index) const { CRNLIB_ASSERT(index < 4); return m_bytes[index*2] | (m_bytes[index * 2 + 1] << 8); }
uint get_be_word(uint index) const { CRNLIB_ASSERT(index < 4); return m_bytes[index*2 + 1] | (m_bytes[index * 2] << 8); }
void set_le_word(uint index, uint val) { CRNLIB_ASSERT((index < 4) && (val <= cUINT16_MAX)); m_bytes[index*2] = static_cast<uint8>(val & 0xFF); m_bytes[index * 2 + 1] = static_cast<uint8>((val >> 8) & 0xFF); }
void set_be_word(uint index, uint val) { CRNLIB_ASSERT((index < 4) && (val <= cUINT16_MAX)); m_bytes[index*2+1] = static_cast<uint8>(val & 0xFF); m_bytes[index * 2] = static_cast<uint8>((val >> 8) & 0xFF); }
void clear()
{
memset(this, 0, sizeof(*this));
}
};
typedef crnlib::vector<element> element_vec;
bool init(dxt_format fmt, uint width, uint height, bool clear_elements);
bool init(dxt_format fmt, uint width, uint height, uint num_elements, element* pElements, bool create_copy);
struct pack_params
{
pack_params()
{
clear();
}
inline bool is_valid() const { return m_blocks_x > 0; }
void clear()
{
m_quality = cCRNDXTQualityUber;
m_perceptual = true;
m_dithering = false;
m_grayscale_sampling = false;
m_use_both_block_types = true;
m_endpoint_caching = true;
m_compressor = cCRNDXTCompressorCRN;
m_pProgress_callback = NULL;
m_pProgress_callback_user_data_ptr = NULL;
m_dxt1a_alpha_threshold = 128;
m_num_helper_threads = 0;
m_progress_start = 0;
m_progress_range = 100;
m_use_transparent_indices_for_black = false;
m_pTask_pool = NULL;
m_color_weights[0] = 1;
m_color_weights[1] = 1;
m_color_weights[2] = 1;
}
uint get_width() const { return m_width; }
uint get_height() const { return m_height; }
void init(const crn_comp_params &params)
{
m_perceptual = (params.m_flags & cCRNCompFlagPerceptual) != 0;
m_num_helper_threads = params.m_num_helper_threads;
m_use_both_block_types = (params.m_flags & cCRNCompFlagUseBothBlockTypes) != 0;
m_use_transparent_indices_for_black = (params.m_flags & cCRNCompFlagUseTransparentIndicesForBlack) != 0;
m_dxt1a_alpha_threshold = params.m_dxt1a_alpha_threshold;
m_quality = params.m_dxt_quality;
m_endpoint_caching = (params.m_flags & cCRNCompFlagDisableEndpointCaching) == 0;
m_grayscale_sampling = (params.m_flags & cCRNCompFlagGrayscaleSampling) != 0;
m_compressor = params.m_dxt_compressor_type;
}
uint m_dxt1a_alpha_threshold;
uint m_num_helper_threads;
crn_dxt_quality m_quality;
crn_dxt_compressor_type m_compressor;
bool m_perceptual;
bool m_dithering;
bool m_grayscale_sampling;
bool m_use_both_block_types;
bool m_endpoint_caching;
bool m_use_transparent_indices_for_black;
typedef bool (*progress_callback_func)(uint percentage_complete, void* pUser_data_ptr);
progress_callback_func m_pProgress_callback;
void* m_pProgress_callback_user_data_ptr;
uint m_progress_start;
uint m_progress_range;
uint get_blocks_x() const { return m_blocks_x; }
uint get_blocks_y() const { return m_blocks_y; }
uint get_total_blocks() const { return m_blocks_x * m_blocks_y; }
task_pool *m_pTask_pool;
uint get_elements_per_block() const { return m_num_elements_per_block; }
uint get_bytes_per_block() const { return m_bytes_per_block; }
int m_color_weights[3];
};
bool init(dxt_format fmt, const image_u8& img, const pack_params& p = dxt_image::pack_params());
bool unpack(image_u8& img) const;
void endian_swap();
uint get_total_elements() const { return m_elements.size(); }
const element_vec& get_element_vec() const { return m_elements; }
element_vec& get_element_vec() { return m_elements; }
const element& get_element(uint block_x, uint block_y, uint element_index) const;
element& get_element(uint block_x, uint block_y, uint element_index);
const element* get_element_ptr() const { return m_pElements; }
element* get_element_ptr() { return m_pElements; }
uint get_size_in_bytes() const { return m_elements.size() * sizeof(element); }
uint get_row_pitch_in_bytes() const { return m_blocks_x * m_bytes_per_block; }
color_quad_u8 get_pixel(uint x, uint y) const;
uint get_pixel_alpha(uint x, uint y, uint element_index) const;
void set_pixel(uint x, uint y, const color_quad_u8& c, bool perceptual = true);
// get_block_pixels() only sets those components stored in the image!
bool get_block_pixels(uint block_x, uint block_y, color_quad_u8* pPixels) const;
dxt_format get_format() const { return m_format; }
struct set_block_pixels_context
{
dxt1_endpoint_optimizer m_dxt1_optimizer;
dxt5_endpoint_optimizer m_dxt5_optimizer;
pack_etc1_block_context m_etc1_optimizer;
bool has_color() const { return (m_format == cDXT1) || (m_format == cDXT1A) || (m_format == cDXT3) || (m_format == cDXT5) || (m_format == cETC1); }
// Will be pretty slow if the image is DXT1, as this method scans for alpha blocks/selectors.
bool has_alpha() const;
enum element_type {
cUnused = 0,
cColorDXT1, // DXT1 color block
cAlphaDXT3, // DXT3 alpha block (only)
cAlphaDXT5, // DXT5 alpha block (only)
cColorETC1, // ETC1 color block
};
element_type get_element_type(uint element_index) const {
CRNLIB_ASSERT(element_index < m_num_elements_per_block);
return m_element_type[element_index];
}
//Returns -1 for RGB, or [0,3]
int8 get_element_component_index(uint element_index) const {
CRNLIB_ASSERT(element_index < m_num_elements_per_block);
return m_element_component_index[element_index];
}
struct element {
uint8 m_bytes[8];
uint get_le_word(uint index) const {
CRNLIB_ASSERT(index < 4);
return m_bytes[index * 2] | (m_bytes[index * 2 + 1] << 8);
}
uint get_be_word(uint index) const {
CRNLIB_ASSERT(index < 4);
return m_bytes[index * 2 + 1] | (m_bytes[index * 2] << 8);
}
void set_le_word(uint index, uint val) {
CRNLIB_ASSERT((index < 4) && (val <= cUINT16_MAX));
m_bytes[index * 2] = static_cast<uint8>(val & 0xFF);
m_bytes[index * 2 + 1] = static_cast<uint8>((val >> 8) & 0xFF);
}
void set_be_word(uint index, uint val) {
CRNLIB_ASSERT((index < 4) && (val <= cUINT16_MAX));
m_bytes[index * 2 + 1] = static_cast<uint8>(val & 0xFF);
m_bytes[index * 2] = static_cast<uint8>((val >> 8) & 0xFF);
}
void clear() {
memset(this, 0, sizeof(*this));
}
};
typedef crnlib::vector<element> element_vec;
bool init(dxt_format fmt, uint width, uint height, bool clear_elements);
bool init(dxt_format fmt, uint width, uint height, uint num_elements, element* pElements, bool create_copy);
struct pack_params {
pack_params() {
clear();
}
void clear() {
m_quality = cCRNDXTQualityUber;
m_perceptual = true;
m_dithering = false;
m_grayscale_sampling = false;
m_use_both_block_types = true;
m_endpoint_caching = true;
m_compressor = cCRNDXTCompressorCRN;
m_pProgress_callback = NULL;
m_pProgress_callback_user_data_ptr = NULL;
m_dxt1a_alpha_threshold = 128;
m_num_helper_threads = 0;
m_progress_start = 0;
m_progress_range = 100;
m_use_transparent_indices_for_black = false;
m_pTask_pool = NULL;
m_color_weights[0] = 1;
m_color_weights[1] = 1;
m_color_weights[2] = 1;
}
void init(const crn_comp_params& params) {
m_perceptual = (params.m_flags & cCRNCompFlagPerceptual) != 0;
m_num_helper_threads = params.m_num_helper_threads;
m_use_both_block_types = (params.m_flags & cCRNCompFlagUseBothBlockTypes) != 0;
m_use_transparent_indices_for_black = (params.m_flags & cCRNCompFlagUseTransparentIndicesForBlack) != 0;
m_dxt1a_alpha_threshold = params.m_dxt1a_alpha_threshold;
m_quality = params.m_dxt_quality;
m_endpoint_caching = (params.m_flags & cCRNCompFlagDisableEndpointCaching) == 0;
m_grayscale_sampling = (params.m_flags & cCRNCompFlagGrayscaleSampling) != 0;
m_compressor = params.m_dxt_compressor_type;
}
uint m_dxt1a_alpha_threshold;
uint m_num_helper_threads;
crn_dxt_quality m_quality;
crn_dxt_compressor_type m_compressor;
bool m_perceptual;
bool m_dithering;
bool m_grayscale_sampling;
bool m_use_both_block_types;
bool m_endpoint_caching;
bool m_use_transparent_indices_for_black;
typedef bool (*progress_callback_func)(uint percentage_complete, void* pUser_data_ptr);
progress_callback_func m_pProgress_callback;
void* m_pProgress_callback_user_data_ptr;
uint m_progress_start;
uint m_progress_range;
task_pool* m_pTask_pool;
int m_color_weights[3];
};
bool init(dxt_format fmt, const image_u8& img, const pack_params& p = dxt_image::pack_params());
bool unpack(image_u8& img) const;
void endian_swap();
uint get_total_elements() const { return m_elements.size(); }
const element_vec& get_element_vec() const { return m_elements; }
element_vec& get_element_vec() { return m_elements; }
const element& get_element(uint block_x, uint block_y, uint element_index) const;
element& get_element(uint block_x, uint block_y, uint element_index);
const element* get_element_ptr() const { return m_pElements; }
element* get_element_ptr() { return m_pElements; }
uint get_size_in_bytes() const { return m_elements.size() * sizeof(element); }
uint get_row_pitch_in_bytes() const { return m_blocks_x * m_bytes_per_block; }
color_quad_u8 get_pixel(uint x, uint y) const;
uint get_pixel_alpha(uint x, uint y, uint element_index) const;
void set_pixel(uint x, uint y, const color_quad_u8& c, bool perceptual = true);
// get_block_pixels() only sets those components stored in the image!
bool get_block_pixels(uint block_x, uint block_y, color_quad_u8* pPixels) const;
struct set_block_pixels_context {
dxt1_endpoint_optimizer m_dxt1_optimizer;
dxt5_endpoint_optimizer m_dxt5_optimizer;
pack_etc1_block_context m_etc1_optimizer;
#if CRNLIB_SUPPORT_ETC_A1
etc_a1::pack_etc1_block_context m_etc1_a1_optimizer;
etc_a1::pack_etc1_block_context m_etc1_a1_optimizer;
#endif
};
void set_block_pixels(uint block_x, uint block_y, const color_quad_u8* pPixels, const pack_params& p, set_block_pixels_context& context);
void set_block_pixels(uint block_x, uint block_y, const color_quad_u8* pPixels, const pack_params& p);
void get_block_endpoints(uint block_x, uint block_y, uint element_index, uint& packed_low_endpoint, uint& packed_high_endpoint) const;
// Returns a value representing the component(s) that where actually set, where -1 = RGB.
// This method does not always set every component!
int get_block_endpoints(uint block_x, uint block_y, uint element_index, color_quad_u8& low_endpoint, color_quad_u8& high_endpoint, bool scaled = true) const;
// pColors should point to a 16 entry array, to handle DXT3.
// Returns the number of block colors: 3, 4, 6, 8, or 16.
uint get_block_colors(uint block_x, uint block_y, uint element_index, color_quad_u8* pColors, uint subblock_index = 0);
uint get_subblock_index(uint x, uint y, uint element_index) const;
uint get_total_subblocks(uint element_index) const;
uint get_selector(uint x, uint y, uint element_index) const;
void change_dxt1_to_dxt1a();
};
bool can_flip(uint axis_index);
void set_block_pixels(uint block_x, uint block_y, const color_quad_u8* pPixels, const pack_params& p, set_block_pixels_context& context);
void set_block_pixels(uint block_x, uint block_y, const color_quad_u8* pPixels, const pack_params& p);
// Returns true if the texture can actually be flipped.
bool flip_x();
bool flip_y();
private:
element_vec m_elements;
element* m_pElements;
uint m_width;
uint m_height;
uint m_blocks_x;
uint m_blocks_y;
uint m_total_blocks;
uint m_total_elements;
uint m_num_elements_per_block; // 1 or 2
uint m_bytes_per_block; // 8 or 16
int8 m_element_component_index[2];
element_type m_element_type[2];
dxt_format m_format; // DXT1, 1A, 3, 5, N/3DC, or 5A
bool init_internal(dxt_format fmt, uint width, uint height);
void init_task(uint64 data, void* pData_ptr);
void get_block_endpoints(uint block_x, uint block_y, uint element_index, uint& packed_low_endpoint, uint& packed_high_endpoint) const;
#if CRNLIB_SUPPORT_ATI_COMPRESS
bool init_ati_compress(dxt_format fmt, const image_u8& img, const pack_params& p);
#endif
// Returns a value representing the component(s) that where actually set, where -1 = RGB.
// This method does not always set every component!
int get_block_endpoints(uint block_x, uint block_y, uint element_index, color_quad_u8& low_endpoint, color_quad_u8& high_endpoint, bool scaled = true) const;
void flip_col(uint x);
void flip_row(uint y);
};
// pColors should point to a 16 entry array, to handle DXT3.
// Returns the number of block colors: 3, 4, 6, 8, or 16.
uint get_block_colors(uint block_x, uint block_y, uint element_index, color_quad_u8* pColors, uint subblock_index = 0);
} // namespace crnlib
uint get_subblock_index(uint x, uint y, uint element_index) const;
uint get_total_subblocks(uint element_index) const;
uint get_selector(uint x, uint y, uint element_index) const;
void change_dxt1_to_dxt1a();
bool can_flip(uint axis_index);
// Returns true if the texture can actually be flipped.
bool flip_x();
bool flip_y();
private:
element_vec m_elements;
element* m_pElements;
uint m_width;
uint m_height;
uint m_blocks_x;
uint m_blocks_y;
uint m_total_blocks;
uint m_total_elements;
uint m_num_elements_per_block; // 1 or 2
uint m_bytes_per_block; // 8 or 16
int8 m_element_component_index[2];
element_type m_element_type[2];
dxt_format m_format; // DXT1, 1A, 3, 5, N/3DC, or 5A
bool init_internal(dxt_format fmt, uint width, uint height);
void init_task(uint64 data, void* pData_ptr);
#if CRNLIB_SUPPORT_ATI_COMPRESS
bool init_ati_compress(dxt_format fmt, const image_u8& img, const pack_params& p);
#endif
void flip_col(uint x);
void flip_row(uint y);
};
} // namespace crnlib
+139 -163
View File
@@ -3,204 +3,180 @@
#pragma once
#include "crn_data_stream.h"
namespace crnlib
{
class dynamic_stream : public data_stream
{
public:
dynamic_stream(uint initial_size, const char* pName = "dynamic_stream", uint attribs = cDataStreamSeekable | cDataStreamWritable | cDataStreamReadable) :
data_stream(pName, attribs),
m_ofs(0)
{
open(initial_size, pName, attribs);
namespace crnlib {
class dynamic_stream : public data_stream {
public:
dynamic_stream(uint initial_size, const char* pName = "dynamic_stream", uint attribs = cDataStreamSeekable | cDataStreamWritable | cDataStreamReadable)
: data_stream(pName, attribs),
m_ofs(0) {
open(initial_size, pName, attribs);
}
dynamic_stream(const void* pBuf, uint size, const char* pName = "dynamic_stream", uint attribs = cDataStreamSeekable | cDataStreamWritable | cDataStreamReadable)
: data_stream(pName, attribs),
m_ofs(0) {
open(pBuf, size, pName, attribs);
}
dynamic_stream()
: data_stream(),
m_ofs(0) {
open();
}
virtual ~dynamic_stream() {
}
bool open(uint initial_size = 0, const char* pName = "dynamic_stream", uint attribs = cDataStreamSeekable | cDataStreamWritable | cDataStreamReadable) {
close();
m_opened = true;
m_buf.clear();
m_buf.resize(initial_size);
m_ofs = 0;
m_name.set(pName ? pName : "dynamic_stream");
m_attribs = static_cast<attribs_t>(attribs);
return true;
}
bool reopen(const char* pName, uint attribs) {
if (!m_opened) {
return open(0, pName, attribs);
}
m_name.set(pName ? pName : "dynamic_stream");
m_attribs = static_cast<attribs_t>(attribs);
return true;
}
bool open(const void* pBuf, uint size, const char* pName = "dynamic_stream", uint attribs = cDataStreamSeekable | cDataStreamWritable | cDataStreamReadable) {
if (!m_opened) {
m_opened = true;
m_buf.resize(size);
if (size) {
CRNLIB_ASSERT(pBuf);
memcpy(&m_buf[0], pBuf, size);
}
m_ofs = 0;
m_name.set(pName ? pName : "dynamic_stream");
m_attribs = static_cast<attribs_t>(attribs);
return true;
}
dynamic_stream(const void* pBuf, uint size, const char* pName = "dynamic_stream", uint attribs = cDataStreamSeekable | cDataStreamWritable | cDataStreamReadable) :
data_stream(pName, attribs),
m_ofs(0)
{
open(pBuf, size, pName, attribs);
}
return false;
}
dynamic_stream() :
data_stream(),
m_ofs(0)
{
open();
}
virtual bool close() {
if (m_opened) {
m_opened = false;
m_buf.clear();
m_ofs = 0;
return true;
}
virtual ~dynamic_stream()
{
}
return false;
}
bool open(uint initial_size = 0, const char* pName = "dynamic_stream", uint attribs = cDataStreamSeekable | cDataStreamWritable | cDataStreamReadable)
{
close();
const crnlib::vector<uint8>& get_buf() const { return m_buf; }
crnlib::vector<uint8>& get_buf() { return m_buf; }
m_opened = true;
m_buf.clear();
m_buf.resize(initial_size);
m_ofs = 0;
m_name.set(pName ? pName : "dynamic_stream");
m_attribs = static_cast<attribs_t>(attribs);
return true;
}
void reserve(uint size) {
if (m_opened) {
m_buf.reserve(size);
}
}
bool reopen(const char* pName, uint attribs)
{
if (!m_opened)
{
return open(0, pName, attribs);
}
virtual const void* get_ptr() const { return m_buf.empty() ? NULL : &m_buf[0]; }
m_name.set(pName ? pName : "dynamic_stream");
m_attribs = static_cast<attribs_t>(attribs);
return true;
}
virtual uint read(void* pBuf, uint len) {
CRNLIB_ASSERT(pBuf && (len <= 0x7FFFFFFF));
bool open(const void* pBuf, uint size, const char* pName = "dynamic_stream", uint attribs = cDataStreamSeekable | cDataStreamWritable | cDataStreamReadable)
{
if (!m_opened)
{
m_opened = true;
m_buf.resize(size);
if (size)
{
CRNLIB_ASSERT(pBuf);
memcpy(&m_buf[0], pBuf, size);
}
m_ofs = 0;
m_name.set(pName ? pName : "dynamic_stream");
m_attribs = static_cast<attribs_t>(attribs);
return true;
}
if ((!m_opened) || (!is_readable()) || (!len))
return 0;
return false;
}
CRNLIB_ASSERT(m_ofs <= m_buf.size());
virtual bool close()
{
if (m_opened)
{
m_opened = false;
m_buf.clear();
m_ofs = 0;
return true;
}
uint bytes_left = m_buf.size() - m_ofs;
return false;
}
len = math::minimum<uint>(len, bytes_left);
const crnlib::vector<uint8>& get_buf() const { return m_buf; }
crnlib::vector<uint8>& get_buf() { return m_buf; }
if (len)
memcpy(pBuf, &m_buf[m_ofs], len);
void reserve(uint size)
{
if (m_opened)
{
m_buf.reserve(size);
}
}
m_ofs += len;
virtual const void* get_ptr() const { return m_buf.empty() ? NULL : &m_buf[0]; }
return len;
}
virtual uint read(void* pBuf, uint len)
{
CRNLIB_ASSERT(pBuf && (len <= 0x7FFFFFFF));
virtual uint write(const void* pBuf, uint len) {
CRNLIB_ASSERT(pBuf && (len <= 0x7FFFFFFF));
if ((!m_opened) || (!is_readable()) || (!len))
return 0;
if ((!m_opened) || (!is_writable()) || (!len))
return 0;
CRNLIB_ASSERT(m_ofs <= m_buf.size());
CRNLIB_ASSERT(m_ofs <= m_buf.size());
uint bytes_left = m_buf.size() - m_ofs;
uint new_ofs = m_ofs + len;
if (new_ofs > m_buf.size())
m_buf.resize(new_ofs);
len = math::minimum<uint>(len, bytes_left);
memcpy(&m_buf[m_ofs], pBuf, len);
m_ofs = new_ofs;
if (len)
memcpy(pBuf, &m_buf[m_ofs], len);
return len;
}
m_ofs += len;
virtual bool flush() {
if (!m_opened)
return false;
return len;
}
return true;
}
virtual uint write(const void* pBuf, uint len)
{
CRNLIB_ASSERT(pBuf && (len <= 0x7FFFFFFF));
virtual uint64 get_size() {
if (!m_opened)
return 0;
if ((!m_opened) || (!is_writable()) || (!len))
return 0;
return m_buf.size();
}
CRNLIB_ASSERT(m_ofs <= m_buf.size());
virtual uint64 get_remaining() {
if (!m_opened)
return 0;
uint new_ofs = m_ofs + len;
if (new_ofs > m_buf.size())
m_buf.resize(new_ofs);
CRNLIB_ASSERT(m_ofs <= m_buf.size());
memcpy(&m_buf[m_ofs], pBuf, len);
m_ofs = new_ofs;
return m_buf.size() - m_ofs;
}
return len;
}
virtual uint64 get_ofs() {
if (!m_opened)
return 0;
virtual bool flush()
{
if (!m_opened)
return false;
return m_ofs;
}
return true;
}
virtual bool seek(int64 ofs, bool relative) {
if ((!m_opened) || (!is_seekable()))
return false;
virtual uint64 get_size()
{
if (!m_opened)
return 0;
int64 new_ofs = relative ? (m_ofs + ofs) : ofs;
return m_buf.size();
}
if (new_ofs < 0)
return false;
else if (new_ofs > m_buf.size())
return false;
virtual uint64 get_remaining()
{
if (!m_opened)
return 0;
m_ofs = static_cast<uint>(new_ofs);
CRNLIB_ASSERT(m_ofs <= m_buf.size());
post_seek();
return m_buf.size() - m_ofs;
}
return true;
}
virtual uint64 get_ofs()
{
if (!m_opened)
return 0;
return m_ofs;
}
virtual bool seek(int64 ofs, bool relative)
{
if ((!m_opened) || (!is_seekable()))
return false;
int64 new_ofs = relative ? (m_ofs + ofs) : ofs;
if (new_ofs < 0)
return false;
else if (new_ofs > m_buf.size())
return false;
m_ofs = static_cast<uint>(new_ofs);
post_seek();
return true;
}
private:
crnlib::vector<uint8> m_buf;
uint m_ofs;
};
} // namespace crnlib
private:
crnlib::vector<uint8> m_buf;
uint m_ofs;
};
} // namespace crnlib
File diff suppressed because it is too large Load Diff
+131 -119
View File
@@ -2,172 +2,184 @@
// See Copyright Notice and license at the end of inc/crnlib.h
#pragma once
namespace crnlib
{
enum { cMaxDynamicStringLen = cUINT16_MAX - 1 };
class dynamic_string
{
public:
inline dynamic_string() : m_buf_size(0), m_len(0), m_pStr(NULL) { }
dynamic_string(eVarArg dummy, const char* p, ...);
dynamic_string(const char* p);
dynamic_string(const char* p, uint len);
dynamic_string(const dynamic_string& other);
namespace crnlib {
enum { cMaxDynamicStringLen = cUINT16_MAX - 1 };
class dynamic_string {
public:
inline dynamic_string()
: m_buf_size(0), m_len(0), m_pStr(NULL) {}
dynamic_string(eVarArg dummy, const char* p, ...);
dynamic_string(const char* p);
dynamic_string(const char* p, uint len);
dynamic_string(const dynamic_string& other);
inline ~dynamic_string() { if (m_pStr) crnlib_delete_array(m_pStr); }
inline ~dynamic_string() {
if (m_pStr)
crnlib_delete_array(m_pStr);
}
// Truncates the string to 0 chars and frees the buffer.
void clear();
void optimize();
// Truncates the string to 0 chars and frees the buffer.
void clear();
void optimize();
// Truncates the string to 0 chars, but does not free the buffer.
void empty();
inline const char *assume_ownership() { const char *p = m_pStr; m_pStr = NULL; m_len = 0; m_buf_size = 0; return p; }
// Truncates the string to 0 chars, but does not free the buffer.
void empty();
inline const char* assume_ownership() {
const char* p = m_pStr;
m_pStr = NULL;
m_len = 0;
m_buf_size = 0;
return p;
}
inline uint get_len() const { return m_len; }
inline bool is_empty() const { return !m_len; }
inline uint get_len() const { return m_len; }
inline bool is_empty() const { return !m_len; }
inline const char* get_ptr() const { return m_pStr ? m_pStr : ""; }
inline const char* c_str() const { return get_ptr(); }
inline const char* get_ptr() const { return m_pStr ? m_pStr : ""; }
inline const char* c_str() const { return get_ptr(); }
inline const char* get_ptr_raw() const { return m_pStr; }
inline char* get_ptr_raw() { return m_pStr; }
inline const char* get_ptr_raw() const { return m_pStr; }
inline char* get_ptr_raw() { return m_pStr; }
inline char front() const { return m_len ? m_pStr[0] : '\0'; }
inline char back() const { return m_len ? m_pStr[m_len - 1] : '\0'; }
inline char front() const { return m_len ? m_pStr[0] : '\0'; }
inline char back() const { return m_len ? m_pStr[m_len - 1] : '\0'; }
inline char operator[] (uint i) const { CRNLIB_ASSERT(i <= m_len); return get_ptr()[i]; }
inline char operator[](uint i) const {
CRNLIB_ASSERT(i <= m_len);
return get_ptr()[i];
}
inline operator size_t() const { return fast_hash(get_ptr(), m_len) ^ fast_hash(&m_len, sizeof(m_len)); }
inline operator size_t() const { return fast_hash(get_ptr(), m_len) ^ fast_hash(&m_len, sizeof(m_len)); }
int compare(const char* p, bool case_sensitive = false) const;
int compare(const dynamic_string& rhs, bool case_sensitive = false) const;
int compare(const char* p, bool case_sensitive = false) const;
int compare(const dynamic_string& rhs, bool case_sensitive = false) const;
inline bool operator== (const dynamic_string& rhs) const { return compare(rhs) == 0; }
inline bool operator== (const char* p) const { return compare(p) == 0; }
inline bool operator==(const dynamic_string& rhs) const { return compare(rhs) == 0; }
inline bool operator==(const char* p) const { return compare(p) == 0; }
inline bool operator!= (const dynamic_string& rhs) const { return compare(rhs) != 0; }
inline bool operator!= (const char* p) const { return compare(p) != 0; }
inline bool operator!=(const dynamic_string& rhs) const { return compare(rhs) != 0; }
inline bool operator!=(const char* p) const { return compare(p) != 0; }
inline bool operator< (const dynamic_string& rhs) const { return compare(rhs) < 0; }
inline bool operator< (const char* p) const { return compare(p) < 0; }
inline bool operator<(const dynamic_string& rhs) const { return compare(rhs) < 0; }
inline bool operator<(const char* p) const { return compare(p) < 0; }
inline bool operator> (const dynamic_string& rhs) const { return compare(rhs) > 0; }
inline bool operator> (const char* p) const { return compare(p) > 0; }
inline bool operator>(const dynamic_string& rhs) const { return compare(rhs) > 0; }
inline bool operator>(const char* p) const { return compare(p) > 0; }
inline bool operator<= (const dynamic_string& rhs) const { return compare(rhs) <= 0; }
inline bool operator<= (const char* p) const { return compare(p) <= 0; }
inline bool operator<=(const dynamic_string& rhs) const { return compare(rhs) <= 0; }
inline bool operator<=(const char* p) const { return compare(p) <= 0; }
inline bool operator>= (const dynamic_string& rhs) const { return compare(rhs) >= 0; }
inline bool operator>= (const char* p) const { return compare(p) >= 0; }
inline bool operator>=(const dynamic_string& rhs) const { return compare(rhs) >= 0; }
inline bool operator>=(const char* p) const { return compare(p) >= 0; }
friend inline bool operator== (const char* p, const dynamic_string& rhs) { return rhs.compare(p) == 0; }
friend inline bool operator==(const char* p, const dynamic_string& rhs) { return rhs.compare(p) == 0; }
dynamic_string& set(const char* p, uint max_len = UINT_MAX);
dynamic_string& set(const dynamic_string& other, uint max_len = UINT_MAX);
dynamic_string& set(const char* p, uint max_len = UINT_MAX);
dynamic_string& set(const dynamic_string& other, uint max_len = UINT_MAX);
bool set_len(uint new_len, char fill_char = ' ');
bool set_len(uint new_len, char fill_char = ' ');
// Set from non-zero terminated buffer.
dynamic_string& set_from_buf(const void* pBuf, uint buf_size);
// Set from non-zero terminated buffer.
dynamic_string& set_from_buf(const void* pBuf, uint buf_size);
dynamic_string& operator= (const dynamic_string& rhs) { return set(rhs); }
dynamic_string& operator= (const char* p) { return set(p); }
dynamic_string& operator=(const dynamic_string& rhs) { return set(rhs); }
dynamic_string& operator=(const char* p) { return set(p); }
dynamic_string& set_char(uint index, char c);
dynamic_string& append_char(char c);
dynamic_string& append_char(int c) { CRNLIB_ASSERT((c >= 0) && (c <= 255)); return append_char(static_cast<char>(c)); }
dynamic_string& truncate(uint new_len);
dynamic_string& tolower();
dynamic_string& toupper();
dynamic_string& set_char(uint index, char c);
dynamic_string& append_char(char c);
dynamic_string& append_char(int c) {
CRNLIB_ASSERT((c >= 0) && (c <= 255));
return append_char(static_cast<char>(c));
}
dynamic_string& truncate(uint new_len);
dynamic_string& tolower();
dynamic_string& toupper();
dynamic_string& append(const char* p);
dynamic_string& append(const dynamic_string& other);
dynamic_string& operator += (const char* p) { return append(p); }
dynamic_string& operator += (const dynamic_string& other) { return append(other); }
dynamic_string& append(const char* p);
dynamic_string& append(const dynamic_string& other);
dynamic_string& operator+=(const char* p) { return append(p); }
dynamic_string& operator+=(const dynamic_string& other) { return append(other); }
friend dynamic_string operator+ (const char* p, const dynamic_string& a);
friend dynamic_string operator+ (const dynamic_string& a, const char* p);
friend dynamic_string operator+ (const dynamic_string& a, const dynamic_string& b);
friend dynamic_string operator+(const char* p, const dynamic_string& a);
friend dynamic_string operator+(const dynamic_string& a, const char* p);
friend dynamic_string operator+(const dynamic_string& a, const dynamic_string& b);
dynamic_string& format_args(const char* p, va_list args);
dynamic_string& format(const char* p, ...);
dynamic_string& format_args(const char* p, va_list args);
dynamic_string& format(const char* p, ...);
dynamic_string& crop(uint start, uint len);
dynamic_string& substring(uint start, uint end);
dynamic_string& left(uint len);
dynamic_string& mid(uint start, uint len);
dynamic_string& right(uint start);
dynamic_string& tail(uint num);
dynamic_string& crop(uint start, uint len);
dynamic_string& substring(uint start, uint end);
dynamic_string& left(uint len);
dynamic_string& mid(uint start, uint len);
dynamic_string& right(uint start);
dynamic_string& tail(uint num);
dynamic_string& unquote();
dynamic_string& unquote();
uint count_char(char c) const;
uint count_char(char c) const;
int find_left(const char* p, bool case_sensitive = false) const;
int find_left(char c) const;
int find_left(const char* p, bool case_sensitive = false) const;
int find_left(char c) const;
int find_right(char c) const;
int find_right(const char* p, bool case_sensitive = false) const;
int find_right(char c) const;
int find_right(const char* p, bool case_sensitive = false) const;
bool contains(const char* p, bool case_sensitive = false) const;
bool contains(const char* p, bool case_sensitive = false) const;
dynamic_string& trim();
dynamic_string& trim_crlf();
dynamic_string& trim();
dynamic_string& trim_crlf();
dynamic_string& remap(int from_char, int to_char);
dynamic_string& remap(int from_char, int to_char);
void swap(dynamic_string& other);
void swap(dynamic_string& other);
// Returns -1 on failure, or the number of bytes written.
int serialize(void* pBuf, uint buf_size, bool little_endian) const;
// Returns -1 on failure, or the number of bytes written.
int serialize(void* pBuf, uint buf_size, bool little_endian) const;
// Returns -1 on failure, or the number of bytes read.
int deserialize(const void* pBuf, uint buf_size, bool little_endian);
// Returns -1 on failure, or the number of bytes read.
int deserialize(const void* pBuf, uint buf_size, bool little_endian);
void translate_lf_to_crlf();
void translate_lf_to_crlf();
static inline char *create_raw_buffer(uint& buf_size_in_chars);
static inline void free_raw_buffer(char *p) { crnlib_delete_array(p); }
dynamic_string& set_from_raw_buf_and_assume_ownership(char *pBuf, uint buf_size_in_chars, uint len_in_chars);
private:
uint16 m_buf_size;
uint16 m_len;
char* m_pStr;
static inline char* create_raw_buffer(uint& buf_size_in_chars);
static inline void free_raw_buffer(char* p) { crnlib_delete_array(p); }
dynamic_string& set_from_raw_buf_and_assume_ownership(char* pBuf, uint buf_size_in_chars, uint len_in_chars);
private:
uint16 m_buf_size;
uint16 m_len;
char* m_pStr;
#ifdef CRNLIB_BUILD_DEBUG
void check() const;
void check() const;
#else
inline void check() const { }
inline void check() const {}
#endif
bool expand_buf(uint new_buf_size, bool preserve_contents);
bool expand_buf(uint new_buf_size, bool preserve_contents);
const char* get_ptr_priv() const { return m_pStr ? m_pStr : ""; }
char* get_ptr_priv() { return (char*)(m_pStr ? m_pStr : ""); }
const char* get_ptr_priv() const { return m_pStr ? m_pStr : ""; }
char* get_ptr_priv() { return (char*)(m_pStr ? m_pStr : ""); }
bool ensure_buf(uint len, bool preserve_contents = true);
};
bool ensure_buf(uint len, bool preserve_contents = true);
};
typedef crnlib::vector<dynamic_string> dynamic_string_array;
typedef crnlib::vector<dynamic_string> dynamic_string_array;
extern dynamic_string g_empty_dynamic_string;
extern dynamic_string g_empty_dynamic_string;
CRNLIB_DEFINE_BITWISE_MOVABLE(dynamic_string);
CRNLIB_DEFINE_BITWISE_MOVABLE(dynamic_string);
inline void swap (dynamic_string& a, dynamic_string& b)
{
a.swap(b);
}
inline void swap(dynamic_string& a, dynamic_string& b) {
a.swap(b);
}
inline char *dynamic_string::create_raw_buffer(uint& buf_size_in_chars)
{
if (buf_size_in_chars > cUINT16_MAX)
{
CRNLIB_ASSERT(0);
return NULL;
}
buf_size_in_chars = math::minimum<uint>(cUINT16_MAX, math::next_pow2(buf_size_in_chars));
return crnlib_new_array<char>(buf_size_in_chars);
}
} // namespace crnlib
inline char* dynamic_string::create_raw_buffer(uint& buf_size_in_chars) {
if (buf_size_in_chars > cUINT16_MAX) {
CRNLIB_ASSERT(0);
return NULL;
}
buf_size_in_chars = math::minimum<uint>(cUINT16_MAX, math::next_pow2(buf_size_in_chars));
return crnlib_new_array<char>(buf_size_in_chars);
}
} // namespace crnlib
+1527 -1423
View File
File diff suppressed because it is too large Load Diff
+536 -603
View File
File diff suppressed because it is too large Load Diff
+398 -451
View File
@@ -18,561 +18,508 @@
#include <libgen.h>
#endif
namespace crnlib
{
namespace crnlib {
#if CRNLIB_USE_WIN32_API
bool file_utils::is_read_only(const char* pFilename)
{
uint32 dst_file_attribs = GetFileAttributesA(pFilename);
if (dst_file_attribs == INVALID_FILE_ATTRIBUTES)
return false;
if (dst_file_attribs & FILE_ATTRIBUTE_READONLY)
return true;
return false;
}
bool file_utils::disable_read_only(const char* pFilename)
{
uint32 dst_file_attribs = GetFileAttributesA(pFilename);
if (dst_file_attribs == INVALID_FILE_ATTRIBUTES)
return false;
if (dst_file_attribs & FILE_ATTRIBUTE_READONLY)
{
dst_file_attribs &= ~FILE_ATTRIBUTE_READONLY;
if (SetFileAttributesA(pFilename, dst_file_attribs))
return true;
}
return false;
}
bool file_utils::is_older_than(const char* pSrcFilename, const char* pDstFilename)
{
WIN32_FILE_ATTRIBUTE_DATA src_file_attribs;
const BOOL src_file_exists = GetFileAttributesExA(pSrcFilename, GetFileExInfoStandard, &src_file_attribs);
WIN32_FILE_ATTRIBUTE_DATA dst_file_attribs;
const BOOL dest_file_exists = GetFileAttributesExA(pDstFilename, GetFileExInfoStandard, &dst_file_attribs);
if ((dest_file_exists) && (src_file_exists))
{
LONG timeComp = CompareFileTime(&src_file_attribs.ftLastWriteTime, &dst_file_attribs.ftLastWriteTime);
if (timeComp < 0)
return true;
}
return false;
}
bool file_utils::does_file_exist(const char* pFilename)
{
const DWORD fullAttributes = GetFileAttributesA(pFilename);
if (fullAttributes == INVALID_FILE_ATTRIBUTES)
return false;
if (fullAttributes & FILE_ATTRIBUTE_DIRECTORY)
return false;
bool file_utils::is_read_only(const char* pFilename) {
uint32 dst_file_attribs = GetFileAttributesA(pFilename);
if (dst_file_attribs == INVALID_FILE_ATTRIBUTES)
return false;
if (dst_file_attribs & FILE_ATTRIBUTE_READONLY)
return true;
return false;
}
bool file_utils::disable_read_only(const char* pFilename) {
uint32 dst_file_attribs = GetFileAttributesA(pFilename);
if (dst_file_attribs == INVALID_FILE_ATTRIBUTES)
return false;
if (dst_file_attribs & FILE_ATTRIBUTE_READONLY) {
dst_file_attribs &= ~FILE_ATTRIBUTE_READONLY;
if (SetFileAttributesA(pFilename, dst_file_attribs))
return true;
}
}
return false;
}
bool file_utils::does_dir_exist(const char* pDir)
{
//-- Get the file attributes.
DWORD fullAttributes = GetFileAttributesA(pDir);
bool file_utils::is_older_than(const char* pSrcFilename, const char* pDstFilename) {
WIN32_FILE_ATTRIBUTE_DATA src_file_attribs;
const BOOL src_file_exists = GetFileAttributesExA(pSrcFilename, GetFileExInfoStandard, &src_file_attribs);
if (fullAttributes == INVALID_FILE_ATTRIBUTES)
return false;
if (fullAttributes & FILE_ATTRIBUTE_DIRECTORY)
return true;
return false;
}
bool file_utils::get_file_size(const char* pFilename, uint64& file_size)
{
file_size = 0;
WIN32_FILE_ATTRIBUTE_DATA attr;
if (0 == GetFileAttributesExA(pFilename, GetFileExInfoStandard, &attr))
return false;
if (attr.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
return false;
file_size = static_cast<uint64>(attr.nFileSizeLow) | (static_cast<uint64>(attr.nFileSizeHigh) << 32U);
WIN32_FILE_ATTRIBUTE_DATA dst_file_attribs;
const BOOL dest_file_exists = GetFileAttributesExA(pDstFilename, GetFileExInfoStandard, &dst_file_attribs);
if ((dest_file_exists) && (src_file_exists)) {
LONG timeComp = CompareFileTime(&src_file_attribs.ftLastWriteTime, &dst_file_attribs.ftLastWriteTime);
if (timeComp < 0)
return true;
}
#elif defined( __GNUC__ )
bool file_utils::is_read_only(const char* pFilename)
{
pFilename;
// TODO
return false;
}
}
return false;
}
bool file_utils::disable_read_only(const char* pFilename)
{
pFilename;
// TODO
return false;
}
bool file_utils::does_file_exist(const char* pFilename) {
const DWORD fullAttributes = GetFileAttributesA(pFilename);
bool file_utils::is_older_than(const char *pSrcFilename, const char* pDstFilename)
{
pSrcFilename, pDstFilename;
// TODO
return false;
}
if (fullAttributes == INVALID_FILE_ATTRIBUTES)
return false;
bool file_utils::does_file_exist(const char* pFilename)
{
struct stat stat_buf;
int result = stat(pFilename, &stat_buf);
if (result)
return false;
if (S_ISREG(stat_buf.st_mode))
return true;
return false;
}
if (fullAttributes & FILE_ATTRIBUTE_DIRECTORY)
return false;
bool file_utils::does_dir_exist(const char* pDir)
{
struct stat stat_buf;
int result = stat(pDir, &stat_buf);
if (result)
return false;
if (S_ISDIR(stat_buf.st_mode) || S_ISLNK(stat_buf.st_mode))
return true;
return false;
}
return true;
}
bool file_utils::get_file_size(const char* pFilename, uint64& file_size)
{
file_size = 0;
struct stat stat_buf;
int result = stat(pFilename, &stat_buf);
if (result)
return false;
if (!S_ISREG(stat_buf.st_mode))
return false;
file_size = stat_buf.st_size;
return true;
}
bool file_utils::does_dir_exist(const char* pDir) {
//-- Get the file attributes.
DWORD fullAttributes = GetFileAttributesA(pDir);
if (fullAttributes == INVALID_FILE_ATTRIBUTES)
return false;
if (fullAttributes & FILE_ATTRIBUTE_DIRECTORY)
return true;
return false;
}
bool file_utils::get_file_size(const char* pFilename, uint64& file_size) {
file_size = 0;
WIN32_FILE_ATTRIBUTE_DATA attr;
if (0 == GetFileAttributesExA(pFilename, GetFileExInfoStandard, &attr))
return false;
if (attr.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
return false;
file_size = static_cast<uint64>(attr.nFileSizeLow) | (static_cast<uint64>(attr.nFileSizeHigh) << 32U);
return true;
}
#elif defined(__GNUC__)
bool file_utils::is_read_only(const char* pFilename) {
pFilename;
// TODO
return false;
}
bool file_utils::disable_read_only(const char* pFilename) {
pFilename;
// TODO
return false;
}
bool file_utils::is_older_than(const char* pSrcFilename, const char* pDstFilename) {
pSrcFilename, pDstFilename;
// TODO
return false;
}
bool file_utils::does_file_exist(const char* pFilename) {
struct stat stat_buf;
int result = stat(pFilename, &stat_buf);
if (result)
return false;
if (S_ISREG(stat_buf.st_mode))
return true;
return false;
}
bool file_utils::does_dir_exist(const char* pDir) {
struct stat stat_buf;
int result = stat(pDir, &stat_buf);
if (result)
return false;
if (S_ISDIR(stat_buf.st_mode) || S_ISLNK(stat_buf.st_mode))
return true;
return false;
}
bool file_utils::get_file_size(const char* pFilename, uint64& file_size) {
file_size = 0;
struct stat stat_buf;
int result = stat(pFilename, &stat_buf);
if (result)
return false;
if (!S_ISREG(stat_buf.st_mode))
return false;
file_size = stat_buf.st_size;
return true;
}
#else
bool file_utils::is_read_only(const char* pFilename)
{
return false;
}
bool file_utils::is_read_only(const char* pFilename) {
return false;
}
bool file_utils::disable_read_only(const char* pFilename)
{
pFilename;
// TODO
return false;
}
bool file_utils::disable_read_only(const char* pFilename) {
pFilename;
// TODO
return false;
}
bool file_utils::is_older_than(const char *pSrcFilename, const char* pDstFilename)
{
return false;
}
bool file_utils::is_older_than(const char* pSrcFilename, const char* pDstFilename) {
return false;
}
bool file_utils::does_file_exist(const char* pFilename)
{
FILE* pFile;
crn_fopen(&pFile, pFilename, "rb");
if (!pFile)
return false;
fclose(pFile);
return true;
}
bool file_utils::does_file_exist(const char* pFilename) {
FILE* pFile;
crn_fopen(&pFile, pFilename, "rb");
if (!pFile)
return false;
fclose(pFile);
return true;
}
bool file_utils::does_dir_exist(const char* pDir)
{
return false;
}
bool file_utils::does_dir_exist(const char* pDir) {
return false;
}
bool file_utils::get_file_size(const char* pFilename, uint64& file_size)
{
FILE* pFile;
crn_fopen(&pFile, pFilename, "rb");
if (!pFile)
return false;
crn_fseek(pFile, 0, SEEK_END);
file_size = crn_ftell(pFile);
fclose(pFile);
return true;
}
bool file_utils::get_file_size(const char* pFilename, uint64& file_size) {
FILE* pFile;
crn_fopen(&pFile, pFilename, "rb");
if (!pFile)
return false;
crn_fseek(pFile, 0, SEEK_END);
file_size = crn_ftell(pFile);
fclose(pFile);
return true;
}
#endif
bool file_utils::get_file_size(const char* pFilename, uint32& file_size)
{
uint64 file_size64;
if (!get_file_size(pFilename, file_size64))
{
file_size = 0;
return false;
}
bool file_utils::get_file_size(const char* pFilename, uint32& file_size) {
uint64 file_size64;
if (!get_file_size(pFilename, file_size64)) {
file_size = 0;
return false;
}
if (file_size64 > cUINT32_MAX)
file_size64 = cUINT32_MAX;
if (file_size64 > cUINT32_MAX)
file_size64 = cUINT32_MAX;
file_size = static_cast<uint32>(file_size64);
return true;
}
file_size = static_cast<uint32>(file_size64);
return true;
}
bool file_utils::is_path_separator(char c)
{
bool file_utils::is_path_separator(char c) {
#ifdef WIN32
return (c == '/') || (c == '\\');
return (c == '/') || (c == '\\');
#else
return (c == '/');
return (c == '/');
#endif
}
}
bool file_utils::is_path_or_drive_separator(char c)
{
bool file_utils::is_path_or_drive_separator(char c) {
#ifdef WIN32
return (c == '/') || (c == '\\') || (c == ':');
return (c == '/') || (c == '\\') || (c == ':');
#else
return (c == '/');
return (c == '/');
#endif
}
}
bool file_utils::is_drive_separator(char c)
{
bool file_utils::is_drive_separator(char c) {
#ifdef WIN32
return (c == ':');
return (c == ':');
#else
c;
return false;
c;
return false;
#endif
}
}
bool file_utils::split_path(const char* p, dynamic_string* pDrive, dynamic_string* pDir, dynamic_string* pFilename, dynamic_string* pExt)
{
CRNLIB_ASSERT(p);
bool file_utils::split_path(const char* p, dynamic_string* pDrive, dynamic_string* pDir, dynamic_string* pFilename, dynamic_string* pExt) {
CRNLIB_ASSERT(p);
#ifdef WIN32
char drive_buf[_MAX_DRIVE];
char dir_buf[_MAX_DIR];
char fname_buf[_MAX_FNAME];
char ext_buf[_MAX_EXT];
char drive_buf[_MAX_DRIVE];
char dir_buf[_MAX_DIR];
char fname_buf[_MAX_FNAME];
char ext_buf[_MAX_EXT];
#ifdef _MSC_VER
// Compiling with MSVC
errno_t error = _splitpath_s(p,
pDrive ? drive_buf : NULL, pDrive ? _MAX_DRIVE : 0,
pDir ? dir_buf : NULL, pDir ? _MAX_DIR : 0,
pFilename ? fname_buf : NULL, pFilename ? _MAX_FNAME : 0,
pExt ? ext_buf : NULL, pExt ? _MAX_EXT : 0);
if (error != 0)
return false;
// Compiling with MSVC
errno_t error = _splitpath_s(p,
pDrive ? drive_buf : NULL, pDrive ? _MAX_DRIVE : 0,
pDir ? dir_buf : NULL, pDir ? _MAX_DIR : 0,
pFilename ? fname_buf : NULL, pFilename ? _MAX_FNAME : 0,
pExt ? ext_buf : NULL, pExt ? _MAX_EXT : 0);
if (error != 0)
return false;
#else
// Compiling with MinGW
_splitpath(p,
pDrive ? drive_buf : NULL,
pDir ? dir_buf : NULL,
pFilename ? fname_buf : NULL,
pExt ? ext_buf : NULL);
// Compiling with MinGW
_splitpath(p,
pDrive ? drive_buf : NULL,
pDir ? dir_buf : NULL,
pFilename ? fname_buf : NULL,
pExt ? ext_buf : NULL);
#endif
if (pDrive) *pDrive = drive_buf;
if (pDir) *pDir = dir_buf;
if (pFilename) *pFilename = fname_buf;
if (pExt) *pExt = ext_buf;
if (pDrive)
*pDrive = drive_buf;
if (pDir)
*pDir = dir_buf;
if (pFilename)
*pFilename = fname_buf;
if (pExt)
*pExt = ext_buf;
#else
char dirtmp[1024];
char nametmp[1024];
strcpy_safe(dirtmp, sizeof(dirtmp), p);
strcpy_safe(nametmp, sizeof(nametmp), p);
char dirtmp[1024];
char nametmp[1024];
strcpy_safe(dirtmp, sizeof(dirtmp), p);
strcpy_safe(nametmp, sizeof(nametmp), p);
if (pDrive) pDrive->clear();
if (pDrive)
pDrive->clear();
const char *pDirName = dirname(dirtmp);
if (!pDirName)
return false;
const char* pDirName = dirname(dirtmp);
if (!pDirName)
return false;
if (pDir)
{
pDir->set(pDirName);
if ((!pDir->is_empty()) && (pDir->back() != '/'))
pDir->append_char('/');
}
if (pDir) {
pDir->set(pDirName);
if ((!pDir->is_empty()) && (pDir->back() != '/'))
pDir->append_char('/');
}
const char *pBaseName = basename(nametmp);
if (!pBaseName)
return false;
const char* pBaseName = basename(nametmp);
if (!pBaseName)
return false;
if (pFilename)
{
pFilename->set(pBaseName);
remove_extension(*pFilename);
}
if (pFilename) {
pFilename->set(pBaseName);
remove_extension(*pFilename);
}
if (pExt)
{
pExt->set(pBaseName);
get_extension(*pExt);
*pExt = "." + *pExt;
}
#endif // #ifdef WIN32
if (pExt) {
pExt->set(pBaseName);
get_extension(*pExt);
*pExt = "." + *pExt;
}
#endif // #ifdef WIN32
return true;
}
return true;
}
bool file_utils::split_path(const char* p, dynamic_string& path, dynamic_string& filename)
{
dynamic_string temp_drive, temp_path, temp_ext;
if (!split_path(p, &temp_drive, &temp_path, &filename, &temp_ext))
return false;
bool file_utils::split_path(const char* p, dynamic_string& path, dynamic_string& filename) {
dynamic_string temp_drive, temp_path, temp_ext;
if (!split_path(p, &temp_drive, &temp_path, &filename, &temp_ext))
return false;
filename += temp_ext;
filename += temp_ext;
combine_path(path, temp_drive.get_ptr(), temp_path.get_ptr());
return true;
}
combine_path(path, temp_drive.get_ptr(), temp_path.get_ptr());
return true;
}
bool file_utils::get_pathname(const char* p, dynamic_string& path)
{
dynamic_string temp_drive, temp_path;
if (!split_path(p, &temp_drive, &temp_path, NULL, NULL))
return false;
bool file_utils::get_pathname(const char* p, dynamic_string& path) {
dynamic_string temp_drive, temp_path;
if (!split_path(p, &temp_drive, &temp_path, NULL, NULL))
return false;
combine_path(path, temp_drive.get_ptr(), temp_path.get_ptr());
return true;
}
combine_path(path, temp_drive.get_ptr(), temp_path.get_ptr());
return true;
}
bool file_utils::get_filename(const char* p, dynamic_string& filename)
{
dynamic_string temp_ext;
if (!split_path(p, NULL, NULL, &filename, &temp_ext))
return false;
bool file_utils::get_filename(const char* p, dynamic_string& filename) {
dynamic_string temp_ext;
if (!split_path(p, NULL, NULL, &filename, &temp_ext))
return false;
filename += temp_ext;
return true;
}
filename += temp_ext;
return true;
}
void file_utils::combine_path(dynamic_string& dst, const char* pA, const char* pB)
{
dynamic_string temp(pA);
if ((!temp.is_empty()) && (!is_path_separator(pB[0])))
{
char c = temp[temp.get_len() - 1];
if (!is_path_separator(c))
temp.append_char(CRNLIB_PATH_SEPERATOR_CHAR);
}
temp += pB;
dst.swap(temp);
}
void file_utils::combine_path(dynamic_string& dst, const char* pA, const char* pB) {
dynamic_string temp(pA);
if ((!temp.is_empty()) && (!is_path_separator(pB[0]))) {
char c = temp[temp.get_len() - 1];
if (!is_path_separator(c))
temp.append_char(CRNLIB_PATH_SEPERATOR_CHAR);
}
temp += pB;
dst.swap(temp);
}
void file_utils::combine_path(dynamic_string& dst, const char* pA, const char* pB, const char* pC)
{
combine_path(dst, pA, pB);
combine_path(dst, dst.get_ptr(), pC);
}
void file_utils::combine_path(dynamic_string& dst, const char* pA, const char* pB, const char* pC) {
combine_path(dst, pA, pB);
combine_path(dst, dst.get_ptr(), pC);
}
bool file_utils::full_path(dynamic_string& path)
{
bool file_utils::full_path(dynamic_string& path) {
#ifdef WIN32
char buf[1024];
char* p = _fullpath(buf, path.get_ptr(), sizeof(buf));
if (!p)
return false;
char buf[1024];
char* p = _fullpath(buf, path.get_ptr(), sizeof(buf));
if (!p)
return false;
#else
char buf[PATH_MAX];
char* p;
dynamic_string pn, fn;
split_path(path.get_ptr(), pn, fn);
if ((fn == ".") || (fn == ".."))
{
p = realpath(path.get_ptr(), buf);
if (!p)
return false;
path.set(buf);
}
else
{
if (pn.is_empty())
pn = "./";
p = realpath(pn.get_ptr(), buf);
if (!p)
return false;
combine_path(path, buf, fn.get_ptr());
}
char buf[PATH_MAX];
char* p;
dynamic_string pn, fn;
split_path(path.get_ptr(), pn, fn);
if ((fn == ".") || (fn == "..")) {
p = realpath(path.get_ptr(), buf);
if (!p)
return false;
path.set(buf);
} else {
if (pn.is_empty())
pn = "./";
p = realpath(pn.get_ptr(), buf);
if (!p)
return false;
combine_path(path, buf, fn.get_ptr());
}
#endif
return true;
}
return true;
}
bool file_utils::get_extension(dynamic_string& filename)
{
int sep = -1;
bool file_utils::get_extension(dynamic_string& filename) {
int sep = -1;
#ifdef WIN32
sep = filename.find_right('\\');
sep = filename.find_right('\\');
#endif
if (sep < 0)
sep = filename.find_right('/');
if (sep < 0)
sep = filename.find_right('/');
int dot = filename.find_right('.');
if (dot < sep)
{
filename.clear();
return false;
}
int dot = filename.find_right('.');
if (dot < sep) {
filename.clear();
return false;
}
filename.right(dot + 1);
filename.right(dot + 1);
return true;
}
return true;
}
bool file_utils::remove_extension(dynamic_string& filename)
{
int sep = -1;
bool file_utils::remove_extension(dynamic_string& filename) {
int sep = -1;
#ifdef WIN32
sep = filename.find_right('\\');
sep = filename.find_right('\\');
#endif
if (sep < 0)
sep = filename.find_right('/');
if (sep < 0)
sep = filename.find_right('/');
int dot = filename.find_right('.');
if (dot < sep)
return false;
int dot = filename.find_right('.');
if (dot < sep)
return false;
filename.left(dot);
filename.left(dot);
return true;
}
return true;
}
bool file_utils::create_path(const dynamic_string& fullpath)
{
bool got_unc = false; got_unc;
dynamic_string cur_path;
bool file_utils::create_path(const dynamic_string& fullpath) {
bool got_unc = false;
got_unc;
dynamic_string cur_path;
const int l = fullpath.get_len();
const int l = fullpath.get_len();
int n = 0;
while (n < l)
{
const char c = fullpath.get_ptr()[n];
int n = 0;
while (n < l) {
const char c = fullpath.get_ptr()[n];
const bool sep = is_path_separator(c);
const bool back_sep = is_path_separator(cur_path.back());
const bool is_last_char = (n == (l - 1));
const bool sep = is_path_separator(c);
const bool back_sep = is_path_separator(cur_path.back());
const bool is_last_char = (n == (l - 1));
if ( ((sep) && (!back_sep)) || (is_last_char) )
{
if ((is_last_char) && (!sep))
cur_path.append_char(c);
if (((sep) && (!back_sep)) || (is_last_char)) {
if ((is_last_char) && (!sep))
cur_path.append_char(c);
bool valid = !cur_path.is_empty();
bool valid = !cur_path.is_empty();
#ifdef WIN32
// reject obvious stuff (drives, beginning of UNC paths):
// c:\b\cool
// \\machine\blah
// \cool\blah
if ((cur_path.get_len() == 2) && (cur_path[1] == ':'))
valid = false;
else if ((cur_path.get_len() >= 2) && (cur_path[0] == '\\') && (cur_path[1] == '\\'))
{
if (!got_unc)
valid = false;
got_unc = true;
}
else if (cur_path == "\\")
valid = false;
// reject obvious stuff (drives, beginning of UNC paths):
// c:\b\cool
// \\machine\blah
// \cool\blah
if ((cur_path.get_len() == 2) && (cur_path[1] == ':'))
valid = false;
else if ((cur_path.get_len() >= 2) && (cur_path[0] == '\\') && (cur_path[1] == '\\')) {
if (!got_unc)
valid = false;
got_unc = true;
} else if (cur_path == "\\")
valid = false;
#endif
if (cur_path == "/")
valid = false;
if (cur_path == "/")
valid = false;
if ((valid) && (cur_path.get_len()))
{
if ((valid) && (cur_path.get_len())) {
#ifdef WIN32
_mkdir(cur_path.get_ptr());
_mkdir(cur_path.get_ptr());
#else
mkdir(cur_path.get_ptr(), S_IRWXU | S_IRWXG | S_IRWXO );
mkdir(cur_path.get_ptr(), S_IRWXU | S_IRWXG | S_IRWXO);
#endif
}
}
cur_path.append_char(c);
n++;
}
}
return true;
}
cur_path.append_char(c);
void file_utils::trim_trailing_seperator(dynamic_string& path)
{
if ((path.get_len()) && (is_path_separator(path.back())))
path.truncate(path.get_len() - 1);
}
n++;
}
// See http://www.codeproject.com/KB/string/wildcmp.aspx
int file_utils::wildcmp(const char* pWild, const char* pString)
{
const char* cp = NULL, *mp = NULL;
return true;
}
while ((*pString) && (*pWild != '*'))
{
if ((*pWild != *pString) && (*pWild != '?'))
return 0;
pWild++;
pString++;
}
void file_utils::trim_trailing_seperator(dynamic_string& path) {
if ((path.get_len()) && (is_path_separator(path.back())))
path.truncate(path.get_len() - 1);
}
// Either *pString=='\0' or *pWild='*' here.
// See http://www.codeproject.com/KB/string/wildcmp.aspx
int file_utils::wildcmp(const char* pWild, const char* pString) {
const char *cp = NULL, *mp = NULL;
while (*pString)
{
if (*pWild == '*')
{
if (!*++pWild)
return 1;
mp = pWild;
cp = pString+1;
}
else if ((*pWild == *pString) || (*pWild == '?'))
{
pWild++;
pString++;
}
else
{
pWild = mp;
pString = cp++;
}
}
while ((*pString) && (*pWild != '*')) {
if ((*pWild != *pString) && (*pWild != '?'))
return 0;
pWild++;
pString++;
}
while (*pWild == '*')
pWild++;
// Either *pString=='\0' or *pWild='*' here.
return !*pWild;
}
while (*pString) {
if (*pWild == '*') {
if (!*++pWild)
return 1;
mp = pWild;
cp = pString + 1;
} else if ((*pWild == *pString) || (*pWild == '?')) {
pWild++;
pString++;
} else {
pWild = mp;
pString = cp++;
}
}
bool file_utils::write_buf_to_file(const char* pPath, const void* pData, size_t data_size)
{
FILE *pFile = NULL;
while (*pWild == '*')
pWild++;
return !*pWild;
}
bool file_utils::write_buf_to_file(const char* pPath, const void* pData, size_t data_size) {
FILE* pFile = NULL;
#ifdef _MSC_VER
// Compiling with MSVC
if (fopen_s(&pFile, pPath, "wb"))
return false;
// Compiling with MSVC
if (fopen_s(&pFile, pPath, "wb"))
return false;
#else
pFile = fopen(pPath, "wb");
pFile = fopen(pPath, "wb");
#endif
if (!pFile)
return false;
if (!pFile)
return false;
bool success = fwrite(pData, 1, data_size, pFile) == data_size;
bool success = fwrite(pData, 1, data_size, pFile) == data_size;
fclose(pFile);
fclose(pFile);
return success;
}
return success;
}
} // namespace crnlib
} // namespace crnlib
+28 -30
View File
@@ -2,42 +2,40 @@
// See Copyright Notice and license at the end of inc/crnlib.h
#pragma once
namespace crnlib
{
struct file_utils
{
// Returns true if pSrcFilename is older than pDstFilename
static bool is_read_only(const char* pFilename);
static bool disable_read_only(const char* pFilename);
static bool is_older_than(const char *pSrcFilename, const char* pDstFilename);
static bool does_file_exist(const char* pFilename);
static bool does_dir_exist(const char* pDir);
static bool get_file_size(const char* pFilename, uint64& file_size);
static bool get_file_size(const char* pFilename, uint32& file_size);
namespace crnlib {
struct file_utils {
// Returns true if pSrcFilename is older than pDstFilename
static bool is_read_only(const char* pFilename);
static bool disable_read_only(const char* pFilename);
static bool is_older_than(const char* pSrcFilename, const char* pDstFilename);
static bool does_file_exist(const char* pFilename);
static bool does_dir_exist(const char* pDir);
static bool get_file_size(const char* pFilename, uint64& file_size);
static bool get_file_size(const char* pFilename, uint32& file_size);
static bool is_path_separator(char c);
static bool is_path_or_drive_separator(char c);
static bool is_drive_separator(char c);
static bool is_path_separator(char c);
static bool is_path_or_drive_separator(char c);
static bool is_drive_separator(char c);
static bool split_path(const char* p, dynamic_string* pDrive, dynamic_string* pDir, dynamic_string* pFilename, dynamic_string* pExt);
static bool split_path(const char* p, dynamic_string& path, dynamic_string& filename);
static bool split_path(const char* p, dynamic_string* pDrive, dynamic_string* pDir, dynamic_string* pFilename, dynamic_string* pExt);
static bool split_path(const char* p, dynamic_string& path, dynamic_string& filename);
static bool get_pathname(const char* p, dynamic_string& path);
static bool get_filename(const char* p, dynamic_string& filename);
static bool get_pathname(const char* p, dynamic_string& path);
static bool get_filename(const char* p, dynamic_string& filename);
static void combine_path(dynamic_string& dst, const char* pA, const char* pB);
static void combine_path(dynamic_string& dst, const char* pA, const char* pB, const char* pC);
static void combine_path(dynamic_string& dst, const char* pA, const char* pB);
static void combine_path(dynamic_string& dst, const char* pA, const char* pB, const char* pC);
static bool full_path(dynamic_string& path);
static bool get_extension(dynamic_string& filename);
static bool remove_extension(dynamic_string& filename);
static bool create_path(const dynamic_string& path);
static void trim_trailing_seperator(dynamic_string& path);
static bool full_path(dynamic_string& path);
static bool get_extension(dynamic_string& filename);
static bool remove_extension(dynamic_string& filename);
static bool create_path(const dynamic_string& path);
static void trim_trailing_seperator(dynamic_string& path);
static int wildcmp(const char* pWild, const char* pString);
static int wildcmp(const char* pWild, const char* pString);
static bool write_buf_to_file(const char* pPath, const void* pData, size_t data_size);
static bool write_buf_to_file(const char* pPath, const void* pData, size_t data_size);
}; // struct file_utils
}; // struct file_utils
} // namespace crnlib
} // namespace crnlib
+201 -235
View File
@@ -13,275 +13,241 @@
#include <dirent.h>
#endif
namespace crnlib
{
namespace crnlib {
#ifdef CRNLIB_USE_WIN32_API
bool find_files::find(const char* pBasepath, const char* pFilespec, uint flags)
{
m_last_error = S_OK;
m_files.resize(0);
bool find_files::find(const char* pBasepath, const char* pFilespec, uint flags) {
m_last_error = S_OK;
m_files.resize(0);
return find_internal(pBasepath, "", pFilespec, flags, 0);
}
return find_internal(pBasepath, "", pFilespec, flags, 0);
}
bool find_files::find(const char* pSpec, uint flags)
{
dynamic_string find_name(pSpec);
bool find_files::find(const char* pSpec, uint flags) {
dynamic_string find_name(pSpec);
if (!file_utils::full_path(find_name))
return false;
if (!file_utils::full_path(find_name))
return false;
dynamic_string find_pathname, find_filename;
if (!file_utils::split_path(find_name.get_ptr(), find_pathname, find_filename))
return false;
dynamic_string find_pathname, find_filename;
if (!file_utils::split_path(find_name.get_ptr(), find_pathname, find_filename))
return false;
return find(find_pathname.get_ptr(), find_filename.get_ptr(), flags);
}
return find(find_pathname.get_ptr(), find_filename.get_ptr(), flags);
}
bool find_files::find_internal(const char* pBasepath, const char* pRelpath, const char* pFilespec, uint flags, int level)
{
WIN32_FIND_DATAA find_data;
bool find_files::find_internal(const char* pBasepath, const char* pRelpath, const char* pFilespec, uint flags, int level) {
WIN32_FIND_DATAA find_data;
dynamic_string filename;
dynamic_string filename;
dynamic_string_array child_paths;
if (flags & cFlagRecursive)
{
if (strlen(pRelpath))
file_utils::combine_path(filename, pBasepath, pRelpath, "*");
else
file_utils::combine_path(filename, pBasepath, "*");
dynamic_string_array child_paths;
if (flags & cFlagRecursive) {
if (strlen(pRelpath))
file_utils::combine_path(filename, pBasepath, pRelpath, "*");
else
file_utils::combine_path(filename, pBasepath, "*");
HANDLE handle = FindFirstFileA(filename.get_ptr(), &find_data);
if (handle == INVALID_HANDLE_VALUE)
{
HRESULT hres = GetLastError();
if ((level == 0) && (hres != NO_ERROR) && (hres != ERROR_FILE_NOT_FOUND))
{
m_last_error = hres;
return false;
}
}
else
{
do
{
const bool is_dir = (find_data.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) != 0;
HANDLE handle = FindFirstFileA(filename.get_ptr(), &find_data);
if (handle == INVALID_HANDLE_VALUE) {
HRESULT hres = GetLastError();
if ((level == 0) && (hres != NO_ERROR) && (hres != ERROR_FILE_NOT_FOUND)) {
m_last_error = hres;
return false;
}
} else {
do {
const bool is_dir = (find_data.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) != 0;
bool skip = !is_dir;
if (is_dir)
skip = (strcmp(find_data.cFileName, ".") == 0) || (strcmp(find_data.cFileName, "..") == 0);
bool skip = !is_dir;
if (is_dir)
skip = (strcmp(find_data.cFileName, ".") == 0) || (strcmp(find_data.cFileName, "..") == 0);
if (find_data.dwFileAttributes & (FILE_ATTRIBUTE_SYSTEM | FILE_ATTRIBUTE_TEMPORARY))
skip = true;
if (find_data.dwFileAttributes & (FILE_ATTRIBUTE_SYSTEM | FILE_ATTRIBUTE_TEMPORARY))
skip = true;
if (find_data.dwFileAttributes & FILE_ATTRIBUTE_HIDDEN)
{
if ((flags & cFlagAllowHidden) == 0)
skip = true;
}
if (find_data.dwFileAttributes & FILE_ATTRIBUTE_HIDDEN) {
if ((flags & cFlagAllowHidden) == 0)
skip = true;
}
if (!skip)
{
dynamic_string child_path(find_data.cFileName);
if ((!child_path.count_char('?')) && (!child_path.count_char('*')))
child_paths.push_back(child_path);
}
if (!skip) {
dynamic_string child_path(find_data.cFileName);
if ((!child_path.count_char('?')) && (!child_path.count_char('*')))
child_paths.push_back(child_path);
}
} while (FindNextFileA(handle, &find_data) != 0);
} while (FindNextFileA(handle, &find_data) != 0);
HRESULT hres = GetLastError();
HRESULT hres = GetLastError();
FindClose(handle);
handle = INVALID_HANDLE_VALUE;
FindClose(handle);
handle = INVALID_HANDLE_VALUE;
if (hres != ERROR_NO_MORE_FILES)
{
m_last_error = hres;
return false;
}
}
if (hres != ERROR_NO_MORE_FILES) {
m_last_error = hres;
return false;
}
}
}
if (strlen(pRelpath))
file_utils::combine_path(filename, pBasepath, pRelpath, pFilespec);
else
file_utils::combine_path(filename, pBasepath, pFilespec);
HANDLE handle = FindFirstFileA(filename.get_ptr(), &find_data);
if (handle == INVALID_HANDLE_VALUE) {
HRESULT hres = GetLastError();
if ((level == 0) && (hres != NO_ERROR) && (hres != ERROR_FILE_NOT_FOUND)) {
m_last_error = hres;
return false;
}
} else {
do {
const bool is_dir = (find_data.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) != 0;
bool skip = false;
if (is_dir)
skip = (strcmp(find_data.cFileName, ".") == 0) || (strcmp(find_data.cFileName, "..") == 0);
if (find_data.dwFileAttributes & (FILE_ATTRIBUTE_SYSTEM | FILE_ATTRIBUTE_TEMPORARY))
skip = true;
if (find_data.dwFileAttributes & FILE_ATTRIBUTE_HIDDEN) {
if ((flags & cFlagAllowHidden) == 0)
skip = true;
}
if (strlen(pRelpath))
file_utils::combine_path(filename, pBasepath, pRelpath, pFilespec);
else
file_utils::combine_path(filename, pBasepath, pFilespec);
HANDLE handle = FindFirstFileA(filename.get_ptr(), &find_data);
if (handle == INVALID_HANDLE_VALUE)
{
HRESULT hres = GetLastError();
if ((level == 0) && (hres != NO_ERROR) && (hres != ERROR_FILE_NOT_FOUND))
{
m_last_error = hres;
return false;
}
}
else
{
do
{
const bool is_dir = (find_data.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) != 0;
bool skip = false;
if (is_dir)
skip = (strcmp(find_data.cFileName, ".") == 0) || (strcmp(find_data.cFileName, "..") == 0);
if (find_data.dwFileAttributes & (FILE_ATTRIBUTE_SYSTEM | FILE_ATTRIBUTE_TEMPORARY))
skip = true;
if (find_data.dwFileAttributes & FILE_ATTRIBUTE_HIDDEN)
{
if ((flags & cFlagAllowHidden) == 0)
skip = true;
}
if (!skip)
{
if (((is_dir) && (flags & cFlagAllowDirs)) || ((!is_dir) && (flags & cFlagAllowFiles)))
{
m_files.resize(m_files.size() + 1);
file_desc& file = m_files.back();
file.m_is_dir = is_dir;
file.m_base = pBasepath;
file.m_name = find_data.cFileName;
file.m_rel = pRelpath;
if (strlen(pRelpath))
file_utils::combine_path(file.m_fullname, pBasepath, pRelpath, find_data.cFileName);
else
file_utils::combine_path(file.m_fullname, pBasepath, find_data.cFileName);
}
}
} while (FindNextFileA(handle, &find_data) != 0);
HRESULT hres = GetLastError();
FindClose(handle);
if (hres != ERROR_NO_MORE_FILES)
{
m_last_error = hres;
return false;
}
if (!skip) {
if (((is_dir) && (flags & cFlagAllowDirs)) || ((!is_dir) && (flags & cFlagAllowFiles))) {
m_files.resize(m_files.size() + 1);
file_desc& file = m_files.back();
file.m_is_dir = is_dir;
file.m_base = pBasepath;
file.m_name = find_data.cFileName;
file.m_rel = pRelpath;
if (strlen(pRelpath))
file_utils::combine_path(file.m_fullname, pBasepath, pRelpath, find_data.cFileName);
else
file_utils::combine_path(file.m_fullname, pBasepath, find_data.cFileName);
}
}
for (uint i = 0; i < child_paths.size(); i++)
{
dynamic_string child_path;
if (strlen(pRelpath))
file_utils::combine_path(child_path, pRelpath, child_paths[i].get_ptr());
else
child_path = child_paths[i];
} while (FindNextFileA(handle, &find_data) != 0);
if (!find_internal(pBasepath, child_path.get_ptr(), pFilespec, flags, level + 1))
return false;
}
HRESULT hres = GetLastError();
return true;
}
FindClose(handle);
if (hres != ERROR_NO_MORE_FILES) {
m_last_error = hres;
return false;
}
}
for (uint i = 0; i < child_paths.size(); i++) {
dynamic_string child_path;
if (strlen(pRelpath))
file_utils::combine_path(child_path, pRelpath, child_paths[i].get_ptr());
else
child_path = child_paths[i];
if (!find_internal(pBasepath, child_path.get_ptr(), pFilespec, flags, level + 1))
return false;
}
return true;
}
#elif defined(__GNUC__)
bool find_files::find(const char* pBasepath, const char* pFilespec, uint flags)
{
m_files.resize(0);
return find_internal(pBasepath, "", pFilespec, flags, 0);
}
bool find_files::find(const char* pBasepath, const char* pFilespec, uint flags) {
m_files.resize(0);
return find_internal(pBasepath, "", pFilespec, flags, 0);
}
bool find_files::find(const char* pSpec, uint flags)
{
dynamic_string find_name(pSpec);
bool find_files::find(const char* pSpec, uint flags) {
dynamic_string find_name(pSpec);
if (!file_utils::full_path(find_name))
return false;
if (!file_utils::full_path(find_name))
return false;
dynamic_string find_pathname, find_filename;
if (!file_utils::split_path(find_name.get_ptr(), find_pathname, find_filename))
return false;
dynamic_string find_pathname, find_filename;
if (!file_utils::split_path(find_name.get_ptr(), find_pathname, find_filename))
return false;
return find(find_pathname.get_ptr(), find_filename.get_ptr(), flags);
}
return find(find_pathname.get_ptr(), find_filename.get_ptr(), flags);
}
bool find_files::find_internal(const char* pBasepath, const char* pRelpath, const char* pFilespec, uint flags, int level)
{
dynamic_string pathname;
bool find_files::find_internal(const char* pBasepath, const char* pRelpath, const char* pFilespec, uint flags, int level) {
dynamic_string pathname;
if (strlen(pRelpath))
file_utils::combine_path(pathname, pBasepath, pRelpath);
else
pathname = pBasepath;
if (!pathname.is_empty()) {
char c = pathname.back();
if (c != '/')
pathname += "/";
}
DIR* dp = opendir(pathname.get_ptr());
if (!dp)
return level ? true : false;
dynamic_string_array paths;
for (;;) {
struct dirent* ep = readdir(dp);
if (!ep)
break;
if ((strcmp(ep->d_name, ".") == 0) || (strcmp(ep->d_name, "..") == 0))
continue;
const bool is_directory = (ep->d_type & DT_DIR) != 0;
const bool is_file = (ep->d_type & DT_REG) != 0;
dynamic_string filename(ep->d_name);
if (is_directory) {
if (flags & cFlagRecursive) {
paths.push_back(filename);
}
}
if (((is_file) && (flags & cFlagAllowFiles)) || ((is_directory) && (flags & cFlagAllowDirs))) {
if (0 == fnmatch(pFilespec, filename.get_ptr(), 0)) {
m_files.resize(m_files.size() + 1);
file_desc& file = m_files.back();
file.m_is_dir = is_directory;
file.m_base = pBasepath;
file.m_rel = pRelpath;
file.m_name = filename;
file.m_fullname = pathname + filename;
}
}
}
closedir(dp);
dp = NULL;
if (flags & cFlagRecursive) {
for (uint i = 0; i < paths.size(); i++) {
dynamic_string childpath;
if (strlen(pRelpath))
file_utils::combine_path(pathname, pBasepath, pRelpath);
file_utils::combine_path(childpath, pRelpath, paths[i].get_ptr());
else
pathname = pBasepath;
childpath = paths[i];
if (!pathname.is_empty())
{
char c = pathname.back();
if (c != '/')
pathname += "/";
}
if (!find_internal(pBasepath, childpath.get_ptr(), pFilespec, flags, level + 1))
return false;
}
}
DIR *dp = opendir(pathname.get_ptr());
if (!dp)
return level ? true : false;
dynamic_string_array paths;
for ( ; ; )
{
struct dirent *ep = readdir(dp);
if (!ep)
break;
if ((strcmp(ep->d_name, ".") == 0) || (strcmp(ep->d_name, "..") == 0))
continue;
const bool is_directory = (ep->d_type & DT_DIR) != 0;
const bool is_file = (ep->d_type & DT_REG) != 0;
dynamic_string filename(ep->d_name);
if (is_directory)
{
if (flags & cFlagRecursive)
{
paths.push_back(filename);
}
}
if (((is_file) && (flags & cFlagAllowFiles)) || ((is_directory) && (flags & cFlagAllowDirs)))
{
if (0 == fnmatch(pFilespec, filename.get_ptr(), 0))
{
m_files.resize(m_files.size() + 1);
file_desc& file = m_files.back();
file.m_is_dir = is_directory;
file.m_base = pBasepath;
file.m_rel = pRelpath;
file.m_name = filename;
file.m_fullname = pathname + filename;
}
}
}
closedir(dp);
dp = NULL;
if (flags & cFlagRecursive)
{
for (uint i = 0; i < paths.size(); i++)
{
dynamic_string childpath;
if (strlen(pRelpath))
file_utils::combine_path(childpath, pRelpath, paths[i].get_ptr());
else
childpath = paths[i];
if (!find_internal(pBasepath, childpath.get_ptr(), pFilespec, flags, level + 1))
return false;
}
}
return true;
}
return true;
}
#else
#error Unimplemented
#error Unimplemented
#endif
} // namespace crnlib
} // namespace crnlib
+37 -41
View File
@@ -2,59 +2,55 @@
// See Copyright Notice and license at the end of inc/crnlib.h
#pragma once
namespace crnlib
{
class find_files
{
public:
struct file_desc
{
inline file_desc() : m_is_dir(false) { }
namespace crnlib {
class find_files {
public:
struct file_desc {
inline file_desc()
: m_is_dir(false) {}
dynamic_string m_fullname;
dynamic_string m_base;
dynamic_string m_rel;
dynamic_string m_name;
bool m_is_dir;
dynamic_string m_fullname;
dynamic_string m_base;
dynamic_string m_rel;
dynamic_string m_name;
bool m_is_dir;
inline bool operator== (const file_desc& other) const { return m_fullname == other.m_fullname; }
inline bool operator< (const file_desc& other) const { return m_fullname < other.m_fullname; }
inline bool operator==(const file_desc& other) const { return m_fullname == other.m_fullname; }
inline bool operator<(const file_desc& other) const { return m_fullname < other.m_fullname; }
inline operator size_t() const { return static_cast<size_t>(m_fullname); }
};
inline operator size_t() const { return static_cast<size_t>(m_fullname); }
};
typedef crnlib::vector<file_desc> file_desc_vec;
typedef crnlib::vector<file_desc> file_desc_vec;
inline find_files()
{
m_last_error = 0; // S_OK;
}
inline find_files() {
m_last_error = 0; // S_OK;
}
enum flags
{
cFlagRecursive = 1,
cFlagAllowDirs = 2,
cFlagAllowFiles = 4,
cFlagAllowHidden = 8
};
enum flags {
cFlagRecursive = 1,
cFlagAllowDirs = 2,
cFlagAllowFiles = 4,
cFlagAllowHidden = 8
};
bool find(const char* pBasepath, const char* pFilespec, uint flags = cFlagAllowFiles);
bool find(const char* pBasepath, const char* pFilespec, uint flags = cFlagAllowFiles);
bool find(const char* pSpec, uint flags = cFlagAllowFiles);
bool find(const char* pSpec, uint flags = cFlagAllowFiles);
// An HRESULT under Win32. FIXME: Abstract this better?
inline int64 get_last_error() const { return m_last_error; }
// An HRESULT under Win32. FIXME: Abstract this better?
inline int64 get_last_error() const { return m_last_error; }
const file_desc_vec& get_files() const { return m_files; }
const file_desc_vec& get_files() const { return m_files; }
private:
file_desc_vec m_files;
private:
file_desc_vec m_files;
// A HRESULT under Win32
int64 m_last_error;
// A HRESULT under Win32
int64 m_last_error;
bool find_internal(const char* pBasepath, const char* pRelpath, const char* pFilespec, uint flags, int level);
bool find_internal(const char* pBasepath, const char* pRelpath, const char* pFilespec, uint flags, int level);
}; // class find_files
}; // class find_files
} // namespace crnlib
} // namespace crnlib
+110 -124
View File
@@ -6,153 +6,139 @@
#include "freeImagePlus.h"
namespace crnlib
{
namespace freeimage_image_utils
{
inline bool load_from_file(image_u8& dest, const wchar_t* pFilename, int fi_flag)
{
fipImage src_image;
namespace crnlib {
namespace freeimage_image_utils {
inline bool load_from_file(image_u8& dest, const wchar_t* pFilename, int fi_flag) {
fipImage src_image;
if (!src_image.loadU(pFilename, fi_flag))
return false;
const uint orig_bits_per_pixel = src_image.getBitsPerPixel();
if (!src_image.loadU(pFilename, fi_flag))
return false;
const FREE_IMAGE_COLOR_TYPE orig_color_type = src_image.getColorType();
if (!src_image.convertTo32Bits())
return false;
const uint orig_bits_per_pixel = src_image.getBitsPerPixel();
if (src_image.getBitsPerPixel() != 32)
return false;
const FREE_IMAGE_COLOR_TYPE orig_color_type = src_image.getColorType();
uint width = src_image.getWidth();
uint height = src_image.getHeight();
if (!src_image.convertTo32Bits())
return false;
dest.resize(src_image.getWidth(), src_image.getHeight(), src_image.getWidth());
if (src_image.getBitsPerPixel() != 32)
return false;
color_quad_u8* pDst = dest.get_ptr();
uint width = src_image.getWidth();
uint height = src_image.getHeight();
bool grayscale = true;
bool has_alpha = false;
for (uint y = 0; y < height; y++)
{
const BYTE* pSrc = src_image.getScanLine((WORD)(height - 1 - y));
color_quad_u8* pD = pDst;
dest.resize(src_image.getWidth(), src_image.getHeight(), src_image.getWidth());
for (uint x = width; x; x--)
{
color_quad_u8 c;
c.r = pSrc[FI_RGBA_RED];
c.g = pSrc[FI_RGBA_GREEN];
c.b = pSrc[FI_RGBA_BLUE];
c.a = pSrc[FI_RGBA_ALPHA];
if (!c.is_grayscale())
grayscale = false;
has_alpha |= (c.a < 255);
color_quad_u8* pDst = dest.get_ptr();
pSrc += 4;
*pD++ = c;
}
bool grayscale = true;
bool has_alpha = false;
for (uint y = 0; y < height; y++) {
const BYTE* pSrc = src_image.getScanLine((WORD)(height - 1 - y));
color_quad_u8* pD = pDst;
pDst += width;
}
for (uint x = width; x; x--) {
color_quad_u8 c;
c.r = pSrc[FI_RGBA_RED];
c.g = pSrc[FI_RGBA_GREEN];
c.b = pSrc[FI_RGBA_BLUE];
c.a = pSrc[FI_RGBA_ALPHA];
dest.reset_comp_flags();
if (grayscale)
dest.set_grayscale(true);
dest.set_component_valid(3, has_alpha || (orig_color_type == FIC_RGBALPHA) || (orig_bits_per_pixel == 32));
if (!c.is_grayscale())
grayscale = false;
has_alpha |= (c.a < 255);
return true;
}
const int cSaveLuma = -1;
inline bool save_to_grayscale_file(const wchar_t* pFilename, const image_u8& src, int component, int fi_flag)
{
fipImage dst_image(FIT_BITMAP, (WORD)src.get_width(), (WORD)src.get_height(), 8);
pSrc += 4;
*pD++ = c;
}
RGBQUAD* p = dst_image.getPalette();
for (uint i = 0; i < dst_image.getPaletteSize(); i++)
{
p[i].rgbRed = (BYTE)i;
p[i].rgbGreen = (BYTE)i;
p[i].rgbBlue = (BYTE)i;
p[i].rgbReserved = 255;
}
pDst += width;
}
for (uint y = 0; y < src.get_height(); y++)
{
const color_quad_u8* pSrc = src.get_scanline(y);
dest.reset_comp_flags();
for (uint x = 0; x < src.get_width(); x++)
{
BYTE v;
if (component == cSaveLuma)
v = (BYTE)(*pSrc).get_luma();
else
v = (*pSrc)[component];
dst_image.setPixelIndex(x, src.get_height() - 1 - y, &v);
if (grayscale)
dest.set_grayscale(true);
pSrc++;
}
}
dest.set_component_valid(3, has_alpha || (orig_color_type == FIC_RGBALPHA) || (orig_bits_per_pixel == 32));
if (!dst_image.saveU(pFilename, fi_flag))
return false;
return true;
}
return true;
}
const int cSaveLuma = -1;
inline bool save_to_file(const wchar_t* pFilename, const image_u8& src, int fi_flag, bool ignore_alpha = false)
{
const bool save_alpha = src.is_component_valid(3);
uint bpp = (save_alpha && !ignore_alpha) ? 32 : 24;
if (bpp == 32)
{
dynamic_wstring ext(pFilename);
get_extension(ext);
inline bool save_to_grayscale_file(const wchar_t* pFilename, const image_u8& src, int component, int fi_flag) {
fipImage dst_image(FIT_BITMAP, (WORD)src.get_width(), (WORD)src.get_height(), 8);
if ((ext == L"jpg") || (ext == L"jpeg") || (ext == L"gif") || (ext == L"jp2"))
bpp = 24;
}
if ((bpp == 24) && (src.is_grayscale()))
return save_to_grayscale_file(pFilename, src, cSaveLuma, fi_flag);
fipImage dst_image(FIT_BITMAP, (WORD)src.get_width(), (WORD)src.get_height(), (WORD)bpp);
RGBQUAD* p = dst_image.getPalette();
for (uint i = 0; i < dst_image.getPaletteSize(); i++) {
p[i].rgbRed = (BYTE)i;
p[i].rgbGreen = (BYTE)i;
p[i].rgbBlue = (BYTE)i;
p[i].rgbReserved = 255;
}
for (uint y = 0; y < src.get_height(); y++)
{
for (uint x = 0; x < src.get_width(); x++)
{
color_quad_u8 c(src(x, y));
for (uint y = 0; y < src.get_height(); y++) {
const color_quad_u8* pSrc = src.get_scanline(y);
RGBQUAD quad;
quad.rgbRed = c.r;
quad.rgbGreen = c.g;
quad.rgbBlue = c.b;
if (bpp == 32)
quad.rgbReserved = c.a;
else
quad.rgbReserved = 255;
for (uint x = 0; x < src.get_width(); x++) {
BYTE v;
if (component == cSaveLuma)
v = (BYTE)(*pSrc).get_luma();
else
v = (*pSrc)[component];
dst_image.setPixelIndex(x, src.get_height() - 1 - y, &v);
dst_image.setPixelColor(x, src.get_height() - 1 - y, &quad);
}
}
pSrc++;
}
}
if (!dst_image.saveU(pFilename, fi_flag))
return false;
if (!dst_image.saveU(pFilename, fi_flag))
return false;
return true;
}
} // namespace freeimage_image_utils
} // namespace crnlib
return true;
}
inline bool save_to_file(const wchar_t* pFilename, const image_u8& src, int fi_flag, bool ignore_alpha = false) {
const bool save_alpha = src.is_component_valid(3);
uint bpp = (save_alpha && !ignore_alpha) ? 32 : 24;
if (bpp == 32) {
dynamic_wstring ext(pFilename);
get_extension(ext);
if ((ext == L"jpg") || (ext == L"jpeg") || (ext == L"gif") || (ext == L"jp2"))
bpp = 24;
}
if ((bpp == 24) && (src.is_grayscale()))
return save_to_grayscale_file(pFilename, src, cSaveLuma, fi_flag);
fipImage dst_image(FIT_BITMAP, (WORD)src.get_width(), (WORD)src.get_height(), (WORD)bpp);
for (uint y = 0; y < src.get_height(); y++) {
for (uint x = 0; x < src.get_width(); x++) {
color_quad_u8 c(src(x, y));
RGBQUAD quad;
quad.rgbRed = c.r;
quad.rgbGreen = c.g;
quad.rgbBlue = c.b;
if (bpp == 32)
quad.rgbReserved = c.a;
else
quad.rgbReserved = 255;
dst_image.setPixelColor(x, src.get_height() - 1 - y, &quad);
}
}
if (!dst_image.saveU(pFilename, fi_flag))
return false;
return true;
}
} // namespace freeimage_image_utils
} // namespace crnlib
+48 -48
View File
@@ -5,64 +5,64 @@
#include "crn_core.h"
#undef get16bits
#if (defined(__GNUC__) && defined(__i386__)) || defined(__WATCOMC__) \
|| defined(_MSC_VER) || defined (__BORLANDC__) || defined (__TURBOC__)
#define get16bits(d) (*((const uint16 *) (d)))
#if (defined(__GNUC__) && defined(__i386__)) || defined(__WATCOMC__) || defined(_MSC_VER) || defined(__BORLANDC__) || defined(__TURBOC__)
#define get16bits(d) (*((const uint16*)(d)))
#endif
#if !defined (get16bits)
#define get16bits(d) ((((uint32)(((const uint8 *)(d))[1])) << 8)\
+(uint32)(((const uint8 *)(d))[0]) )
#if !defined(get16bits)
#define get16bits(d) ((((uint32)(((const uint8*)(d))[1])) << 8) + (uint32)(((const uint8*)(d))[0]))
#endif
namespace crnlib
{
uint32 fast_hash (const void* p, int len)
{
const char * data = static_cast<const char *>(p);
uint32 hash = len, tmp;
int rem;
namespace crnlib {
uint32 fast_hash(const void* p, int len) {
const char* data = static_cast<const char*>(p);
if (len <= 0 || data == NULL) return 0;
uint32 hash = len, tmp;
int rem;
rem = len & 3;
len >>= 2;
if (len <= 0 || data == NULL)
return 0;
/* Main loop */
for (;len > 0; len--) {
hash += get16bits (data);
tmp = (get16bits (data+2) << 11) ^ hash;
hash = (hash << 16) ^ tmp;
data += 2*sizeof (uint16);
hash += hash >> 11;
}
rem = len & 3;
len >>= 2;
/* Handle end cases */
switch (rem) {
case 3: hash += get16bits (data);
hash ^= hash << 16;
hash ^= data[sizeof (uint16)] << 18;
hash += hash >> 11;
break;
case 2: hash += get16bits (data);
hash ^= hash << 11;
hash += hash >> 17;
break;
case 1: hash += *data;
hash ^= hash << 10;
hash += hash >> 1;
}
/* Main loop */
for (; len > 0; len--) {
hash += get16bits(data);
tmp = (get16bits(data + 2) << 11) ^ hash;
hash = (hash << 16) ^ tmp;
data += 2 * sizeof(uint16);
hash += hash >> 11;
}
/* Force "avalanching" of final 127 bits */
hash ^= hash << 3;
hash += hash >> 5;
hash ^= hash << 4;
/* Handle end cases */
switch (rem) {
case 3:
hash += get16bits(data);
hash ^= hash << 16;
hash ^= data[sizeof(uint16)] << 18;
hash += hash >> 11;
break;
case 2:
hash += get16bits(data);
hash ^= hash << 11;
hash += hash >> 17;
hash ^= hash << 25;
hash += hash >> 6;
break;
case 1:
hash += *data;
hash ^= hash << 10;
hash += hash >> 1;
}
return hash;
}
/* Force "avalanching" of final 127 bits */
hash ^= hash << 3;
hash += hash >> 5;
hash ^= hash << 4;
hash += hash >> 17;
hash ^= hash << 25;
hash += hash >> 6;
return hash;
}
} // namespace crnlib
+26 -29
View File
@@ -2,33 +2,30 @@
// See Copyright Notice and license at the end of inc/crnlib.h
#pragma once
namespace crnlib
{
uint32 fast_hash (const void* p, int len);
// 4-byte integer hash, full avalanche
inline uint32 bitmix32c(uint32 a)
{
a = (a+0x7ed55d16) + (a<<12);
a = (a^0xc761c23c) ^ (a>>19);
a = (a+0x165667b1) + (a<<5);
a = (a+0xd3a2646c) ^ (a<<9);
a = (a+0xfd7046c5) + (a<<3);
a = (a^0xb55a4f09) ^ (a>>16);
return a;
}
// 4-byte integer hash, full avalanche, no constants
inline uint32 bitmix32(uint32 a)
{
a -= (a<<6);
a ^= (a>>17);
a -= (a<<9);
a ^= (a<<4);
a -= (a<<3);
a ^= (a<<10);
a ^= (a>>15);
return a;
}
namespace crnlib {
uint32 fast_hash(const void* p, int len);
// 4-byte integer hash, full avalanche
inline uint32 bitmix32c(uint32 a) {
a = (a + 0x7ed55d16) + (a << 12);
a = (a ^ 0xc761c23c) ^ (a >> 19);
a = (a + 0x165667b1) + (a << 5);
a = (a + 0xd3a2646c) ^ (a << 9);
a = (a + 0xfd7046c5) + (a << 3);
a = (a ^ 0xb55a4f09) ^ (a >> 16);
return a;
}
// 4-byte integer hash, full avalanche, no constants
inline uint32 bitmix32(uint32 a) {
a -= (a << 6);
a ^= (a >> 17);
a -= (a << 9);
a ^= (a << 4);
a -= (a << 3);
a ^= (a << 10);
a ^= (a >> 15);
return a;
}
} // namespace crnlib
+2 -3
View File
@@ -4,8 +4,7 @@
#include "crn_hash_map.h"
#include "crn_rand.h"
namespace crnlib
{
namespace crnlib {
#if 0
class counted_obj
{
@@ -152,4 +151,4 @@ namespace crnlib
}
#endif
} // namespace crnlib
} // namespace crnlib
+681 -792
View File
File diff suppressed because it is too large Load Diff
+53 -55
View File
@@ -2,63 +2,61 @@
// See Copyright Notice and license at the end of inc/crnlib.h
#pragma once
#define CRNLIB_NO_COPY_OR_ASSIGNMENT_OP(c) c(const c&); c& operator= (const c&);
#define CRNLIB_NO_HEAP_ALLOC() private: static void* operator new(size_t); static void* operator new[](size_t);
#define CRNLIB_NO_COPY_OR_ASSIGNMENT_OP(c) \
c(const c&); \
c& operator=(const c&);
#define CRNLIB_NO_HEAP_ALLOC() \
private: \
static void* operator new(size_t); \
static void* operator new[](size_t);
namespace crnlib
{
namespace helpers
{
template<typename T> struct rel_ops
{
friend bool operator!=(const T& x, const T& y) { return (!(x == y)); }
friend bool operator> (const T& x, const T& y) { return (y < x); }
friend bool operator<=(const T& x, const T& y) { return (!(y < x)); }
friend bool operator>=(const T& x, const T& y) { return (!(x < y)); }
};
template <typename T>
inline T* construct(T* p)
{
return new (static_cast<void*>(p)) T;
}
namespace crnlib {
namespace helpers {
template <typename T>
struct rel_ops {
friend bool operator!=(const T& x, const T& y) { return (!(x == y)); }
friend bool operator>(const T& x, const T& y) { return (y < x); }
friend bool operator<=(const T& x, const T& y) { return (!(y < x)); }
friend bool operator>=(const T& x, const T& y) { return (!(x < y)); }
};
template <typename T, typename U>
inline T* construct(T* p, const U& init)
{
return new (static_cast<void*>(p)) T(init);
}
template <typename T>
inline T* construct(T* p) {
return new (static_cast<void*>(p)) T;
}
template <typename T>
inline void construct_array(T* p, uint n)
{
T* q = p + n;
for ( ; p != q; ++p)
new (static_cast<void*>(p)) T;
}
template <typename T, typename U>
inline void construct_array(T* p, uint n, const U& init)
{
T* q = p + n;
for ( ; p != q; ++p)
new (static_cast<void*>(p)) T(init);
}
template <typename T, typename U>
inline T* construct(T* p, const U& init) {
return new (static_cast<void*>(p)) T(init);
}
template <typename T>
inline void construct_array(T* p, uint n) {
T* q = p + n;
for (; p != q; ++p)
new (static_cast<void*>(p)) T;
}
template <typename T, typename U>
inline void construct_array(T* p, uint n, const U& init) {
T* q = p + n;
for (; p != q; ++p)
new (static_cast<void*>(p)) T(init);
}
template <typename T>
inline void destruct(T* p) {
p;
p->~T();
}
template <typename T>
inline void destruct_array(T* p, uint n) {
T* q = p + n;
for (; p != q; ++p)
p->~T();
}
} // namespace helpers
template <typename T>
inline void destruct(T* p)
{
p;
p->~T();
}
template <typename T> inline void destruct_array(T* p, uint n)
{
T* q = p + n;
for ( ; p != q; ++p)
p->~T();
}
} // namespace helpers
} // namespace crnlib
+322 -343
View File
@@ -3,385 +3,364 @@
#include "crn_core.h"
#include "crn_huffman_codes.h"
namespace crnlib
{
struct sym_freq
{
uint m_freq;
uint16 m_left;
uint16 m_right;
namespace crnlib {
struct sym_freq {
uint m_freq;
uint16 m_left;
uint16 m_right;
inline bool operator< (const sym_freq& other) const
{
return m_freq > other.m_freq;
}
};
static inline sym_freq* radix_sort_syms(uint num_syms, sym_freq* syms0, sym_freq* syms1)
{
const uint cMaxPasses = 2;
uint hist[256 * cMaxPasses];
memset(hist, 0, sizeof(hist[0]) * 256 * cMaxPasses);
inline bool operator<(const sym_freq& other) const {
return m_freq > other.m_freq;
}
};
sym_freq* p = syms0;
sym_freq* q = syms0 + (num_syms >> 1) * 2;
static inline sym_freq* radix_sort_syms(uint num_syms, sym_freq* syms0, sym_freq* syms1) {
const uint cMaxPasses = 2;
uint hist[256 * cMaxPasses];
for ( ; p != q; p += 2)
{
const uint freq0 = p[0].m_freq;
const uint freq1 = p[1].m_freq;
memset(hist, 0, sizeof(hist[0]) * 256 * cMaxPasses);
hist[ freq0 & 0xFF]++;
hist[256 + ((freq0 >> 8) & 0xFF)]++;
sym_freq* p = syms0;
sym_freq* q = syms0 + (num_syms >> 1) * 2;
hist[ freq1 & 0xFF]++;
hist[256 + ((freq1 >> 8) & 0xFF)]++;
for (; p != q; p += 2) {
const uint freq0 = p[0].m_freq;
const uint freq1 = p[1].m_freq;
hist[freq0 & 0xFF]++;
hist[256 + ((freq0 >> 8) & 0xFF)]++;
hist[freq1 & 0xFF]++;
hist[256 + ((freq1 >> 8) & 0xFF)]++;
}
if (num_syms & 1) {
const uint freq = p->m_freq;
hist[freq & 0xFF]++;
hist[256 + ((freq >> 8) & 0xFF)]++;
}
sym_freq* pCur_syms = syms0;
sym_freq* pNew_syms = syms1;
for (uint pass = 0; pass < cMaxPasses; pass++) {
const uint* pHist = &hist[pass << 8];
uint offsets[256];
uint cur_ofs = 0;
for (uint i = 0; i < 256; i += 2) {
offsets[i] = cur_ofs;
cur_ofs += pHist[i];
offsets[i + 1] = cur_ofs;
cur_ofs += pHist[i + 1];
}
const uint pass_shift = pass << 3;
sym_freq* p = pCur_syms;
sym_freq* q = pCur_syms + (num_syms >> 1) * 2;
for (; p != q; p += 2) {
uint c0 = p[0].m_freq;
uint c1 = p[1].m_freq;
if (pass) {
c0 >>= 8;
c1 >>= 8;
}
if (num_syms & 1)
{
const uint freq = p->m_freq;
c0 &= 0xFF;
c1 &= 0xFF;
hist[ freq & 0xFF]++;
hist[256 + ((freq >> 8) & 0xFF)]++;
if (c0 == c1) {
uint dst_offset0 = offsets[c0];
offsets[c0] = dst_offset0 + 2;
pNew_syms[dst_offset0] = p[0];
pNew_syms[dst_offset0 + 1] = p[1];
} else {
uint dst_offset0 = offsets[c0]++;
uint dst_offset1 = offsets[c1]++;
pNew_syms[dst_offset0] = p[0];
pNew_syms[dst_offset1] = p[1];
}
sym_freq* pCur_syms = syms0;
sym_freq* pNew_syms = syms1;
}
for (uint pass = 0; pass < cMaxPasses; pass++)
{
const uint* pHist = &hist[pass << 8];
if (num_syms & 1) {
uint c = ((p->m_freq) >> pass_shift) & 0xFF;
uint offsets[256];
uint dst_offset = offsets[c];
offsets[c] = dst_offset + 1;
uint cur_ofs = 0;
for (uint i = 0; i < 256; i += 2)
{
offsets[i] = cur_ofs;
cur_ofs += pHist[i];
pNew_syms[dst_offset] = *p;
}
offsets[i+1] = cur_ofs;
cur_ofs += pHist[i+1];
}
const uint pass_shift = pass << 3;
sym_freq* p = pCur_syms;
sym_freq* q = pCur_syms + (num_syms >> 1) * 2;
for ( ; p != q; p += 2)
{
uint c0 = p[0].m_freq;
uint c1 = p[1].m_freq;
if (pass)
{
c0 >>= 8;
c1 >>= 8;
}
c0 &= 0xFF;
c1 &= 0xFF;
if (c0 == c1)
{
uint dst_offset0 = offsets[c0];
offsets[c0] = dst_offset0 + 2;
pNew_syms[dst_offset0] = p[0];
pNew_syms[dst_offset0 + 1] = p[1];
}
else
{
uint dst_offset0 = offsets[c0]++;
uint dst_offset1 = offsets[c1]++;
pNew_syms[dst_offset0] = p[0];
pNew_syms[dst_offset1] = p[1];
}
}
if (num_syms & 1)
{
uint c = ((p->m_freq) >> pass_shift) & 0xFF;
uint dst_offset = offsets[c];
offsets[c] = dst_offset + 1;
pNew_syms[dst_offset] = *p;
}
sym_freq* t = pCur_syms;
pCur_syms = pNew_syms;
pNew_syms = t;
}
sym_freq* t = pCur_syms;
pCur_syms = pNew_syms;
pNew_syms = t;
}
#ifdef CRNLIB_ASSERTS_ENABLED
uint prev_freq = 0;
for (uint i = 0; i < num_syms; i++)
{
CRNLIB_ASSERT(!(pCur_syms[i].m_freq < prev_freq));
prev_freq = pCur_syms[i].m_freq;
}
uint prev_freq = 0;
for (uint i = 0; i < num_syms; i++) {
CRNLIB_ASSERT(!(pCur_syms[i].m_freq < prev_freq));
prev_freq = pCur_syms[i].m_freq;
}
#endif
return pCur_syms;
}
struct huffman_work_tables
{
enum { cMaxInternalNodes = cHuffmanMaxSupportedSyms };
sym_freq syms0[cHuffmanMaxSupportedSyms + 1 + cMaxInternalNodes];
sym_freq syms1[cHuffmanMaxSupportedSyms + 1 + cMaxInternalNodes];
uint16 queue[cMaxInternalNodes];
};
void* create_generate_huffman_codes_tables()
{
return crnlib_new<huffman_work_tables>();
}
void free_generate_huffman_codes_tables(void* p)
{
crnlib_delete(static_cast<huffman_work_tables*>(p));
}
#if USE_CALCULATE_MINIMUM_REDUNDANCY
/* calculate_minimum_redundancy() written by
return pCur_syms;
}
struct huffman_work_tables {
enum { cMaxInternalNodes = cHuffmanMaxSupportedSyms };
sym_freq syms0[cHuffmanMaxSupportedSyms + 1 + cMaxInternalNodes];
sym_freq syms1[cHuffmanMaxSupportedSyms + 1 + cMaxInternalNodes];
uint16 queue[cMaxInternalNodes];
};
void* create_generate_huffman_codes_tables() {
return crnlib_new<huffman_work_tables>();
}
void free_generate_huffman_codes_tables(void* p) {
crnlib_delete(static_cast<huffman_work_tables*>(p));
}
#if USE_CALCULATE_MINIMUM_REDUNDANCY
/* calculate_minimum_redundancy() written by
Alistair Moffat, alistair@cs.mu.oz.au,
Jyrki Katajainen, jyrki@diku.dk
November 1996.
*/
static void calculate_minimum_redundancy(int A[], int n) {
int root; /* next root node to be used */
int leaf; /* next leaf to be used */
int next; /* next value to be assigned */
int avbl; /* number of available nodes */
int used; /* number of internal nodes */
int dpth; /* current depth of leaves */
static void calculate_minimum_redundancy(int A[], int n) {
int root; /* next root node to be used */
int leaf; /* next leaf to be used */
int next; /* next value to be assigned */
int avbl; /* number of available nodes */
int used; /* number of internal nodes */
int dpth; /* current depth of leaves */
/* check for pathological cases */
if (n==0) { return; }
if (n==1) { A[0] = 0; return; }
/* check for pathological cases */
if (n == 0) {
return;
}
if (n == 1) {
A[0] = 0;
return;
}
/* first pass, left to right, setting parent pointers */
A[0] += A[1]; root = 0; leaf = 2;
for (next=1; next < n-1; next++) {
/* select first item for a pairing */
if (leaf>=n || A[root]<A[leaf]) {
A[next] = A[root]; A[root++] = next;
} else
A[next] = A[leaf++];
/* first pass, left to right, setting parent pointers */
A[0] += A[1];
root = 0;
leaf = 2;
for (next = 1; next < n - 1; next++) {
/* select first item for a pairing */
if (leaf >= n || A[root] < A[leaf]) {
A[next] = A[root];
A[root++] = next;
} else
A[next] = A[leaf++];
/* add on the second item */
if (leaf>=n || (root<next && A[root]<A[leaf])) {
A[next] += A[root]; A[root++] = next;
} else
A[next] += A[leaf++];
}
/* add on the second item */
if (leaf >= n || (root < next && A[root] < A[leaf])) {
A[next] += A[root];
A[root++] = next;
} else
A[next] += A[leaf++];
}
/* second pass, right to left, setting internal depths */
A[n-2] = 0;
for (next=n-3; next>=0; next--)
A[next] = A[A[next]]+1;
/* second pass, right to left, setting internal depths */
A[n - 2] = 0;
for (next = n - 3; next >= 0; next--)
A[next] = A[A[next]] + 1;
/* third pass, right to left, setting leaf depths */
avbl = 1; used = dpth = 0; root = n-2; next = n-1;
while (avbl>0) {
while (root>=0 && A[root]==dpth) {
used++; root--;
}
while (avbl>used) {
A[next--] = dpth; avbl--;
}
avbl = 2*used; dpth++; used = 0;
}
}
/* third pass, right to left, setting leaf depths */
avbl = 1;
used = dpth = 0;
root = n - 2;
next = n - 1;
while (avbl > 0) {
while (root >= 0 && A[root] == dpth) {
used++;
root--;
}
while (avbl > used) {
A[next--] = dpth;
avbl--;
}
avbl = 2 * used;
dpth++;
used = 0;
}
}
#endif
bool generate_huffman_codes(void* pContext, uint num_syms, const uint16* pFreq, uint8* pCodesizes, uint& max_code_size, uint& total_freq_ret)
{
if ((!num_syms) || (num_syms > cHuffmanMaxSupportedSyms))
return false;
huffman_work_tables& state = *static_cast<huffman_work_tables*>(pContext);;
uint max_freq = 0;
uint total_freq = 0;
uint num_used_syms = 0;
for (uint i = 0; i < num_syms; i++)
{
uint freq = pFreq[i];
if (!freq)
pCodesizes[i] = 0;
else
{
total_freq += freq;
max_freq = math::maximum(max_freq, freq);
sym_freq& sf = state.syms0[num_used_syms];
sf.m_left = (uint16)i;
sf.m_right = cUINT16_MAX;
sf.m_freq = freq;
num_used_syms++;
}
}
total_freq_ret = total_freq;
if (num_used_syms == 1)
{
pCodesizes[state.syms0[0].m_left] = 1;
return true;
}
bool generate_huffman_codes(void* pContext, uint num_syms, const uint16* pFreq, uint8* pCodesizes, uint& max_code_size, uint& total_freq_ret) {
if ((!num_syms) || (num_syms > cHuffmanMaxSupportedSyms))
return false;
sym_freq* syms = radix_sort_syms(num_used_syms, state.syms0, state.syms1);
huffman_work_tables& state = *static_cast<huffman_work_tables*>(pContext);
;
uint max_freq = 0;
uint total_freq = 0;
uint num_used_syms = 0;
for (uint i = 0; i < num_syms; i++) {
uint freq = pFreq[i];
if (!freq)
pCodesizes[i] = 0;
else {
total_freq += freq;
max_freq = math::maximum(max_freq, freq);
sym_freq& sf = state.syms0[num_used_syms];
sf.m_left = (uint16)i;
sf.m_right = cUINT16_MAX;
sf.m_freq = freq;
num_used_syms++;
}
}
total_freq_ret = total_freq;
if (num_used_syms == 1) {
pCodesizes[state.syms0[0].m_left] = 1;
return true;
}
sym_freq* syms = radix_sort_syms(num_used_syms, state.syms0, state.syms1);
#if USE_CALCULATE_MINIMUM_REDUNDANCY
int x[cHuffmanMaxSupportedSyms];
for (uint i = 0; i < num_used_syms; i++)
x[i] = state.syms0[i].m_freq;
calculate_minimum_redundancy(x, num_used_syms);
uint max_len = 0;
for (uint i = 0; i < num_used_syms; i++)
{
uint len = x[i];
max_len = math::maximum(len, max_len);
pCodesizes[state.syms0[i].m_left] = static_cast<uint8>(len);
int x[cHuffmanMaxSupportedSyms];
for (uint i = 0; i < num_used_syms; i++)
x[i] = state.syms0[i].m_freq;
calculate_minimum_redundancy(x, num_used_syms);
uint max_len = 0;
for (uint i = 0; i < num_used_syms; i++) {
uint len = x[i];
max_len = math::maximum(len, max_len);
pCodesizes[state.syms0[i].m_left] = static_cast<uint8>(len);
}
return true;
#else
// Dummy node
sym_freq& sf = state.syms0[num_used_syms];
sf.m_left = cUINT16_MAX;
sf.m_right = cUINT16_MAX;
sf.m_freq = UINT_MAX;
uint next_internal_node = num_used_syms + 1;
uint queue_front = 0;
uint queue_end = 0;
uint next_lowest_sym = 0;
uint num_nodes_remaining = num_used_syms;
do {
uint left_freq = syms[next_lowest_sym].m_freq;
uint left_child = next_lowest_sym;
if ((queue_end > queue_front) && (syms[state.queue[queue_front]].m_freq < left_freq)) {
left_child = state.queue[queue_front];
left_freq = syms[left_child].m_freq;
queue_front++;
} else
next_lowest_sym++;
uint right_freq = syms[next_lowest_sym].m_freq;
uint right_child = next_lowest_sym;
if ((queue_end > queue_front) && (syms[state.queue[queue_front]].m_freq < right_freq)) {
right_child = state.queue[queue_front];
right_freq = syms[right_child].m_freq;
queue_front++;
} else
next_lowest_sym++;
const uint internal_node_index = next_internal_node;
next_internal_node++;
CRNLIB_ASSERT(next_internal_node < CRNLIB_ARRAYSIZE(state.syms0));
syms[internal_node_index].m_freq = left_freq + right_freq;
syms[internal_node_index].m_left = static_cast<uint16>(left_child);
syms[internal_node_index].m_right = static_cast<uint16>(right_child);
CRNLIB_ASSERT(queue_end < huffman_work_tables::cMaxInternalNodes);
state.queue[queue_end] = static_cast<uint16>(internal_node_index);
queue_end++;
num_nodes_remaining--;
} while (num_nodes_remaining > 1);
CRNLIB_ASSERT(next_lowest_sym == num_used_syms);
CRNLIB_ASSERT((queue_end - queue_front) == 1);
uint cur_node_index = state.queue[queue_front];
uint32* pStack = (syms == state.syms0) ? (uint32*)state.syms1 : (uint32*)state.syms0;
uint32* pStack_top = pStack;
uint max_level = 0;
for (;;) {
uint level = cur_node_index >> 16;
uint node_index = cur_node_index & 0xFFFF;
uint left_child = syms[node_index].m_left;
uint right_child = syms[node_index].m_right;
uint next_level = (cur_node_index + 0x10000) & 0xFFFF0000;
if (left_child < num_used_syms) {
max_level = math::maximum(max_level, level);
pCodesizes[syms[left_child].m_left] = static_cast<uint8>(level + 1);
if (right_child < num_used_syms) {
pCodesizes[syms[right_child].m_left] = static_cast<uint8>(level + 1);
if (pStack == pStack_top)
break;
cur_node_index = *--pStack;
} else {
cur_node_index = next_level | right_child;
}
return true;
#else
// Dummy node
sym_freq& sf = state.syms0[num_used_syms];
sf.m_left = cUINT16_MAX;
sf.m_right = cUINT16_MAX;
sf.m_freq = UINT_MAX;
uint next_internal_node = num_used_syms + 1;
uint queue_front = 0;
uint queue_end = 0;
uint next_lowest_sym = 0;
uint num_nodes_remaining = num_used_syms;
do
{
uint left_freq = syms[next_lowest_sym].m_freq;
uint left_child = next_lowest_sym;
if ((queue_end > queue_front) && (syms[state.queue[queue_front]].m_freq < left_freq))
{
left_child = state.queue[queue_front];
left_freq = syms[left_child].m_freq;
queue_front++;
}
else
next_lowest_sym++;
uint right_freq = syms[next_lowest_sym].m_freq;
uint right_child = next_lowest_sym;
} else {
if (right_child < num_used_syms) {
max_level = math::maximum(max_level, level);
if ((queue_end > queue_front) && (syms[state.queue[queue_front]].m_freq < right_freq))
{
right_child = state.queue[queue_front];
right_freq = syms[right_child].m_freq;
queue_front++;
}
else
next_lowest_sym++;
const uint internal_node_index = next_internal_node;
next_internal_node++;
pCodesizes[syms[right_child].m_left] = static_cast<uint8>(level + 1);
CRNLIB_ASSERT(next_internal_node < CRNLIB_ARRAYSIZE(state.syms0));
syms[internal_node_index].m_freq = left_freq + right_freq;
syms[internal_node_index].m_left = static_cast<uint16>(left_child);
syms[internal_node_index].m_right = static_cast<uint16>(right_child);
CRNLIB_ASSERT(queue_end < huffman_work_tables::cMaxInternalNodes);
state.queue[queue_end] = static_cast<uint16>(internal_node_index);
queue_end++;
num_nodes_remaining--;
} while (num_nodes_remaining > 1);
CRNLIB_ASSERT(next_lowest_sym == num_used_syms);
CRNLIB_ASSERT((queue_end - queue_front) == 1);
uint cur_node_index = state.queue[queue_front];
uint32* pStack = (syms == state.syms0) ? (uint32*)state.syms1 : (uint32*)state.syms0;
uint32* pStack_top = pStack;
cur_node_index = next_level | left_child;
} else {
*pStack++ = next_level | left_child;
uint max_level = 0;
for ( ; ; )
{
uint level = cur_node_index >> 16;
uint node_index = cur_node_index & 0xFFFF;
uint left_child = syms[node_index].m_left;
uint right_child = syms[node_index].m_right;
uint next_level = (cur_node_index + 0x10000) & 0xFFFF0000;
if (left_child < num_used_syms)
{
max_level = math::maximum(max_level, level);
pCodesizes[syms[left_child].m_left] = static_cast<uint8>(level + 1);
if (right_child < num_used_syms)
{
pCodesizes[syms[right_child].m_left] = static_cast<uint8>(level + 1);
if (pStack == pStack_top) break;
cur_node_index = *--pStack;
}
else
{
cur_node_index = next_level | right_child;
}
}
else
{
if (right_child < num_used_syms)
{
max_level = math::maximum(max_level, level);
pCodesizes[syms[right_child].m_left] = static_cast<uint8>(level + 1);
cur_node_index = next_level | left_child;
}
else
{
*pStack++ = next_level | left_child;
cur_node_index = next_level | right_child;
}
}
cur_node_index = next_level | right_child;
}
max_code_size = max_level + 1;
}
}
max_code_size = max_level + 1;
#endif
return true;
}
} // namespace crnlib
return true;
}
} // namespace crnlib
+7 -8
View File
@@ -2,13 +2,12 @@
// See Copyright Notice and license at the end of inc/crnlib.h
#pragma once
namespace crnlib
{
const uint cHuffmanMaxSupportedSyms = 8192;
namespace crnlib {
const uint cHuffmanMaxSupportedSyms = 8192;
void* create_generate_huffman_codes_tables();
void free_generate_huffman_codes_tables(void* p);
bool generate_huffman_codes(void* pContext, uint num_syms, const uint16* pFreq, uint8* pCodesizes, uint& max_code_size, uint& total_freq_ret);
void* create_generate_huffman_codes_tables();
void free_generate_huffman_codes_tables(void* p);
} // namespace crnlib
bool generate_huffman_codes(void* pContext, uint num_syms, const uint16* pFreq, uint8* pCodesizes, uint& max_code_size, uint& total_freq_ret);
} // namespace crnlib
+601 -689
View File
File diff suppressed because it is too large Load Diff
+1111 -1261
View File
File diff suppressed because it is too large Load Diff
+130 -140
View File
@@ -4,190 +4,180 @@
#include "crn_image.h"
#include "crn_data_stream_serializer.h"
namespace crnlib
{
enum pixel_format;
namespace crnlib {
enum pixel_format;
namespace image_utils
{
enum read_flags_t
{
cReadFlagForceSTB = 1,
namespace image_utils {
enum read_flags_t {
cReadFlagForceSTB = 1,
cReadFlagsAllFlags = 1
};
cReadFlagsAllFlags = 1
};
bool read_from_stream_stb(data_stream_serializer& serializer, image_u8& img);
bool read_from_stream_jpgd(data_stream_serializer& serializer, image_u8& img);
bool read_from_stream(image_u8& dest, data_stream_serializer& serializer, uint read_flags = 0);
bool read_from_file(image_u8& dest, const char* pFilename, uint read_flags = 0);
bool read_from_stream_stb(data_stream_serializer& serializer, image_u8& img);
bool read_from_stream_jpgd(data_stream_serializer& serializer, image_u8& img);
bool read_from_stream(image_u8& dest, data_stream_serializer& serializer, uint read_flags = 0);
bool read_from_file(image_u8& dest, const char* pFilename, uint read_flags = 0);
// Reads texture from memory, results returned stb_image.c style.
// *pActual_comps is set to 1, 3, or 4. req_comps must range from 1-4.
uint8* read_from_memory(const uint8* pImage, int nSize, int* pWidth, int* pHeight, int* pActualComps, int req_comps, const char* pFilename);
// Reads texture from memory, results returned stb_image.c style.
// *pActual_comps is set to 1, 3, or 4. req_comps must range from 1-4.
uint8* read_from_memory(const uint8* pImage, int nSize, int* pWidth, int* pHeight, int* pActualComps, int req_comps, const char* pFilename);
enum
{
cWriteFlagIgnoreAlpha = 0x00000001,
cWriteFlagGrayscale = 0x00000002,
enum {
cWriteFlagIgnoreAlpha = 0x00000001,
cWriteFlagGrayscale = 0x00000002,
cWriteFlagJPEGH1V1 = 0x00010000,
cWriteFlagJPEGH2V1 = 0x00020000,
cWriteFlagJPEGH2V2 = 0x00040000,
cWriteFlagJPEGTwoPass = 0x00080000,
cWriteFlagJPEGNoChromaDiscrim = 0x00100000,
cWriteFlagJPEGQualityLevelMask = 0xFF000000,
cWriteFlagJPEGQualityLevelShift = 24,
};
cWriteFlagJPEGH1V1 = 0x00010000,
cWriteFlagJPEGH2V1 = 0x00020000,
cWriteFlagJPEGH2V2 = 0x00040000,
cWriteFlagJPEGTwoPass = 0x00080000,
cWriteFlagJPEGNoChromaDiscrim = 0x00100000,
cWriteFlagJPEGQualityLevelMask = 0xFF000000,
cWriteFlagJPEGQualityLevelShift = 24,
};
const int cLumaComponentIndex = -1;
const int cLumaComponentIndex = -1;
inline uint create_jpeg_write_flags(uint base_flags, uint quality_level) { CRNLIB_ASSERT(quality_level <= 100); return base_flags | ((quality_level << cWriteFlagJPEGQualityLevelShift) & cWriteFlagJPEGQualityLevelMask); }
inline uint create_jpeg_write_flags(uint base_flags, uint quality_level) {
CRNLIB_ASSERT(quality_level <= 100);
return base_flags | ((quality_level << cWriteFlagJPEGQualityLevelShift) & cWriteFlagJPEGQualityLevelMask);
}
bool write_to_file(const char* pFilename, const image_u8& img, uint write_flags = 0, int grayscale_comp_index = cLumaComponentIndex);
bool write_to_file(const char* pFilename, const image_u8& img, uint write_flags = 0, int grayscale_comp_index = cLumaComponentIndex);
bool has_alpha(const image_u8& img);
bool is_normal_map(const image_u8& img, const char* pFilename = NULL);
void renorm_normal_map(image_u8& img);
bool has_alpha(const image_u8& img);
bool is_normal_map(const image_u8& img, const char* pFilename = NULL);
void renorm_normal_map(image_u8& img);
struct resample_params
{
resample_params() :
m_dst_width(0),
m_dst_height(0),
m_pFilter("lanczos4"),
m_filter_scale(1.0f),
m_srgb(true),
m_wrapping(false),
m_first_comp(0),
m_num_comps(4),
m_source_gamma(2.2f), // 1.75f
m_multithreaded(true)
{
}
struct resample_params {
resample_params()
: m_dst_width(0),
m_dst_height(0),
m_pFilter("lanczos4"),
m_filter_scale(1.0f),
m_srgb(true),
m_wrapping(false),
m_first_comp(0),
m_num_comps(4),
m_source_gamma(2.2f), // 1.75f
m_multithreaded(true) {
}
uint m_dst_width;
uint m_dst_height;
const char* m_pFilter;
float m_filter_scale;
bool m_srgb;
bool m_wrapping;
uint m_first_comp;
uint m_num_comps;
float m_source_gamma;
bool m_multithreaded;
};
uint m_dst_width;
uint m_dst_height;
const char* m_pFilter;
float m_filter_scale;
bool m_srgb;
bool m_wrapping;
uint m_first_comp;
uint m_num_comps;
float m_source_gamma;
bool m_multithreaded;
};
bool resample_single_thread(const image_u8& src, image_u8& dst, const resample_params& params);
bool resample_multithreaded(const image_u8& src, image_u8& dst, const resample_params& params);
bool resample(const image_u8& src, image_u8& dst, const resample_params& params);
bool resample_single_thread(const image_u8& src, image_u8& dst, const resample_params& params);
bool resample_multithreaded(const image_u8& src, image_u8& dst, const resample_params& params);
bool resample(const image_u8& src, image_u8& dst, const resample_params& params);
bool compute_delta(image_u8& dest, image_u8& a, image_u8& b, uint scale = 2);
bool compute_delta(image_u8& dest, image_u8& a, image_u8& b, uint scale = 2);
class error_metrics
{
public:
error_metrics() { utils::zero_this(this); }
class error_metrics {
public:
error_metrics() { utils::zero_this(this); }
void print(const char* pName) const;
void print(const char* pName) const;
// If num_channels==0, luma error is computed.
// If pHist != NULL, it must point to a 256 entry array.
bool compute(const image_u8& a, const image_u8& b, uint first_channel, uint num_channels, bool average_component_error = true);
// If num_channels==0, luma error is computed.
// If pHist != NULL, it must point to a 256 entry array.
bool compute(const image_u8& a, const image_u8& b, uint first_channel, uint num_channels, bool average_component_error = true);
uint mMax;
double mMean;
double mMeanSquared;
double mRootMeanSquared;
double mPeakSNR;
uint mMax;
double mMean;
double mMeanSquared;
double mRootMeanSquared;
double mPeakSNR;
inline bool operator== (const error_metrics& other) const
{
return mPeakSNR == other.mPeakSNR;
}
inline bool operator==(const error_metrics& other) const {
return mPeakSNR == other.mPeakSNR;
}
inline bool operator< (const error_metrics& other) const
{
return mPeakSNR < other.mPeakSNR;
}
inline bool operator<(const error_metrics& other) const {
return mPeakSNR < other.mPeakSNR;
}
inline bool operator> (const error_metrics& other) const
{
return mPeakSNR > other.mPeakSNR;
}
};
inline bool operator>(const error_metrics& other) const {
return mPeakSNR > other.mPeakSNR;
}
};
void print_image_metrics(const image_u8& src_img, const image_u8& dst_img);
void print_image_metrics(const image_u8& src_img, const image_u8& dst_img);
double compute_block_ssim(uint n, const uint8* pX, const uint8* pY);
double compute_ssim(const image_u8& a, const image_u8& b, int channel_index);
void print_ssim(const image_u8& src_img, const image_u8& dst_img);
double compute_block_ssim(uint n, const uint8* pX, const uint8* pY);
double compute_ssim(const image_u8& a, const image_u8& b, int channel_index);
void print_ssim(const image_u8& src_img, const image_u8& dst_img);
enum conversion_type
{
cConversion_Invalid = -1,
enum conversion_type {
cConversion_Invalid = -1,
cConversion_To_CCxY,
cConversion_From_CCxY,
cConversion_To_CCxY,
cConversion_From_CCxY,
cConversion_To_xGxR,
cConversion_From_xGxR,
cConversion_To_xGxR,
cConversion_From_xGxR,
cConversion_To_xGBR,
cConversion_From_xGBR,
cConversion_To_xGBR,
cConversion_From_xGBR,
cConversion_To_AGBR,
cConversion_From_AGBR,
cConversion_To_AGBR,
cConversion_From_AGBR,
cConversion_XY_to_XYZ,
cConversion_XY_to_XYZ,
cConversion_Y_To_A,
cConversion_Y_To_A,
cConversion_A_To_RGBA,
cConversion_Y_To_RGB,
cConversion_A_To_RGBA,
cConversion_Y_To_RGB,
cConversion_To_Y,
cConversion_To_Y,
cConversionTotal
};
cConversionTotal
};
void convert_image(image_u8& img, conversion_type conv_type);
void convert_image(image_u8& img, conversion_type conv_type);
template<typename image_type>
inline uint8* pack_image(const image_type& img, const pixel_packer& packer, uint& n)
{
n = 0;
template <typename image_type>
inline uint8* pack_image(const image_type& img, const pixel_packer& packer, uint& n) {
n = 0;
if (!packer.is_valid())
return NULL;
if (!packer.is_valid())
return NULL;
const uint width = img.get_width(), height = img.get_height();
uint dst_pixel_stride = packer.get_pixel_stride();
uint dst_pitch = width * dst_pixel_stride;
const uint width = img.get_width(), height = img.get_height();
uint dst_pixel_stride = packer.get_pixel_stride();
uint dst_pitch = width * dst_pixel_stride;
n = dst_pitch * height;
n = dst_pitch * height;
uint8* pImage = static_cast<uint8*>(crnlib_malloc(n));
uint8* pImage = static_cast<uint8*>(crnlib_malloc(n));
uint8* pDst = pImage;
for (uint y = 0; y < height; y++)
{
const typename image_type::color_t* pSrc = img.get_scanline(y);
for (uint x = 0; x < width; x++)
pDst = (uint8*)packer.pack(*pSrc++, pDst);
}
uint8* pDst = pImage;
for (uint y = 0; y < height; y++) {
const typename image_type::color_t* pSrc = img.get_scanline(y);
for (uint x = 0; x < width; x++)
pDst = (uint8*)packer.pack(*pSrc++, pDst);
}
return pImage;
}
return pImage;
}
image_utils::conversion_type get_conversion_type(bool cooking, pixel_format fmt);
image_utils::conversion_type get_conversion_type(bool cooking, pixel_format fmt);
image_utils::conversion_type get_image_conversion_type_from_crn_format(crn_format fmt);
image_utils::conversion_type get_image_conversion_type_from_crn_format(crn_format fmt);
double compute_std_dev(uint n, const color_quad_u8* pPixels, uint first_channel, uint num_channels);
double compute_std_dev(uint n, const color_quad_u8* pPixels, uint first_channel, uint num_channels);
uint8* read_image_from_memory(const uint8* pImage, int nSize, int* pWidth, int* pHeight, int* pActualComps, int req_comps, const char* pFilename);
uint8* read_image_from_memory(const uint8* pImage, int nSize, int* pWidth, int* pHeight, int* pActualComps, int req_comps, const char* pFilename);
} // namespace image_utils
} // namespace image_utils
} // namespace crnlib
} // namespace crnlib
+88 -107
View File
@@ -3,121 +3,102 @@
#pragma once
#include "crn_ray.h"
namespace crnlib
{
namespace intersection
{
enum result
{
cBackfacing = -1,
cFailure = 0,
cSuccess,
cParallel,
cInside,
};
// Returns cInside, cSuccess, or cFailure.
// Algorithm: Graphics Gems 1
template<typename vector_type, typename scalar_type, typename ray_type, typename aabb_type>
result ray_aabb(vector_type& coord, scalar_type& t, const ray_type& ray, const aabb_type& box)
{
enum
{
cNumDim = vector_type::num_elements,
cRight = 0,
cLeft = 1,
cMiddle = 2
};
namespace crnlib {
namespace intersection {
enum result {
cBackfacing = -1,
cFailure = 0,
cSuccess,
cParallel,
cInside,
};
bool inside = true;
int quadrant[cNumDim];
scalar_type candidate_plane[cNumDim];
// Returns cInside, cSuccess, or cFailure.
// Algorithm: Graphics Gems 1
template <typename vector_type, typename scalar_type, typename ray_type, typename aabb_type>
result ray_aabb(vector_type& coord, scalar_type& t, const ray_type& ray, const aabb_type& box) {
enum {
cNumDim = vector_type::num_elements,
cRight = 0,
cLeft = 1,
cMiddle = 2
};
for (int i = 0; i < cNumDim; i++)
{
if (ray.get_origin()[i] < box[0][i])
{
quadrant[i] = cLeft;
candidate_plane[i] = box[0][i];
inside = false;
}
else if (ray.get_origin()[i] > box[1][i])
{
quadrant[i] = cRight;
candidate_plane[i] = box[1][i];
inside = false;
}
else
{
quadrant[i] = cMiddle;
}
}
bool inside = true;
int quadrant[cNumDim];
scalar_type candidate_plane[cNumDim];
if (inside)
{
coord = ray.get_origin();
t = 0.0f;
return cInside;
}
for (int i = 0; i < cNumDim; i++) {
if (ray.get_origin()[i] < box[0][i]) {
quadrant[i] = cLeft;
candidate_plane[i] = box[0][i];
inside = false;
} else if (ray.get_origin()[i] > box[1][i]) {
quadrant[i] = cRight;
candidate_plane[i] = box[1][i];
inside = false;
} else {
quadrant[i] = cMiddle;
}
}
scalar_type max_t[cNumDim];
for (int i = 0; i < cNumDim; i++)
{
if ((quadrant[i] != cMiddle) && (ray.get_direction()[i] != 0.0f))
max_t[i] = (candidate_plane[i] - ray.get_origin()[i]) / ray.get_direction()[i];
else
max_t[i] = -1.0f;
}
if (inside) {
coord = ray.get_origin();
t = 0.0f;
return cInside;
}
int which_plane = 0;
for (int i = 1; i < cNumDim; i++)
if (max_t[which_plane] < max_t[i])
which_plane = i;
scalar_type max_t[cNumDim];
for (int i = 0; i < cNumDim; i++) {
if ((quadrant[i] != cMiddle) && (ray.get_direction()[i] != 0.0f))
max_t[i] = (candidate_plane[i] - ray.get_origin()[i]) / ray.get_direction()[i];
else
max_t[i] = -1.0f;
}
if (max_t[which_plane] < 0.0f)
return cFailure;
int which_plane = 0;
for (int i = 1; i < cNumDim; i++)
if (max_t[which_plane] < max_t[i])
which_plane = i;
for (int i = 0; i < cNumDim; i++)
{
if (i != which_plane)
{
coord[i] = ray.get_origin()[i] + max_t[which_plane] * ray.get_direction()[i];
if (max_t[which_plane] < 0.0f)
return cFailure;
if ( (coord[i] < box[0][i]) || (coord[i] > box[1][i]) )
return cFailure;
}
else
{
coord[i] = candidate_plane[i];
}
for (int i = 0; i < cNumDim; i++) {
if (i != which_plane) {
coord[i] = ray.get_origin()[i] + max_t[which_plane] * ray.get_direction()[i];
CRNLIB_ASSERT(coord[i] >= box[0][i] && coord[i] <= box[1][i]);
}
if ((coord[i] < box[0][i]) || (coord[i] > box[1][i]))
return cFailure;
} else {
coord[i] = candidate_plane[i];
}
t = max_t[which_plane];
return cSuccess;
}
template<typename vector_type, typename scalar_type, typename ray_type, typename aabb_type>
result ray_aabb(bool& started_within, vector_type& coord, scalar_type& t, const ray_type& ray, const aabb_type& box)
{
if (!box.contains(ray.get_origin()))
{
started_within = false;
return ray_aabb(coord, t, ray, box);
}
started_within = true;
float diag_dist = box.diagonal_length() * 1.5f;
ray_type outside_ray(ray.eval(diag_dist), -ray.get_direction());
result res(ray_aabb(coord, t, outside_ray, box));
if (res != cSuccess)
return res;
t = math::maximum(0.0f, diag_dist - t);
return cSuccess;
}
}
CRNLIB_ASSERT(coord[i] >= box[0][i] && coord[i] <= box[1][i]);
}
t = max_t[which_plane];
return cSuccess;
}
template <typename vector_type, typename scalar_type, typename ray_type, typename aabb_type>
result ray_aabb(bool& started_within, vector_type& coord, scalar_type& t, const ray_type& ray, const aabb_type& box) {
if (!box.contains(ray.get_origin())) {
started_within = false;
return ray_aabb(coord, t, ray, box);
}
started_within = true;
float diag_dist = box.diagonal_length() * 1.5f;
ray_type outside_ray(ray.eval(diag_dist), -ray.get_direction());
result res(ray_aabb(coord, t, outside_ray, box));
if (res != cSuccess)
return res;
t = math::maximum(0.0f, diag_dist - t);
return cSuccess;
}
}
}
+926 -1155
View File
File diff suppressed because it is too large Load Diff
+323 -293
View File
@@ -8,312 +8,342 @@
#include <setjmp.h>
#ifdef _MSC_VER
#define JPGD_NORETURN __declspec(noreturn)
#define JPGD_NORETURN __declspec(noreturn)
#elif defined(__GNUC__)
#define JPGD_NORETURN __attribute__ ((noreturn))
#define JPGD_NORETURN __attribute__((noreturn))
#else
#define JPGD_NORETURN
#define JPGD_NORETURN
#endif
namespace jpgd
{
typedef unsigned char uint8;
typedef signed short int16;
typedef unsigned short uint16;
typedef unsigned int uint;
typedef signed int int32;
namespace jpgd {
typedef unsigned char uint8;
typedef signed short int16;
typedef unsigned short uint16;
typedef unsigned int uint;
typedef signed int int32;
// Loads a JPEG image from a memory buffer or a file.
// req_comps can be 1 (grayscale), 3 (RGB), or 4 (RGBA).
// On return, width/height will be set to the image's dimensions, and actual_comps will be set to the either 1 (grayscale) or 3 (RGB).
// Notes: For more control over where and how the source data is read, see the decompress_jpeg_image_from_stream() function below, or call the jpeg_decoder class directly.
// Requesting a 8 or 32bpp image is currently a little faster than 24bpp because the jpeg_decoder class itself currently always unpacks to either 8 or 32bpp.
unsigned char *decompress_jpeg_image_from_memory(const unsigned char *pSrc_data, int src_data_size, int *width, int *height, int *actual_comps, int req_comps);
unsigned char *decompress_jpeg_image_from_file(const char *pSrc_filename, int *width, int *height, int *actual_comps, int req_comps);
// Loads a JPEG image from a memory buffer or a file.
// req_comps can be 1 (grayscale), 3 (RGB), or 4 (RGBA).
// On return, width/height will be set to the image's dimensions, and actual_comps will be set to the either 1 (grayscale) or 3 (RGB).
// Notes: For more control over where and how the source data is read, see the decompress_jpeg_image_from_stream() function below, or call the jpeg_decoder class directly.
// Requesting a 8 or 32bpp image is currently a little faster than 24bpp because the jpeg_decoder class itself currently always unpacks to either 8 or 32bpp.
unsigned char* decompress_jpeg_image_from_memory(const unsigned char* pSrc_data, int src_data_size, int* width, int* height, int* actual_comps, int req_comps);
unsigned char* decompress_jpeg_image_from_file(const char* pSrc_filename, int* width, int* height, int* actual_comps, int req_comps);
// Success/failure error codes.
enum jpgd_status
{
JPGD_SUCCESS = 0, JPGD_FAILED = -1, JPGD_DONE = 1,
JPGD_BAD_DHT_COUNTS = -256, JPGD_BAD_DHT_INDEX, JPGD_BAD_DHT_MARKER, JPGD_BAD_DQT_MARKER, JPGD_BAD_DQT_TABLE,
JPGD_BAD_PRECISION, JPGD_BAD_HEIGHT, JPGD_BAD_WIDTH, JPGD_TOO_MANY_COMPONENTS,
JPGD_BAD_SOF_LENGTH, JPGD_BAD_VARIABLE_MARKER, JPGD_BAD_DRI_LENGTH, JPGD_BAD_SOS_LENGTH,
JPGD_BAD_SOS_COMP_ID, JPGD_W_EXTRA_BYTES_BEFORE_MARKER, JPGD_NO_ARITHMITIC_SUPPORT, JPGD_UNEXPECTED_MARKER,
JPGD_NOT_JPEG, JPGD_UNSUPPORTED_MARKER, JPGD_BAD_DQT_LENGTH, JPGD_TOO_MANY_BLOCKS,
JPGD_UNDEFINED_QUANT_TABLE, JPGD_UNDEFINED_HUFF_TABLE, JPGD_NOT_SINGLE_SCAN, JPGD_UNSUPPORTED_COLORSPACE,
JPGD_UNSUPPORTED_SAMP_FACTORS, JPGD_DECODE_ERROR, JPGD_BAD_RESTART_MARKER, JPGD_ASSERTION_ERROR,
JPGD_BAD_SOS_SPECTRAL, JPGD_BAD_SOS_SUCCESSIVE, JPGD_STREAM_READ, JPGD_NOTENOUGHMEM
};
// Input stream interface.
// Derive from this class to read input data from sources other than files or memory. Set m_eof_flag to true when no more data is available.
// The decoder is rather greedy: it will keep on calling this method until its internal input buffer is full, or until the EOF flag is set.
// It the input stream contains data after the JPEG stream's EOI (end of image) marker it will probably be pulled into the internal buffer.
// Call the get_total_bytes_read() method to determine the actual size of the JPEG stream after successful decoding.
class jpeg_decoder_stream
{
public:
jpeg_decoder_stream() { }
virtual ~jpeg_decoder_stream() { }
// Success/failure error codes.
enum jpgd_status {
JPGD_SUCCESS = 0,
JPGD_FAILED = -1,
JPGD_DONE = 1,
JPGD_BAD_DHT_COUNTS = -256,
JPGD_BAD_DHT_INDEX,
JPGD_BAD_DHT_MARKER,
JPGD_BAD_DQT_MARKER,
JPGD_BAD_DQT_TABLE,
JPGD_BAD_PRECISION,
JPGD_BAD_HEIGHT,
JPGD_BAD_WIDTH,
JPGD_TOO_MANY_COMPONENTS,
JPGD_BAD_SOF_LENGTH,
JPGD_BAD_VARIABLE_MARKER,
JPGD_BAD_DRI_LENGTH,
JPGD_BAD_SOS_LENGTH,
JPGD_BAD_SOS_COMP_ID,
JPGD_W_EXTRA_BYTES_BEFORE_MARKER,
JPGD_NO_ARITHMITIC_SUPPORT,
JPGD_UNEXPECTED_MARKER,
JPGD_NOT_JPEG,
JPGD_UNSUPPORTED_MARKER,
JPGD_BAD_DQT_LENGTH,
JPGD_TOO_MANY_BLOCKS,
JPGD_UNDEFINED_QUANT_TABLE,
JPGD_UNDEFINED_HUFF_TABLE,
JPGD_NOT_SINGLE_SCAN,
JPGD_UNSUPPORTED_COLORSPACE,
JPGD_UNSUPPORTED_SAMP_FACTORS,
JPGD_DECODE_ERROR,
JPGD_BAD_RESTART_MARKER,
JPGD_ASSERTION_ERROR,
JPGD_BAD_SOS_SPECTRAL,
JPGD_BAD_SOS_SUCCESSIVE,
JPGD_STREAM_READ,
JPGD_NOTENOUGHMEM
};
// The read() method is called when the internal input buffer is empty.
// Parameters:
// pBuf - input buffer
// max_bytes_to_read - maximum bytes that can be written to pBuf
// pEOF_flag - set this to true if at end of stream (no more bytes remaining)
// Returns -1 on error, otherwise return the number of bytes actually written to the buffer (which may be 0).
// Notes: This method will be called in a loop until you set *pEOF_flag to true or the internal buffer is full.
virtual int read(uint8 *pBuf, int max_bytes_to_read, bool *pEOF_flag) = 0;
// Input stream interface.
// Derive from this class to read input data from sources other than files or memory. Set m_eof_flag to true when no more data is available.
// The decoder is rather greedy: it will keep on calling this method until its internal input buffer is full, or until the EOF flag is set.
// It the input stream contains data after the JPEG stream's EOI (end of image) marker it will probably be pulled into the internal buffer.
// Call the get_total_bytes_read() method to determine the actual size of the JPEG stream after successful decoding.
class jpeg_decoder_stream {
public:
jpeg_decoder_stream() {}
virtual ~jpeg_decoder_stream() {}
// The read() method is called when the internal input buffer is empty.
// Parameters:
// pBuf - input buffer
// max_bytes_to_read - maximum bytes that can be written to pBuf
// pEOF_flag - set this to true if at end of stream (no more bytes remaining)
// Returns -1 on error, otherwise return the number of bytes actually written to the buffer (which may be 0).
// Notes: This method will be called in a loop until you set *pEOF_flag to true or the internal buffer is full.
virtual int read(uint8* pBuf, int max_bytes_to_read, bool* pEOF_flag) = 0;
};
// stdio FILE stream class.
class jpeg_decoder_file_stream : public jpeg_decoder_stream {
jpeg_decoder_file_stream(const jpeg_decoder_file_stream&);
jpeg_decoder_file_stream& operator=(const jpeg_decoder_file_stream&);
FILE* m_pFile;
bool m_eof_flag, m_error_flag;
public:
jpeg_decoder_file_stream();
virtual ~jpeg_decoder_file_stream();
bool open(const char* Pfilename);
void close();
virtual int read(uint8* pBuf, int max_bytes_to_read, bool* pEOF_flag);
};
// Memory stream class.
class jpeg_decoder_mem_stream : public jpeg_decoder_stream {
const uint8* m_pSrc_data;
uint m_ofs, m_size;
public:
jpeg_decoder_mem_stream()
: m_pSrc_data(NULL), m_ofs(0), m_size(0) {}
jpeg_decoder_mem_stream(const uint8* pSrc_data, uint size)
: m_pSrc_data(pSrc_data), m_ofs(0), m_size(size) {}
virtual ~jpeg_decoder_mem_stream() {}
bool open(const uint8* pSrc_data, uint size);
void close() {
m_pSrc_data = NULL;
m_ofs = 0;
m_size = 0;
}
virtual int read(uint8* pBuf, int max_bytes_to_read, bool* pEOF_flag);
};
// Loads JPEG file from a jpeg_decoder_stream.
unsigned char* decompress_jpeg_image_from_stream(jpeg_decoder_stream* pStream, int* width, int* height, int* actual_comps, int req_comps);
enum {
JPGD_IN_BUF_SIZE = 8192,
JPGD_MAX_BLOCKS_PER_MCU = 10,
JPGD_MAX_HUFF_TABLES = 8,
JPGD_MAX_QUANT_TABLES = 4,
JPGD_MAX_COMPONENTS = 4,
JPGD_MAX_COMPS_IN_SCAN = 4,
JPGD_MAX_BLOCKS_PER_ROW = 8192,
JPGD_MAX_HEIGHT = 16384,
JPGD_MAX_WIDTH = 16384
};
typedef int16 jpgd_quant_t;
typedef int16 jpgd_block_t;
class jpeg_decoder {
public:
// Call get_error_code() after constructing to determine if the stream is valid or not. You may call the get_width(), get_height(), etc.
// methods after the constructor is called. You may then either destruct the object, or begin decoding the image by calling begin_decoding(), then decode() on each scanline.
jpeg_decoder(jpeg_decoder_stream* pStream);
~jpeg_decoder();
// Call this method after constructing the object to begin decompression.
// If JPGD_SUCCESS is returned you may then call decode() on each scanline.
int begin_decoding();
// Returns the next scan line.
// For grayscale images, pScan_line will point to a buffer containing 8-bit pixels (get_bytes_per_pixel() will return 1).
// Otherwise, it will always point to a buffer containing 32-bit RGBA pixels (A will always be 255, and get_bytes_per_pixel() will return 4).
// Returns JPGD_SUCCESS if a scan line has been returned.
// Returns JPGD_DONE if all scan lines have been returned.
// Returns JPGD_FAILED if an error occurred. Call get_error_code() for a more info.
int decode(const void** pScan_line, uint* pScan_line_len);
inline jpgd_status get_error_code() const { return m_error_code; }
inline int get_width() const { return m_image_x_size; }
inline int get_height() const { return m_image_y_size; }
inline int get_num_components() const { return m_comps_in_frame; }
inline int get_bytes_per_pixel() const { return m_dest_bytes_per_pixel; }
inline int get_bytes_per_scan_line() const { return m_image_x_size * get_bytes_per_pixel(); }
// Returns the total number of bytes actually consumed by the decoder (which should equal the actual size of the JPEG file).
inline int get_total_bytes_read() const { return m_total_bytes_read; }
private:
jpeg_decoder(const jpeg_decoder&);
jpeg_decoder& operator=(const jpeg_decoder&);
typedef void (*pDecode_block_func)(jpeg_decoder*, int, int, int);
struct huff_tables {
bool ac_table;
uint look_up[256];
uint look_up2[256];
uint8 code_size[256];
uint tree[512];
};
// stdio FILE stream class.
class jpeg_decoder_file_stream : public jpeg_decoder_stream
{
jpeg_decoder_file_stream(const jpeg_decoder_file_stream &);
jpeg_decoder_file_stream &operator =(const jpeg_decoder_file_stream &);
FILE *m_pFile;
bool m_eof_flag, m_error_flag;
public:
jpeg_decoder_file_stream();
virtual ~jpeg_decoder_file_stream();
bool open(const char *Pfilename);
void close();
virtual int read(uint8 *pBuf, int max_bytes_to_read, bool *pEOF_flag);
struct coeff_buf {
uint8* pData;
int block_num_x, block_num_y;
int block_len_x, block_len_y;
int block_size;
};
// Memory stream class.
class jpeg_decoder_mem_stream : public jpeg_decoder_stream
{
const uint8 *m_pSrc_data;
uint m_ofs, m_size;
public:
jpeg_decoder_mem_stream() : m_pSrc_data(NULL), m_ofs(0), m_size(0) { }
jpeg_decoder_mem_stream(const uint8 *pSrc_data, uint size) : m_pSrc_data(pSrc_data), m_ofs(0), m_size(size) { }
virtual ~jpeg_decoder_mem_stream() { }
bool open(const uint8 *pSrc_data, uint size);
void close() { m_pSrc_data = NULL; m_ofs = 0; m_size = 0; }
virtual int read(uint8 *pBuf, int max_bytes_to_read, bool *pEOF_flag);
struct mem_block {
mem_block* m_pNext;
size_t m_used_count;
size_t m_size;
char m_data[1];
};
// Loads JPEG file from a jpeg_decoder_stream.
unsigned char *decompress_jpeg_image_from_stream(jpeg_decoder_stream *pStream, int *width, int *height, int *actual_comps, int req_comps);
jmp_buf m_jmp_state;
mem_block* m_pMem_blocks;
int m_image_x_size;
int m_image_y_size;
jpeg_decoder_stream* m_pStream;
int m_progressive_flag;
uint8 m_huff_ac[JPGD_MAX_HUFF_TABLES];
uint8* m_huff_num[JPGD_MAX_HUFF_TABLES]; // pointer to number of Huffman codes per bit size
uint8* m_huff_val[JPGD_MAX_HUFF_TABLES]; // pointer to Huffman codes per bit size
jpgd_quant_t* m_quant[JPGD_MAX_QUANT_TABLES]; // pointer to quantization tables
int m_scan_type; // Gray, Yh1v1, Yh1v2, Yh2v1, Yh2v2 (CMYK111, CMYK4114 no longer supported)
int m_comps_in_frame; // # of components in frame
int m_comp_h_samp[JPGD_MAX_COMPONENTS]; // component's horizontal sampling factor
int m_comp_v_samp[JPGD_MAX_COMPONENTS]; // component's vertical sampling factor
int m_comp_quant[JPGD_MAX_COMPONENTS]; // component's quantization table selector
int m_comp_ident[JPGD_MAX_COMPONENTS]; // component's ID
int m_comp_h_blocks[JPGD_MAX_COMPONENTS];
int m_comp_v_blocks[JPGD_MAX_COMPONENTS];
int m_comps_in_scan; // # of components in scan
int m_comp_list[JPGD_MAX_COMPS_IN_SCAN]; // components in this scan
int m_comp_dc_tab[JPGD_MAX_COMPONENTS]; // component's DC Huffman coding table selector
int m_comp_ac_tab[JPGD_MAX_COMPONENTS]; // component's AC Huffman coding table selector
int m_spectral_start; // spectral selection start
int m_spectral_end; // spectral selection end
int m_successive_low; // successive approximation low
int m_successive_high; // successive approximation high
int m_max_mcu_x_size; // MCU's max. X size in pixels
int m_max_mcu_y_size; // MCU's max. Y size in pixels
int m_blocks_per_mcu;
int m_max_blocks_per_row;
int m_mcus_per_row, m_mcus_per_col;
int m_mcu_org[JPGD_MAX_BLOCKS_PER_MCU];
int m_total_lines_left; // total # lines left in image
int m_mcu_lines_left; // total # lines left in this MCU
int m_real_dest_bytes_per_scan_line;
int m_dest_bytes_per_scan_line; // rounded up
int m_dest_bytes_per_pixel; // 4 (RGB) or 1 (Y)
huff_tables* m_pHuff_tabs[JPGD_MAX_HUFF_TABLES];
coeff_buf* m_dc_coeffs[JPGD_MAX_COMPONENTS];
coeff_buf* m_ac_coeffs[JPGD_MAX_COMPONENTS];
int m_eob_run;
int m_block_y_mcu[JPGD_MAX_COMPONENTS];
uint8* m_pIn_buf_ofs;
int m_in_buf_left;
int m_tem_flag;
bool m_eof_flag;
uint8 m_in_buf_pad_start[128];
uint8 m_in_buf[JPGD_IN_BUF_SIZE + 128];
uint8 m_in_buf_pad_end[128];
int m_bits_left;
uint m_bit_buf;
int m_restart_interval;
int m_restarts_left;
int m_next_restart_num;
int m_max_mcus_per_row;
int m_max_blocks_per_mcu;
int m_expanded_blocks_per_mcu;
int m_expanded_blocks_per_row;
int m_expanded_blocks_per_component;
bool m_freq_domain_chroma_upsample;
int m_max_mcus_per_col;
uint m_last_dc_val[JPGD_MAX_COMPONENTS];
jpgd_block_t* m_pMCU_coefficients;
int m_mcu_block_max_zag[JPGD_MAX_BLOCKS_PER_MCU];
uint8* m_pSample_buf;
int m_crr[256];
int m_cbb[256];
int m_crg[256];
int m_cbg[256];
uint8* m_pScan_line_0;
uint8* m_pScan_line_1;
jpgd_status m_error_code;
bool m_ready_flag;
int m_total_bytes_read;
enum
{
JPGD_IN_BUF_SIZE = 8192, JPGD_MAX_BLOCKS_PER_MCU = 10, JPGD_MAX_HUFF_TABLES = 8, JPGD_MAX_QUANT_TABLES = 4,
JPGD_MAX_COMPONENTS = 4, JPGD_MAX_COMPS_IN_SCAN = 4, JPGD_MAX_BLOCKS_PER_ROW = 8192, JPGD_MAX_HEIGHT = 16384, JPGD_MAX_WIDTH = 16384
};
typedef int16 jpgd_quant_t;
typedef int16 jpgd_block_t;
void free_all_blocks();
JPGD_NORETURN void stop_decoding(jpgd_status status);
void* alloc(size_t n, bool zero = false);
void word_clear(void* p, uint16 c, uint n);
void prep_in_buffer();
void read_dht_marker();
void read_dqt_marker();
void read_sof_marker();
void skip_variable_marker();
void read_dri_marker();
void read_sos_marker();
int next_marker();
int process_markers();
void locate_soi_marker();
void locate_sof_marker();
int locate_sos_marker();
void init(jpeg_decoder_stream* pStream);
void create_look_ups();
void fix_in_buffer();
void transform_mcu(int mcu_row);
void transform_mcu_expand(int mcu_row);
coeff_buf* coeff_buf_open(int block_num_x, int block_num_y, int block_len_x, int block_len_y);
inline jpgd_block_t* coeff_buf_getp(coeff_buf* cb, int block_x, int block_y);
void load_next_row();
void decode_next_row();
void make_huff_table(int index, huff_tables* pH);
void check_quant_tables();
void check_huff_tables();
void calc_mcu_block_order();
int init_scan();
void init_frame();
void process_restart();
void decode_scan(pDecode_block_func decode_block_func);
void init_progressive();
void init_sequential();
void decode_start();
void decode_init(jpeg_decoder_stream* pStream);
void H2V2Convert();
void H2V1Convert();
void H1V2Convert();
void H1V1Convert();
void gray_convert();
void expanded_convert();
void find_eoi();
inline uint get_char();
inline uint get_char(bool* pPadding_flag);
inline void stuff_char(uint8 q);
inline uint8 get_octet();
inline uint get_bits(int num_bits);
inline uint get_bits_no_markers(int numbits);
inline int huff_decode(huff_tables* pH);
inline int huff_decode(huff_tables* pH, int& extrabits);
static inline uint8 clamp(int i);
static void decode_block_dc_first(jpeg_decoder* pD, int component_id, int block_x, int block_y);
static void decode_block_dc_refine(jpeg_decoder* pD, int component_id, int block_x, int block_y);
static void decode_block_ac_first(jpeg_decoder* pD, int component_id, int block_x, int block_y);
static void decode_block_ac_refine(jpeg_decoder* pD, int component_id, int block_x, int block_y);
};
class jpeg_decoder
{
public:
// Call get_error_code() after constructing to determine if the stream is valid or not. You may call the get_width(), get_height(), etc.
// methods after the constructor is called. You may then either destruct the object, or begin decoding the image by calling begin_decoding(), then decode() on each scanline.
jpeg_decoder(jpeg_decoder_stream *pStream);
} // namespace jpgd
~jpeg_decoder();
// Call this method after constructing the object to begin decompression.
// If JPGD_SUCCESS is returned you may then call decode() on each scanline.
int begin_decoding();
// Returns the next scan line.
// For grayscale images, pScan_line will point to a buffer containing 8-bit pixels (get_bytes_per_pixel() will return 1).
// Otherwise, it will always point to a buffer containing 32-bit RGBA pixels (A will always be 255, and get_bytes_per_pixel() will return 4).
// Returns JPGD_SUCCESS if a scan line has been returned.
// Returns JPGD_DONE if all scan lines have been returned.
// Returns JPGD_FAILED if an error occurred. Call get_error_code() for a more info.
int decode(const void** pScan_line, uint* pScan_line_len);
inline jpgd_status get_error_code() const { return m_error_code; }
inline int get_width() const { return m_image_x_size; }
inline int get_height() const { return m_image_y_size; }
inline int get_num_components() const { return m_comps_in_frame; }
inline int get_bytes_per_pixel() const { return m_dest_bytes_per_pixel; }
inline int get_bytes_per_scan_line() const { return m_image_x_size * get_bytes_per_pixel(); }
// Returns the total number of bytes actually consumed by the decoder (which should equal the actual size of the JPEG file).
inline int get_total_bytes_read() const { return m_total_bytes_read; }
private:
jpeg_decoder(const jpeg_decoder &);
jpeg_decoder &operator =(const jpeg_decoder &);
typedef void (*pDecode_block_func)(jpeg_decoder *, int, int, int);
struct huff_tables
{
bool ac_table;
uint look_up[256];
uint look_up2[256];
uint8 code_size[256];
uint tree[512];
};
struct coeff_buf
{
uint8 *pData;
int block_num_x, block_num_y;
int block_len_x, block_len_y;
int block_size;
};
struct mem_block
{
mem_block *m_pNext;
size_t m_used_count;
size_t m_size;
char m_data[1];
};
jmp_buf m_jmp_state;
mem_block *m_pMem_blocks;
int m_image_x_size;
int m_image_y_size;
jpeg_decoder_stream *m_pStream;
int m_progressive_flag;
uint8 m_huff_ac[JPGD_MAX_HUFF_TABLES];
uint8* m_huff_num[JPGD_MAX_HUFF_TABLES]; // pointer to number of Huffman codes per bit size
uint8* m_huff_val[JPGD_MAX_HUFF_TABLES]; // pointer to Huffman codes per bit size
jpgd_quant_t* m_quant[JPGD_MAX_QUANT_TABLES]; // pointer to quantization tables
int m_scan_type; // Gray, Yh1v1, Yh1v2, Yh2v1, Yh2v2 (CMYK111, CMYK4114 no longer supported)
int m_comps_in_frame; // # of components in frame
int m_comp_h_samp[JPGD_MAX_COMPONENTS]; // component's horizontal sampling factor
int m_comp_v_samp[JPGD_MAX_COMPONENTS]; // component's vertical sampling factor
int m_comp_quant[JPGD_MAX_COMPONENTS]; // component's quantization table selector
int m_comp_ident[JPGD_MAX_COMPONENTS]; // component's ID
int m_comp_h_blocks[JPGD_MAX_COMPONENTS];
int m_comp_v_blocks[JPGD_MAX_COMPONENTS];
int m_comps_in_scan; // # of components in scan
int m_comp_list[JPGD_MAX_COMPS_IN_SCAN]; // components in this scan
int m_comp_dc_tab[JPGD_MAX_COMPONENTS]; // component's DC Huffman coding table selector
int m_comp_ac_tab[JPGD_MAX_COMPONENTS]; // component's AC Huffman coding table selector
int m_spectral_start; // spectral selection start
int m_spectral_end; // spectral selection end
int m_successive_low; // successive approximation low
int m_successive_high; // successive approximation high
int m_max_mcu_x_size; // MCU's max. X size in pixels
int m_max_mcu_y_size; // MCU's max. Y size in pixels
int m_blocks_per_mcu;
int m_max_blocks_per_row;
int m_mcus_per_row, m_mcus_per_col;
int m_mcu_org[JPGD_MAX_BLOCKS_PER_MCU];
int m_total_lines_left; // total # lines left in image
int m_mcu_lines_left; // total # lines left in this MCU
int m_real_dest_bytes_per_scan_line;
int m_dest_bytes_per_scan_line; // rounded up
int m_dest_bytes_per_pixel; // 4 (RGB) or 1 (Y)
huff_tables* m_pHuff_tabs[JPGD_MAX_HUFF_TABLES];
coeff_buf* m_dc_coeffs[JPGD_MAX_COMPONENTS];
coeff_buf* m_ac_coeffs[JPGD_MAX_COMPONENTS];
int m_eob_run;
int m_block_y_mcu[JPGD_MAX_COMPONENTS];
uint8* m_pIn_buf_ofs;
int m_in_buf_left;
int m_tem_flag;
bool m_eof_flag;
uint8 m_in_buf_pad_start[128];
uint8 m_in_buf[JPGD_IN_BUF_SIZE + 128];
uint8 m_in_buf_pad_end[128];
int m_bits_left;
uint m_bit_buf;
int m_restart_interval;
int m_restarts_left;
int m_next_restart_num;
int m_max_mcus_per_row;
int m_max_blocks_per_mcu;
int m_expanded_blocks_per_mcu;
int m_expanded_blocks_per_row;
int m_expanded_blocks_per_component;
bool m_freq_domain_chroma_upsample;
int m_max_mcus_per_col;
uint m_last_dc_val[JPGD_MAX_COMPONENTS];
jpgd_block_t* m_pMCU_coefficients;
int m_mcu_block_max_zag[JPGD_MAX_BLOCKS_PER_MCU];
uint8* m_pSample_buf;
int m_crr[256];
int m_cbb[256];
int m_crg[256];
int m_cbg[256];
uint8* m_pScan_line_0;
uint8* m_pScan_line_1;
jpgd_status m_error_code;
bool m_ready_flag;
int m_total_bytes_read;
void free_all_blocks();
JPGD_NORETURN void stop_decoding(jpgd_status status);
void *alloc(size_t n, bool zero = false);
void word_clear(void *p, uint16 c, uint n);
void prep_in_buffer();
void read_dht_marker();
void read_dqt_marker();
void read_sof_marker();
void skip_variable_marker();
void read_dri_marker();
void read_sos_marker();
int next_marker();
int process_markers();
void locate_soi_marker();
void locate_sof_marker();
int locate_sos_marker();
void init(jpeg_decoder_stream * pStream);
void create_look_ups();
void fix_in_buffer();
void transform_mcu(int mcu_row);
void transform_mcu_expand(int mcu_row);
coeff_buf* coeff_buf_open(int block_num_x, int block_num_y, int block_len_x, int block_len_y);
inline jpgd_block_t *coeff_buf_getp(coeff_buf *cb, int block_x, int block_y);
void load_next_row();
void decode_next_row();
void make_huff_table(int index, huff_tables *pH);
void check_quant_tables();
void check_huff_tables();
void calc_mcu_block_order();
int init_scan();
void init_frame();
void process_restart();
void decode_scan(pDecode_block_func decode_block_func);
void init_progressive();
void init_sequential();
void decode_start();
void decode_init(jpeg_decoder_stream * pStream);
void H2V2Convert();
void H2V1Convert();
void H1V2Convert();
void H1V1Convert();
void gray_convert();
void expanded_convert();
void find_eoi();
inline uint get_char();
inline uint get_char(bool *pPadding_flag);
inline void stuff_char(uint8 q);
inline uint8 get_octet();
inline uint get_bits(int num_bits);
inline uint get_bits_no_markers(int numbits);
inline int huff_decode(huff_tables *pH);
inline int huff_decode(huff_tables *pH, int& extrabits);
static inline uint8 clamp(int i);
static void decode_block_dc_first(jpeg_decoder *pD, int component_id, int block_x, int block_y);
static void decode_block_dc_refine(jpeg_decoder *pD, int component_id, int block_x, int block_y);
static void decode_block_ac_first(jpeg_decoder *pD, int component_id, int block_x, int block_y);
static void decode_block_ac_refine(jpeg_decoder *pD, int component_id, int block_x, int block_y);
};
} // namespace jpgd
#endif // JPEG_DECODER_H
#endif // JPEG_DECODER_H
+1010 -934
View File
File diff suppressed because it is too large Load Diff
+143 -141
View File
@@ -4,166 +4,168 @@
#ifndef JPEG_ENCODER_H
#define JPEG_ENCODER_H
namespace jpge
{
typedef unsigned char uint8;
typedef signed short int16;
typedef signed int int32;
typedef unsigned short uint16;
typedef unsigned int uint32;
typedef unsigned int uint;
namespace jpge {
typedef unsigned char uint8;
typedef signed short int16;
typedef signed int int32;
typedef unsigned short uint16;
typedef unsigned int uint32;
typedef unsigned int uint;
// JPEG chroma subsampling factors. Y_ONLY (grayscale images) and H2V2 (color images) are the most common.
enum subsampling_t { Y_ONLY = 0, H1V1 = 1, H2V1 = 2, H2V2 = 3 };
// JPEG chroma subsampling factors. Y_ONLY (grayscale images) and H2V2 (color images) are the most common.
enum subsampling_t { Y_ONLY = 0,
H1V1 = 1,
H2V1 = 2,
H2V2 = 3 };
// JPEG compression parameters structure.
struct params
{
inline params() : m_quality(85), m_subsampling(H2V2), m_no_chroma_discrim_flag(false), m_two_pass_flag(false) { }
// JPEG compression parameters structure.
struct params {
inline params()
: m_quality(85), m_subsampling(H2V2), m_no_chroma_discrim_flag(false), m_two_pass_flag(false) {}
inline bool check() const
{
if ((m_quality < 1) || (m_quality > 100)) return false;
if ((uint)m_subsampling > (uint)H2V2) return false;
return true;
}
inline bool check() const {
if ((m_quality < 1) || (m_quality > 100))
return false;
if ((uint)m_subsampling > (uint)H2V2)
return false;
return true;
}
// Quality: 1-100, higher is better. Typical values are around 50-95.
int m_quality;
// Quality: 1-100, higher is better. Typical values are around 50-95.
int m_quality;
// m_subsampling:
// 0 = Y (grayscale) only
// 1 = YCbCr, no subsampling (H1V1, YCbCr 1x1x1, 3 blocks per MCU)
// 2 = YCbCr, H2V1 subsampling (YCbCr 2x1x1, 4 blocks per MCU)
// 3 = YCbCr, H2V2 subsampling (YCbCr 4x1x1, 6 blocks per MCU-- very common)
subsampling_t m_subsampling;
// m_subsampling:
// 0 = Y (grayscale) only
// 1 = YCbCr, no subsampling (H1V1, YCbCr 1x1x1, 3 blocks per MCU)
// 2 = YCbCr, H2V1 subsampling (YCbCr 2x1x1, 4 blocks per MCU)
// 3 = YCbCr, H2V2 subsampling (YCbCr 4x1x1, 6 blocks per MCU-- very common)
subsampling_t m_subsampling;
// Disables CbCr discrimination - only intended for testing.
// If true, the Y quantization table is also used for the CbCr channels.
bool m_no_chroma_discrim_flag;
// Disables CbCr discrimination - only intended for testing.
// If true, the Y quantization table is also used for the CbCr channels.
bool m_no_chroma_discrim_flag;
bool m_two_pass_flag;
};
bool m_two_pass_flag;
};
// Writes JPEG image to a file.
// num_channels must be 1 (Y) or 3 (RGB), image pitch must be width*num_channels.
bool compress_image_to_jpeg_file(const char *pFilename, int width, int height, int num_channels, const uint8 *pImage_data, const params &comp_params = params());
// Writes JPEG image to a file.
// num_channels must be 1 (Y) or 3 (RGB), image pitch must be width*num_channels.
bool compress_image_to_jpeg_file(const char* pFilename, int width, int height, int num_channels, const uint8* pImage_data, const params& comp_params = params());
// Writes JPEG image to memory buffer.
// On entry, buf_size is the size of the output buffer pointed at by pBuf, which should be at least ~1024 bytes.
// If return value is true, buf_size will be set to the size of the compressed data.
bool compress_image_to_jpeg_file_in_memory(void *pBuf, int &buf_size, int width, int height, int num_channels, const uint8 *pImage_data, const params &comp_params = params());
// Writes JPEG image to memory buffer.
// On entry, buf_size is the size of the output buffer pointed at by pBuf, which should be at least ~1024 bytes.
// If return value is true, buf_size will be set to the size of the compressed data.
bool compress_image_to_jpeg_file_in_memory(void* pBuf, int& buf_size, int width, int height, int num_channels, const uint8* pImage_data, const params& comp_params = params());
// Output stream abstract class - used by the jpeg_encoder class to write to the output stream.
// put_buf() is generally called with len==JPGE_OUT_BUF_SIZE bytes, but for headers it'll be called with smaller amounts.
class output_stream
{
public:
virtual ~output_stream() { };
virtual bool put_buf(const void* Pbuf, int len) = 0;
template<class T> inline bool put_obj(const T& obj) { return put_buf(&obj, sizeof(T)); }
};
// Output stream abstract class - used by the jpeg_encoder class to write to the output stream.
// put_buf() is generally called with len==JPGE_OUT_BUF_SIZE bytes, but for headers it'll be called with smaller amounts.
class output_stream {
public:
virtual ~output_stream(){};
virtual bool put_buf(const void* Pbuf, int len) = 0;
template <class T>
inline bool put_obj(const T& obj) { return put_buf(&obj, sizeof(T)); }
};
// Lower level jpeg_encoder class - useful if more control is needed than the above helper functions.
class jpeg_encoder
{
public:
jpeg_encoder();
~jpeg_encoder();
// Lower level jpeg_encoder class - useful if more control is needed than the above helper functions.
class jpeg_encoder {
public:
jpeg_encoder();
~jpeg_encoder();
// Initializes the compressor.
// pStream: The stream object to use for writing compressed data.
// params - Compression parameters structure, defined above.
// width, height - Image dimensions.
// channels - May be 1, or 3. 1 indicates grayscale, 3 indicates RGB source data.
// Returns false on out of memory or if a stream write fails.
bool init(output_stream *pStream, int width, int height, int src_channels, const params &comp_params = params());
// Initializes the compressor.
// pStream: The stream object to use for writing compressed data.
// params - Compression parameters structure, defined above.
// width, height - Image dimensions.
// channels - May be 1, or 3. 1 indicates grayscale, 3 indicates RGB source data.
// Returns false on out of memory or if a stream write fails.
bool init(output_stream* pStream, int width, int height, int src_channels, const params& comp_params = params());
const params &get_params() const { return m_params; }
const params& get_params() const { return m_params; }
// Deinitializes the compressor, freeing any allocated memory. May be called at any time.
void deinit();
// Deinitializes the compressor, freeing any allocated memory. May be called at any time.
void deinit();
uint get_total_passes() const { return m_params.m_two_pass_flag ? 2 : 1; }
inline uint get_cur_pass() { return m_pass_num; }
uint get_total_passes() const { return m_params.m_two_pass_flag ? 2 : 1; }
inline uint get_cur_pass() { return m_pass_num; }
// Call this method with each source scanline.
// width * src_channels bytes per scanline is expected (RGB or Y format).
// You must call with NULL after all scanlines are processed to finish compression.
// Returns false on out of memory or if a stream write fails.
bool process_scanline(const void* pScanline);
// Call this method with each source scanline.
// width * src_channels bytes per scanline is expected (RGB or Y format).
// You must call with NULL after all scanlines are processed to finish compression.
// Returns false on out of memory or if a stream write fails.
bool process_scanline(const void* pScanline);
private:
jpeg_encoder(const jpeg_encoder &);
jpeg_encoder &operator =(const jpeg_encoder &);
private:
jpeg_encoder(const jpeg_encoder&);
jpeg_encoder& operator=(const jpeg_encoder&);
typedef int32 sample_array_t;
typedef int32 sample_array_t;
output_stream *m_pStream;
params m_params;
uint8 m_num_components;
uint8 m_comp_h_samp[3], m_comp_v_samp[3];
int m_image_x, m_image_y, m_image_bpp, m_image_bpl;
int m_image_x_mcu, m_image_y_mcu;
int m_image_bpl_xlt, m_image_bpl_mcu;
int m_mcus_per_row;
int m_mcu_x, m_mcu_y;
uint8 *m_mcu_lines[16];
uint8 m_mcu_y_ofs;
sample_array_t m_sample_array[64];
int16 m_coefficient_array[64];
int32 m_quantization_tables[2][64];
uint m_huff_codes[4][256];
uint8 m_huff_code_sizes[4][256];
uint8 m_huff_bits[4][17];
uint8 m_huff_val[4][256];
uint32 m_huff_count[4][256];
int m_last_dc_val[3];
enum { JPGE_OUT_BUF_SIZE = 2048 };
uint8 m_out_buf[JPGE_OUT_BUF_SIZE];
uint8 *m_pOut_buf;
uint m_out_buf_left;
uint32 m_bit_buffer;
uint m_bits_in;
uint8 m_pass_num;
bool m_all_stream_writes_succeeded;
output_stream* m_pStream;
params m_params;
uint8 m_num_components;
uint8 m_comp_h_samp[3], m_comp_v_samp[3];
int m_image_x, m_image_y, m_image_bpp, m_image_bpl;
int m_image_x_mcu, m_image_y_mcu;
int m_image_bpl_xlt, m_image_bpl_mcu;
int m_mcus_per_row;
int m_mcu_x, m_mcu_y;
uint8* m_mcu_lines[16];
uint8 m_mcu_y_ofs;
sample_array_t m_sample_array[64];
int16 m_coefficient_array[64];
int32 m_quantization_tables[2][64];
uint m_huff_codes[4][256];
uint8 m_huff_code_sizes[4][256];
uint8 m_huff_bits[4][17];
uint8 m_huff_val[4][256];
uint32 m_huff_count[4][256];
int m_last_dc_val[3];
enum { JPGE_OUT_BUF_SIZE = 2048 };
uint8 m_out_buf[JPGE_OUT_BUF_SIZE];
uint8* m_pOut_buf;
uint m_out_buf_left;
uint32 m_bit_buffer;
uint m_bits_in;
uint8 m_pass_num;
bool m_all_stream_writes_succeeded;
void optimize_huffman_table(int table_num, int table_len);
void emit_byte(uint8 i);
void emit_word(uint i);
void emit_marker(int marker);
void emit_jfif_app0();
void emit_dqt();
void emit_sof();
void emit_dht(uint8 *bits, uint8 *val, int index, bool ac_flag);
void emit_dhts();
void emit_sos();
void emit_markers();
void compute_huffman_table(uint *codes, uint8 *code_sizes, uint8 *bits, uint8 *val);
void compute_quant_table(int32 *dst, int16 *src);
void adjust_quant_table(int32 *dst, int32 *src);
void first_pass_init();
bool second_pass_init();
bool jpg_open(int p_x_res, int p_y_res, int src_channels);
void load_block_8_8_grey(int x);
void load_block_8_8(int x, int y, int c);
void load_block_16_8(int x, int c);
void load_block_16_8_8(int x, int c);
void load_quantized_coefficients(int component_num);
void flush_output_buffer();
void put_bits(uint bits, uint len);
void code_coefficients_pass_one(int component_num);
void code_coefficients_pass_two(int component_num);
void code_block(int component_num);
void process_mcu_row();
bool terminate_pass_one();
bool terminate_pass_two();
bool process_end_of_image();
void load_mcu(const void* src);
void clear();
void init();
};
void optimize_huffman_table(int table_num, int table_len);
void emit_byte(uint8 i);
void emit_word(uint i);
void emit_marker(int marker);
void emit_jfif_app0();
void emit_dqt();
void emit_sof();
void emit_dht(uint8* bits, uint8* val, int index, bool ac_flag);
void emit_dhts();
void emit_sos();
void emit_markers();
void compute_huffman_table(uint* codes, uint8* code_sizes, uint8* bits, uint8* val);
void compute_quant_table(int32* dst, int16* src);
void adjust_quant_table(int32* dst, int32* src);
void first_pass_init();
bool second_pass_init();
bool jpg_open(int p_x_res, int p_y_res, int src_channels);
void load_block_8_8_grey(int x);
void load_block_8_8(int x, int y, int c);
void load_block_16_8(int x, int c);
void load_block_16_8_8(int x, int c);
void load_quantized_coefficients(int component_num);
void flush_output_buffer();
void put_bits(uint bits, uint len);
void code_coefficients_pass_one(int component_num);
void code_coefficients_pass_two(int component_num);
void code_block(int component_num);
void process_mcu_row();
bool terminate_pass_one();
bool terminate_pass_two();
bool process_end_of_image();
void load_mcu(const void* src);
void clear();
void init();
};
} // namespace jpge
} // namespace jpge
#endif // JPEG_ENCODER
#endif // JPEG_ENCODER
+739 -826
View File
File diff suppressed because it is too large Load Diff
+242 -197
View File
@@ -10,235 +10,280 @@
#define KTX_ENDIAN 0x04030201
#define KTX_OPPOSITE_ENDIAN 0x01020304
namespace crnlib
{
extern const uint8 s_ktx_file_id[12];
namespace crnlib {
extern const uint8 s_ktx_file_id[12];
struct ktx_header
{
uint8 m_identifier[12];
uint32 m_endianness;
uint32 m_glType;
uint32 m_glTypeSize;
uint32 m_glFormat;
uint32 m_glInternalFormat;
uint32 m_glBaseInternalFormat;
uint32 m_pixelWidth;
uint32 m_pixelHeight;
uint32 m_pixelDepth;
uint32 m_numberOfArrayElements;
uint32 m_numberOfFaces;
uint32 m_numberOfMipmapLevels;
uint32 m_bytesOfKeyValueData;
struct ktx_header {
uint8 m_identifier[12];
uint32 m_endianness;
uint32 m_glType;
uint32 m_glTypeSize;
uint32 m_glFormat;
uint32 m_glInternalFormat;
uint32 m_glBaseInternalFormat;
uint32 m_pixelWidth;
uint32 m_pixelHeight;
uint32 m_pixelDepth;
uint32 m_numberOfArrayElements;
uint32 m_numberOfFaces;
uint32 m_numberOfMipmapLevels;
uint32 m_bytesOfKeyValueData;
void clear()
{
memset(this, 0, sizeof(*this));
}
void clear() {
memset(this, 0, sizeof(*this));
}
void endian_swap()
{
utils::endian_swap_mem32(&m_endianness, (sizeof(*this) - sizeof(m_identifier)) / sizeof(uint32));
}
};
void endian_swap() {
utils::endian_swap_mem32(&m_endianness, (sizeof(*this) - sizeof(m_identifier)) / sizeof(uint32));
}
};
typedef crnlib::vector<uint8_vec> ktx_key_value_vec;
typedef crnlib::vector<uint8_vec> ktx_image_data_vec;
typedef crnlib::vector<uint8_vec> ktx_key_value_vec;
typedef crnlib::vector<uint8_vec> ktx_image_data_vec;
// Compressed pixel data formats: ETC1, DXT1, DXT3, DXT5
enum
{
KTX_ETC1_RGB8_OES = 0x8D64, KTX_RGB_S3TC = 0x83A0, KTX_RGB4_S3TC = 0x83A1, KTX_COMPRESSED_RGB_S3TC_DXT1_EXT = 0x83F0,
KTX_COMPRESSED_RGBA_S3TC_DXT1_EXT = 0x83F1, KTX_COMPRESSED_SRGB_S3TC_DXT1_EXT = 0x8C4C, KTX_COMPRESSED_SRGB_ALPHA_S3TC_DXT1_EXT = 0x8C4D,
KTX_RGBA_S3TC = 0x83A2, KTX_RGBA4_S3TC = 0x83A3, KTX_COMPRESSED_RGBA_S3TC_DXT3_EXT = 0x83F2, KTX_COMPRESSED_SRGB_ALPHA_S3TC_DXT3_EXT = 0x8C4E,
KTX_COMPRESSED_RGBA_S3TC_DXT5_EXT = 0x83F3, KTX_COMPRESSED_SRGB_ALPHA_S3TC_DXT5_EXT = 0x8C4F, KTX_RGBA_DXT5_S3TC = 0x83A4, KTX_RGBA4_DXT5_S3TC = 0x83A5,
KTX_COMPRESSED_RED_RGTC1_EXT = 0x8DBB, KTX_COMPRESSED_SIGNED_RED_RGTC1_EXT = 0x8DBC, KTX_COMPRESSED_RED_GREEN_RGTC2_EXT = 0x8DBD, KTX_COMPRESSED_SIGNED_RED_GREEN_RGTC2_EXT = 0x8DBE,
KTX_COMPRESSED_LUMINANCE_LATC1_EXT = 0x8C70, KTX_COMPRESSED_SIGNED_LUMINANCE_LATC1_EXT = 0x8C71, KTX_COMPRESSED_LUMINANCE_ALPHA_LATC2_EXT = 0x8C72, KTX_COMPRESSED_SIGNED_LUMINANCE_ALPHA_LATC2_EXT = 0x8C73
};
// Compressed pixel data formats: ETC1, DXT1, DXT3, DXT5
enum {
KTX_ETC1_RGB8_OES = 0x8D64,
KTX_RGB_S3TC = 0x83A0,
KTX_RGB4_S3TC = 0x83A1,
KTX_COMPRESSED_RGB_S3TC_DXT1_EXT = 0x83F0,
KTX_COMPRESSED_RGBA_S3TC_DXT1_EXT = 0x83F1,
KTX_COMPRESSED_SRGB_S3TC_DXT1_EXT = 0x8C4C,
KTX_COMPRESSED_SRGB_ALPHA_S3TC_DXT1_EXT = 0x8C4D,
KTX_RGBA_S3TC = 0x83A2,
KTX_RGBA4_S3TC = 0x83A3,
KTX_COMPRESSED_RGBA_S3TC_DXT3_EXT = 0x83F2,
KTX_COMPRESSED_SRGB_ALPHA_S3TC_DXT3_EXT = 0x8C4E,
KTX_COMPRESSED_RGBA_S3TC_DXT5_EXT = 0x83F3,
KTX_COMPRESSED_SRGB_ALPHA_S3TC_DXT5_EXT = 0x8C4F,
KTX_RGBA_DXT5_S3TC = 0x83A4,
KTX_RGBA4_DXT5_S3TC = 0x83A5,
KTX_COMPRESSED_RED_RGTC1_EXT = 0x8DBB,
KTX_COMPRESSED_SIGNED_RED_RGTC1_EXT = 0x8DBC,
KTX_COMPRESSED_RED_GREEN_RGTC2_EXT = 0x8DBD,
KTX_COMPRESSED_SIGNED_RED_GREEN_RGTC2_EXT = 0x8DBE,
KTX_COMPRESSED_LUMINANCE_LATC1_EXT = 0x8C70,
KTX_COMPRESSED_SIGNED_LUMINANCE_LATC1_EXT = 0x8C71,
KTX_COMPRESSED_LUMINANCE_ALPHA_LATC2_EXT = 0x8C72,
KTX_COMPRESSED_SIGNED_LUMINANCE_ALPHA_LATC2_EXT = 0x8C73
};
// Pixel formats (various internal, base, and base internal formats)
enum
{
KTX_R8 = 0x8229, KTX_R8UI = 0x8232, KTX_RGB8 = 0x8051, KTX_SRGB8 = 0x8C41, KTX_SRGB = 0x8C40, KTX_SRGB_ALPHA = 0x8C42,
KTX_SRGB8_ALPHA8 = 0x8C43, KTX_RGBA8 = 0x8058, KTX_STENCIL_INDEX = 0x1901, KTX_DEPTH_COMPONENT = 0x1902, KTX_DEPTH_STENCIL = 0x84F9, KTX_RED = 0x1903,
KTX_GREEN = 0x1904, KTX_BLUE = 0x1905, KTX_ALPHA = 0x1906, KTX_RG = 0x8227, KTX_RGB = 0x1907, KTX_RGBA = 0x1908, KTX_BGR = 0x80E0, KTX_BGRA = 0x80E1,
KTX_RED_INTEGER = 0x8D94, KTX_GREEN_INTEGER = 0x8D95, KTX_BLUE_INTEGER = 0x8D96, KTX_ALPHA_INTEGER = 0x8D97, KTX_RGB_INTEGER = 0x8D98, KTX_RGBA_INTEGER = 0x8D99,
KTX_BGR_INTEGER = 0x8D9A, KTX_BGRA_INTEGER = 0x8D9B, KTX_LUMINANCE = 0x1909, KTX_LUMINANCE_ALPHA = 0x190A, KTX_RG_INTEGER = 0x8228, KTX_RG8 = 0x822B,
KTX_ALPHA8 = 0x803C, KTX_LUMINANCE8 = 0x8040, KTX_LUMINANCE8_ALPHA8 = 0x8045
};
// Pixel formats (various internal, base, and base internal formats)
enum {
KTX_R8 = 0x8229,
KTX_R8UI = 0x8232,
KTX_RGB8 = 0x8051,
KTX_SRGB8 = 0x8C41,
KTX_SRGB = 0x8C40,
KTX_SRGB_ALPHA = 0x8C42,
KTX_SRGB8_ALPHA8 = 0x8C43,
KTX_RGBA8 = 0x8058,
KTX_STENCIL_INDEX = 0x1901,
KTX_DEPTH_COMPONENT = 0x1902,
KTX_DEPTH_STENCIL = 0x84F9,
KTX_RED = 0x1903,
KTX_GREEN = 0x1904,
KTX_BLUE = 0x1905,
KTX_ALPHA = 0x1906,
KTX_RG = 0x8227,
KTX_RGB = 0x1907,
KTX_RGBA = 0x1908,
KTX_BGR = 0x80E0,
KTX_BGRA = 0x80E1,
KTX_RED_INTEGER = 0x8D94,
KTX_GREEN_INTEGER = 0x8D95,
KTX_BLUE_INTEGER = 0x8D96,
KTX_ALPHA_INTEGER = 0x8D97,
KTX_RGB_INTEGER = 0x8D98,
KTX_RGBA_INTEGER = 0x8D99,
KTX_BGR_INTEGER = 0x8D9A,
KTX_BGRA_INTEGER = 0x8D9B,
KTX_LUMINANCE = 0x1909,
KTX_LUMINANCE_ALPHA = 0x190A,
KTX_RG_INTEGER = 0x8228,
KTX_RG8 = 0x822B,
KTX_ALPHA8 = 0x803C,
KTX_LUMINANCE8 = 0x8040,
KTX_LUMINANCE8_ALPHA8 = 0x8045
};
// Pixel data types
enum
{
KTX_UNSIGNED_BYTE = 0x1401, KTX_BYTE = 0x1400, KTX_UNSIGNED_SHORT = 0x1403, KTX_SHORT = 0x1402,
KTX_UNSIGNED_INT = 0x1405, KTX_INT = 0x1404, KTX_HALF_FLOAT = 0x140B, KTX_FLOAT = 0x1406,
KTX_UNSIGNED_BYTE_3_3_2 = 0x8032, KTX_UNSIGNED_BYTE_2_3_3_REV = 0x8362, KTX_UNSIGNED_SHORT_5_6_5 = 0x8363,
KTX_UNSIGNED_SHORT_5_6_5_REV = 0x8364, KTX_UNSIGNED_SHORT_4_4_4_4 = 0x8033, KTX_UNSIGNED_SHORT_4_4_4_4_REV = 0x8365,
KTX_UNSIGNED_SHORT_5_5_5_1 = 0x8034, KTX_UNSIGNED_SHORT_1_5_5_5_REV = 0x8366, KTX_UNSIGNED_INT_8_8_8_8 = 0x8035,
KTX_UNSIGNED_INT_8_8_8_8_REV = 0x8367, KTX_UNSIGNED_INT_10_10_10_2 = 0x8036, KTX_UNSIGNED_INT_2_10_10_10_REV = 0x8368,
KTX_UNSIGNED_INT_24_8 = 0x84FA, KTX_UNSIGNED_INT_10F_11F_11F_REV = 0x8C3B, KTX_UNSIGNED_INT_5_9_9_9_REV = 0x8C3E,
KTX_FLOAT_32_UNSIGNED_INT_24_8_REV = 0x8DAD
};
bool is_packed_pixel_ogl_type(uint32 ogl_type);
uint get_ogl_type_size(uint32 ogl_type);
bool get_ogl_fmt_desc(uint32 ogl_fmt, uint32 ogl_type, uint& block_dim, uint& bytes_per_block);
uint get_ogl_type_size(uint32 ogl_type);
uint32 get_ogl_base_internal_fmt(uint32 ogl_fmt);
// Pixel data types
enum {
KTX_UNSIGNED_BYTE = 0x1401,
KTX_BYTE = 0x1400,
KTX_UNSIGNED_SHORT = 0x1403,
KTX_SHORT = 0x1402,
KTX_UNSIGNED_INT = 0x1405,
KTX_INT = 0x1404,
KTX_HALF_FLOAT = 0x140B,
KTX_FLOAT = 0x1406,
KTX_UNSIGNED_BYTE_3_3_2 = 0x8032,
KTX_UNSIGNED_BYTE_2_3_3_REV = 0x8362,
KTX_UNSIGNED_SHORT_5_6_5 = 0x8363,
KTX_UNSIGNED_SHORT_5_6_5_REV = 0x8364,
KTX_UNSIGNED_SHORT_4_4_4_4 = 0x8033,
KTX_UNSIGNED_SHORT_4_4_4_4_REV = 0x8365,
KTX_UNSIGNED_SHORT_5_5_5_1 = 0x8034,
KTX_UNSIGNED_SHORT_1_5_5_5_REV = 0x8366,
KTX_UNSIGNED_INT_8_8_8_8 = 0x8035,
KTX_UNSIGNED_INT_8_8_8_8_REV = 0x8367,
KTX_UNSIGNED_INT_10_10_10_2 = 0x8036,
KTX_UNSIGNED_INT_2_10_10_10_REV = 0x8368,
KTX_UNSIGNED_INT_24_8 = 0x84FA,
KTX_UNSIGNED_INT_10F_11F_11F_REV = 0x8C3B,
KTX_UNSIGNED_INT_5_9_9_9_REV = 0x8C3E,
KTX_FLOAT_32_UNSIGNED_INT_24_8_REV = 0x8DAD
};
class ktx_texture
{
public:
ktx_texture()
{
clear();
}
bool is_packed_pixel_ogl_type(uint32 ogl_type);
uint get_ogl_type_size(uint32 ogl_type);
bool get_ogl_fmt_desc(uint32 ogl_fmt, uint32 ogl_type, uint& block_dim, uint& bytes_per_block);
uint get_ogl_type_size(uint32 ogl_type);
uint32 get_ogl_base_internal_fmt(uint32 ogl_fmt);
ktx_texture(const ktx_texture& other)
{
*this = other;
}
class ktx_texture {
public:
ktx_texture() {
clear();
}
ktx_texture& operator= (const ktx_texture& rhs)
{
if (this == &rhs)
return *this;
ktx_texture(const ktx_texture& other) {
*this = other;
}
clear();
ktx_texture& operator=(const ktx_texture& rhs) {
if (this == &rhs)
return *this;
m_header = rhs.m_header;
m_key_values = rhs.m_key_values;
m_image_data = rhs.m_image_data;
m_block_dim = rhs.m_block_dim;
m_bytes_per_block = rhs.m_bytes_per_block;
m_opposite_endianness = rhs.m_opposite_endianness;
clear();
return *this;
}
m_header = rhs.m_header;
m_key_values = rhs.m_key_values;
m_image_data = rhs.m_image_data;
m_block_dim = rhs.m_block_dim;
m_bytes_per_block = rhs.m_bytes_per_block;
m_opposite_endianness = rhs.m_opposite_endianness;
void clear()
{
m_header.clear();
m_key_values.clear();
m_image_data.clear();
m_block_dim = 0;
m_bytes_per_block = 0;
return *this;
}
m_opposite_endianness = false;
}
void clear() {
m_header.clear();
m_key_values.clear();
m_image_data.clear();
// High level methods
bool read_from_stream(data_stream_serializer& serializer);
bool write_to_stream(data_stream_serializer& serializer, bool no_keyvalue_data = false);
bool init_2D(uint width, uint height, uint num_mips, uint32 ogl_internal_fmt, uint32 ogl_fmt, uint32 ogl_type);
bool init_2D_array(uint width, uint height, uint num_mips, uint array_size, uint32 ogl_internal_fmt, uint32 ogl_fmt, uint32 ogl_type);
bool init_3D(uint width, uint height, uint depth, uint num_mips, uint32 ogl_internal_fmt, uint32 ogl_fmt, uint32 ogl_type);
bool init_cubemap(uint dim, uint num_mips, uint32 ogl_internal_fmt, uint32 ogl_fmt, uint32 ogl_type);
m_block_dim = 0;
m_bytes_per_block = 0;
bool check_header() const;
bool consistency_check() const;
m_opposite_endianness = false;
}
// General info
// High level methods
bool read_from_stream(data_stream_serializer& serializer);
bool write_to_stream(data_stream_serializer& serializer, bool no_keyvalue_data = false);
bool is_valid() const { return (m_header.m_pixelWidth > 0) && (m_image_data.size() > 0); }
bool init_2D(uint width, uint height, uint num_mips, uint32 ogl_internal_fmt, uint32 ogl_fmt, uint32 ogl_type);
bool init_2D_array(uint width, uint height, uint num_mips, uint array_size, uint32 ogl_internal_fmt, uint32 ogl_fmt, uint32 ogl_type);
bool init_3D(uint width, uint height, uint depth, uint num_mips, uint32 ogl_internal_fmt, uint32 ogl_fmt, uint32 ogl_type);
bool init_cubemap(uint dim, uint num_mips, uint32 ogl_internal_fmt, uint32 ogl_fmt, uint32 ogl_type);
uint get_width() const { return m_header.m_pixelWidth; }
uint get_height() const { return CRNLIB_MAX(m_header.m_pixelHeight, 1); }
uint get_depth() const { return CRNLIB_MAX(m_header.m_pixelDepth, 1); }
uint get_num_mips() const { return CRNLIB_MAX(m_header.m_numberOfMipmapLevels, 1); }
uint get_array_size() const { return CRNLIB_MAX(m_header.m_numberOfArrayElements, 1); }
uint get_num_faces() const { return m_header.m_numberOfFaces; }
bool check_header() const;
bool consistency_check() const;
uint32 get_ogl_type() const { return m_header.m_glType; }
uint32 get_ogl_fmt() const { return m_header.m_glFormat; }
uint32 get_ogl_base_fmt() const { return m_header.m_glBaseInternalFormat; }
uint32 get_ogl_internal_fmt() const { return m_header.m_glInternalFormat; }
uint get_total_images() const { return get_num_mips() * (get_depth() * get_num_faces() * get_array_size()); }
// General info
bool is_compressed() const { return m_block_dim > 1; }
bool is_uncompressed() const { return !is_compressed(); }
bool get_opposite_endianness() const { return m_opposite_endianness; }
void set_opposite_endianness(bool flag) { m_opposite_endianness = flag; }
bool is_valid() const { return (m_header.m_pixelWidth > 0) && (m_image_data.size() > 0); }
uint32 get_block_dim() const { return m_block_dim; }
uint32 get_bytes_per_block() const { return m_bytes_per_block; }
uint get_width() const { return m_header.m_pixelWidth; }
uint get_height() const { return CRNLIB_MAX(m_header.m_pixelHeight, 1); }
uint get_depth() const { return CRNLIB_MAX(m_header.m_pixelDepth, 1); }
uint get_num_mips() const { return CRNLIB_MAX(m_header.m_numberOfMipmapLevels, 1); }
uint get_array_size() const { return CRNLIB_MAX(m_header.m_numberOfArrayElements, 1); }
uint get_num_faces() const { return m_header.m_numberOfFaces; }
const ktx_header& get_header() const { return m_header; }
uint32 get_ogl_type() const { return m_header.m_glType; }
uint32 get_ogl_fmt() const { return m_header.m_glFormat; }
uint32 get_ogl_base_fmt() const { return m_header.m_glBaseInternalFormat; }
uint32 get_ogl_internal_fmt() const { return m_header.m_glInternalFormat; }
// Key values
const ktx_key_value_vec& get_key_value_vec() const { return m_key_values; }
ktx_key_value_vec& get_key_value_vec() { return m_key_values; }
uint get_total_images() const { return get_num_mips() * (get_depth() * get_num_faces() * get_array_size()); }
const uint8_vec* find_key(const char* pKey) const;
bool get_key_value_as_string(const char* pKey, dynamic_string& str) const;
bool is_compressed() const { return m_block_dim > 1; }
bool is_uncompressed() const { return !is_compressed(); }
uint add_key_value(const char* pKey, const void* pVal, uint val_size);
uint add_key_value(const char* pKey, const char* pVal) { return add_key_value(pKey, pVal, static_cast<uint>(strlen(pVal)) + 1); }
bool get_opposite_endianness() const { return m_opposite_endianness; }
void set_opposite_endianness(bool flag) { m_opposite_endianness = flag; }
// Image data
uint get_num_images() const { return m_image_data.size(); }
uint32 get_block_dim() const { return m_block_dim; }
uint32 get_bytes_per_block() const { return m_bytes_per_block; }
const uint8_vec& get_image_data(uint image_index) const { return m_image_data[image_index]; }
uint8_vec& get_image_data(uint image_index) { return m_image_data[image_index]; }
const ktx_header& get_header() const { return m_header; }
const uint8_vec& get_image_data(uint mip_index, uint array_index, uint face_index, uint zslice_index) const { return get_image_data(get_image_index(mip_index, array_index, face_index, zslice_index)); }
uint8_vec& get_image_data(uint mip_index, uint array_index, uint face_index, uint zslice_index) { return get_image_data(get_image_index(mip_index, array_index, face_index, zslice_index)); }
const ktx_image_data_vec& get_image_data_vec() const { return m_image_data; }
ktx_image_data_vec& get_image_data_vec() { return m_image_data; }
// Key values
const ktx_key_value_vec& get_key_value_vec() const { return m_key_values; }
ktx_key_value_vec& get_key_value_vec() { return m_key_values; }
void add_image(uint face_index, uint mip_index, const void* pImage, uint image_size)
{
const uint image_index = get_image_index(mip_index, 0, face_index, 0);
if (image_index >= m_image_data.size())
m_image_data.resize(image_index + 1);
if (image_size)
{
uint8_vec& v = m_image_data[image_index];
v.resize(image_size);
memcpy(&v[0], pImage, image_size);
}
}
const uint8_vec* find_key(const char* pKey) const;
bool get_key_value_as_string(const char* pKey, dynamic_string& str) const;
uint get_image_index(uint mip_index, uint array_index, uint face_index, uint zslice_index) const
{
CRNLIB_ASSERT((mip_index < get_num_mips()) && (array_index < get_array_size()) && (face_index < get_num_faces()) && (zslice_index < get_depth()));
return zslice_index + (face_index * get_depth()) + (array_index * (get_depth() * get_num_faces())) + (mip_index * (get_depth() * get_num_faces() * get_array_size()));
}
void get_mip_dim(uint mip_index, uint& mip_width, uint& mip_height) const
{
CRNLIB_ASSERT(mip_index < get_num_mips());
mip_width = CRNLIB_MAX(get_width() >> mip_index, 1);
mip_height = CRNLIB_MAX(get_height() >> mip_index, 1);
}
uint add_key_value(const char* pKey, const void* pVal, uint val_size);
uint add_key_value(const char* pKey, const char* pVal) { return add_key_value(pKey, pVal, static_cast<uint>(strlen(pVal)) + 1); }
void get_mip_dim(uint mip_index, uint& mip_width, uint& mip_height, uint& mip_depth) const
{
CRNLIB_ASSERT(mip_index < get_num_mips());
mip_width = CRNLIB_MAX(get_width() >> mip_index, 1);
mip_height = CRNLIB_MAX(get_height() >> mip_index, 1);
mip_depth = CRNLIB_MAX(get_depth() >> mip_index, 1);
}
private:
ktx_header m_header;
ktx_key_value_vec m_key_values;
ktx_image_data_vec m_image_data;
// Image data
uint get_num_images() const { return m_image_data.size(); }
uint32 m_block_dim;
uint32 m_bytes_per_block;
bool m_opposite_endianness;
bool compute_pixel_info();
};
} // namespace crnlib
const uint8_vec& get_image_data(uint image_index) const { return m_image_data[image_index]; }
uint8_vec& get_image_data(uint image_index) { return m_image_data[image_index]; }
#endif // #ifndef _KTX_TEXTURE_H_
const uint8_vec& get_image_data(uint mip_index, uint array_index, uint face_index, uint zslice_index) const { return get_image_data(get_image_index(mip_index, array_index, face_index, zslice_index)); }
uint8_vec& get_image_data(uint mip_index, uint array_index, uint face_index, uint zslice_index) { return get_image_data(get_image_index(mip_index, array_index, face_index, zslice_index)); }
const ktx_image_data_vec& get_image_data_vec() const { return m_image_data; }
ktx_image_data_vec& get_image_data_vec() { return m_image_data; }
void add_image(uint face_index, uint mip_index, const void* pImage, uint image_size) {
const uint image_index = get_image_index(mip_index, 0, face_index, 0);
if (image_index >= m_image_data.size())
m_image_data.resize(image_index + 1);
if (image_size) {
uint8_vec& v = m_image_data[image_index];
v.resize(image_size);
memcpy(&v[0], pImage, image_size);
}
}
uint get_image_index(uint mip_index, uint array_index, uint face_index, uint zslice_index) const {
CRNLIB_ASSERT((mip_index < get_num_mips()) && (array_index < get_array_size()) && (face_index < get_num_faces()) && (zslice_index < get_depth()));
return zslice_index + (face_index * get_depth()) + (array_index * (get_depth() * get_num_faces())) + (mip_index * (get_depth() * get_num_faces() * get_array_size()));
}
void get_mip_dim(uint mip_index, uint& mip_width, uint& mip_height) const {
CRNLIB_ASSERT(mip_index < get_num_mips());
mip_width = CRNLIB_MAX(get_width() >> mip_index, 1);
mip_height = CRNLIB_MAX(get_height() >> mip_index, 1);
}
void get_mip_dim(uint mip_index, uint& mip_width, uint& mip_height, uint& mip_depth) const {
CRNLIB_ASSERT(mip_index < get_num_mips());
mip_width = CRNLIB_MAX(get_width() >> mip_index, 1);
mip_height = CRNLIB_MAX(get_height() >> mip_index, 1);
mip_depth = CRNLIB_MAX(get_depth() >> mip_index, 1);
}
private:
ktx_header m_header;
ktx_key_value_vec m_key_values;
ktx_image_data_vec m_image_data;
uint32 m_block_dim;
uint32 m_bytes_per_block;
bool m_opposite_endianness;
bool compute_pixel_info();
};
} // namespace crnlib
#endif // #ifndef _KTX_TEXTURE_H_
+89 -99
View File
@@ -7,136 +7,126 @@
#include "lzma_LzmaLib.h"
#include "crn_threading.h"
namespace crnlib
{
lzma_codec::lzma_codec() :
m_pCompress(LzmaCompress),
m_pUncompress(LzmaUncompress)
{
CRNLIB_ASSUME(cLZMAPropsSize == LZMA_PROPS_SIZE);
}
namespace crnlib {
lzma_codec::lzma_codec()
: m_pCompress(LzmaCompress),
m_pUncompress(LzmaUncompress) {
CRNLIB_ASSUME(cLZMAPropsSize == LZMA_PROPS_SIZE);
}
lzma_codec::~lzma_codec()
{
}
lzma_codec::~lzma_codec() {
}
bool lzma_codec::pack(const void* p, uint n, crnlib::vector<uint8>& buf)
{
if (n > 1024U*1024U*1024U)
return false;
bool lzma_codec::pack(const void* p, uint n, crnlib::vector<uint8>& buf) {
if (n > 1024U * 1024U * 1024U)
return false;
uint max_comp_size = n + math::maximum<uint>(128, n >> 8);
buf.resize(sizeof(header) + max_comp_size);
uint max_comp_size = n + math::maximum<uint>(128, n >> 8);
buf.resize(sizeof(header) + max_comp_size);
header* pHDR = reinterpret_cast<header*>(&buf[0]);
uint8* pComp_data = &buf[sizeof(header)];
header* pHDR = reinterpret_cast<header*>(&buf[0]);
uint8* pComp_data = &buf[sizeof(header)];
utils::zero_object(*pHDR);
utils::zero_object(*pHDR);
pHDR->m_uncomp_size = n;
pHDR->m_adler32 = adler32(p, n);
pHDR->m_uncomp_size = n;
pHDR->m_adler32 = adler32(p, n);
if (n)
{
size_t destLen = 0;
size_t outPropsSize = 0;
int status = SZ_ERROR_INPUT_EOF;
if (n) {
size_t destLen = 0;
size_t outPropsSize = 0;
int status = SZ_ERROR_INPUT_EOF;
for (uint trial = 0; trial < 3; trial++)
{
destLen = max_comp_size;
outPropsSize = cLZMAPropsSize;
for (uint trial = 0; trial < 3; trial++) {
destLen = max_comp_size;
outPropsSize = cLZMAPropsSize;
status = (*m_pCompress)(pComp_data, &destLen, reinterpret_cast<const unsigned char*>(p), n,
pHDR->m_lzma_props, &outPropsSize,
-1, /* 0 <= level <= 9, default = 5 */
0, /* default = (1 << 24) */
-1, /* 0 <= lc <= 8, default = 3 */
-1, /* 0 <= lp <= 4, default = 0 */
-1, /* 0 <= pb <= 4, default = 2 */
-1, /* 5 <= fb <= 273, default = 32 */
status = (*m_pCompress)(pComp_data, &destLen, reinterpret_cast<const unsigned char*>(p), n,
pHDR->m_lzma_props, &outPropsSize,
-1, /* 0 <= level <= 9, default = 5 */
0, /* default = (1 << 24) */
-1, /* 0 <= lc <= 8, default = 3 */
-1, /* 0 <= lp <= 4, default = 0 */
-1, /* 0 <= pb <= 4, default = 2 */
-1, /* 5 <= fb <= 273, default = 32 */
#ifdef WIN32
(g_number_of_processors > 1) ? 2 : 1
(g_number_of_processors > 1) ? 2 : 1
#else
1
1
#endif
);
);
if (status != SZ_ERROR_OUTPUT_EOF)
break;
if (status != SZ_ERROR_OUTPUT_EOF)
break;
max_comp_size += ((n+1)/2);
buf.resize(sizeof(header) + max_comp_size);
pHDR = reinterpret_cast<header*>(&buf[0]);
pComp_data = &buf[sizeof(header)];
}
max_comp_size += ((n + 1) / 2);
buf.resize(sizeof(header) + max_comp_size);
pHDR = reinterpret_cast<header*>(&buf[0]);
pComp_data = &buf[sizeof(header)];
}
if (status != SZ_OK)
{
buf.clear();
return false;
}
if (status != SZ_OK) {
buf.clear();
return false;
}
pHDR->m_comp_size = static_cast<uint>(destLen);
pHDR->m_comp_size = static_cast<uint>(destLen);
buf.resize(CRNLIB_SIZEOF_U32(header) + static_cast<uint32>(destLen));
}
buf.resize(CRNLIB_SIZEOF_U32(header) + static_cast<uint32>(destLen));
}
pHDR->m_sig = header::cSig;
pHDR->m_checksum = static_cast<uint8>(adler32((uint8*)pHDR + header::cChecksumSkipBytes, sizeof(header) - header::cChecksumSkipBytes));
pHDR->m_sig = header::cSig;
pHDR->m_checksum = static_cast<uint8>(adler32((uint8*)pHDR + header::cChecksumSkipBytes, sizeof(header) - header::cChecksumSkipBytes));
return true;
}
return true;
}
bool lzma_codec::unpack(const void* p, uint n, crnlib::vector<uint8>& buf)
{
buf.resize(0);
bool lzma_codec::unpack(const void* p, uint n, crnlib::vector<uint8>& buf) {
buf.resize(0);
if (n < sizeof(header))
return false;
if (n < sizeof(header))
return false;
const header& hdr = *static_cast<const header*>(p);
if (hdr.m_sig != header::cSig)
return false;
const header& hdr = *static_cast<const header*>(p);
if (hdr.m_sig != header::cSig)
return false;
if (static_cast<uint8>(adler32((const uint8*)&hdr + header::cChecksumSkipBytes, sizeof(hdr) - header::cChecksumSkipBytes)) != hdr.m_checksum)
return false;
if (static_cast<uint8>(adler32((const uint8*)&hdr + header::cChecksumSkipBytes, sizeof(hdr) - header::cChecksumSkipBytes)) != hdr.m_checksum)
return false;
if (!hdr.m_uncomp_size)
return true;
if (!hdr.m_uncomp_size)
return true;
if (!hdr.m_comp_size)
return false;
if (!hdr.m_comp_size)
return false;
if (hdr.m_uncomp_size > 1024U*1024U*1024U)
return false;
if (hdr.m_uncomp_size > 1024U * 1024U * 1024U)
return false;
if (!buf.try_resize(hdr.m_uncomp_size))
return false;
if (!buf.try_resize(hdr.m_uncomp_size))
return false;
const uint8* pComp_data = static_cast<const uint8*>(p) + sizeof(header);
size_t srcLen = n - sizeof(header);
if (srcLen < hdr.m_comp_size)
return false;
const uint8* pComp_data = static_cast<const uint8*>(p) + sizeof(header);
size_t srcLen = n - sizeof(header);
if (srcLen < hdr.m_comp_size)
return false;
size_t destLen = hdr.m_uncomp_size;
size_t destLen = hdr.m_uncomp_size;
int status = (*m_pUncompress)(&buf[0], &destLen, pComp_data, &srcLen,
hdr.m_lzma_props, cLZMAPropsSize);
int status = (*m_pUncompress)(&buf[0], &destLen, pComp_data, &srcLen,
hdr.m_lzma_props, cLZMAPropsSize);
if ((status != SZ_OK) || (destLen != hdr.m_uncomp_size))
{
buf.clear();
return false;
}
if ((status != SZ_OK) || (destLen != hdr.m_uncomp_size)) {
buf.clear();
return false;
}
if (adler32(&buf[0], buf.size()) != hdr.m_adler32)
{
buf.clear();
return false;
}
if (adler32(&buf[0], buf.size()) != hdr.m_adler32) {
buf.clear();
return false;
}
return true;
}
return true;
}
} // namespace crnlib
} // namespace crnlib
+37 -40
View File
@@ -3,58 +3,55 @@
#pragma once
#include "crn_packed_uint.h"
namespace crnlib
{
class lzma_codec
{
public:
lzma_codec();
~lzma_codec();
namespace crnlib {
class lzma_codec {
public:
lzma_codec();
~lzma_codec();
// Always available, because we're statically linking in lzmalib now vs. dynamically loading the DLL.
bool is_initialized() const { return true; }
// Always available, because we're statically linking in lzmalib now vs. dynamically loading the DLL.
bool is_initialized() const { return true; }
bool pack(const void* p, uint n, crnlib::vector<uint8>& buf);
bool pack(const void* p, uint n, crnlib::vector<uint8>& buf);
bool unpack(const void* p, uint n, crnlib::vector<uint8>& buf);
bool unpack(const void* p, uint n, crnlib::vector<uint8>& buf);
private:
typedef int (CRNLIB_STDCALL *LzmaCompressFuncPtr)(unsigned char *dest, size_t *destLen, const unsigned char *src, size_t srcLen,
unsigned char *outProps, size_t *outPropsSize, /* *outPropsSize must be = 5 */
int level, /* 0 <= level <= 9, default = 5 */
unsigned dictSize, /* default = (1 << 24) */
int lc, /* 0 <= lc <= 8, default = 3 */
int lp, /* 0 <= lp <= 4, default = 0 */
int pb, /* 0 <= pb <= 4, default = 2 */
int fb, /* 5 <= fb <= 273, default = 32 */
int numThreads /* 1 or 2, default = 2 */
);
private:
typedef int(CRNLIB_STDCALL* LzmaCompressFuncPtr)(unsigned char* dest, size_t* destLen, const unsigned char* src, size_t srcLen,
unsigned char* outProps, size_t* outPropsSize, /* *outPropsSize must be = 5 */
int level, /* 0 <= level <= 9, default = 5 */
unsigned dictSize, /* default = (1 << 24) */
int lc, /* 0 <= lc <= 8, default = 3 */
int lp, /* 0 <= lp <= 4, default = 0 */
int pb, /* 0 <= pb <= 4, default = 2 */
int fb, /* 5 <= fb <= 273, default = 32 */
int numThreads /* 1 or 2, default = 2 */
);
typedef int (CRNLIB_STDCALL *LzmaUncompressFuncPtr)(unsigned char *dest, size_t *destLen, const unsigned char *src, size_t *srcLen,
const unsigned char *props, size_t propsSize);
typedef int(CRNLIB_STDCALL* LzmaUncompressFuncPtr)(unsigned char* dest, size_t* destLen, const unsigned char* src, size_t* srcLen,
const unsigned char* props, size_t propsSize);
LzmaCompressFuncPtr m_pCompress;
LzmaUncompressFuncPtr m_pUncompress;
LzmaCompressFuncPtr m_pCompress;
LzmaUncompressFuncPtr m_pUncompress;
enum { cLZMAPropsSize = 5 };
enum { cLZMAPropsSize = 5 };
#pragma pack(push)
#pragma pack(1)
struct header
{
enum { cSig = 'L' | ('0' << 8), cChecksumSkipBytes = 3 };
packed_uint<2> m_sig;
uint8 m_checksum;
struct header {
enum { cSig = 'L' | ('0' << 8),
cChecksumSkipBytes = 3 };
packed_uint<2> m_sig;
uint8 m_checksum;
uint8 m_lzma_props[cLZMAPropsSize];
uint8 m_lzma_props[cLZMAPropsSize];
packed_uint<4> m_comp_size;
packed_uint<4> m_uncomp_size;
packed_uint<4> m_comp_size;
packed_uint<4> m_uncomp_size;
packed_uint<4> m_adler32;
};
packed_uint<4> m_adler32;
};
#pragma pack(pop)
};
};
} // namespace crnlib
} // namespace crnlib
+58 -67
View File
@@ -2,75 +2,66 @@
// See Copyright Notice and license at the end of inc/crnlib.h
#include "crn_core.h"
namespace crnlib
{
namespace math
{
uint g_bitmasks[32] =
{
1U << 0U, 1U << 1U, 1U << 2U, 1U << 3U,
1U << 4U, 1U << 5U, 1U << 6U, 1U << 7U,
1U << 8U, 1U << 9U, 1U << 10U, 1U << 11U,
1U << 12U, 1U << 13U, 1U << 14U, 1U << 15U,
1U << 16U, 1U << 17U, 1U << 18U, 1U << 19U,
1U << 20U, 1U << 21U, 1U << 22U, 1U << 23U,
1U << 24U, 1U << 25U, 1U << 26U, 1U << 27U,
1U << 28U, 1U << 29U, 1U << 30U, 1U << 31U
};
double compute_entropy(const uint8* p, uint n)
{
uint hist[256];
utils::zero_object(hist);
for (uint i = 0; i < n; i++)
hist[*p++]++;
double entropy = 0.0f;
const double invln2 = 1.0f/log(2.0f);
for (uint i = 0; i < 256; i++)
{
if (!hist[i])
continue;
double prob = static_cast<double>(hist[i]) / n;
entropy += (-log(prob) * invln2) * hist[i];
}
return entropy;
}
namespace crnlib {
namespace math {
uint g_bitmasks[32] =
{
1U << 0U, 1U << 1U, 1U << 2U, 1U << 3U,
1U << 4U, 1U << 5U, 1U << 6U, 1U << 7U,
1U << 8U, 1U << 9U, 1U << 10U, 1U << 11U,
1U << 12U, 1U << 13U, 1U << 14U, 1U << 15U,
1U << 16U, 1U << 17U, 1U << 18U, 1U << 19U,
1U << 20U, 1U << 21U, 1U << 22U, 1U << 23U,
1U << 24U, 1U << 25U, 1U << 26U, 1U << 27U,
1U << 28U, 1U << 29U, 1U << 30U, 1U << 31U};
void compute_lower_pow2_dim(int& width, int& height)
{
const int tex_width = width;
const int tex_height = height;
double compute_entropy(const uint8* p, uint n) {
uint hist[256];
utils::zero_object(hist);
width = 1;
for ( ; ; )
{
if ((width * 2) > tex_width)
break;
width *= 2;
}
for (uint i = 0; i < n; i++)
hist[*p++]++;
height = 1;
for ( ; ; )
{
if ((height * 2) > tex_height)
break;
height *= 2;
}
}
double entropy = 0.0f;
void compute_upper_pow2_dim(int& width, int& height)
{
if (!math::is_power_of_2((uint32)width))
width = math::next_pow2((uint32)width);
const double invln2 = 1.0f / log(2.0f);
for (uint i = 0; i < 256; i++) {
if (!hist[i])
continue;
if (!math::is_power_of_2((uint32)height))
height = math::next_pow2((uint32)height);
}
} // namespace math
} // namespace crnlib
double prob = static_cast<double>(hist[i]) / n;
entropy += (-log(prob) * invln2) * hist[i];
}
return entropy;
}
void compute_lower_pow2_dim(int& width, int& height) {
const int tex_width = width;
const int tex_height = height;
width = 1;
for (;;) {
if ((width * 2) > tex_width)
break;
width *= 2;
}
height = 1;
for (;;) {
if ((height * 2) > tex_height)
break;
height *= 2;
}
}
void compute_upper_pow2_dim(int& width, int& height) {
if (!math::is_power_of_2((uint32)width))
width = math::next_pow2((uint32)width);
if (!math::is_power_of_2((uint32)height))
height = math::next_pow2((uint32)height);
}
} // namespace math
} // namespace crnlib
+228 -185
View File
@@ -3,235 +3,278 @@
#pragma once
#if defined(_M_IX86) && defined(_MSC_VER)
#include <intrin.h>
#pragma intrinsic(__emulu)
unsigned __int64 __emulu(unsigned int a,unsigned int b );
#include <intrin.h>
#pragma intrinsic(__emulu)
unsigned __int64 __emulu(unsigned int a, unsigned int b);
#endif
namespace crnlib
{
namespace math
{
const float cNearlyInfinite = 1.0e+37f;
const float cDegToRad = 0.01745329252f;
const float cRadToDeg = 57.29577951f;
namespace crnlib {
namespace math {
const float cNearlyInfinite = 1.0e+37f;
extern uint g_bitmasks[32];
const float cDegToRad = 0.01745329252f;
const float cRadToDeg = 57.29577951f;
template<typename T> inline bool within_closed_range(T a, T b, T c) { return (a >= b) && (a <= c); }
extern uint g_bitmasks[32];
template<typename T> inline bool within_open_range(T a, T b, T c) { return (a >= b) && (a < c); }
template <typename T>
inline bool within_closed_range(T a, T b, T c) {
return (a >= b) && (a <= c);
}
// Yes I know these should probably be pass by ref, not val:
// http://www.stepanovpapers.com/notes.pdf
// Just don't use them on non-simple (non built-in) types!
template<typename T> inline T minimum(T a, T b) { return (a < b) ? a : b; }
template <typename T>
inline bool within_open_range(T a, T b, T c) {
return (a >= b) && (a < c);
}
template<typename T> inline T minimum(T a, T b, T c) { return minimum(minimum(a, b), c); }
// Yes I know these should probably be pass by ref, not val:
// http://www.stepanovpapers.com/notes.pdf
// Just don't use them on non-simple (non built-in) types!
template <typename T>
inline T minimum(T a, T b) {
return (a < b) ? a : b;
}
template<typename T> inline T maximum(T a, T b) { return (a > b) ? a : b; }
template <typename T>
inline T minimum(T a, T b, T c) {
return minimum(minimum(a, b), c);
}
template<typename T> inline T maximum(T a, T b, T c) { return maximum(maximum(a, b), c); }
template <typename T>
inline T maximum(T a, T b) {
return (a > b) ? a : b;
}
template<typename T, typename U> inline T lerp(T a, T b, U c) { return a + (b - a) * c; }
template <typename T>
inline T maximum(T a, T b, T c) {
return maximum(maximum(a, b), c);
}
template<typename T> inline T clamp(T value, T low, T high) { return (value < low) ? low : ((value > high) ? high : value); }
template <typename T, typename U>
inline T lerp(T a, T b, U c) {
return a + (b - a) * c;
}
template<typename T> inline T saturate(T value) { return (value < 0.0f) ? 0.0f : ((value > 1.0f) ? 1.0f : value); }
template <typename T>
inline T clamp(T value, T low, T high) {
return (value < low) ? low : ((value > high) ? high : value);
}
inline int float_to_int(float f) { return static_cast<int>(f); }
template <typename T>
inline T saturate(T value) {
return (value < 0.0f) ? 0.0f : ((value > 1.0f) ? 1.0f : value);
}
inline uint float_to_uint(float f) { return static_cast<uint>(f); }
inline int float_to_int(float f) {
return static_cast<int>(f);
}
inline int float_to_int(double f) { return static_cast<int>(f); }
inline uint float_to_uint(float f) {
return static_cast<uint>(f);
}
inline uint float_to_uint(double f) { return static_cast<uint>(f); }
inline int float_to_int(double f) {
return static_cast<int>(f);
}
inline int float_to_int_round(float f) { return static_cast<int>((f < 0.0f) ? -floor(-f + .5f) : floor(f + .5f)); }
inline uint float_to_uint(double f) {
return static_cast<uint>(f);
}
inline uint float_to_uint_round(float f) { return static_cast<uint>((f < 0.0f) ? 0.0f : floor(f + .5f)); }
inline int float_to_int_round(float f) {
return static_cast<int>((f < 0.0f) ? -floor(-f + .5f) : floor(f + .5f));
}
template<typename T> inline int sign(T value) { return (value < 0) ? -1 : ((value > 0) ? 1 : 0); }
inline uint float_to_uint_round(float f) {
return static_cast<uint>((f < 0.0f) ? 0.0f : floor(f + .5f));
}
template<typename T> inline T square(T value) { return value * value; }
template <typename T>
inline int sign(T value) {
return (value < 0) ? -1 : ((value > 0) ? 1 : 0);
}
inline bool is_power_of_2(uint32 x) { return x && ((x & (x - 1U)) == 0U); }
inline bool is_power_of_2(uint64 x) { return x && ((x & (x - 1U)) == 0U); }
template <typename T>
inline T square(T value) {
return value * value;
}
template<typename T> inline T align_up_value(T x, uint alignment)
{
CRNLIB_ASSERT(is_power_of_2(alignment));
uint q = static_cast<uint>(x);
q = (q + alignment - 1) & (~(alignment - 1));
return static_cast<T>(q);
}
inline bool is_power_of_2(uint32 x) {
return x && ((x & (x - 1U)) == 0U);
}
inline bool is_power_of_2(uint64 x) {
return x && ((x & (x - 1U)) == 0U);
}
template<typename T> inline T align_down_value(T x, uint alignment)
{
CRNLIB_ASSERT(is_power_of_2(alignment));
uint q = static_cast<uint>(x);
q = q & (~(alignment - 1));
return static_cast<T>(q);
}
template <typename T>
inline T align_up_value(T x, uint alignment) {
CRNLIB_ASSERT(is_power_of_2(alignment));
uint q = static_cast<uint>(x);
q = (q + alignment - 1) & (~(alignment - 1));
return static_cast<T>(q);
}
template<typename T> inline T get_align_up_value_delta(T x, uint alignment)
{
return align_up_value(x, alignment) - x;
}
// From "Hackers Delight"
inline uint32 next_pow2(uint32 val)
{
val--;
val |= val >> 16;
val |= val >> 8;
val |= val >> 4;
val |= val >> 2;
val |= val >> 1;
return val + 1;
}
template <typename T>
inline T align_down_value(T x, uint alignment) {
CRNLIB_ASSERT(is_power_of_2(alignment));
uint q = static_cast<uint>(x);
q = q & (~(alignment - 1));
return static_cast<T>(q);
}
inline uint64 next_pow2(uint64 val)
{
val--;
val |= val >> 32;
val |= val >> 16;
val |= val >> 8;
val |= val >> 4;
val |= val >> 2;
val |= val >> 1;
return val + 1;
}
inline uint floor_log2i(uint v)
{
uint l = 0;
while (v > 1U)
{
v >>= 1;
l++;
}
return l;
}
template <typename T>
inline T get_align_up_value_delta(T x, uint alignment) {
return align_up_value(x, alignment) - x;
}
inline uint ceil_log2i(uint v)
{
uint l = floor_log2i(v);
if ((l != cIntBits) && (v > (1U << l)))
l++;
return l;
}
// From "Hackers Delight"
inline uint32 next_pow2(uint32 val) {
val--;
val |= val >> 16;
val |= val >> 8;
val |= val >> 4;
val |= val >> 2;
val |= val >> 1;
return val + 1;
}
// Returns the total number of bits needed to encode v.
inline uint total_bits(uint v)
{
uint l = 0;
while (v > 0U)
{
v >>= 1;
l++;
}
return l;
}
inline uint64 next_pow2(uint64 val) {
val--;
val |= val >> 32;
val |= val >> 16;
val |= val >> 8;
val |= val >> 4;
val |= val >> 2;
val |= val >> 1;
return val + 1;
}
// Actually counts the number of set bits, but hey
inline uint bitmask_size(uint mask)
{
uint size = 0;
while (mask)
{
mask &= (mask - 1U);
size++;
}
return size;
}
inline uint floor_log2i(uint v) {
uint l = 0;
while (v > 1U) {
v >>= 1;
l++;
}
return l;
}
inline uint bitmask_ofs(uint mask)
{
if (!mask)
return 0;
uint ofs = 0;
while ((mask & 1U) == 0)
{
mask >>= 1U;
ofs++;
}
return ofs;
}
inline uint ceil_log2i(uint v) {
uint l = floor_log2i(v);
if ((l != cIntBits) && (v > (1U << l)))
l++;
return l;
}
// See Bit Twiddling Hacks (public domain)
// http://www-graphics.stanford.edu/~seander/bithacks.html
inline uint count_trailing_zero_bits(uint v)
{
uint c = 32; // c will be the number of zero bits on the right
// Returns the total number of bits needed to encode v.
inline uint total_bits(uint v) {
uint l = 0;
while (v > 0U) {
v >>= 1;
l++;
}
return l;
}
static const unsigned int B[] = { 0x55555555, 0x33333333, 0x0F0F0F0F, 0x00FF00FF, 0x0000FFFF };
static const unsigned int S[] = { 1, 2, 4, 8, 16 }; // Our Magic Binary Numbers
// Actually counts the number of set bits, but hey
inline uint bitmask_size(uint mask) {
uint size = 0;
while (mask) {
mask &= (mask - 1U);
size++;
}
return size;
}
for (int i = 4; i >= 0; --i) // unroll for more speed
{
if (v & B[i])
{
v <<= S[i];
c -= S[i];
}
}
inline uint bitmask_ofs(uint mask) {
if (!mask)
return 0;
uint ofs = 0;
while ((mask & 1U) == 0) {
mask >>= 1U;
ofs++;
}
return ofs;
}
if (v)
{
c--;
}
// See Bit Twiddling Hacks (public domain)
// http://www-graphics.stanford.edu/~seander/bithacks.html
inline uint count_trailing_zero_bits(uint v) {
uint c = 32; // c will be the number of zero bits on the right
return c;
}
static const unsigned int B[] = {0x55555555, 0x33333333, 0x0F0F0F0F, 0x00FF00FF, 0x0000FFFF};
static const unsigned int S[] = {1, 2, 4, 8, 16}; // Our Magic Binary Numbers
inline uint count_leading_zero_bits(uint v)
{
uint temp;
uint result = 32U;
for (int i = 4; i >= 0; --i) // unroll for more speed
{
if (v & B[i]) {
v <<= S[i];
c -= S[i];
}
}
temp = (v >> 16U); if (temp) { result -= 16U; v = temp; }
temp = (v >> 8U); if (temp) { result -= 8U; v = temp; }
temp = (v >> 4U); if (temp) { result -= 4U; v = temp; }
temp = (v >> 2U); if (temp) { result -= 2U; v = temp; }
temp = (v >> 1U); if (temp) { result -= 1U; v = temp; }
if (v) {
c--;
}
if (v & 1U)
result--;
return c;
}
return result;
}
inline uint count_leading_zero_bits(uint v) {
uint temp;
uint result = 32U;
inline uint64 emulu(uint32 a, uint32 b)
{
temp = (v >> 16U);
if (temp) {
result -= 16U;
v = temp;
}
temp = (v >> 8U);
if (temp) {
result -= 8U;
v = temp;
}
temp = (v >> 4U);
if (temp) {
result -= 4U;
v = temp;
}
temp = (v >> 2U);
if (temp) {
result -= 2U;
v = temp;
}
temp = (v >> 1U);
if (temp) {
result -= 1U;
v = temp;
}
if (v & 1U)
result--;
return result;
}
inline uint64 emulu(uint32 a, uint32 b) {
#if defined(_M_IX86) && defined(_MSC_VER)
return __emulu(a, b);
return __emulu(a, b);
#else
return static_cast<uint64>(a) * static_cast<uint64>(b);
return static_cast<uint64>(a) * static_cast<uint64>(b);
#endif
}
double compute_entropy(const uint8* p, uint n);
void compute_lower_pow2_dim(int& width, int& height);
void compute_upper_pow2_dim(int& width, int& height);
inline bool equal_tol(float a, float b, float t)
{
return fabs(a - b) < ((maximum(fabs(a), fabs(b)) + 1.0f) * t);
}
inline bool equal_tol(double a, double b, double t)
{
return fabs(a - b) < ((maximum(fabs(a), fabs(b)) + 1.0f) * t);
}
}
} // namespace crnlib
}
double compute_entropy(const uint8* p, uint n);
void compute_lower_pow2_dim(int& width, int& height);
void compute_upper_pow2_dim(int& width, int& height);
inline bool equal_tol(float a, float b, float t) {
return fabs(a - b) < ((maximum(fabs(a), fabs(b)) + 1.0f) * t);
}
inline bool equal_tol(double a, double b, double t) {
return fabs(a - b) < ((maximum(fabs(a), fabs(b)) + 1.0f) * t);
}
}
} // namespace crnlib
+446 -517
View File
File diff suppressed because it is too large Load Diff
+232 -274
View File
@@ -14,121 +14,102 @@
#define _msize malloc_usable_size
#endif
namespace crnlib
{
namespace crnlib {
#if CRNLIB_MEM_STATS
#if CRNLIB_64BIT_POINTERS
typedef LONGLONG mem_stat_t;
#define CRNLIB_MEM_COMPARE_EXCHANGE InterlockedCompareExchange64
#else
typedef LONG mem_stat_t;
#define CRNLIB_MEM_COMPARE_EXCHANGE InterlockedCompareExchange
#endif
static volatile mem_stat_t g_total_blocks;
static volatile mem_stat_t g_total_allocated;
static volatile mem_stat_t g_max_allocated;
static mem_stat_t update_total_allocated(int block_delta, mem_stat_t byte_delta)
{
mem_stat_t cur_total_blocks;
for ( ; ; )
{
cur_total_blocks = (mem_stat_t)g_total_blocks;
mem_stat_t new_total_blocks = static_cast<mem_stat_t>(cur_total_blocks + block_delta);
CRNLIB_ASSERT(new_total_blocks >= 0);
if (CRNLIB_MEM_COMPARE_EXCHANGE(&g_total_blocks, new_total_blocks, cur_total_blocks) == cur_total_blocks)
break;
}
mem_stat_t cur_total_allocated, new_total_allocated;
for ( ; ; )
{
cur_total_allocated = g_total_allocated;
new_total_allocated = static_cast<mem_stat_t>(cur_total_allocated + byte_delta);
CRNLIB_ASSERT(new_total_allocated >= 0);
if (CRNLIB_MEM_COMPARE_EXCHANGE(&g_total_allocated, new_total_allocated, cur_total_allocated) == cur_total_allocated)
break;
}
for ( ; ; )
{
mem_stat_t cur_max_allocated = g_max_allocated;
mem_stat_t new_max_allocated = CRNLIB_MAX(new_total_allocated, cur_max_allocated);
if (CRNLIB_MEM_COMPARE_EXCHANGE(&g_max_allocated, new_max_allocated, cur_max_allocated) == cur_max_allocated)
break;
}
return new_total_allocated;
}
#endif // CRNLIB_MEM_STATS
static void* crnlib_default_realloc(void* p, size_t size, size_t* pActual_size, bool movable, void* pUser_data)
{
pUser_data;
void* p_new;
if (!p)
{
p_new = ::malloc(size);
CRNLIB_ASSERT( (reinterpret_cast<ptr_bits_t>(p_new) & (CRNLIB_MIN_ALLOC_ALIGNMENT - 1)) == 0 );
if (!p_new)
{
printf("WARNING: ::malloc() of size %u failed!\n", (uint)size);
}
if (pActual_size)
*pActual_size = p_new ? ::_msize(p_new) : 0;
}
else if (!size)
{
::free(p);
p_new = NULL;
if (pActual_size)
*pActual_size = 0;
}
else
{
void* p_final_block = p;
#ifdef WIN32
p_new = ::_expand(p, size);
#if CRNLIB_64BIT_POINTERS
typedef LONGLONG mem_stat_t;
#define CRNLIB_MEM_COMPARE_EXCHANGE InterlockedCompareExchange64
#else
p_new = NULL;
typedef LONG mem_stat_t;
#define CRNLIB_MEM_COMPARE_EXCHANGE InterlockedCompareExchange
#endif
if (p_new)
{
CRNLIB_ASSERT( (reinterpret_cast<ptr_bits_t>(p_new) & (CRNLIB_MIN_ALLOC_ALIGNMENT - 1)) == 0 );
p_final_block = p_new;
}
else if (movable)
{
p_new = ::realloc(p, size);
static volatile mem_stat_t g_total_blocks;
static volatile mem_stat_t g_total_allocated;
static volatile mem_stat_t g_max_allocated;
if (p_new)
{
CRNLIB_ASSERT( (reinterpret_cast<ptr_bits_t>(p_new) & (CRNLIB_MIN_ALLOC_ALIGNMENT - 1)) == 0 );
p_final_block = p_new;
}
else
{
printf("WARNING: ::realloc() of size %u failed!\n", (uint)size);
}
}
static mem_stat_t update_total_allocated(int block_delta, mem_stat_t byte_delta) {
mem_stat_t cur_total_blocks;
for (;;) {
cur_total_blocks = (mem_stat_t)g_total_blocks;
mem_stat_t new_total_blocks = static_cast<mem_stat_t>(cur_total_blocks + block_delta);
CRNLIB_ASSERT(new_total_blocks >= 0);
if (CRNLIB_MEM_COMPARE_EXCHANGE(&g_total_blocks, new_total_blocks, cur_total_blocks) == cur_total_blocks)
break;
}
if (pActual_size)
*pActual_size = ::_msize(p_final_block);
mem_stat_t cur_total_allocated, new_total_allocated;
for (;;) {
cur_total_allocated = g_total_allocated;
new_total_allocated = static_cast<mem_stat_t>(cur_total_allocated + byte_delta);
CRNLIB_ASSERT(new_total_allocated >= 0);
if (CRNLIB_MEM_COMPARE_EXCHANGE(&g_total_allocated, new_total_allocated, cur_total_allocated) == cur_total_allocated)
break;
}
for (;;) {
mem_stat_t cur_max_allocated = g_max_allocated;
mem_stat_t new_max_allocated = CRNLIB_MAX(new_total_allocated, cur_max_allocated);
if (CRNLIB_MEM_COMPARE_EXCHANGE(&g_max_allocated, new_max_allocated, cur_max_allocated) == cur_max_allocated)
break;
}
return new_total_allocated;
}
#endif // CRNLIB_MEM_STATS
static void* crnlib_default_realloc(void* p, size_t size, size_t* pActual_size, bool movable, void* pUser_data) {
pUser_data;
void* p_new;
if (!p) {
p_new = ::malloc(size);
CRNLIB_ASSERT((reinterpret_cast<ptr_bits_t>(p_new) & (CRNLIB_MIN_ALLOC_ALIGNMENT - 1)) == 0);
if (!p_new) {
printf("WARNING: ::malloc() of size %u failed!\n", (uint)size);
}
if (pActual_size)
*pActual_size = p_new ? ::_msize(p_new) : 0;
} else if (!size) {
::free(p);
p_new = NULL;
if (pActual_size)
*pActual_size = 0;
} else {
void* p_final_block = p;
#ifdef WIN32
p_new = ::_expand(p, size);
#else
p_new = NULL;
#endif
if (p_new) {
CRNLIB_ASSERT((reinterpret_cast<ptr_bits_t>(p_new) & (CRNLIB_MIN_ALLOC_ALIGNMENT - 1)) == 0);
p_final_block = p_new;
} else if (movable) {
p_new = ::realloc(p, size);
if (p_new) {
CRNLIB_ASSERT((reinterpret_cast<ptr_bits_t>(p_new) & (CRNLIB_MIN_ALLOC_ALIGNMENT - 1)) == 0);
p_final_block = p_new;
} else {
printf("WARNING: ::realloc() of size %u failed!\n", (uint)size);
}
}
return p_new;
}
if (pActual_size)
*pActual_size = ::_msize(p_final_block);
}
static size_t crnlib_default_msize(void* p, void* pUser_data)
{
pUser_data;
return p ? _msize(p) : 0;
}
return p_new;
}
static size_t crnlib_default_msize(void* p, void* pUser_data) {
pUser_data;
return p ? _msize(p) : 0;
}
#if 0
static __declspec(thread) void *g_pBuf;
@@ -206,174 +187,151 @@ namespace crnlib
static crn_realloc_func g_pRealloc = crnlib_nofree_realloc;
static crn_msize_func g_pMSize = crnlib_nofree_msize;
#else
static crn_realloc_func g_pRealloc = crnlib_default_realloc;
static crn_msize_func g_pMSize = crnlib_default_msize;
static crn_realloc_func g_pRealloc = crnlib_default_realloc;
static crn_msize_func g_pMSize = crnlib_default_msize;
#endif
static void* g_pUser_data;
static void* g_pUser_data;
void crnlib_mem_error(const char* p_msg)
{
crnlib_assert(p_msg, __FILE__, __LINE__);
}
void* crnlib_malloc(size_t size)
{
return crnlib_malloc(size, NULL);
}
void* crnlib_malloc(size_t size, size_t* pActual_size)
{
size = (size + sizeof(uint32) - 1U) & ~(sizeof(uint32) - 1U);
if (!size)
size = sizeof(uint32);
if (size > CRNLIB_MAX_POSSIBLE_BLOCK_SIZE)
{
crnlib_mem_error("crnlib_malloc: size too big");
return NULL;
}
size_t actual_size = size;
uint8* p_new = static_cast<uint8*>((*g_pRealloc)(NULL, size, &actual_size, true, g_pUser_data));
if (pActual_size)
*pActual_size = actual_size;
if ((!p_new) || (actual_size < size))
{
crnlib_mem_error("crnlib_malloc: out of memory");
return NULL;
}
CRNLIB_ASSERT((reinterpret_cast<ptr_bits_t>(p_new) & (CRNLIB_MIN_ALLOC_ALIGNMENT - 1)) == 0);
#if CRNLIB_MEM_STATS
CRNLIB_ASSERT((*g_pMSize)(p_new, g_pUser_data) == actual_size);
update_total_allocated(1, static_cast<mem_stat_t>(actual_size));
#endif
return p_new;
}
void* crnlib_realloc(void* p, size_t size, size_t* pActual_size, bool movable)
{
if ((ptr_bits_t)p & (CRNLIB_MIN_ALLOC_ALIGNMENT - 1))
{
crnlib_mem_error("crnlib_realloc: bad ptr");
return NULL;
}
if (size > CRNLIB_MAX_POSSIBLE_BLOCK_SIZE)
{
crnlib_mem_error("crnlib_malloc: size too big");
return NULL;
}
#if CRNLIB_MEM_STATS
size_t cur_size = p ? (*g_pMSize)(p, g_pUser_data) : 0;
CRNLIB_ASSERT(!p || (cur_size >= sizeof(uint32)));
#endif
if ((size) && (size < sizeof(uint32)))
size = sizeof(uint32);
size_t actual_size = size;
void* p_new = (*g_pRealloc)(p, size, &actual_size, movable, g_pUser_data);
if (pActual_size)
*pActual_size = actual_size;
CRNLIB_ASSERT((reinterpret_cast<ptr_bits_t>(p_new) & (CRNLIB_MIN_ALLOC_ALIGNMENT - 1)) == 0);
#if CRNLIB_MEM_STATS
CRNLIB_ASSERT(!p_new || ((*g_pMSize)(p_new, g_pUser_data) == actual_size));
int num_new_blocks = 0;
if (p)
{
if (!p_new)
num_new_blocks = -1;
}
else if (p_new)
{
num_new_blocks = 1;
}
update_total_allocated(num_new_blocks, static_cast<mem_stat_t>(actual_size) - static_cast<mem_stat_t>(cur_size));
#endif
return p_new;
}
void* crnlib_calloc(size_t count, size_t size, size_t* pActual_size)
{
size_t total = count * size;
void *p = crnlib_malloc(total, pActual_size);
if (p) memset(p, 0, total);
return p;
}
void crnlib_free(void* p)
{
if (!p)
return;
if (reinterpret_cast<ptr_bits_t>(p) & (CRNLIB_MIN_ALLOC_ALIGNMENT - 1))
{
crnlib_mem_error("crnlib_free: bad ptr");
return;
}
#if CRNLIB_MEM_STATS
size_t cur_size = (*g_pMSize)(p, g_pUser_data);
CRNLIB_ASSERT(cur_size >= sizeof(uint32));
update_total_allocated(-1, -static_cast<mem_stat_t>(cur_size));
#endif
(*g_pRealloc)(p, 0, NULL, true, g_pUser_data);
}
size_t crnlib_msize(void* p)
{
if (!p)
return 0;
if (reinterpret_cast<ptr_bits_t>(p) & (CRNLIB_MIN_ALLOC_ALIGNMENT - 1))
{
crnlib_mem_error("crnlib_msize: bad ptr");
return 0;
}
return (*g_pMSize)(p, g_pUser_data);
}
void crnlib_print_mem_stats()
{
#if CRNLIB_MEM_STATS
if (console::is_initialized())
{
console::debug("crnlib_print_mem_stats:");
console::debug("Current blocks: %u, allocated: " CRNLIB_INT64_FORMAT_SPECIFIER ", max ever allocated: " CRNLIB_INT64_FORMAT_SPECIFIER, g_total_blocks, (int64)g_total_allocated, (int64)g_max_allocated);
}
else
{
printf("crnlib_print_mem_stats:\n");
printf("Current blocks: %u, allocated: " CRNLIB_INT64_FORMAT_SPECIFIER ", max ever allocated: " CRNLIB_INT64_FORMAT_SPECIFIER "\n", g_total_blocks, (int64)g_total_allocated, (int64)g_max_allocated);
}
#endif
}
} // namespace crnlib
void crn_set_memory_callbacks(crn_realloc_func pRealloc, crn_msize_func pMSize, void* pUser_data)
{
if ((!pRealloc) || (!pMSize))
{
crnlib::g_pRealloc = crnlib::crnlib_default_realloc;
crnlib::g_pMSize = crnlib::crnlib_default_msize;
crnlib::g_pUser_data = NULL;
}
else
{
crnlib::g_pRealloc = pRealloc;
crnlib::g_pMSize = pMSize;
crnlib::g_pUser_data = pUser_data;
}
void crnlib_mem_error(const char* p_msg) {
crnlib_assert(p_msg, __FILE__, __LINE__);
}
void* crnlib_malloc(size_t size) {
return crnlib_malloc(size, NULL);
}
void* crnlib_malloc(size_t size, size_t* pActual_size) {
size = (size + sizeof(uint32) - 1U) & ~(sizeof(uint32) - 1U);
if (!size)
size = sizeof(uint32);
if (size > CRNLIB_MAX_POSSIBLE_BLOCK_SIZE) {
crnlib_mem_error("crnlib_malloc: size too big");
return NULL;
}
size_t actual_size = size;
uint8* p_new = static_cast<uint8*>((*g_pRealloc)(NULL, size, &actual_size, true, g_pUser_data));
if (pActual_size)
*pActual_size = actual_size;
if ((!p_new) || (actual_size < size)) {
crnlib_mem_error("crnlib_malloc: out of memory");
return NULL;
}
CRNLIB_ASSERT((reinterpret_cast<ptr_bits_t>(p_new) & (CRNLIB_MIN_ALLOC_ALIGNMENT - 1)) == 0);
#if CRNLIB_MEM_STATS
CRNLIB_ASSERT((*g_pMSize)(p_new, g_pUser_data) == actual_size);
update_total_allocated(1, static_cast<mem_stat_t>(actual_size));
#endif
return p_new;
}
void* crnlib_realloc(void* p, size_t size, size_t* pActual_size, bool movable) {
if ((ptr_bits_t)p & (CRNLIB_MIN_ALLOC_ALIGNMENT - 1)) {
crnlib_mem_error("crnlib_realloc: bad ptr");
return NULL;
}
if (size > CRNLIB_MAX_POSSIBLE_BLOCK_SIZE) {
crnlib_mem_error("crnlib_malloc: size too big");
return NULL;
}
#if CRNLIB_MEM_STATS
size_t cur_size = p ? (*g_pMSize)(p, g_pUser_data) : 0;
CRNLIB_ASSERT(!p || (cur_size >= sizeof(uint32)));
#endif
if ((size) && (size < sizeof(uint32)))
size = sizeof(uint32);
size_t actual_size = size;
void* p_new = (*g_pRealloc)(p, size, &actual_size, movable, g_pUser_data);
if (pActual_size)
*pActual_size = actual_size;
CRNLIB_ASSERT((reinterpret_cast<ptr_bits_t>(p_new) & (CRNLIB_MIN_ALLOC_ALIGNMENT - 1)) == 0);
#if CRNLIB_MEM_STATS
CRNLIB_ASSERT(!p_new || ((*g_pMSize)(p_new, g_pUser_data) == actual_size));
int num_new_blocks = 0;
if (p) {
if (!p_new)
num_new_blocks = -1;
} else if (p_new) {
num_new_blocks = 1;
}
update_total_allocated(num_new_blocks, static_cast<mem_stat_t>(actual_size) - static_cast<mem_stat_t>(cur_size));
#endif
return p_new;
}
void* crnlib_calloc(size_t count, size_t size, size_t* pActual_size) {
size_t total = count * size;
void* p = crnlib_malloc(total, pActual_size);
if (p)
memset(p, 0, total);
return p;
}
void crnlib_free(void* p) {
if (!p)
return;
if (reinterpret_cast<ptr_bits_t>(p) & (CRNLIB_MIN_ALLOC_ALIGNMENT - 1)) {
crnlib_mem_error("crnlib_free: bad ptr");
return;
}
#if CRNLIB_MEM_STATS
size_t cur_size = (*g_pMSize)(p, g_pUser_data);
CRNLIB_ASSERT(cur_size >= sizeof(uint32));
update_total_allocated(-1, -static_cast<mem_stat_t>(cur_size));
#endif
(*g_pRealloc)(p, 0, NULL, true, g_pUser_data);
}
size_t crnlib_msize(void* p) {
if (!p)
return 0;
if (reinterpret_cast<ptr_bits_t>(p) & (CRNLIB_MIN_ALLOC_ALIGNMENT - 1)) {
crnlib_mem_error("crnlib_msize: bad ptr");
return 0;
}
return (*g_pMSize)(p, g_pUser_data);
}
void crnlib_print_mem_stats() {
#if CRNLIB_MEM_STATS
if (console::is_initialized()) {
console::debug("crnlib_print_mem_stats:");
console::debug("Current blocks: %u, allocated: " CRNLIB_INT64_FORMAT_SPECIFIER ", max ever allocated: " CRNLIB_INT64_FORMAT_SPECIFIER, g_total_blocks, (int64)g_total_allocated, (int64)g_max_allocated);
} else {
printf("crnlib_print_mem_stats:\n");
printf("Current blocks: %u, allocated: " CRNLIB_INT64_FORMAT_SPECIFIER ", max ever allocated: " CRNLIB_INT64_FORMAT_SPECIFIER "\n", g_total_blocks, (int64)g_total_allocated, (int64)g_max_allocated);
}
#endif
}
} // namespace crnlib
void crn_set_memory_callbacks(crn_realloc_func pRealloc, crn_msize_func pMSize, void* pUser_data) {
if ((!pRealloc) || (!pMSize)) {
crnlib::g_pRealloc = crnlib::crnlib_default_realloc;
crnlib::g_pMSize = crnlib::crnlib_default_msize;
crnlib::g_pUser_data = NULL;
} else {
crnlib::g_pRealloc = pRealloc;
crnlib::g_pMSize = pMSize;
crnlib::g_pUser_data = pUser_data;
}
}
+151 -179
View File
@@ -6,204 +6,176 @@
#define CRNLIB_MIN_ALLOC_ALIGNMENT sizeof(size_t) * 2
#endif
namespace crnlib
{
namespace crnlib {
#if CRNLIB_64BIT_POINTERS
const uint64 CRNLIB_MAX_POSSIBLE_BLOCK_SIZE = 0x400000000ULL;
const uint64 CRNLIB_MAX_POSSIBLE_BLOCK_SIZE = 0x400000000ULL;
#else
const uint32 CRNLIB_MAX_POSSIBLE_BLOCK_SIZE = 0x7FFF0000U;
const uint32 CRNLIB_MAX_POSSIBLE_BLOCK_SIZE = 0x7FFF0000U;
#endif
void* crnlib_malloc(size_t size);
void* crnlib_malloc(size_t size, size_t* pActual_size);
void* crnlib_realloc(void* p, size_t size, size_t* pActual_size = NULL, bool movable = true);
void* crnlib_calloc(size_t count, size_t size, size_t* pActual_size = NULL);
void crnlib_free(void* p);
size_t crnlib_msize(void* p);
void crnlib_print_mem_stats();
void crnlib_mem_error(const char* p_msg);
// omfg - there must be a better way
template<typename T>
inline T* crnlib_new()
{
T* p = static_cast<T*>(crnlib_malloc(sizeof(T)));
if (CRNLIB_IS_SCALAR_TYPE(T))
return p;
return helpers::construct(p);
}
void* crnlib_malloc(size_t size);
void* crnlib_malloc(size_t size, size_t* pActual_size);
void* crnlib_realloc(void* p, size_t size, size_t* pActual_size = NULL, bool movable = true);
void* crnlib_calloc(size_t count, size_t size, size_t* pActual_size = NULL);
void crnlib_free(void* p);
size_t crnlib_msize(void* p);
void crnlib_print_mem_stats();
void crnlib_mem_error(const char* p_msg);
template<typename T, typename A>
inline T* crnlib_new(const A& init0)
{
T* p = static_cast<T*>(crnlib_malloc(sizeof(T)));
return new (static_cast<void*>(p)) T(init0);
}
// omfg - there must be a better way
template<typename T, typename A>
inline T* crnlib_new(A& init0)
{
T* p = static_cast<T*>(crnlib_malloc(sizeof(T)));
return new (static_cast<void*>(p)) T(init0);
}
template <typename T>
inline T* crnlib_new() {
T* p = static_cast<T*>(crnlib_malloc(sizeof(T)));
if (CRNLIB_IS_SCALAR_TYPE(T))
return p;
return helpers::construct(p);
}
template<typename T, typename A, typename B>
inline T* crnlib_new(const A& init0, const B& init1)
{
T* p = static_cast<T*>(crnlib_malloc(sizeof(T)));
return new (static_cast<void*>(p)) T(init0, init1);
}
template <typename T, typename A>
inline T* crnlib_new(const A& init0) {
T* p = static_cast<T*>(crnlib_malloc(sizeof(T)));
return new (static_cast<void*>(p)) T(init0);
}
template<typename T, typename A, typename B, typename C>
inline T* crnlib_new(const A& init0, const B& init1, const C& init2)
{
T* p = static_cast<T*>(crnlib_malloc(sizeof(T)));
return new (static_cast<void*>(p)) T(init0, init1, init2);
}
template <typename T, typename A>
inline T* crnlib_new(A& init0) {
T* p = static_cast<T*>(crnlib_malloc(sizeof(T)));
return new (static_cast<void*>(p)) T(init0);
}
template<typename T, typename A, typename B, typename C, typename D>
inline T* crnlib_new(const A& init0, const B& init1, const C& init2, const D& init3)
{
T* p = static_cast<T*>(crnlib_malloc(sizeof(T)));
return new (static_cast<void*>(p)) T(init0, init1, init2, init3);
}
template <typename T, typename A, typename B>
inline T* crnlib_new(const A& init0, const B& init1) {
T* p = static_cast<T*>(crnlib_malloc(sizeof(T)));
return new (static_cast<void*>(p)) T(init0, init1);
}
template<typename T, typename A, typename B, typename C, typename D, typename E>
inline T* crnlib_new(const A& init0, const B& init1, const C& init2, const D& init3, const E& init4)
{
T* p = static_cast<T*>(crnlib_malloc(sizeof(T)));
return new (static_cast<void*>(p)) T(init0, init1, init2, init3, init4);
}
template <typename T, typename A, typename B, typename C>
inline T* crnlib_new(const A& init0, const B& init1, const C& init2) {
T* p = static_cast<T*>(crnlib_malloc(sizeof(T)));
return new (static_cast<void*>(p)) T(init0, init1, init2);
}
template<typename T, typename A, typename B, typename C, typename D, typename E, typename F>
inline T* crnlib_new(const A& init0, const B& init1, const C& init2, const D& init3, const E& init4, const F& init5)
{
T* p = static_cast<T*>(crnlib_malloc(sizeof(T)));
return new (static_cast<void*>(p)) T(init0, init1, init2, init3, init4, init5);
}
template <typename T, typename A, typename B, typename C, typename D>
inline T* crnlib_new(const A& init0, const B& init1, const C& init2, const D& init3) {
T* p = static_cast<T*>(crnlib_malloc(sizeof(T)));
return new (static_cast<void*>(p)) T(init0, init1, init2, init3);
}
template<typename T, typename A, typename B, typename C, typename D, typename E, typename F, typename G>
inline T* crnlib_new(const A& init0, const B& init1, const C& init2, const D& init3, const E& init4, const F& init5, const G& init6)
{
T* p = static_cast<T*>(crnlib_malloc(sizeof(T)));
return new (static_cast<void*>(p)) T(init0, init1, init2, init3, init4, init5, init6);
}
template <typename T, typename A, typename B, typename C, typename D, typename E>
inline T* crnlib_new(const A& init0, const B& init1, const C& init2, const D& init3, const E& init4) {
T* p = static_cast<T*>(crnlib_malloc(sizeof(T)));
return new (static_cast<void*>(p)) T(init0, init1, init2, init3, init4);
}
template<typename T, typename A, typename B, typename C, typename D, typename E, typename F, typename G, typename H>
inline T* crnlib_new(const A& init0, const B& init1, const C& init2, const D& init3, const E& init4, const F& init5, const G& init6, const H& init7)
{
T* p = static_cast<T*>(crnlib_malloc(sizeof(T)));
return new (static_cast<void*>(p)) T(init0, init1, init2, init3, init4, init5, init6, init7);
}
template <typename T, typename A, typename B, typename C, typename D, typename E, typename F>
inline T* crnlib_new(const A& init0, const B& init1, const C& init2, const D& init3, const E& init4, const F& init5) {
T* p = static_cast<T*>(crnlib_malloc(sizeof(T)));
return new (static_cast<void*>(p)) T(init0, init1, init2, init3, init4, init5);
}
template<typename T, typename A, typename B, typename C, typename D, typename E, typename F, typename G, typename H, typename I>
inline T* crnlib_new(const A& init0, const B& init1, const C& init2, const D& init3, const E& init4, const F& init5, const G& init6, const H& init7, const I& init8)
{
T* p = static_cast<T*>(crnlib_malloc(sizeof(T)));
return new (static_cast<void*>(p)) T(init0, init1, init2, init3, init4, init5, init6, init7, init8);
}
template <typename T, typename A, typename B, typename C, typename D, typename E, typename F, typename G>
inline T* crnlib_new(const A& init0, const B& init1, const C& init2, const D& init3, const E& init4, const F& init5, const G& init6) {
T* p = static_cast<T*>(crnlib_malloc(sizeof(T)));
return new (static_cast<void*>(p)) T(init0, init1, init2, init3, init4, init5, init6);
}
template<typename T, typename A, typename B, typename C, typename D, typename E, typename F, typename G, typename H, typename I, typename J>
inline T* crnlib_new(const A& init0, const B& init1, const C& init2, const D& init3, const E& init4, const F& init5, const G& init6, const H& init7, const I& init8, const J& init9)
{
T* p = static_cast<T*>(crnlib_malloc(sizeof(T)));
return new (static_cast<void*>(p)) T(init0, init1, init2, init3, init4, init5, init6, init7, init8, init9);
}
template <typename T, typename A, typename B, typename C, typename D, typename E, typename F, typename G, typename H>
inline T* crnlib_new(const A& init0, const B& init1, const C& init2, const D& init3, const E& init4, const F& init5, const G& init6, const H& init7) {
T* p = static_cast<T*>(crnlib_malloc(sizeof(T)));
return new (static_cast<void*>(p)) T(init0, init1, init2, init3, init4, init5, init6, init7);
}
template<typename T, typename A, typename B, typename C, typename D, typename E, typename F, typename G, typename H, typename I, typename J, typename K>
inline T* crnlib_new(const A& init0, const B& init1, const C& init2, const D& init3, const E& init4, const F& init5, const G& init6, const H& init7, const I& init8, const J& init9, const K& init10)
{
T* p = static_cast<T*>(crnlib_malloc(sizeof(T)));
return new (static_cast<void*>(p)) T(init0, init1, init2, init3, init4, init5, init6, init7, init8, init9, init10);
}
template <typename T, typename A, typename B, typename C, typename D, typename E, typename F, typename G, typename H, typename I>
inline T* crnlib_new(const A& init0, const B& init1, const C& init2, const D& init3, const E& init4, const F& init5, const G& init6, const H& init7, const I& init8) {
T* p = static_cast<T*>(crnlib_malloc(sizeof(T)));
return new (static_cast<void*>(p)) T(init0, init1, init2, init3, init4, init5, init6, init7, init8);
}
template<typename T, typename A, typename B, typename C, typename D, typename E, typename F, typename G, typename H, typename I, typename J, typename K, typename L>
inline T* crnlib_new(const A& init0, const B& init1, const C& init2, const D& init3, const E& init4, const F& init5, const G& init6, const H& init7, const I& init8, const J& init9, const K& init10, const L& init11)
{
T* p = static_cast<T*>(crnlib_malloc(sizeof(T)));
return new (static_cast<void*>(p)) T(init0, init1, init2, init3, init4, init5, init6, init7, init8, init9, init10, init11);
}
template <typename T, typename A, typename B, typename C, typename D, typename E, typename F, typename G, typename H, typename I, typename J>
inline T* crnlib_new(const A& init0, const B& init1, const C& init2, const D& init3, const E& init4, const F& init5, const G& init6, const H& init7, const I& init8, const J& init9) {
T* p = static_cast<T*>(crnlib_malloc(sizeof(T)));
return new (static_cast<void*>(p)) T(init0, init1, init2, init3, init4, init5, init6, init7, init8, init9);
}
template<typename T>
inline T* crnlib_new_array(uint32 num)
{
if (!num) num = 1;
template <typename T, typename A, typename B, typename C, typename D, typename E, typename F, typename G, typename H, typename I, typename J, typename K>
inline T* crnlib_new(const A& init0, const B& init1, const C& init2, const D& init3, const E& init4, const F& init5, const G& init6, const H& init7, const I& init8, const J& init9, const K& init10) {
T* p = static_cast<T*>(crnlib_malloc(sizeof(T)));
return new (static_cast<void*>(p)) T(init0, init1, init2, init3, init4, init5, init6, init7, init8, init9, init10);
}
uint64 total = CRNLIB_MIN_ALLOC_ALIGNMENT + sizeof(T) * num;
if (total > CRNLIB_MAX_POSSIBLE_BLOCK_SIZE)
{
crnlib_mem_error("crnlib_new_array: Array too large!");
return NULL;
template <typename T, typename A, typename B, typename C, typename D, typename E, typename F, typename G, typename H, typename I, typename J, typename K, typename L>
inline T* crnlib_new(const A& init0, const B& init1, const C& init2, const D& init3, const E& init4, const F& init5, const G& init6, const H& init7, const I& init8, const J& init9, const K& init10, const L& init11) {
T* p = static_cast<T*>(crnlib_malloc(sizeof(T)));
return new (static_cast<void*>(p)) T(init0, init1, init2, init3, init4, init5, init6, init7, init8, init9, init10, init11);
}
template <typename T>
inline T* crnlib_new_array(uint32 num) {
if (!num)
num = 1;
uint64 total = CRNLIB_MIN_ALLOC_ALIGNMENT + sizeof(T) * num;
if (total > CRNLIB_MAX_POSSIBLE_BLOCK_SIZE) {
crnlib_mem_error("crnlib_new_array: Array too large!");
return NULL;
}
uint8* q = static_cast<uint8*>(crnlib_malloc(static_cast<size_t>(total)));
T* p = reinterpret_cast<T*>(q + CRNLIB_MIN_ALLOC_ALIGNMENT);
reinterpret_cast<uint32*>(p)[-1] = num;
reinterpret_cast<uint32*>(p)[-2] = ~num;
if (!CRNLIB_IS_SCALAR_TYPE(T)) {
helpers::construct_array(p, num);
}
return p;
}
template <typename T>
inline void crnlib_delete(T* p) {
if (p) {
if (!CRNLIB_IS_SCALAR_TYPE(T)) {
helpers::destruct(p);
}
crnlib_free(p);
}
}
template <typename T>
inline void crnlib_delete_array(T* p) {
if (p) {
const uint32 num = reinterpret_cast<uint32*>(p)[-1];
const uint32 num_check = reinterpret_cast<uint32*>(p)[-2];
CRNLIB_ASSERT(num && (num == ~num_check));
if (num == ~num_check) {
if (!CRNLIB_IS_SCALAR_TYPE(T)) {
helpers::destruct_array(p, num);
}
uint8* q = static_cast<uint8*>(crnlib_malloc(static_cast<size_t>(total)));
T* p = reinterpret_cast<T*>(q + CRNLIB_MIN_ALLOC_ALIGNMENT);
crnlib_free(reinterpret_cast<uint8*>(p) - CRNLIB_MIN_ALLOC_ALIGNMENT);
}
}
}
reinterpret_cast<uint32*>(p)[-1] = num;
reinterpret_cast<uint32*>(p)[-2] = ~num;
if (!CRNLIB_IS_SCALAR_TYPE(T))
{
helpers::construct_array(p, num);
}
return p;
}
template<typename T>
inline void crnlib_delete(T* p)
{
if (p)
{
if (!CRNLIB_IS_SCALAR_TYPE(T))
{
helpers::destruct(p);
}
crnlib_free(p);
}
}
template<typename T>
inline void crnlib_delete_array(T* p)
{
if (p)
{
const uint32 num = reinterpret_cast<uint32*>(p)[-1];
const uint32 num_check = reinterpret_cast<uint32*>(p)[-2];
CRNLIB_ASSERT(num && (num == ~num_check));
if (num == ~num_check)
{
if (!CRNLIB_IS_SCALAR_TYPE(T))
{
helpers::destruct_array(p, num);
}
crnlib_free(reinterpret_cast<uint8*>(p) - CRNLIB_MIN_ALLOC_ALIGNMENT);
}
}
}
} // namespace crnlib
#define CRNLIB_DEFINE_NEW_DELETE \
void* operator new (size_t size) \
{ \
void* p = crnlib::crnlib_malloc(size); \
if (!p) \
crnlib_fail("new: Out of memory!", __FILE__, __LINE__); \
return p; \
} \
void* operator new[] (size_t size) \
{ \
void* p = crnlib::crnlib_malloc(size); \
if (!p) \
crnlib_fail("new[]: Out of memory!", __FILE__, __LINE__); \
return p; \
} \
void operator delete (void* p_block) \
{ \
crnlib::crnlib_free(p_block); \
} \
void operator delete[] (void* p_block) \
{ \
crnlib::crnlib_free(p_block); \
}
} // namespace crnlib
#define CRNLIB_DEFINE_NEW_DELETE \
void* operator new(size_t size) { \
void* p = crnlib::crnlib_malloc(size); \
if (!p) \
crnlib_fail("new: Out of memory!", __FILE__, __LINE__); \
return p; \
} \
void* operator new[](size_t size) { \
void* p = crnlib::crnlib_malloc(size); \
if (!p) \
crnlib_fail("new[]: Out of memory!", __FILE__, __LINE__); \
return p; \
} \
void operator delete(void* p_block) { \
crnlib::crnlib_free(p_block); \
} \
void operator delete[](void* p_block) { \
crnlib::crnlib_free(p_block); \
}
+1876 -1502
View File
File diff suppressed because it is too large Load Diff
+262 -221
View File
@@ -174,7 +174,7 @@
#define MINIZ_X86_OR_X64_CPU 1
#endif
#if (__BYTE_ORDER__==__ORDER_LITTLE_ENDIAN__) || MINIZ_X86_OR_X64_CPU
#if (__BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__) || MINIZ_X86_OR_X64_CPU
// Set MINIZ_LITTLE_ENDIAN to 1 if the processor is little endian.
#define MINIZ_LITTLE_ENDIAN 1
#endif
@@ -199,18 +199,22 @@ extern "C" {
typedef unsigned long mz_ulong;
// mz_free() internally uses the MZ_FREE() macro (which by default calls free() unless you've modified the MZ_MALLOC macro) to release a block allocated from the heap.
void mz_free(void *p);
void mz_free(void* p);
#define MZ_ADLER32_INIT (1)
// mz_adler32() returns the initial adler-32 value to use when called with ptr==NULL.
mz_ulong mz_adler32(mz_ulong adler, const unsigned char *ptr, size_t buf_len);
mz_ulong mz_adler32(mz_ulong adler, const unsigned char* ptr, size_t buf_len);
#define MZ_CRC32_INIT (0)
// mz_crc32() returns the initial CRC-32 value to use when called with ptr==NULL.
mz_ulong mz_crc32(mz_ulong crc, const unsigned char *ptr, size_t buf_len);
mz_ulong mz_crc32(mz_ulong crc, const unsigned char* ptr, size_t buf_len);
// Compression strategies.
enum { MZ_DEFAULT_STRATEGY = 0, MZ_FILTERED = 1, MZ_HUFFMAN_ONLY = 2, MZ_RLE = 3, MZ_FIXED = 4 };
enum { MZ_DEFAULT_STRATEGY = 0,
MZ_FILTERED = 1,
MZ_HUFFMAN_ONLY = 2,
MZ_RLE = 3,
MZ_FIXED = 4 };
// Method
#define MZ_DEFLATED 8
@@ -219,25 +223,44 @@ enum { MZ_DEFAULT_STRATEGY = 0, MZ_FILTERED = 1, MZ_HUFFMAN_ONLY = 2, MZ_RLE = 3
// Heap allocation callbacks.
// Note that mz_alloc_func parameter types purpsosely differ from zlib's: items/size is size_t, not unsigned long.
typedef void *(*mz_alloc_func)(void *opaque, size_t items, size_t size);
typedef void (*mz_free_func)(void *opaque, void *address);
typedef void *(*mz_realloc_func)(void *opaque, void *address, size_t items, size_t size);
typedef void* (*mz_alloc_func)(void* opaque, size_t items, size_t size);
typedef void (*mz_free_func)(void* opaque, void* address);
typedef void* (*mz_realloc_func)(void* opaque, void* address, size_t items, size_t size);
#define MZ_VERSION "9.1.14"
#define MZ_VERNUM 0x91E0
#define MZ_VER_MAJOR 9
#define MZ_VER_MINOR 1
#define MZ_VER_REVISION 14
#define MZ_VER_SUBREVISION 0
#define MZ_VERSION "9.1.14"
#define MZ_VERNUM 0x91E0
#define MZ_VER_MAJOR 9
#define MZ_VER_MINOR 1
#define MZ_VER_REVISION 14
#define MZ_VER_SUBREVISION 0
// Flush values. For typical usage you only need MZ_NO_FLUSH and MZ_FINISH. The other values are for advanced use (refer to the zlib docs).
enum { MZ_NO_FLUSH = 0, MZ_PARTIAL_FLUSH = 1, MZ_SYNC_FLUSH = 2, MZ_FULL_FLUSH = 3, MZ_FINISH = 4, MZ_BLOCK = 5 };
enum { MZ_NO_FLUSH = 0,
MZ_PARTIAL_FLUSH = 1,
MZ_SYNC_FLUSH = 2,
MZ_FULL_FLUSH = 3,
MZ_FINISH = 4,
MZ_BLOCK = 5 };
// Return status codes. MZ_PARAM_ERROR is non-standard.
enum { MZ_OK = 0, MZ_STREAM_END = 1, MZ_NEED_DICT = 2, MZ_ERRNO = -1, MZ_STREAM_ERROR = -2, MZ_DATA_ERROR = -3, MZ_MEM_ERROR = -4, MZ_BUF_ERROR = -5, MZ_VERSION_ERROR = -6, MZ_PARAM_ERROR = -10000 };
enum { MZ_OK = 0,
MZ_STREAM_END = 1,
MZ_NEED_DICT = 2,
MZ_ERRNO = -1,
MZ_STREAM_ERROR = -2,
MZ_DATA_ERROR = -3,
MZ_MEM_ERROR = -4,
MZ_BUF_ERROR = -5,
MZ_VERSION_ERROR = -6,
MZ_PARAM_ERROR = -10000 };
// Compression levels: 0-9 are the standard zlib-style levels, 10 is best possible compression (not zlib compatible, and may be very slow), MZ_DEFAULT_COMPRESSION=MZ_DEFAULT_LEVEL.
enum { MZ_NO_COMPRESSION = 0, MZ_BEST_SPEED = 1, MZ_BEST_COMPRESSION = 9, MZ_UBER_COMPRESSION = 10, MZ_DEFAULT_LEVEL = 6, MZ_DEFAULT_COMPRESSION = -1 };
enum { MZ_NO_COMPRESSION = 0,
MZ_BEST_SPEED = 1,
MZ_BEST_COMPRESSION = 9,
MZ_UBER_COMPRESSION = 10,
MZ_DEFAULT_LEVEL = 6,
MZ_DEFAULT_COMPRESSION = -1 };
// Window bits
#define MZ_DEFAULT_WINDOW_BITS 15
@@ -245,32 +268,31 @@ enum { MZ_NO_COMPRESSION = 0, MZ_BEST_SPEED = 1, MZ_BEST_COMPRESSION = 9, MZ_UBE
struct mz_internal_state;
// Compression/decompression stream struct.
typedef struct mz_stream_s
{
const unsigned char *next_in; // pointer to next byte to read
unsigned int avail_in; // number of bytes available at next_in
mz_ulong total_in; // total number of bytes consumed so far
typedef struct mz_stream_s {
const unsigned char* next_in; // pointer to next byte to read
unsigned int avail_in; // number of bytes available at next_in
mz_ulong total_in; // total number of bytes consumed so far
unsigned char *next_out; // pointer to next byte to write
unsigned int avail_out; // number of bytes that can be written to next_out
mz_ulong total_out; // total number of bytes produced so far
unsigned char* next_out; // pointer to next byte to write
unsigned int avail_out; // number of bytes that can be written to next_out
mz_ulong total_out; // total number of bytes produced so far
char *msg; // error msg (unused)
struct mz_internal_state *state; // internal state, allocated by zalloc/zfree
char* msg; // error msg (unused)
struct mz_internal_state* state; // internal state, allocated by zalloc/zfree
mz_alloc_func zalloc; // optional heap allocation function (defaults to malloc)
mz_free_func zfree; // optional heap free function (defaults to free)
void *opaque; // heap alloc function user pointer
mz_alloc_func zalloc; // optional heap allocation function (defaults to malloc)
mz_free_func zfree; // optional heap free function (defaults to free)
void* opaque; // heap alloc function user pointer
int data_type; // data_type (unused)
mz_ulong adler; // adler32 of the source or uncompressed data
mz_ulong reserved; // not used
int data_type; // data_type (unused)
mz_ulong adler; // adler32 of the source or uncompressed data
mz_ulong reserved; // not used
} mz_stream;
typedef mz_stream *mz_streamp;
typedef mz_stream* mz_streamp;
// Returns the version string of miniz.c.
const char *mz_version(void);
const char* mz_version(void);
// mz_deflateInit() initializes a compressor with default options:
// Parameters:
@@ -318,8 +340,8 @@ mz_ulong mz_deflateBound(mz_streamp pStream, mz_ulong source_len);
// Single-call compression functions mz_compress() and mz_compress2():
// Returns MZ_OK on success, or one of the error codes from mz_deflate() on failure.
int mz_compress(unsigned char *pDest, mz_ulong *pDest_len, const unsigned char *pSource, mz_ulong source_len);
int mz_compress2(unsigned char *pDest, mz_ulong *pDest_len, const unsigned char *pSource, mz_ulong source_len, int level);
int mz_compress(unsigned char* pDest, mz_ulong* pDest_len, const unsigned char* pSource, mz_ulong source_len);
int mz_compress2(unsigned char* pDest, mz_ulong* pDest_len, const unsigned char* pSource, mz_ulong source_len, int level);
// mz_compressBound() returns a (very) conservative upper bound on the amount of data that could be generated by calling mz_compress().
mz_ulong mz_compressBound(mz_ulong source_len);
@@ -352,87 +374,87 @@ int mz_inflateEnd(mz_streamp pStream);
// Single-call decompression.
// Returns MZ_OK on success, or one of the error codes from mz_inflate() on failure.
int mz_uncompress(unsigned char *pDest, mz_ulong *pDest_len, const unsigned char *pSource, mz_ulong source_len);
int mz_uncompress(unsigned char* pDest, mz_ulong* pDest_len, const unsigned char* pSource, mz_ulong source_len);
// Returns a string description of the specified error code, or NULL if the error code is invalid.
const char *mz_error(int err);
const char* mz_error(int err);
// Redefine zlib-compatible names to miniz equivalents, so miniz.c can be used as a drop-in replacement for the subset of zlib that miniz.c supports.
// Define MINIZ_NO_ZLIB_COMPATIBLE_NAMES to disable zlib-compatibility if you use zlib in the same project.
#ifndef MINIZ_NO_ZLIB_COMPATIBLE_NAMES
typedef unsigned char Byte;
typedef unsigned int uInt;
typedef mz_ulong uLong;
typedef Byte Bytef;
typedef uInt uIntf;
typedef char charf;
typedef int intf;
typedef void *voidpf;
typedef uLong uLongf;
typedef void *voidp;
typedef void *const voidpc;
#define Z_NULL 0
#define Z_NO_FLUSH MZ_NO_FLUSH
#define Z_PARTIAL_FLUSH MZ_PARTIAL_FLUSH
#define Z_SYNC_FLUSH MZ_SYNC_FLUSH
#define Z_FULL_FLUSH MZ_FULL_FLUSH
#define Z_FINISH MZ_FINISH
#define Z_BLOCK MZ_BLOCK
#define Z_OK MZ_OK
#define Z_STREAM_END MZ_STREAM_END
#define Z_NEED_DICT MZ_NEED_DICT
#define Z_ERRNO MZ_ERRNO
#define Z_STREAM_ERROR MZ_STREAM_ERROR
#define Z_DATA_ERROR MZ_DATA_ERROR
#define Z_MEM_ERROR MZ_MEM_ERROR
#define Z_BUF_ERROR MZ_BUF_ERROR
#define Z_VERSION_ERROR MZ_VERSION_ERROR
#define Z_PARAM_ERROR MZ_PARAM_ERROR
#define Z_NO_COMPRESSION MZ_NO_COMPRESSION
#define Z_BEST_SPEED MZ_BEST_SPEED
#define Z_BEST_COMPRESSION MZ_BEST_COMPRESSION
#define Z_DEFAULT_COMPRESSION MZ_DEFAULT_COMPRESSION
#define Z_DEFAULT_STRATEGY MZ_DEFAULT_STRATEGY
#define Z_FILTERED MZ_FILTERED
#define Z_HUFFMAN_ONLY MZ_HUFFMAN_ONLY
#define Z_RLE MZ_RLE
#define Z_FIXED MZ_FIXED
#define Z_DEFLATED MZ_DEFLATED
#define Z_DEFAULT_WINDOW_BITS MZ_DEFAULT_WINDOW_BITS
#define alloc_func mz_alloc_func
#define free_func mz_free_func
#define internal_state mz_internal_state
#define z_stream mz_stream
#define deflateInit mz_deflateInit
#define deflateInit2 mz_deflateInit2
#define deflateReset mz_deflateReset
#define deflate mz_deflate
#define deflateEnd mz_deflateEnd
#define deflateBound mz_deflateBound
#define compress mz_compress
#define compress2 mz_compress2
#define compressBound mz_compressBound
#define inflateInit mz_inflateInit
#define inflateInit2 mz_inflateInit2
#define inflate mz_inflate
#define inflateEnd mz_inflateEnd
#define uncompress mz_uncompress
#define crc32 mz_crc32
#define adler32 mz_adler32
#define MAX_WBITS 15
#define MAX_MEM_LEVEL 9
#define zError mz_error
#define ZLIB_VERSION MZ_VERSION
#define ZLIB_VERNUM MZ_VERNUM
#define ZLIB_VER_MAJOR MZ_VER_MAJOR
#define ZLIB_VER_MINOR MZ_VER_MINOR
#define ZLIB_VER_REVISION MZ_VER_REVISION
#define ZLIB_VER_SUBREVISION MZ_VER_SUBREVISION
#define zlibVersion mz_version
#define zlib_version mz_version()
#endif // #ifndef MINIZ_NO_ZLIB_COMPATIBLE_NAMES
typedef unsigned char Byte;
typedef unsigned int uInt;
typedef mz_ulong uLong;
typedef Byte Bytef;
typedef uInt uIntf;
typedef char charf;
typedef int intf;
typedef void* voidpf;
typedef uLong uLongf;
typedef void* voidp;
typedef void* const voidpc;
#define Z_NULL 0
#define Z_NO_FLUSH MZ_NO_FLUSH
#define Z_PARTIAL_FLUSH MZ_PARTIAL_FLUSH
#define Z_SYNC_FLUSH MZ_SYNC_FLUSH
#define Z_FULL_FLUSH MZ_FULL_FLUSH
#define Z_FINISH MZ_FINISH
#define Z_BLOCK MZ_BLOCK
#define Z_OK MZ_OK
#define Z_STREAM_END MZ_STREAM_END
#define Z_NEED_DICT MZ_NEED_DICT
#define Z_ERRNO MZ_ERRNO
#define Z_STREAM_ERROR MZ_STREAM_ERROR
#define Z_DATA_ERROR MZ_DATA_ERROR
#define Z_MEM_ERROR MZ_MEM_ERROR
#define Z_BUF_ERROR MZ_BUF_ERROR
#define Z_VERSION_ERROR MZ_VERSION_ERROR
#define Z_PARAM_ERROR MZ_PARAM_ERROR
#define Z_NO_COMPRESSION MZ_NO_COMPRESSION
#define Z_BEST_SPEED MZ_BEST_SPEED
#define Z_BEST_COMPRESSION MZ_BEST_COMPRESSION
#define Z_DEFAULT_COMPRESSION MZ_DEFAULT_COMPRESSION
#define Z_DEFAULT_STRATEGY MZ_DEFAULT_STRATEGY
#define Z_FILTERED MZ_FILTERED
#define Z_HUFFMAN_ONLY MZ_HUFFMAN_ONLY
#define Z_RLE MZ_RLE
#define Z_FIXED MZ_FIXED
#define Z_DEFLATED MZ_DEFLATED
#define Z_DEFAULT_WINDOW_BITS MZ_DEFAULT_WINDOW_BITS
#define alloc_func mz_alloc_func
#define free_func mz_free_func
#define internal_state mz_internal_state
#define z_stream mz_stream
#define deflateInit mz_deflateInit
#define deflateInit2 mz_deflateInit2
#define deflateReset mz_deflateReset
#define deflate mz_deflate
#define deflateEnd mz_deflateEnd
#define deflateBound mz_deflateBound
#define compress mz_compress
#define compress2 mz_compress2
#define compressBound mz_compressBound
#define inflateInit mz_inflateInit
#define inflateInit2 mz_inflateInit2
#define inflate mz_inflate
#define inflateEnd mz_inflateEnd
#define uncompress mz_uncompress
#define crc32 mz_crc32
#define adler32 mz_adler32
#define MAX_WBITS 15
#define MAX_MEM_LEVEL 9
#define zError mz_error
#define ZLIB_VERSION MZ_VERSION
#define ZLIB_VERNUM MZ_VERNUM
#define ZLIB_VER_MAJOR MZ_VER_MAJOR
#define ZLIB_VER_MINOR MZ_VER_MINOR
#define ZLIB_VER_REVISION MZ_VER_REVISION
#define ZLIB_VER_SUBREVISION MZ_VER_SUBREVISION
#define zlibVersion mz_version
#define zlib_version mz_version()
#endif // #ifndef MINIZ_NO_ZLIB_COMPATIBLE_NAMES
#endif // MINIZ_NO_ZLIB_APIS
#endif // MINIZ_NO_ZLIB_APIS
// ------------------- Types and macros
@@ -450,18 +472,17 @@ typedef int mz_bool;
// Works around MSVC's spammy "warning C4127: conditional expression is constant" message.
#ifdef _MSC_VER
#define MZ_MACRO_END while (0, 0)
#define MZ_MACRO_END while (0, 0)
#else
#define MZ_MACRO_END while (0)
#define MZ_MACRO_END while (0)
#endif
// ------------------- ZIP archive reading/writing
#ifndef MINIZ_NO_ARCHIVE_APIS
enum
{
MZ_ZIP_MAX_IO_BUF_SIZE = 64*1024,
enum {
MZ_ZIP_MAX_IO_BUF_SIZE = 64 * 1024,
MZ_ZIP_MAX_ARCHIVE_FILENAME_SIZE = 260,
MZ_ZIP_MAX_ARCHIVE_FILE_COMMENT_SIZE = 256
};
@@ -488,14 +509,13 @@ typedef struct
char m_comment[MZ_ZIP_MAX_ARCHIVE_FILE_COMMENT_SIZE];
} mz_zip_archive_file_stat;
typedef size_t (*mz_file_read_func)(void *pOpaque, mz_uint64 file_ofs, void *pBuf, size_t n);
typedef size_t (*mz_file_write_func)(void *pOpaque, mz_uint64 file_ofs, const void *pBuf, size_t n);
typedef size_t (*mz_file_read_func)(void* pOpaque, mz_uint64 file_ofs, void* pBuf, size_t n);
typedef size_t (*mz_file_write_func)(void* pOpaque, mz_uint64 file_ofs, const void* pBuf, size_t n);
struct mz_zip_internal_state_tag;
typedef struct mz_zip_internal_state_tag mz_zip_internal_state;
typedef enum
{
typedef enum {
MZ_ZIP_MODE_INVALID = 0,
MZ_ZIP_MODE_READING = 1,
MZ_ZIP_MODE_WRITING = 2,
@@ -514,21 +534,20 @@ typedef struct
mz_alloc_func m_pAlloc;
mz_free_func m_pFree;
mz_realloc_func m_pRealloc;
void *m_pAlloc_opaque;
void* m_pAlloc_opaque;
mz_file_read_func m_pRead;
mz_file_write_func m_pWrite;
void *m_pIO_opaque;
void* m_pIO_opaque;
mz_zip_internal_state *m_pState;
mz_zip_internal_state* m_pState;
} mz_zip_archive;
typedef enum
{
MZ_ZIP_FLAG_CASE_SENSITIVE = 0x0100,
MZ_ZIP_FLAG_IGNORE_PATH = 0x0200,
MZ_ZIP_FLAG_COMPRESSED_DATA = 0x0400,
typedef enum {
MZ_ZIP_FLAG_CASE_SENSITIVE = 0x0100,
MZ_ZIP_FLAG_IGNORE_PATH = 0x0200,
MZ_ZIP_FLAG_COMPRESSED_DATA = 0x0400,
MZ_ZIP_FLAG_DO_NOT_SORT_CENTRAL_DIRECTORY = 0x0800
} mz_zip_flags;
@@ -536,68 +555,68 @@ typedef enum
// Inits a ZIP archive reader.
// These functions read and validate the archive's central directory.
mz_bool mz_zip_reader_init(mz_zip_archive *pZip, mz_uint64 size, mz_uint32 flags);
mz_bool mz_zip_reader_init_mem(mz_zip_archive *pZip, const void *pMem, size_t size, mz_uint32 flags);
mz_bool mz_zip_reader_init(mz_zip_archive* pZip, mz_uint64 size, mz_uint32 flags);
mz_bool mz_zip_reader_init_mem(mz_zip_archive* pZip, const void* pMem, size_t size, mz_uint32 flags);
#ifndef MINIZ_NO_STDIO
mz_bool mz_zip_reader_init_file(mz_zip_archive *pZip, const char *pFilename, mz_uint32 flags);
mz_bool mz_zip_reader_init_file(mz_zip_archive* pZip, const char* pFilename, mz_uint32 flags);
#endif
// Returns the total number of files in the archive.
mz_uint mz_zip_reader_get_num_files(mz_zip_archive *pZip);
mz_uint mz_zip_reader_get_num_files(mz_zip_archive* pZip);
// Returns detailed information about an archive file entry.
mz_bool mz_zip_reader_file_stat(mz_zip_archive *pZip, mz_uint file_index, mz_zip_archive_file_stat *pStat);
mz_bool mz_zip_reader_file_stat(mz_zip_archive* pZip, mz_uint file_index, mz_zip_archive_file_stat* pStat);
// Determines if an archive file entry is a directory entry.
mz_bool mz_zip_reader_is_file_a_directory(mz_zip_archive *pZip, mz_uint file_index);
mz_bool mz_zip_reader_is_file_encrypted(mz_zip_archive *pZip, mz_uint file_index);
mz_bool mz_zip_reader_is_file_a_directory(mz_zip_archive* pZip, mz_uint file_index);
mz_bool mz_zip_reader_is_file_encrypted(mz_zip_archive* pZip, mz_uint file_index);
// Retrieves the filename of an archive file entry.
// Returns the number of bytes written to pFilename, or if filename_buf_size is 0 this function returns the number of bytes needed to fully store the filename.
mz_uint mz_zip_reader_get_filename(mz_zip_archive *pZip, mz_uint file_index, char *pFilename, mz_uint filename_buf_size);
mz_uint mz_zip_reader_get_filename(mz_zip_archive* pZip, mz_uint file_index, char* pFilename, mz_uint filename_buf_size);
// Attempts to locates a file in the archive's central directory.
// Valid flags: MZ_ZIP_FLAG_CASE_SENSITIVE, MZ_ZIP_FLAG_IGNORE_PATH
// Returns -1 if the file cannot be found.
int mz_zip_reader_locate_file(mz_zip_archive *pZip, const char *pName, const char *pComment, mz_uint flags);
int mz_zip_reader_locate_file(mz_zip_archive* pZip, const char* pName, const char* pComment, mz_uint flags);
// Extracts a archive file to a memory buffer using no memory allocation.
mz_bool mz_zip_reader_extract_to_mem_no_alloc(mz_zip_archive *pZip, mz_uint file_index, void *pBuf, size_t buf_size, mz_uint flags, void *pUser_read_buf, size_t user_read_buf_size);
mz_bool mz_zip_reader_extract_file_to_mem_no_alloc(mz_zip_archive *pZip, const char *pFilename, void *pBuf, size_t buf_size, mz_uint flags, void *pUser_read_buf, size_t user_read_buf_size);
mz_bool mz_zip_reader_extract_to_mem_no_alloc(mz_zip_archive* pZip, mz_uint file_index, void* pBuf, size_t buf_size, mz_uint flags, void* pUser_read_buf, size_t user_read_buf_size);
mz_bool mz_zip_reader_extract_file_to_mem_no_alloc(mz_zip_archive* pZip, const char* pFilename, void* pBuf, size_t buf_size, mz_uint flags, void* pUser_read_buf, size_t user_read_buf_size);
// Extracts a archive file to a memory buffer.
mz_bool mz_zip_reader_extract_to_mem(mz_zip_archive *pZip, mz_uint file_index, void *pBuf, size_t buf_size, mz_uint flags);
mz_bool mz_zip_reader_extract_file_to_mem(mz_zip_archive *pZip, const char *pFilename, void *pBuf, size_t buf_size, mz_uint flags);
mz_bool mz_zip_reader_extract_to_mem(mz_zip_archive* pZip, mz_uint file_index, void* pBuf, size_t buf_size, mz_uint flags);
mz_bool mz_zip_reader_extract_file_to_mem(mz_zip_archive* pZip, const char* pFilename, void* pBuf, size_t buf_size, mz_uint flags);
// Extracts a archive file to a dynamically allocated heap buffer.
void *mz_zip_reader_extract_to_heap(mz_zip_archive *pZip, mz_uint file_index, size_t *pSize, mz_uint flags);
void *mz_zip_reader_extract_file_to_heap(mz_zip_archive *pZip, const char *pFilename, size_t *pSize, mz_uint flags);
void* mz_zip_reader_extract_to_heap(mz_zip_archive* pZip, mz_uint file_index, size_t* pSize, mz_uint flags);
void* mz_zip_reader_extract_file_to_heap(mz_zip_archive* pZip, const char* pFilename, size_t* pSize, mz_uint flags);
// Extracts a archive file using a callback function to output the file's data.
mz_bool mz_zip_reader_extract_to_callback(mz_zip_archive *pZip, mz_uint file_index, mz_file_write_func pCallback, void *pOpaque, mz_uint flags);
mz_bool mz_zip_reader_extract_file_to_callback(mz_zip_archive *pZip, const char *pFilename, mz_file_write_func pCallback, void *pOpaque, mz_uint flags);
mz_bool mz_zip_reader_extract_to_callback(mz_zip_archive* pZip, mz_uint file_index, mz_file_write_func pCallback, void* pOpaque, mz_uint flags);
mz_bool mz_zip_reader_extract_file_to_callback(mz_zip_archive* pZip, const char* pFilename, mz_file_write_func pCallback, void* pOpaque, mz_uint flags);
#ifndef MINIZ_NO_STDIO
// Extracts a archive file to a disk file and sets its last accessed and modified times.
// This function only extracts files, not archive directory records.
mz_bool mz_zip_reader_extract_to_file(mz_zip_archive *pZip, mz_uint file_index, const char *pDst_filename, mz_uint flags);
mz_bool mz_zip_reader_extract_file_to_file(mz_zip_archive *pZip, const char *pArchive_filename, const char *pDst_filename, mz_uint flags);
mz_bool mz_zip_reader_extract_to_file(mz_zip_archive* pZip, mz_uint file_index, const char* pDst_filename, mz_uint flags);
mz_bool mz_zip_reader_extract_file_to_file(mz_zip_archive* pZip, const char* pArchive_filename, const char* pDst_filename, mz_uint flags);
#endif
// Ends archive reading, freeing all allocations, and closing the input archive file if mz_zip_reader_init_file() was used.
mz_bool mz_zip_reader_end(mz_zip_archive *pZip);
mz_bool mz_zip_reader_end(mz_zip_archive* pZip);
// ZIP archive writing
#ifndef MINIZ_NO_ARCHIVE_WRITING_APIS
// Inits a ZIP archive writer.
mz_bool mz_zip_writer_init(mz_zip_archive *pZip, mz_uint64 existing_size);
mz_bool mz_zip_writer_init_heap(mz_zip_archive *pZip, size_t size_to_reserve_at_beginning, size_t initial_allocation_size);
mz_bool mz_zip_writer_init(mz_zip_archive* pZip, mz_uint64 existing_size);
mz_bool mz_zip_writer_init_heap(mz_zip_archive* pZip, size_t size_to_reserve_at_beginning, size_t initial_allocation_size);
#ifndef MINIZ_NO_STDIO
mz_bool mz_zip_writer_init_file(mz_zip_archive *pZip, const char *pFilename, mz_uint64 size_to_reserve_at_beginning);
mz_bool mz_zip_writer_init_file(mz_zip_archive* pZip, const char* pFilename, mz_uint64 size_to_reserve_at_beginning);
#endif
// Converts a ZIP archive reader object into a writer object, to allow efficient in-place file appends to occur on an existing archive.
@@ -606,48 +625,48 @@ mz_bool mz_zip_writer_init_file(mz_zip_archive *pZip, const char *pFilename, mz_
// Finally, for archives opened using mz_zip_reader_init, the mz_zip_archive's user provided m_pWrite function cannot be NULL.
// Note: In-place archive modification is not recommended unless you know what you're doing, because if execution stops or something goes wrong before
// the archive is finalized the file's central directory will be hosed.
mz_bool mz_zip_writer_init_from_reader(mz_zip_archive *pZip, const char *pFilename);
mz_bool mz_zip_writer_init_from_reader(mz_zip_archive* pZip, const char* pFilename);
// Adds the contents of a memory buffer to an archive. These functions record the current local time into the archive.
// To add a directory entry, call this method with an archive name ending in a forwardslash with empty buffer.
// level_and_flags - compression level (0-10, see MZ_BEST_SPEED, MZ_BEST_COMPRESSION, etc.) logically OR'd with zero or more mz_zip_flags, or just set to MZ_DEFAULT_COMPRESSION.
mz_bool mz_zip_writer_add_mem(mz_zip_archive *pZip, const char *pArchive_name, const void *pBuf, size_t buf_size, mz_uint level_and_flags);
mz_bool mz_zip_writer_add_mem_ex(mz_zip_archive *pZip, const char *pArchive_name, const void *pBuf, size_t buf_size, const void *pComment, mz_uint16 comment_size, mz_uint level_and_flags, mz_uint64 uncomp_size, mz_uint32 uncomp_crc32);
mz_bool mz_zip_writer_add_mem(mz_zip_archive* pZip, const char* pArchive_name, const void* pBuf, size_t buf_size, mz_uint level_and_flags);
mz_bool mz_zip_writer_add_mem_ex(mz_zip_archive* pZip, const char* pArchive_name, const void* pBuf, size_t buf_size, const void* pComment, mz_uint16 comment_size, mz_uint level_and_flags, mz_uint64 uncomp_size, mz_uint32 uncomp_crc32);
#ifndef MINIZ_NO_STDIO
// Adds the contents of a disk file to an archive. This function also records the disk file's modified time into the archive.
// level_and_flags - compression level (0-10, see MZ_BEST_SPEED, MZ_BEST_COMPRESSION, etc.) logically OR'd with zero or more mz_zip_flags, or just set to MZ_DEFAULT_COMPRESSION.
mz_bool mz_zip_writer_add_file(mz_zip_archive *pZip, const char *pArchive_name, const char *pSrc_filename, const void *pComment, mz_uint16 comment_size, mz_uint level_and_flags);
mz_bool mz_zip_writer_add_file(mz_zip_archive* pZip, const char* pArchive_name, const char* pSrc_filename, const void* pComment, mz_uint16 comment_size, mz_uint level_and_flags);
#endif
// Adds a file to an archive by fully cloning the data from another archive.
// This function fully clones the source file's compressed data (no recompression), along with its full filename, extra data, and comment fields.
mz_bool mz_zip_writer_add_from_zip_reader(mz_zip_archive *pZip, mz_zip_archive *pSource_zip, mz_uint file_index);
mz_bool mz_zip_writer_add_from_zip_reader(mz_zip_archive* pZip, mz_zip_archive* pSource_zip, mz_uint file_index);
// Finalizes the archive by writing the central directory records followed by the end of central directory record.
// After an archive is finalized, the only valid call on the mz_zip_archive struct is mz_zip_writer_end().
// An archive must be manually finalized by calling this function for it to be valid.
mz_bool mz_zip_writer_finalize_archive(mz_zip_archive *pZip);
mz_bool mz_zip_writer_finalize_heap_archive(mz_zip_archive *pZip, void **pBuf, size_t *pSize);
mz_bool mz_zip_writer_finalize_archive(mz_zip_archive* pZip);
mz_bool mz_zip_writer_finalize_heap_archive(mz_zip_archive* pZip, void** pBuf, size_t* pSize);
// Ends archive writing, freeing all allocations, and closing the output file if mz_zip_writer_init_file() was used.
// Note for the archive to be valid, it must have been finalized before ending.
mz_bool mz_zip_writer_end(mz_zip_archive *pZip);
mz_bool mz_zip_writer_end(mz_zip_archive* pZip);
// Misc. high-level helper functions:
// mz_zip_add_mem_to_archive_file_in_place() efficiently (but not atomically) appends a memory blob to a ZIP archive.
// level_and_flags - compression level (0-10, see MZ_BEST_SPEED, MZ_BEST_COMPRESSION, etc.) logically OR'd with zero or more mz_zip_flags, or just set to MZ_DEFAULT_COMPRESSION.
mz_bool mz_zip_add_mem_to_archive_file_in_place(const char *pZip_filename, const char *pArchive_name, const void *pBuf, size_t buf_size, const void *pComment, mz_uint16 comment_size, mz_uint level_and_flags);
mz_bool mz_zip_add_mem_to_archive_file_in_place(const char* pZip_filename, const char* pArchive_name, const void* pBuf, size_t buf_size, const void* pComment, mz_uint16 comment_size, mz_uint level_and_flags);
// Reads a single file from an archive into a heap block.
// If pComment is not NULL, only the file with the specified comment will be extracted.
// Returns NULL on failure.
void *mz_zip_extract_archive_file_to_heap(const char *pZip_filename, const char *pArchive_name, const char *pComment, size_t *pSize, mz_uint flags);
void* mz_zip_extract_archive_file_to_heap(const char* pZip_filename, const char* pArchive_name, const char* pComment, size_t* pSize, mz_uint flags);
#endif // #ifndef MINIZ_NO_ARCHIVE_WRITING_APIS
#endif // #ifndef MINIZ_NO_ARCHIVE_WRITING_APIS
#endif // #ifndef MINIZ_NO_ARCHIVE_APIS
#endif // #ifndef MINIZ_NO_ARCHIVE_APIS
// ------------------- Low-level Decompression API Definitions
@@ -656,8 +675,7 @@ void *mz_zip_extract_archive_file_to_heap(const char *pZip_filename, const char
// TINFL_FLAG_HAS_MORE_INPUT: If set, there are more input bytes available beyond the end of the supplied input buffer. If clear, the input buffer contains all remaining input.
// TINFL_FLAG_USING_NON_WRAPPING_OUTPUT_BUF: If set, the output buffer is large enough to hold the entire decompressed stream. If clear, the output buffer is at least the size of the dictionary (typically 32KB).
// TINFL_FLAG_COMPUTE_ADLER32: Force adler-32 checksum computation of the decompressed bytes.
enum
{
enum {
TINFL_FLAG_PARSE_ZLIB_HEADER = 1,
TINFL_FLAG_HAS_MORE_INPUT = 2,
TINFL_FLAG_USING_NON_WRAPPING_OUTPUT_BUF = 4,
@@ -672,26 +690,26 @@ enum
// Function returns a pointer to the decompressed data, or NULL on failure.
// *pOut_len will be set to the decompressed data's size, which could be larger than src_buf_len on uncompressible data.
// The caller must call mz_free() on the returned block when it's no longer needed.
void *tinfl_decompress_mem_to_heap(const void *pSrc_buf, size_t src_buf_len, size_t *pOut_len, int flags);
void* tinfl_decompress_mem_to_heap(const void* pSrc_buf, size_t src_buf_len, size_t* pOut_len, int flags);
// tinfl_decompress_mem_to_mem() decompresses a block in memory to another block in memory.
// Returns TINFL_DECOMPRESS_MEM_TO_MEM_FAILED on failure, or the number of bytes written on success.
#define TINFL_DECOMPRESS_MEM_TO_MEM_FAILED ((size_t)(-1))
size_t tinfl_decompress_mem_to_mem(void *pOut_buf, size_t out_buf_len, const void *pSrc_buf, size_t src_buf_len, int flags);
size_t tinfl_decompress_mem_to_mem(void* pOut_buf, size_t out_buf_len, const void* pSrc_buf, size_t src_buf_len, int flags);
// tinfl_decompress_mem_to_callback() decompresses a block in memory to an internal 32KB buffer, and a user provided callback function will be called to flush the buffer.
// Returns 1 on success or 0 on failure.
typedef int (*tinfl_put_buf_func_ptr)(const void* pBuf, int len, void *pUser);
int tinfl_decompress_mem_to_callback(const void *pIn_buf, size_t *pIn_buf_size, tinfl_put_buf_func_ptr pPut_buf_func, void *pPut_buf_user, int flags);
typedef int (*tinfl_put_buf_func_ptr)(const void* pBuf, int len, void* pUser);
int tinfl_decompress_mem_to_callback(const void* pIn_buf, size_t* pIn_buf_size, tinfl_put_buf_func_ptr pPut_buf_func, void* pPut_buf_user, int flags);
struct tinfl_decompressor_tag; typedef struct tinfl_decompressor_tag tinfl_decompressor;
struct tinfl_decompressor_tag;
typedef struct tinfl_decompressor_tag tinfl_decompressor;
// Max size of LZ dictionary.
#define TINFL_LZ_DICT_SIZE 32768
// Return status.
typedef enum
{
typedef enum {
TINFL_STATUS_BAD_PARAM = -3,
TINFL_STATUS_ADLER32_MISMATCH = -2,
TINFL_STATUS_FAILED = -1,
@@ -701,18 +719,25 @@ typedef enum
} tinfl_status;
// Initializes the decompressor to its initial state.
#define tinfl_init(r) do { (r)->m_state = 0; } MZ_MACRO_END
#define tinfl_init(r) \
do { \
(r)->m_state = 0; \
} \
MZ_MACRO_END
#define tinfl_get_adler32(r) (r)->m_check_adler32
// Main low-level decompressor coroutine function. This is the only function actually needed for decompression. All the other functions are just high-level helpers for improved usability.
// This is a universal API, i.e. it can be used as a building block to build any desired higher level decompression API. In the limit case, it can be called once per every byte input or output.
tinfl_status tinfl_decompress(tinfl_decompressor *r, const mz_uint8 *pIn_buf_next, size_t *pIn_buf_size, mz_uint8 *pOut_buf_start, mz_uint8 *pOut_buf_next, size_t *pOut_buf_size, const mz_uint32 decomp_flags);
tinfl_status tinfl_decompress(tinfl_decompressor* r, const mz_uint8* pIn_buf_next, size_t* pIn_buf_size, mz_uint8* pOut_buf_start, mz_uint8* pOut_buf_next, size_t* pOut_buf_size, const mz_uint32 decomp_flags);
// Internal/private bits follow.
enum
{
TINFL_MAX_HUFF_TABLES = 3, TINFL_MAX_HUFF_SYMBOLS_0 = 288, TINFL_MAX_HUFF_SYMBOLS_1 = 32, TINFL_MAX_HUFF_SYMBOLS_2 = 19,
TINFL_FAST_LOOKUP_BITS = 10, TINFL_FAST_LOOKUP_SIZE = 1 << TINFL_FAST_LOOKUP_BITS
enum {
TINFL_MAX_HUFF_TABLES = 3,
TINFL_MAX_HUFF_SYMBOLS_0 = 288,
TINFL_MAX_HUFF_SYMBOLS_1 = 32,
TINFL_MAX_HUFF_SYMBOLS_2 = 19,
TINFL_FAST_LOOKUP_BITS = 10,
TINFL_FAST_LOOKUP_SIZE = 1 << TINFL_FAST_LOOKUP_BITS
};
typedef struct
@@ -722,19 +747,18 @@ typedef struct
} tinfl_huff_table;
#if MINIZ_HAS_64BIT_REGISTERS
#define TINFL_USE_64BIT_BITBUF 1
#define TINFL_USE_64BIT_BITBUF 1
#endif
#if TINFL_USE_64BIT_BITBUF
typedef mz_uint64 tinfl_bit_buf_t;
#define TINFL_BITBUF_SIZE (64)
typedef mz_uint64 tinfl_bit_buf_t;
#define TINFL_BITBUF_SIZE (64)
#else
typedef mz_uint32 tinfl_bit_buf_t;
#define TINFL_BITBUF_SIZE (32)
typedef mz_uint32 tinfl_bit_buf_t;
#define TINFL_BITBUF_SIZE (32)
#endif
struct tinfl_decompressor_tag
{
struct tinfl_decompressor_tag {
mz_uint32 m_state, m_num_bits, m_zhdr0, m_zhdr1, m_z_adler32, m_final, m_type, m_check_adler32, m_dist, m_counter, m_num_extra, m_table_sizes[TINFL_MAX_HUFF_TABLES];
tinfl_bit_buf_t m_bit_buf;
size_t m_dist_from_out_buf_start;
@@ -749,9 +773,10 @@ struct tinfl_decompressor_tag
// tdefl_init() compression flags logically OR'd together (low 12 bits contain the max. number of probes per dictionary search):
// TDEFL_DEFAULT_MAX_PROBES: The compressor defaults to 128 dictionary probes per dictionary search. 0=Huffman only, 1=Huffman+LZ (fastest/crap compression), 4095=Huffman+LZ (slowest/best compression).
enum
{
TDEFL_HUFFMAN_ONLY = 0, TDEFL_DEFAULT_MAX_PROBES = 128, TDEFL_MAX_PROBES_MASK = 0xFFF
enum {
TDEFL_HUFFMAN_ONLY = 0,
TDEFL_DEFAULT_MAX_PROBES = 128,
TDEFL_MAX_PROBES_MASK = 0xFFF
};
// TDEFL_WRITE_ZLIB_HEADER: If set, the compressor outputs a zlib header before the deflate data, and the Adler-32 of the source data at the end. Otherwise, you'll get raw deflate data.
@@ -762,16 +787,15 @@ enum
// TDEFL_FILTER_MATCHES: Discards matches <= 5 chars if enabled.
// TDEFL_FORCE_ALL_STATIC_BLOCKS: Disable usage of optimized Huffman tables.
// TDEFL_FORCE_ALL_RAW_BLOCKS: Only use raw (uncompressed) deflate blocks.
enum
{
TDEFL_WRITE_ZLIB_HEADER = 0x01000,
TDEFL_COMPUTE_ADLER32 = 0x02000,
TDEFL_GREEDY_PARSING_FLAG = 0x04000,
enum {
TDEFL_WRITE_ZLIB_HEADER = 0x01000,
TDEFL_COMPUTE_ADLER32 = 0x02000,
TDEFL_GREEDY_PARSING_FLAG = 0x04000,
TDEFL_NONDETERMINISTIC_PARSING_FLAG = 0x08000,
TDEFL_RLE_MATCHES = 0x10000,
TDEFL_FILTER_MATCHES = 0x20000,
TDEFL_FORCE_ALL_STATIC_BLOCKS = 0x40000,
TDEFL_FORCE_ALL_RAW_BLOCKS = 0x80000
TDEFL_RLE_MATCHES = 0x10000,
TDEFL_FILTER_MATCHES = 0x20000,
TDEFL_FORCE_ALL_STATIC_BLOCKS = 0x40000,
TDEFL_FORCE_ALL_RAW_BLOCKS = 0x80000
};
// High level compression functions:
@@ -783,40 +807,58 @@ enum
// Function returns a pointer to the compressed data, or NULL on failure.
// *pOut_len will be set to the compressed data's size, which could be larger than src_buf_len on uncompressible data.
// The caller must free() the returned block when it's no longer needed.
void *tdefl_compress_mem_to_heap(const void *pSrc_buf, size_t src_buf_len, size_t *pOut_len, int flags);
void* tdefl_compress_mem_to_heap(const void* pSrc_buf, size_t src_buf_len, size_t* pOut_len, int flags);
// tdefl_compress_mem_to_mem() compresses a block in memory to another block in memory.
// Returns 0 on failure.
size_t tdefl_compress_mem_to_mem(void *pOut_buf, size_t out_buf_len, const void *pSrc_buf, size_t src_buf_len, int flags);
size_t tdefl_compress_mem_to_mem(void* pOut_buf, size_t out_buf_len, const void* pSrc_buf, size_t src_buf_len, int flags);
// Compresses an image to a compressed PNG file in memory.
// On entry:
// pImage, w, h, and num_chans describe the image to compress. num_chans may be 1, 2, 3, or 4.
// pImage, w, h, and num_chans describe the image to compress. num_chans may be 1, 2, 3, or 4.
// The image pitch in bytes per scanline will be w*num_chans. The leftmost pixel on the top scanline is stored first in memory.
// On return:
// Function returns a pointer to the compressed data, or NULL on failure.
// *pLen_out will be set to the size of the PNG image file.
// The caller must mz_free() the returned heap block (which will typically be larger than *pLen_out) when it's no longer needed.
void *tdefl_write_image_to_png_file_in_memory(const void *pImage, int w, int h, int num_chans, size_t *pLen_out);
void* tdefl_write_image_to_png_file_in_memory(const void* pImage, int w, int h, int num_chans, size_t* pLen_out);
// Output stream interface. The compressor uses this interface to write compressed data. It'll typically be called TDEFL_OUT_BUF_SIZE at a time.
typedef mz_bool (*tdefl_put_buf_func_ptr)(const void* pBuf, int len, void *pUser);
typedef mz_bool (*tdefl_put_buf_func_ptr)(const void* pBuf, int len, void* pUser);
// tdefl_compress_mem_to_output() compresses a block to an output stream. The above helpers use this function internally.
mz_bool tdefl_compress_mem_to_output(const void *pBuf, size_t buf_len, tdefl_put_buf_func_ptr pPut_buf_func, void *pPut_buf_user, int flags);
mz_bool tdefl_compress_mem_to_output(const void* pBuf, size_t buf_len, tdefl_put_buf_func_ptr pPut_buf_func, void* pPut_buf_user, int flags);
enum { TDEFL_MAX_HUFF_TABLES = 3, TDEFL_MAX_HUFF_SYMBOLS_0 = 288, TDEFL_MAX_HUFF_SYMBOLS_1 = 32, TDEFL_MAX_HUFF_SYMBOLS_2 = 19, TDEFL_LZ_DICT_SIZE = 32768, TDEFL_LZ_DICT_SIZE_MASK = TDEFL_LZ_DICT_SIZE - 1, TDEFL_MIN_MATCH_LEN = 3, TDEFL_MAX_MATCH_LEN = 258 };
enum { TDEFL_MAX_HUFF_TABLES = 3,
TDEFL_MAX_HUFF_SYMBOLS_0 = 288,
TDEFL_MAX_HUFF_SYMBOLS_1 = 32,
TDEFL_MAX_HUFF_SYMBOLS_2 = 19,
TDEFL_LZ_DICT_SIZE = 32768,
TDEFL_LZ_DICT_SIZE_MASK = TDEFL_LZ_DICT_SIZE - 1,
TDEFL_MIN_MATCH_LEN = 3,
TDEFL_MAX_MATCH_LEN = 258 };
// TDEFL_OUT_BUF_SIZE MUST be large enough to hold a single entire compressed output block (using static/fixed Huffman codes).
#if TDEFL_LESS_MEMORY
enum { TDEFL_LZ_CODE_BUF_SIZE = 24 * 1024, TDEFL_OUT_BUF_SIZE = (TDEFL_LZ_CODE_BUF_SIZE * 13 ) / 10, TDEFL_MAX_HUFF_SYMBOLS = 288, TDEFL_LZ_HASH_BITS = 12, TDEFL_LEVEL1_HASH_SIZE_MASK = 4095, TDEFL_LZ_HASH_SHIFT = (TDEFL_LZ_HASH_BITS + 2) / 3, TDEFL_LZ_HASH_SIZE = 1 << TDEFL_LZ_HASH_BITS };
enum { TDEFL_LZ_CODE_BUF_SIZE = 24 * 1024,
TDEFL_OUT_BUF_SIZE = (TDEFL_LZ_CODE_BUF_SIZE * 13) / 10,
TDEFL_MAX_HUFF_SYMBOLS = 288,
TDEFL_LZ_HASH_BITS = 12,
TDEFL_LEVEL1_HASH_SIZE_MASK = 4095,
TDEFL_LZ_HASH_SHIFT = (TDEFL_LZ_HASH_BITS + 2) / 3,
TDEFL_LZ_HASH_SIZE = 1 << TDEFL_LZ_HASH_BITS };
#else
enum { TDEFL_LZ_CODE_BUF_SIZE = 64 * 1024, TDEFL_OUT_BUF_SIZE = (TDEFL_LZ_CODE_BUF_SIZE * 13 ) / 10, TDEFL_MAX_HUFF_SYMBOLS = 288, TDEFL_LZ_HASH_BITS = 15, TDEFL_LEVEL1_HASH_SIZE_MASK = 4095, TDEFL_LZ_HASH_SHIFT = (TDEFL_LZ_HASH_BITS + 2) / 3, TDEFL_LZ_HASH_SIZE = 1 << TDEFL_LZ_HASH_BITS };
enum { TDEFL_LZ_CODE_BUF_SIZE = 64 * 1024,
TDEFL_OUT_BUF_SIZE = (TDEFL_LZ_CODE_BUF_SIZE * 13) / 10,
TDEFL_MAX_HUFF_SYMBOLS = 288,
TDEFL_LZ_HASH_BITS = 15,
TDEFL_LEVEL1_HASH_SIZE_MASK = 4095,
TDEFL_LZ_HASH_SHIFT = (TDEFL_LZ_HASH_BITS + 2) / 3,
TDEFL_LZ_HASH_SIZE = 1 << TDEFL_LZ_HASH_BITS };
#endif
// The low-level tdefl functions below may be used directly if the above helper functions aren't flexible enough. The low-level functions don't make any heap allocations, unlike the above helper functions.
typedef enum
{
typedef enum {
TDEFL_STATUS_BAD_PARAM = -2,
TDEFL_STATUS_PUT_BUF_FAILED = -1,
TDEFL_STATUS_OKAY = 0,
@@ -824,8 +866,7 @@ typedef enum
} tdefl_status;
// Must map to MZ_NO_FLUSH, MZ_SYNC_FLUSH, etc. enums
typedef enum
{
typedef enum {
TDEFL_NO_FLUSH = 0,
TDEFL_SYNC_FLUSH = 2,
TDEFL_FULL_FLUSH = 3,
@@ -836,7 +877,7 @@ typedef enum
typedef struct
{
tdefl_put_buf_func_ptr m_pPut_buf_func;
void *m_pPut_buf_user;
void* m_pPut_buf_user;
mz_uint m_flags, m_max_probes[2];
int m_greedy_parsing;
mz_uint m_adler32, m_lookahead_pos, m_lookahead_size, m_dict_size;
@@ -844,11 +885,11 @@ typedef struct
mz_uint m_num_flags_left, m_total_lz_bytes, m_lz_code_buf_dict_pos, m_bits_in, m_bit_buffer;
mz_uint m_saved_match_dist, m_saved_match_len, m_saved_lit, m_output_flush_ofs, m_output_flush_remaining, m_finished, m_block_index, m_wants_to_finish;
tdefl_status m_prev_return_status;
const void *m_pIn_buf;
void *m_pOut_buf;
const void* m_pIn_buf;
void* m_pOut_buf;
size_t *m_pIn_buf_size, *m_pOut_buf_size;
tdefl_flush m_flush;
const mz_uint8 *m_pSrc;
const mz_uint8* m_pSrc;
size_t m_src_buf_left, m_out_buf_ofs;
mz_uint8 m_dict[TDEFL_LZ_DICT_SIZE + TDEFL_MAX_MATCH_LEN - 1];
mz_uint16 m_huff_count[TDEFL_MAX_HUFF_TABLES][TDEFL_MAX_HUFF_SYMBOLS];
@@ -865,17 +906,17 @@ typedef struct
// pBut_buf_func: If NULL, output data will be supplied to the specified callback. In this case, the user should call the tdefl_compress_buffer() API for compression.
// If pBut_buf_func is NULL the user should always call the tdefl_compress() API.
// flags: See the above enums (TDEFL_HUFFMAN_ONLY, TDEFL_WRITE_ZLIB_HEADER, etc.)
tdefl_status tdefl_init(tdefl_compressor *d, tdefl_put_buf_func_ptr pPut_buf_func, void *pPut_buf_user, int flags);
tdefl_status tdefl_init(tdefl_compressor* d, tdefl_put_buf_func_ptr pPut_buf_func, void* pPut_buf_user, int flags);
// Compresses a block of data, consuming as much of the specified input buffer as possible, and writing as much compressed data to the specified output buffer as possible.
tdefl_status tdefl_compress(tdefl_compressor *d, const void *pIn_buf, size_t *pIn_buf_size, void *pOut_buf, size_t *pOut_buf_size, tdefl_flush flush);
tdefl_status tdefl_compress(tdefl_compressor* d, const void* pIn_buf, size_t* pIn_buf_size, void* pOut_buf, size_t* pOut_buf_size, tdefl_flush flush);
// tdefl_compress_buffer() is only usable when the tdefl_init() is called with a non-NULL tdefl_put_buf_func_ptr.
// tdefl_compress_buffer() always consumes the entire input buffer.
tdefl_status tdefl_compress_buffer(tdefl_compressor *d, const void *pIn_buf, size_t in_buf_size, tdefl_flush flush);
tdefl_status tdefl_compress_buffer(tdefl_compressor* d, const void* pIn_buf, size_t in_buf_size, tdefl_flush flush);
tdefl_status tdefl_get_prev_return_status(tdefl_compressor *d);
mz_uint32 tdefl_get_adler32(tdefl_compressor *d);
tdefl_status tdefl_get_prev_return_status(tdefl_compressor* d);
mz_uint32 tdefl_get_adler32(tdefl_compressor* d);
// Can't use tdefl_create_comp_flags_from_zip_params if MINIZ_NO_ZLIB_APIS isn't defined, because it uses some of its macros.
#ifndef MINIZ_NO_ZLIB_APIS
@@ -884,10 +925,10 @@ mz_uint32 tdefl_get_adler32(tdefl_compressor *d);
// window_bits may be -15 (raw deflate) or 15 (zlib)
// strategy may be either MZ_DEFAULT_STRATEGY, MZ_FILTERED, MZ_HUFFMAN_ONLY, MZ_RLE, or MZ_FIXED
mz_uint tdefl_create_comp_flags_from_zip_params(int level, int window_bits, int strategy);
#endif // #ifndef MINIZ_NO_ZLIB_APIS
#endif // #ifndef MINIZ_NO_ZLIB_APIS
#ifdef __cplusplus
}
#endif
#endif // MINIZ_HEADER_INCLUDED
#endif // MINIZ_HEADER_INCLUDED
File diff suppressed because it is too large Load Diff
+285 -287
View File
@@ -12,328 +12,326 @@
#include "crn_texture_file_types.h"
#include "crn_image_utils.h"
namespace crnlib
{
extern const vec2I g_vertical_cross_image_offsets[6];
namespace crnlib {
extern const vec2I g_vertical_cross_image_offsets[6];
enum orientation_flags_t
{
cOrientationFlagXFlipped = 1,
cOrientationFlagYFlipped = 2,
enum orientation_flags_t {
cOrientationFlagXFlipped = 1,
cOrientationFlagYFlipped = 2,
cDefaultOrientationFlags = 0
};
cDefaultOrientationFlags = 0
};
enum unpack_flags_t
{
cUnpackFlagUncook = 1,
cUnpackFlagUnflip = 2
};
enum unpack_flags_t {
cUnpackFlagUncook = 1,
cUnpackFlagUnflip = 2
};
class mip_level
{
friend class mipmapped_texture;
class mip_level {
friend class mipmapped_texture;
public:
mip_level();
~mip_level();
public:
mip_level();
~mip_level();
mip_level(const mip_level& other);
mip_level& operator= (const mip_level& rhs);
mip_level(const mip_level& other);
mip_level& operator=(const mip_level& rhs);
// Assumes ownership.
void assign(image_u8* p, pixel_format fmt = PIXEL_FMT_INVALID, orientation_flags_t orient_flags = cDefaultOrientationFlags);
void assign(dxt_image* p, pixel_format fmt = PIXEL_FMT_INVALID, orientation_flags_t orient_flags = cDefaultOrientationFlags);
// Assumes ownership.
void assign(image_u8* p, pixel_format fmt = PIXEL_FMT_INVALID, orientation_flags_t orient_flags = cDefaultOrientationFlags);
void assign(dxt_image* p, pixel_format fmt = PIXEL_FMT_INVALID, orientation_flags_t orient_flags = cDefaultOrientationFlags);
void clear();
void clear();
inline uint get_width() const { return m_width; }
inline uint get_height() const { return m_height; }
inline uint get_total_pixels() const { return m_width * m_height; }
orientation_flags_t get_orientation_flags() const { return m_orient_flags; }
void set_orientation_flags(orientation_flags_t flags) { m_orient_flags = flags; }
inline uint get_width() const { return m_width; }
inline uint get_height() const { return m_height; }
inline uint get_total_pixels() const { return m_width * m_height; }
inline image_u8* get_image() const { return m_pImage; }
inline dxt_image* get_dxt_image() const { return m_pDXTImage; }
image_u8* get_unpacked_image(image_u8& tmp, uint unpack_flags) const;
orientation_flags_t get_orientation_flags() const { return m_orient_flags; }
void set_orientation_flags(orientation_flags_t flags) { m_orient_flags = flags; }
inline bool is_packed() const { return m_pDXTImage != NULL; }
inline image_u8* get_image() const { return m_pImage; }
inline dxt_image* get_dxt_image() const { return m_pDXTImage; }
inline bool is_valid() const { return (m_pImage != NULL) || (m_pDXTImage != NULL); }
image_u8* get_unpacked_image(image_u8& tmp, uint unpack_flags) const;
inline pixel_format_helpers::component_flags get_comp_flags() const { return m_comp_flags; }
inline void set_comp_flags(pixel_format_helpers::component_flags comp_flags) { m_comp_flags = comp_flags; }
inline bool is_packed() const { return m_pDXTImage != NULL; }
inline pixel_format get_format() const { return m_format; }
inline void set_format(pixel_format fmt) { m_format = fmt; }
inline bool is_valid() const { return (m_pImage != NULL) || (m_pDXTImage != NULL); }
bool convert(pixel_format fmt, bool cook, const dxt_image::pack_params& p);
inline pixel_format_helpers::component_flags get_comp_flags() const { return m_comp_flags; }
inline void set_comp_flags(pixel_format_helpers::component_flags comp_flags) { m_comp_flags = comp_flags; }
bool pack_to_dxt(const image_u8& img, pixel_format fmt, bool cook, const dxt_image::pack_params& p, orientation_flags_t orient_flags = cDefaultOrientationFlags);
bool pack_to_dxt(pixel_format fmt, bool cook, const dxt_image::pack_params& p);
inline pixel_format get_format() const { return m_format; }
inline void set_format(pixel_format fmt) { m_format = fmt; }
bool unpack_from_dxt(bool uncook = true);
bool convert(pixel_format fmt, bool cook, const dxt_image::pack_params& p);
// Returns true if flipped on either axis.
bool is_flipped() const;
bool is_x_flipped() const;
bool is_y_flipped() const;
bool can_unflip_without_unpacking() const;
// Returns true if unflipped on either axis.
// Will try to flip packed (DXT/ETC) data in-place, if this isn't possible it'll unpack/uncook the mip level then unflip.
bool unflip(bool allow_unpacking_to_flip, bool uncook_during_unpack);
bool set_alpha_to_luma();
bool convert(image_utils::conversion_type conv_type);
bool pack_to_dxt(const image_u8& img, pixel_format fmt, bool cook, const dxt_image::pack_params& p, orientation_flags_t orient_flags = cDefaultOrientationFlags);
bool pack_to_dxt(pixel_format fmt, bool cook, const dxt_image::pack_params& p);
bool flip_x();
bool flip_y();
bool unpack_from_dxt(bool uncook = true);
private:
uint m_width;
uint m_height;
// Returns true if flipped on either axis.
bool is_flipped() const;
pixel_format_helpers::component_flags m_comp_flags;
pixel_format m_format;
bool is_x_flipped() const;
bool is_y_flipped() const;
image_u8* m_pImage;
dxt_image* m_pDXTImage;
bool can_unflip_without_unpacking() const;
orientation_flags_t m_orient_flags;
// Returns true if unflipped on either axis.
// Will try to flip packed (DXT/ETC) data in-place, if this isn't possible it'll unpack/uncook the mip level then unflip.
bool unflip(bool allow_unpacking_to_flip, bool uncook_during_unpack);
void cook_image(image_u8& img) const;
void uncook_image(image_u8& img) const;
};
bool set_alpha_to_luma();
bool convert(image_utils::conversion_type conv_type);
// A face is an array of mip_level ptr's.
typedef crnlib::vector<mip_level*> mip_ptr_vec;
bool flip_x();
bool flip_y();
// And an array of one, six, or N faces make up a texture.
typedef crnlib::vector<mip_ptr_vec> face_vec;
private:
uint m_width;
uint m_height;
class mipmapped_texture
{
public:
// Construction/destruction
mipmapped_texture();
~mipmapped_texture();
pixel_format_helpers::component_flags m_comp_flags;
pixel_format m_format;
mipmapped_texture(const mipmapped_texture& other);
mipmapped_texture& operator= (const mipmapped_texture& rhs);
image_u8* m_pImage;
dxt_image* m_pDXTImage;
void clear();
orientation_flags_t m_orient_flags;
void init(uint width, uint height, uint levels, uint faces, pixel_format fmt, const char* pName, orientation_flags_t orient_flags);
void cook_image(image_u8& img) const;
void uncook_image(image_u8& img) const;
};
// Assumes ownership.
void assign(face_vec& faces);
void assign(mip_level* pLevel);
void assign(image_u8* p, pixel_format fmt = PIXEL_FMT_INVALID, orientation_flags_t orient_flags = cDefaultOrientationFlags);
void assign(dxt_image* p, pixel_format fmt = PIXEL_FMT_INVALID, orientation_flags_t orient_flags = cDefaultOrientationFlags);
// A face is an array of mip_level ptr's.
typedef crnlib::vector<mip_level*> mip_ptr_vec;
void set(texture_file_types::format source_file_type, const mipmapped_texture& mipmapped_texture);
// And an array of one, six, or N faces make up a texture.
typedef crnlib::vector<mip_ptr_vec> face_vec;
// Accessors
image_u8* get_level_image(uint face, uint level, image_u8& img, uint unpack_flags = cUnpackFlagUncook | cUnpackFlagUnflip) const;
class mipmapped_texture {
public:
// Construction/destruction
mipmapped_texture();
~mipmapped_texture();
inline bool is_valid() const { return m_faces.size() > 0; }
const dynamic_string& get_name() const { return m_name; }
void set_name(const dynamic_string& name) { m_name = name; }
const dynamic_string& get_source_filename() const { return get_name(); }
texture_file_types::format get_source_file_type() const { return m_source_file_type; }
inline uint get_width() const { return m_width; }
inline uint get_height() const { return m_height; }
inline uint get_total_pixels() const { return m_width * m_height; }
uint get_total_pixels_in_all_faces_and_mips() const;
mipmapped_texture(const mipmapped_texture& other);
mipmapped_texture& operator=(const mipmapped_texture& rhs);
inline uint get_num_faces() const { return m_faces.size(); }
inline uint get_num_levels() const { if (m_faces.empty()) return 0; else return m_faces[0].size(); }
void clear();
inline pixel_format_helpers::component_flags get_comp_flags() const { return m_comp_flags; }
inline pixel_format get_format() const { return m_format; }
void init(uint width, uint height, uint levels, uint faces, pixel_format fmt, const char* pName, orientation_flags_t orient_flags);
inline bool is_unpacked() const { if (get_num_faces()) { return get_level(0, 0)->get_image() != NULL; } return false; }
// Assumes ownership.
void assign(face_vec& faces);
void assign(mip_level* pLevel);
void assign(image_u8* p, pixel_format fmt = PIXEL_FMT_INVALID, orientation_flags_t orient_flags = cDefaultOrientationFlags);
void assign(dxt_image* p, pixel_format fmt = PIXEL_FMT_INVALID, orientation_flags_t orient_flags = cDefaultOrientationFlags);
inline const mip_ptr_vec& get_face(uint face) const { return m_faces[face]; }
inline mip_ptr_vec& get_face(uint face) { return m_faces[face]; }
inline const mip_level* get_level(uint face, uint mip) const { return m_faces[face][mip]; }
inline mip_level* get_level(uint face, uint mip) { return m_faces[face][mip]; }
bool has_alpha() const;
bool is_normal_map() const;
bool is_vertical_cross() const;
bool is_packed() const;
texture_type determine_texture_type() const;
const dynamic_string& get_last_error() const { return m_last_error; }
void clear_last_error() { m_last_error.clear(); }
// Reading/writing
bool read_dds(data_stream_serializer& serializer);
bool write_dds(data_stream_serializer& serializer) const;
bool read_ktx(data_stream_serializer& serializer);
bool write_ktx(data_stream_serializer& serializer) const;
bool read_crn(data_stream_serializer& serializer);
bool read_crn_from_memory(const void *pData, uint data_size, const char* pFilename);
// If file_format is texture_file_types::cFormatInvalid, the format will be determined from the filename's extension.
bool read_from_file(const char* pFilename, texture_file_types::format file_format = texture_file_types::cFormatInvalid);
bool read_from_stream(data_stream_serializer& serializer, texture_file_types::format file_format = texture_file_types::cFormatInvalid);
bool write_to_file(
const char* pFilename,
texture_file_types::format file_format = texture_file_types::cFormatInvalid,
crn_comp_params* pComp_params = NULL,
uint32* pActual_quality_level = NULL, float* pActual_bitrate = NULL,
uint32 image_write_flags = 0);
// Conversion
bool convert(pixel_format fmt, bool cook, const dxt_image::pack_params& p);
bool convert(pixel_format fmt, const dxt_image::pack_params& p);
bool convert(pixel_format fmt, bool cook, const dxt_image::pack_params& p, int qdxt_quality, bool hierarchical = true);
bool convert(image_utils::conversion_type conv_type);
bool unpack_from_dxt(bool uncook = true);
bool set_alpha_to_luma();
void discard_mipmaps();
void discard_mips();
struct resample_params
{
resample_params() :
m_pFilter("kaiser"),
m_wrapping(false),
m_srgb(false),
m_renormalize(false),
m_filter_scale(.9f),
m_gamma(1.75f), // or 2.2f
m_multithreaded(true)
{
}
const char* m_pFilter;
bool m_wrapping;
bool m_srgb;
bool m_renormalize;
float m_filter_scale;
float m_gamma;
bool m_multithreaded;
};
bool resize(uint new_width, uint new_height, const resample_params& params);
struct generate_mipmap_params : public resample_params
{
generate_mipmap_params() :
resample_params(),
m_min_mip_size(1),
m_max_mips(0)
{
}
uint m_min_mip_size;
uint m_max_mips; // actually the max # of total levels
};
bool generate_mipmaps(const generate_mipmap_params& params, bool force);
bool crop(uint x, uint y, uint width, uint height);
bool vertical_cross_to_cubemap();
// Low-level clustered DXT (QDXT) compression
struct qdxt_state
{
qdxt_state(task_pool& tp) : m_fmt(PIXEL_FMT_INVALID), m_qdxt1(tp), m_qdxt5a(tp), m_qdxt5b(tp)
{
}
pixel_format m_fmt;
qdxt1 m_qdxt1;
qdxt5 m_qdxt5a;
qdxt5 m_qdxt5b;
crnlib::vector<dxt_pixel_block> m_pixel_blocks;
qdxt1_params m_qdxt1_params;
qdxt5_params m_qdxt5_params[2];
bool m_has_blocks[3];
void clear()
{
m_fmt = PIXEL_FMT_INVALID;
m_qdxt1.clear();
m_qdxt5a.clear();
m_qdxt5b.clear();
m_pixel_blocks.clear();
m_qdxt1_params.clear();
m_qdxt5_params[0].clear();
m_qdxt5_params[1].clear();
utils::zero_object(m_has_blocks);
}
};
bool qdxt_pack_init(qdxt_state& state, mipmapped_texture& dst_tex, const qdxt1_params& dxt1_params, const qdxt5_params& dxt5_params, pixel_format fmt, bool cook);
bool qdxt_pack(qdxt_state& state, mipmapped_texture& dst_tex, const qdxt1_params& dxt1_params, const qdxt5_params& dxt5_params);
void swap(mipmapped_texture& img);
bool check() const;
void set_orientation_flags(orientation_flags_t flags);
// Returns true if any face/miplevel is flipped.
bool is_flipped() const;
bool is_x_flipped() const;
bool is_y_flipped() const;
bool can_unflip_without_unpacking() const;
bool unflip(bool allow_unpacking_to_flip, bool uncook_if_necessary_to_unpack);
bool flip_y(bool update_orientation_flags);
private:
dynamic_string m_name;
uint m_width;
uint m_height;
pixel_format_helpers::component_flags m_comp_flags;
pixel_format m_format;
face_vec m_faces;
texture_file_types::format m_source_file_type;
mutable dynamic_string m_last_error;
inline void clear_last_error() const { m_last_error.clear(); }
inline void set_last_error(const char* p) const { m_last_error = p; }
void free_all_mips();
bool read_regular_image(data_stream_serializer &serializer, texture_file_types::format file_format);
bool write_regular_image(const char* pFilename, uint32 image_write_flags);
bool read_dds_internal(data_stream_serializer& serializer);
void print_crn_comp_params(const crn_comp_params& p);
bool write_comp_texture(const char* pFilename, const crn_comp_params &comp_params, uint32 *pActual_quality_level, float *pActual_bitrate);
void change_dxt1_to_dxt1a();
bool flip_y_helper();
};
inline void swap(mipmapped_texture& a, mipmapped_texture& b)
{
a.swap(b);
}
} // namespace crnlib
void set(texture_file_types::format source_file_type, const mipmapped_texture& mipmapped_texture);
// Accessors
image_u8* get_level_image(uint face, uint level, image_u8& img, uint unpack_flags = cUnpackFlagUncook | cUnpackFlagUnflip) const;
inline bool is_valid() const { return m_faces.size() > 0; }
const dynamic_string& get_name() const { return m_name; }
void set_name(const dynamic_string& name) { m_name = name; }
const dynamic_string& get_source_filename() const { return get_name(); }
texture_file_types::format get_source_file_type() const { return m_source_file_type; }
inline uint get_width() const { return m_width; }
inline uint get_height() const { return m_height; }
inline uint get_total_pixels() const { return m_width * m_height; }
uint get_total_pixels_in_all_faces_and_mips() const;
inline uint get_num_faces() const { return m_faces.size(); }
inline uint get_num_levels() const {
if (m_faces.empty())
return 0;
else
return m_faces[0].size();
}
inline pixel_format_helpers::component_flags get_comp_flags() const { return m_comp_flags; }
inline pixel_format get_format() const { return m_format; }
inline bool is_unpacked() const {
if (get_num_faces()) {
return get_level(0, 0)->get_image() != NULL;
}
return false;
}
inline const mip_ptr_vec& get_face(uint face) const { return m_faces[face]; }
inline mip_ptr_vec& get_face(uint face) { return m_faces[face]; }
inline const mip_level* get_level(uint face, uint mip) const { return m_faces[face][mip]; }
inline mip_level* get_level(uint face, uint mip) { return m_faces[face][mip]; }
bool has_alpha() const;
bool is_normal_map() const;
bool is_vertical_cross() const;
bool is_packed() const;
texture_type determine_texture_type() const;
const dynamic_string& get_last_error() const { return m_last_error; }
void clear_last_error() { m_last_error.clear(); }
// Reading/writing
bool read_dds(data_stream_serializer& serializer);
bool write_dds(data_stream_serializer& serializer) const;
bool read_ktx(data_stream_serializer& serializer);
bool write_ktx(data_stream_serializer& serializer) const;
bool read_crn(data_stream_serializer& serializer);
bool read_crn_from_memory(const void* pData, uint data_size, const char* pFilename);
// If file_format is texture_file_types::cFormatInvalid, the format will be determined from the filename's extension.
bool read_from_file(const char* pFilename, texture_file_types::format file_format = texture_file_types::cFormatInvalid);
bool read_from_stream(data_stream_serializer& serializer, texture_file_types::format file_format = texture_file_types::cFormatInvalid);
bool write_to_file(
const char* pFilename,
texture_file_types::format file_format = texture_file_types::cFormatInvalid,
crn_comp_params* pComp_params = NULL,
uint32* pActual_quality_level = NULL, float* pActual_bitrate = NULL,
uint32 image_write_flags = 0);
// Conversion
bool convert(pixel_format fmt, bool cook, const dxt_image::pack_params& p);
bool convert(pixel_format fmt, const dxt_image::pack_params& p);
bool convert(pixel_format fmt, bool cook, const dxt_image::pack_params& p, int qdxt_quality, bool hierarchical = true);
bool convert(image_utils::conversion_type conv_type);
bool unpack_from_dxt(bool uncook = true);
bool set_alpha_to_luma();
void discard_mipmaps();
void discard_mips();
struct resample_params {
resample_params()
: m_pFilter("kaiser"),
m_wrapping(false),
m_srgb(false),
m_renormalize(false),
m_filter_scale(.9f),
m_gamma(1.75f), // or 2.2f
m_multithreaded(true) {
}
const char* m_pFilter;
bool m_wrapping;
bool m_srgb;
bool m_renormalize;
float m_filter_scale;
float m_gamma;
bool m_multithreaded;
};
bool resize(uint new_width, uint new_height, const resample_params& params);
struct generate_mipmap_params : public resample_params {
generate_mipmap_params()
: resample_params(),
m_min_mip_size(1),
m_max_mips(0) {
}
uint m_min_mip_size;
uint m_max_mips; // actually the max # of total levels
};
bool generate_mipmaps(const generate_mipmap_params& params, bool force);
bool crop(uint x, uint y, uint width, uint height);
bool vertical_cross_to_cubemap();
// Low-level clustered DXT (QDXT) compression
struct qdxt_state {
qdxt_state(task_pool& tp)
: m_fmt(PIXEL_FMT_INVALID), m_qdxt1(tp), m_qdxt5a(tp), m_qdxt5b(tp) {
}
pixel_format m_fmt;
qdxt1 m_qdxt1;
qdxt5 m_qdxt5a;
qdxt5 m_qdxt5b;
crnlib::vector<dxt_pixel_block> m_pixel_blocks;
qdxt1_params m_qdxt1_params;
qdxt5_params m_qdxt5_params[2];
bool m_has_blocks[3];
void clear() {
m_fmt = PIXEL_FMT_INVALID;
m_qdxt1.clear();
m_qdxt5a.clear();
m_qdxt5b.clear();
m_pixel_blocks.clear();
m_qdxt1_params.clear();
m_qdxt5_params[0].clear();
m_qdxt5_params[1].clear();
utils::zero_object(m_has_blocks);
}
};
bool qdxt_pack_init(qdxt_state& state, mipmapped_texture& dst_tex, const qdxt1_params& dxt1_params, const qdxt5_params& dxt5_params, pixel_format fmt, bool cook);
bool qdxt_pack(qdxt_state& state, mipmapped_texture& dst_tex, const qdxt1_params& dxt1_params, const qdxt5_params& dxt5_params);
void swap(mipmapped_texture& img);
bool check() const;
void set_orientation_flags(orientation_flags_t flags);
// Returns true if any face/miplevel is flipped.
bool is_flipped() const;
bool is_x_flipped() const;
bool is_y_flipped() const;
bool can_unflip_without_unpacking() const;
bool unflip(bool allow_unpacking_to_flip, bool uncook_if_necessary_to_unpack);
bool flip_y(bool update_orientation_flags);
private:
dynamic_string m_name;
uint m_width;
uint m_height;
pixel_format_helpers::component_flags m_comp_flags;
pixel_format m_format;
face_vec m_faces;
texture_file_types::format m_source_file_type;
mutable dynamic_string m_last_error;
inline void clear_last_error() const { m_last_error.clear(); }
inline void set_last_error(const char* p) const { m_last_error = p; }
void free_all_mips();
bool read_regular_image(data_stream_serializer& serializer, texture_file_types::format file_format);
bool write_regular_image(const char* pFilename, uint32 image_write_flags);
bool read_dds_internal(data_stream_serializer& serializer);
void print_crn_comp_params(const crn_comp_params& p);
bool write_comp_texture(const char* pFilename, const crn_comp_params& comp_params, uint32* pActual_quality_level, float* pActual_bitrate);
void change_dxt1_to_dxt1a();
bool flip_y_helper();
};
inline void swap(mipmapped_texture& a, mipmapped_texture& b) {
a.swap(b);
}
} // namespace crnlib
+65 -77
View File
@@ -2,90 +2,78 @@
// See Copyright Notice and license at the end of inc/crnlib.h
#pragma once
namespace crnlib
{
template<unsigned int N>
struct packed_uint
{
inline packed_uint() { }
namespace crnlib {
template <unsigned int N>
struct packed_uint {
inline packed_uint() {}
inline packed_uint(unsigned int val) { *this = val; }
inline packed_uint(unsigned int val) { *this = val; }
inline packed_uint(const packed_uint& other) { *this = other; }
inline packed_uint(const packed_uint& other) { *this = other; }
inline packed_uint& operator= (const packed_uint& rhs)
{
if (this != &rhs)
memcpy(m_buf, rhs.m_buf, sizeof(m_buf));
return *this;
}
inline packed_uint& operator=(const packed_uint& rhs) {
if (this != &rhs)
memcpy(m_buf, rhs.m_buf, sizeof(m_buf));
return *this;
}
inline packed_uint& operator= (unsigned int val)
{
inline packed_uint& operator=(unsigned int val) {
#ifdef CRNLIB_BUILD_DEBUG
if (N == 1)
{
CRNLIB_ASSERT(val <= 0xFFU);
}
else if (N == 2)
{
CRNLIB_ASSERT(val <= 0xFFFFU);
}
else if (N == 3)
{
CRNLIB_ASSERT(val <= 0xFFFFFFU);
}
#endif
val <<= (8U * (4U - N));
if (N == 1) {
CRNLIB_ASSERT(val <= 0xFFU);
} else if (N == 2) {
CRNLIB_ASSERT(val <= 0xFFFFU);
} else if (N == 3) {
CRNLIB_ASSERT(val <= 0xFFFFFFU);
}
#endif
for (unsigned int i = 0; i < N; i++)
{
m_buf[i] = static_cast<unsigned char>(val >> 24U);
val <<= 8U;
}
val <<= (8U * (4U - N));
return *this;
}
for (unsigned int i = 0; i < N; i++) {
m_buf[i] = static_cast<unsigned char>(val >> 24U);
val <<= 8U;
}
inline operator unsigned int() const
{
switch (N)
{
case 1: return m_buf[0];
case 2: return (m_buf[0] << 8U) | m_buf[1];
case 3: return (m_buf[0] << 16U) | (m_buf[1] << 8U) | (m_buf[2]);
default: return (m_buf[0] << 24U) | (m_buf[1] << 16U) | (m_buf[2] << 8U) | (m_buf[3]);
}
}
return *this;
}
unsigned char m_buf[N];
};
template<typename T>
class packed_value
{
public:
packed_value() { }
packed_value(T val) { *this = val; }
inline operator unsigned int() const {
switch (N) {
case 1:
return m_buf[0];
case 2:
return (m_buf[0] << 8U) | m_buf[1];
case 3:
return (m_buf[0] << 16U) | (m_buf[1] << 8U) | (m_buf[2]);
default:
return (m_buf[0] << 24U) | (m_buf[1] << 16U) | (m_buf[2] << 8U) | (m_buf[3]);
}
}
inline operator T() const
{
T result = 0;
for (int i = sizeof(T) - 1; i >= 0; i--)
result = static_cast<T>((result << 8) | m_bytes[i]);
return result;
}
packed_value& operator= (T val)
{
for (int i = 0; i < sizeof(T); i++)
{
m_bytes[i] = static_cast<uint8>(val);
val >>= 8;
}
return *this;
}
private:
uint8 m_bytes[sizeof(T)];
};
} // namespace crnlib
unsigned char m_buf[N];
};
template <typename T>
class packed_value {
public:
packed_value() {}
packed_value(T val) { *this = val; }
inline operator T() const {
T result = 0;
for (int i = sizeof(T) - 1; i >= 0; i--)
result = static_cast<T>((result << 8) | m_bytes[i]);
return result;
}
packed_value& operator=(T val) {
for (int i = 0; i < sizeof(T); i++) {
m_bytes[i] = static_cast<uint8>(val);
val >>= 8;
}
return *this;
}
private:
uint8 m_bytes[sizeof(T)];
};
} // namespace crnlib
+272 -263
View File
@@ -4,277 +4,286 @@
#include "crn_pixel_format.h"
#include "crn_image.h"
namespace crnlib
{
namespace pixel_format_helpers
{
const pixel_format g_all_pixel_formats[] =
{
PIXEL_FMT_DXT1,
PIXEL_FMT_DXT2,
PIXEL_FMT_DXT3,
PIXEL_FMT_DXT4,
PIXEL_FMT_DXT5,
PIXEL_FMT_3DC,
PIXEL_FMT_DXN,
PIXEL_FMT_DXT5A,
PIXEL_FMT_DXT5_CCxY,
PIXEL_FMT_DXT5_xGxR,
PIXEL_FMT_DXT5_xGBR,
PIXEL_FMT_DXT5_AGBR,
PIXEL_FMT_DXT1A,
PIXEL_FMT_ETC1,
PIXEL_FMT_R8G8B8,
PIXEL_FMT_L8,
PIXEL_FMT_A8,
PIXEL_FMT_A8L8,
PIXEL_FMT_A8R8G8B8
};
namespace crnlib {
namespace pixel_format_helpers {
const pixel_format g_all_pixel_formats[] =
{
PIXEL_FMT_DXT1,
PIXEL_FMT_DXT2,
PIXEL_FMT_DXT3,
PIXEL_FMT_DXT4,
PIXEL_FMT_DXT5,
PIXEL_FMT_3DC,
PIXEL_FMT_DXN,
PIXEL_FMT_DXT5A,
PIXEL_FMT_DXT5_CCxY,
PIXEL_FMT_DXT5_xGxR,
PIXEL_FMT_DXT5_xGBR,
PIXEL_FMT_DXT5_AGBR,
PIXEL_FMT_DXT1A,
PIXEL_FMT_ETC1,
PIXEL_FMT_R8G8B8,
PIXEL_FMT_L8,
PIXEL_FMT_A8,
PIXEL_FMT_A8L8,
PIXEL_FMT_A8R8G8B8};
uint get_num_formats()
{
return sizeof(g_all_pixel_formats) / sizeof(g_all_pixel_formats[0]);
}
uint get_num_formats() {
return sizeof(g_all_pixel_formats) / sizeof(g_all_pixel_formats[0]);
}
pixel_format get_pixel_format_by_index(uint index)
{
CRNLIB_ASSERT(index < get_num_formats());
return g_all_pixel_formats[index];
}
pixel_format get_pixel_format_by_index(uint index) {
CRNLIB_ASSERT(index < get_num_formats());
return g_all_pixel_formats[index];
}
const char* get_pixel_format_string(pixel_format fmt)
{
switch (fmt)
{
case PIXEL_FMT_INVALID: return "INVALID";
case PIXEL_FMT_DXT1: return "DXT1";
case PIXEL_FMT_DXT1A: return "DXT1A";
case PIXEL_FMT_DXT2: return "DXT2";
case PIXEL_FMT_DXT3: return "DXT3";
case PIXEL_FMT_DXT4: return "DXT4";
case PIXEL_FMT_DXT5: return "DXT5";
case PIXEL_FMT_3DC: return "3DC";
case PIXEL_FMT_DXN: return "DXN";
case PIXEL_FMT_DXT5A: return "DXT5A";
case PIXEL_FMT_DXT5_CCxY: return "DXT5_CCxY";
case PIXEL_FMT_DXT5_xGxR: return "DXT5_xGxR";
case PIXEL_FMT_DXT5_xGBR: return "DXT5_xGBR";
case PIXEL_FMT_DXT5_AGBR: return "DXT5_AGBR";
case PIXEL_FMT_ETC1: return "ETC1";
case PIXEL_FMT_R8G8B8: return "R8G8B8";
case PIXEL_FMT_A8R8G8B8: return "A8R8G8B8";
case PIXEL_FMT_A8: return "A8";
case PIXEL_FMT_L8: return "L8";
case PIXEL_FMT_A8L8: return "A8L8";
default: break;
}
CRNLIB_ASSERT(false);
return "?";
}
const char* get_pixel_format_string(pixel_format fmt) {
switch (fmt) {
case PIXEL_FMT_INVALID:
return "INVALID";
case PIXEL_FMT_DXT1:
return "DXT1";
case PIXEL_FMT_DXT1A:
return "DXT1A";
case PIXEL_FMT_DXT2:
return "DXT2";
case PIXEL_FMT_DXT3:
return "DXT3";
case PIXEL_FMT_DXT4:
return "DXT4";
case PIXEL_FMT_DXT5:
return "DXT5";
case PIXEL_FMT_3DC:
return "3DC";
case PIXEL_FMT_DXN:
return "DXN";
case PIXEL_FMT_DXT5A:
return "DXT5A";
case PIXEL_FMT_DXT5_CCxY:
return "DXT5_CCxY";
case PIXEL_FMT_DXT5_xGxR:
return "DXT5_xGxR";
case PIXEL_FMT_DXT5_xGBR:
return "DXT5_xGBR";
case PIXEL_FMT_DXT5_AGBR:
return "DXT5_AGBR";
case PIXEL_FMT_ETC1:
return "ETC1";
case PIXEL_FMT_R8G8B8:
return "R8G8B8";
case PIXEL_FMT_A8R8G8B8:
return "A8R8G8B8";
case PIXEL_FMT_A8:
return "A8";
case PIXEL_FMT_L8:
return "L8";
case PIXEL_FMT_A8L8:
return "A8L8";
default:
break;
}
CRNLIB_ASSERT(false);
return "?";
}
const char* get_crn_format_string(crn_format fmt)
{
switch (fmt)
{
case cCRNFmtDXT1: return "DXT1";
case cCRNFmtDXT3: return "DXT3";
case cCRNFmtDXT5: return "DXT5";
case cCRNFmtDXT5_CCxY: return "DXT5_CCxY";
case cCRNFmtDXT5_xGBR: return "DXT5_xGBR";
case cCRNFmtDXT5_AGBR: return "DXT5_AGBR";
case cCRNFmtDXT5_xGxR: return "DXT5_xGxR";
case cCRNFmtDXN_XY: return "DXN_XY";
case cCRNFmtDXN_YX: return "DXN_YX";
case cCRNFmtDXT5A: return "DXT5A";
case cCRNFmtETC1: return "ETC1";
default: break;
}
CRNLIB_ASSERT(false);
return "?";
}
const char* get_crn_format_string(crn_format fmt) {
switch (fmt) {
case cCRNFmtDXT1:
return "DXT1";
case cCRNFmtDXT3:
return "DXT3";
case cCRNFmtDXT5:
return "DXT5";
case cCRNFmtDXT5_CCxY:
return "DXT5_CCxY";
case cCRNFmtDXT5_xGBR:
return "DXT5_xGBR";
case cCRNFmtDXT5_AGBR:
return "DXT5_AGBR";
case cCRNFmtDXT5_xGxR:
return "DXT5_xGxR";
case cCRNFmtDXN_XY:
return "DXN_XY";
case cCRNFmtDXN_YX:
return "DXN_YX";
case cCRNFmtDXT5A:
return "DXT5A";
case cCRNFmtETC1:
return "ETC1";
default:
break;
}
CRNLIB_ASSERT(false);
return "?";
}
component_flags get_component_flags(pixel_format fmt)
{
// These flags are for *uncooked* pixels, i.e. after after adding Z to DXN maps, or converting YCC maps to RGB, etc.
component_flags get_component_flags(pixel_format fmt) {
// These flags are for *uncooked* pixels, i.e. after after adding Z to DXN maps, or converting YCC maps to RGB, etc.
uint flags = cCompFlagRValid | cCompFlagGValid | cCompFlagBValid | cCompFlagAValid | cCompFlagGrayscale;
switch (fmt)
{
case PIXEL_FMT_DXT1:
case PIXEL_FMT_ETC1:
{
flags = cCompFlagRValid | cCompFlagGValid | cCompFlagBValid;
break;
}
case PIXEL_FMT_DXT1A:
{
flags = cCompFlagRValid | cCompFlagGValid | cCompFlagBValid | cCompFlagAValid;
break;
}
case PIXEL_FMT_DXT2:
case PIXEL_FMT_DXT3:
{
flags = cCompFlagRValid | cCompFlagGValid | cCompFlagBValid | cCompFlagAValid;
break;
}
case PIXEL_FMT_DXT4:
case PIXEL_FMT_DXT5:
{
flags = cCompFlagRValid | cCompFlagGValid | cCompFlagBValid | cCompFlagAValid;
break;
}
case PIXEL_FMT_DXT5A:
{
flags = cCompFlagAValid;
break;
}
case PIXEL_FMT_DXT5_CCxY:
{
flags = cCompFlagRValid | cCompFlagGValid | cCompFlagBValid | cCompFlagLumaChroma;
break;
}
case PIXEL_FMT_DXT5_xGBR:
{
flags = cCompFlagRValid | cCompFlagGValid | cCompFlagBValid | cCompFlagNormalMap;
break;
}
case PIXEL_FMT_DXT5_AGBR:
{
flags = cCompFlagRValid | cCompFlagGValid | cCompFlagBValid | cCompFlagAValid | cCompFlagNormalMap;
break;
}
case PIXEL_FMT_DXT5_xGxR:
{
flags = cCompFlagRValid | cCompFlagGValid | cCompFlagBValid | cCompFlagNormalMap;
break;
}
case PIXEL_FMT_3DC:
{
flags = cCompFlagRValid | cCompFlagGValid | cCompFlagBValid | cCompFlagNormalMap;
break;
}
case PIXEL_FMT_DXN:
{
flags = cCompFlagRValid | cCompFlagGValid | cCompFlagBValid | cCompFlagNormalMap;
break;
}
case PIXEL_FMT_R8G8B8:
{
flags = cCompFlagRValid | cCompFlagGValid | cCompFlagBValid;
break;
}
case PIXEL_FMT_A8R8G8B8:
{
flags = cCompFlagRValid | cCompFlagGValid | cCompFlagBValid | cCompFlagAValid;
break;
}
case PIXEL_FMT_A8:
{
flags = cCompFlagAValid;
break;
}
case PIXEL_FMT_L8:
{
flags = cCompFlagRValid | cCompFlagGValid | cCompFlagBValid | cCompFlagGrayscale;
break;
}
case PIXEL_FMT_A8L8:
{
flags = cCompFlagRValid | cCompFlagGValid | cCompFlagBValid | cCompFlagAValid | cCompFlagGrayscale;
break;
}
default:
{
CRNLIB_ASSERT(0);
break;
}
}
return static_cast<component_flags>(flags);
}
uint flags = cCompFlagRValid | cCompFlagGValid | cCompFlagBValid | cCompFlagAValid | cCompFlagGrayscale;
switch (fmt) {
case PIXEL_FMT_DXT1:
case PIXEL_FMT_ETC1: {
flags = cCompFlagRValid | cCompFlagGValid | cCompFlagBValid;
break;
}
case PIXEL_FMT_DXT1A: {
flags = cCompFlagRValid | cCompFlagGValid | cCompFlagBValid | cCompFlagAValid;
break;
}
case PIXEL_FMT_DXT2:
case PIXEL_FMT_DXT3: {
flags = cCompFlagRValid | cCompFlagGValid | cCompFlagBValid | cCompFlagAValid;
break;
}
case PIXEL_FMT_DXT4:
case PIXEL_FMT_DXT5: {
flags = cCompFlagRValid | cCompFlagGValid | cCompFlagBValid | cCompFlagAValid;
break;
}
case PIXEL_FMT_DXT5A: {
flags = cCompFlagAValid;
break;
}
case PIXEL_FMT_DXT5_CCxY: {
flags = cCompFlagRValid | cCompFlagGValid | cCompFlagBValid | cCompFlagLumaChroma;
break;
}
case PIXEL_FMT_DXT5_xGBR: {
flags = cCompFlagRValid | cCompFlagGValid | cCompFlagBValid | cCompFlagNormalMap;
break;
}
case PIXEL_FMT_DXT5_AGBR: {
flags = cCompFlagRValid | cCompFlagGValid | cCompFlagBValid | cCompFlagAValid | cCompFlagNormalMap;
break;
}
case PIXEL_FMT_DXT5_xGxR: {
flags = cCompFlagRValid | cCompFlagGValid | cCompFlagBValid | cCompFlagNormalMap;
break;
}
case PIXEL_FMT_3DC: {
flags = cCompFlagRValid | cCompFlagGValid | cCompFlagBValid | cCompFlagNormalMap;
break;
}
case PIXEL_FMT_DXN: {
flags = cCompFlagRValid | cCompFlagGValid | cCompFlagBValid | cCompFlagNormalMap;
break;
}
case PIXEL_FMT_R8G8B8: {
flags = cCompFlagRValid | cCompFlagGValid | cCompFlagBValid;
break;
}
case PIXEL_FMT_A8R8G8B8: {
flags = cCompFlagRValid | cCompFlagGValid | cCompFlagBValid | cCompFlagAValid;
break;
}
case PIXEL_FMT_A8: {
flags = cCompFlagAValid;
break;
}
case PIXEL_FMT_L8: {
flags = cCompFlagRValid | cCompFlagGValid | cCompFlagBValid | cCompFlagGrayscale;
break;
}
case PIXEL_FMT_A8L8: {
flags = cCompFlagRValid | cCompFlagGValid | cCompFlagBValid | cCompFlagAValid | cCompFlagGrayscale;
break;
}
default: {
CRNLIB_ASSERT(0);
break;
}
}
return static_cast<component_flags>(flags);
}
crn_format convert_pixel_format_to_best_crn_format(pixel_format crn_fmt)
{
crn_format fmt = cCRNFmtDXT1;
switch (crn_fmt)
{
case PIXEL_FMT_DXT1:
case PIXEL_FMT_DXT1A:
fmt = cCRNFmtDXT1;
break;
case PIXEL_FMT_DXT2:
case PIXEL_FMT_DXT3:
case PIXEL_FMT_DXT4:
case PIXEL_FMT_DXT5:
fmt = cCRNFmtDXT5;
break;
case PIXEL_FMT_3DC:
fmt = cCRNFmtDXN_YX;
break;
case PIXEL_FMT_DXN:
fmt = cCRNFmtDXN_XY;
break;
case PIXEL_FMT_DXT5A:
fmt = cCRNFmtDXT5A;
break;
case PIXEL_FMT_R8G8B8:
case PIXEL_FMT_L8:
fmt = cCRNFmtDXT1;
break;
case PIXEL_FMT_A8R8G8B8:
case PIXEL_FMT_A8:
case PIXEL_FMT_A8L8:
fmt = cCRNFmtDXT5;
break;
case PIXEL_FMT_DXT5_CCxY:
fmt = cCRNFmtDXT5_CCxY;
break;
case PIXEL_FMT_DXT5_xGBR:
fmt = cCRNFmtDXT5_xGBR;
break;
case PIXEL_FMT_DXT5_AGBR:
fmt = cCRNFmtDXT5_AGBR;
break;
case PIXEL_FMT_DXT5_xGxR:
fmt = cCRNFmtDXT5_xGxR;
break;
case PIXEL_FMT_ETC1:
fmt = cCRNFmtETC1;
break;
default:
{
CRNLIB_ASSERT(false);
break;
}
}
return fmt;
}
crn_format convert_pixel_format_to_best_crn_format(pixel_format crn_fmt) {
crn_format fmt = cCRNFmtDXT1;
switch (crn_fmt) {
case PIXEL_FMT_DXT1:
case PIXEL_FMT_DXT1A:
fmt = cCRNFmtDXT1;
break;
case PIXEL_FMT_DXT2:
case PIXEL_FMT_DXT3:
case PIXEL_FMT_DXT4:
case PIXEL_FMT_DXT5:
fmt = cCRNFmtDXT5;
break;
case PIXEL_FMT_3DC:
fmt = cCRNFmtDXN_YX;
break;
case PIXEL_FMT_DXN:
fmt = cCRNFmtDXN_XY;
break;
case PIXEL_FMT_DXT5A:
fmt = cCRNFmtDXT5A;
break;
case PIXEL_FMT_R8G8B8:
case PIXEL_FMT_L8:
fmt = cCRNFmtDXT1;
break;
case PIXEL_FMT_A8R8G8B8:
case PIXEL_FMT_A8:
case PIXEL_FMT_A8L8:
fmt = cCRNFmtDXT5;
break;
case PIXEL_FMT_DXT5_CCxY:
fmt = cCRNFmtDXT5_CCxY;
break;
case PIXEL_FMT_DXT5_xGBR:
fmt = cCRNFmtDXT5_xGBR;
break;
case PIXEL_FMT_DXT5_AGBR:
fmt = cCRNFmtDXT5_AGBR;
break;
case PIXEL_FMT_DXT5_xGxR:
fmt = cCRNFmtDXT5_xGxR;
break;
case PIXEL_FMT_ETC1:
fmt = cCRNFmtETC1;
break;
default: {
CRNLIB_ASSERT(false);
break;
}
}
return fmt;
}
pixel_format convert_crn_format_to_pixel_format(crn_format fmt)
{
switch (fmt)
{
case cCRNFmtDXT1: return PIXEL_FMT_DXT1;
case cCRNFmtDXT3: return PIXEL_FMT_DXT3;
case cCRNFmtDXT5: return PIXEL_FMT_DXT5;
case cCRNFmtDXT5_CCxY: return PIXEL_FMT_DXT5_CCxY;
case cCRNFmtDXT5_xGxR: return PIXEL_FMT_DXT5_xGxR;
case cCRNFmtDXT5_xGBR: return PIXEL_FMT_DXT5_xGBR;
case cCRNFmtDXT5_AGBR: return PIXEL_FMT_DXT5_AGBR;
case cCRNFmtDXN_XY: return PIXEL_FMT_DXN;
case cCRNFmtDXN_YX: return PIXEL_FMT_3DC;
case cCRNFmtDXT5A: return PIXEL_FMT_DXT5A;
case cCRNFmtETC1: return PIXEL_FMT_ETC1;
default:
{
CRNLIB_ASSERT(false);
break;
}
}
pixel_format convert_crn_format_to_pixel_format(crn_format fmt) {
switch (fmt) {
case cCRNFmtDXT1:
return PIXEL_FMT_DXT1;
case cCRNFmtDXT3:
return PIXEL_FMT_DXT3;
case cCRNFmtDXT5:
return PIXEL_FMT_DXT5;
case cCRNFmtDXT5_CCxY:
return PIXEL_FMT_DXT5_CCxY;
case cCRNFmtDXT5_xGxR:
return PIXEL_FMT_DXT5_xGxR;
case cCRNFmtDXT5_xGBR:
return PIXEL_FMT_DXT5_xGBR;
case cCRNFmtDXT5_AGBR:
return PIXEL_FMT_DXT5_AGBR;
case cCRNFmtDXN_XY:
return PIXEL_FMT_DXN;
case cCRNFmtDXN_YX:
return PIXEL_FMT_3DC;
case cCRNFmtDXT5A:
return PIXEL_FMT_DXT5A;
case cCRNFmtETC1:
return PIXEL_FMT_ETC1;
default: {
CRNLIB_ASSERT(false);
break;
}
}
return PIXEL_FMT_INVALID;
}
return PIXEL_FMT_INVALID;
}
} // namespace pixel_format
} // namespace crnlib
} // namespace pixel_format
} // namespace crnlib
+284 -254
View File
@@ -5,280 +5,310 @@
#include "../inc/crnlib.h"
#include "../inc/dds_defs.h"
namespace crnlib
{
namespace pixel_format_helpers
{
uint get_num_formats();
pixel_format get_pixel_format_by_index(uint index);
namespace crnlib {
namespace pixel_format_helpers {
uint get_num_formats();
pixel_format get_pixel_format_by_index(uint index);
const char* get_pixel_format_string(pixel_format fmt);
const char* get_pixel_format_string(pixel_format fmt);
const char* get_crn_format_string(crn_format fmt);
const char* get_crn_format_string(crn_format fmt);
inline bool is_grayscale(pixel_format fmt)
{
switch (fmt)
{
case PIXEL_FMT_L8:
case PIXEL_FMT_A8L8:
return true;
default: break;
}
return false;
}
inline bool is_grayscale(pixel_format fmt) {
switch (fmt) {
case PIXEL_FMT_L8:
case PIXEL_FMT_A8L8:
return true;
default:
break;
}
return false;
}
inline bool is_dxt1(pixel_format fmt)
{
return (fmt == PIXEL_FMT_DXT1) || (fmt == PIXEL_FMT_DXT1A);
}
inline bool is_dxt1(pixel_format fmt) {
return (fmt == PIXEL_FMT_DXT1) || (fmt == PIXEL_FMT_DXT1A);
}
// has_alpha() should probably be called "has_opacity()" - it indicates if the format encodes opacity
// because some swizzled DXT5 formats do not encode opacity.
inline bool has_alpha(pixel_format fmt)
{
switch (fmt)
{
case PIXEL_FMT_DXT1A:
case PIXEL_FMT_DXT2:
case PIXEL_FMT_DXT3:
case PIXEL_FMT_DXT4:
case PIXEL_FMT_DXT5:
case PIXEL_FMT_DXT5A:
case PIXEL_FMT_A8R8G8B8:
case PIXEL_FMT_A8:
case PIXEL_FMT_A8L8:
case PIXEL_FMT_DXT5_AGBR:
return true;
default: break;
}
return false;
}
// has_alpha() should probably be called "has_opacity()" - it indicates if the format encodes opacity
// because some swizzled DXT5 formats do not encode opacity.
inline bool has_alpha(pixel_format fmt) {
switch (fmt) {
case PIXEL_FMT_DXT1A:
case PIXEL_FMT_DXT2:
case PIXEL_FMT_DXT3:
case PIXEL_FMT_DXT4:
case PIXEL_FMT_DXT5:
case PIXEL_FMT_DXT5A:
case PIXEL_FMT_A8R8G8B8:
case PIXEL_FMT_A8:
case PIXEL_FMT_A8L8:
case PIXEL_FMT_DXT5_AGBR:
return true;
default:
break;
}
return false;
}
inline bool is_alpha_only(pixel_format fmt)
{
switch (fmt)
{
case PIXEL_FMT_A8:
case PIXEL_FMT_DXT5A:
return true;
default: break;
}
return false;
}
inline bool is_alpha_only(pixel_format fmt) {
switch (fmt) {
case PIXEL_FMT_A8:
case PIXEL_FMT_DXT5A:
return true;
default:
break;
}
return false;
}
inline bool is_normal_map(pixel_format fmt)
{
switch (fmt)
{
case PIXEL_FMT_3DC:
case PIXEL_FMT_DXN:
case PIXEL_FMT_DXT5_xGBR:
case PIXEL_FMT_DXT5_xGxR:
case PIXEL_FMT_DXT5_AGBR:
return true;
default: break;
}
return false;
}
inline bool is_normal_map(pixel_format fmt) {
switch (fmt) {
case PIXEL_FMT_3DC:
case PIXEL_FMT_DXN:
case PIXEL_FMT_DXT5_xGBR:
case PIXEL_FMT_DXT5_xGxR:
case PIXEL_FMT_DXT5_AGBR:
return true;
default:
break;
}
return false;
}
inline int is_dxt(pixel_format fmt)
{
switch (fmt)
{
case PIXEL_FMT_DXT1:
case PIXEL_FMT_DXT1A:
case PIXEL_FMT_DXT2:
case PIXEL_FMT_DXT3:
case PIXEL_FMT_DXT4:
case PIXEL_FMT_DXT5:
case PIXEL_FMT_3DC:
case PIXEL_FMT_DXT5A:
case PIXEL_FMT_DXN:
case PIXEL_FMT_DXT5_CCxY:
case PIXEL_FMT_DXT5_xGxR:
case PIXEL_FMT_DXT5_xGBR:
case PIXEL_FMT_DXT5_AGBR:
case PIXEL_FMT_ETC1:
return true;
default: break;
}
return false;
}
inline int is_dxt(pixel_format fmt) {
switch (fmt) {
case PIXEL_FMT_DXT1:
case PIXEL_FMT_DXT1A:
case PIXEL_FMT_DXT2:
case PIXEL_FMT_DXT3:
case PIXEL_FMT_DXT4:
case PIXEL_FMT_DXT5:
case PIXEL_FMT_3DC:
case PIXEL_FMT_DXT5A:
case PIXEL_FMT_DXN:
case PIXEL_FMT_DXT5_CCxY:
case PIXEL_FMT_DXT5_xGxR:
case PIXEL_FMT_DXT5_xGBR:
case PIXEL_FMT_DXT5_AGBR:
case PIXEL_FMT_ETC1:
return true;
default:
break;
}
return false;
}
inline int get_fundamental_format(pixel_format fmt)
{
switch (fmt)
{
case PIXEL_FMT_DXT1A:
return PIXEL_FMT_DXT1;
case PIXEL_FMT_DXT5_CCxY:
case PIXEL_FMT_DXT5_xGxR:
case PIXEL_FMT_DXT5_xGBR:
case PIXEL_FMT_DXT5_AGBR:
return PIXEL_FMT_DXT5;
default: break;
}
return fmt;
}
inline int get_fundamental_format(pixel_format fmt) {
switch (fmt) {
case PIXEL_FMT_DXT1A:
return PIXEL_FMT_DXT1;
case PIXEL_FMT_DXT5_CCxY:
case PIXEL_FMT_DXT5_xGxR:
case PIXEL_FMT_DXT5_xGBR:
case PIXEL_FMT_DXT5_AGBR:
return PIXEL_FMT_DXT5;
default:
break;
}
return fmt;
}
inline dxt_format get_dxt_format(pixel_format fmt)
{
switch (fmt)
{
case PIXEL_FMT_DXT1: return cDXT1;
case PIXEL_FMT_DXT1A: return cDXT1A;
case PIXEL_FMT_DXT2: return cDXT3;
case PIXEL_FMT_DXT3: return cDXT3;
case PIXEL_FMT_DXT4: return cDXT5;
case PIXEL_FMT_DXT5: return cDXT5;
case PIXEL_FMT_3DC: return cDXN_YX;
case PIXEL_FMT_DXT5A: return cDXT5A;
case PIXEL_FMT_DXN: return cDXN_XY;
case PIXEL_FMT_DXT5_CCxY: return cDXT5;
case PIXEL_FMT_DXT5_xGxR: return cDXT5;
case PIXEL_FMT_DXT5_xGBR: return cDXT5;
case PIXEL_FMT_DXT5_AGBR: return cDXT5;
case PIXEL_FMT_ETC1: return cETC1;
default: break;
}
return cDXTInvalid;
}
inline dxt_format get_dxt_format(pixel_format fmt) {
switch (fmt) {
case PIXEL_FMT_DXT1:
return cDXT1;
case PIXEL_FMT_DXT1A:
return cDXT1A;
case PIXEL_FMT_DXT2:
return cDXT3;
case PIXEL_FMT_DXT3:
return cDXT3;
case PIXEL_FMT_DXT4:
return cDXT5;
case PIXEL_FMT_DXT5:
return cDXT5;
case PIXEL_FMT_3DC:
return cDXN_YX;
case PIXEL_FMT_DXT5A:
return cDXT5A;
case PIXEL_FMT_DXN:
return cDXN_XY;
case PIXEL_FMT_DXT5_CCxY:
return cDXT5;
case PIXEL_FMT_DXT5_xGxR:
return cDXT5;
case PIXEL_FMT_DXT5_xGBR:
return cDXT5;
case PIXEL_FMT_DXT5_AGBR:
return cDXT5;
case PIXEL_FMT_ETC1:
return cETC1;
default:
break;
}
return cDXTInvalid;
}
inline pixel_format from_dxt_format(dxt_format dxt_fmt)
{
switch (dxt_fmt)
{
case cDXT1:
return PIXEL_FMT_DXT1;
case cDXT1A:
return PIXEL_FMT_DXT1A;
case cDXT3:
return PIXEL_FMT_DXT3;
case cDXT5:
return PIXEL_FMT_DXT5;
case cDXN_XY:
return PIXEL_FMT_DXN;
case cDXN_YX:
return PIXEL_FMT_3DC;
case cDXT5A:
return PIXEL_FMT_DXT5A;
case cETC1:
return PIXEL_FMT_ETC1;
default: break;
}
CRNLIB_ASSERT(false);
return PIXEL_FMT_INVALID;
}
inline pixel_format from_dxt_format(dxt_format dxt_fmt) {
switch (dxt_fmt) {
case cDXT1:
return PIXEL_FMT_DXT1;
case cDXT1A:
return PIXEL_FMT_DXT1A;
case cDXT3:
return PIXEL_FMT_DXT3;
case cDXT5:
return PIXEL_FMT_DXT5;
case cDXN_XY:
return PIXEL_FMT_DXN;
case cDXN_YX:
return PIXEL_FMT_3DC;
case cDXT5A:
return PIXEL_FMT_DXT5A;
case cETC1:
return PIXEL_FMT_ETC1;
default:
break;
}
CRNLIB_ASSERT(false);
return PIXEL_FMT_INVALID;
}
inline bool is_pixel_format_non_srgb(pixel_format fmt)
{
switch (fmt)
{
case PIXEL_FMT_3DC:
case PIXEL_FMT_DXN:
case PIXEL_FMT_DXT5A:
case PIXEL_FMT_DXT5_CCxY:
case PIXEL_FMT_DXT5_xGxR:
case PIXEL_FMT_DXT5_xGBR:
case PIXEL_FMT_DXT5_AGBR:
return true;
default: break;
}
return false;
}
inline bool is_pixel_format_non_srgb(pixel_format fmt) {
switch (fmt) {
case PIXEL_FMT_3DC:
case PIXEL_FMT_DXN:
case PIXEL_FMT_DXT5A:
case PIXEL_FMT_DXT5_CCxY:
case PIXEL_FMT_DXT5_xGxR:
case PIXEL_FMT_DXT5_xGBR:
case PIXEL_FMT_DXT5_AGBR:
return true;
default:
break;
}
return false;
}
inline bool is_crn_format_non_srgb(crn_format fmt)
{
switch (fmt)
{
case cCRNFmtDXN_XY:
case cCRNFmtDXN_YX:
case cCRNFmtDXT5A:
case cCRNFmtDXT5_CCxY:
case cCRNFmtDXT5_xGxR:
case cCRNFmtDXT5_xGBR:
case cCRNFmtDXT5_AGBR:
return true;
default: break;
}
return false;
}
inline bool is_crn_format_non_srgb(crn_format fmt) {
switch (fmt) {
case cCRNFmtDXN_XY:
case cCRNFmtDXN_YX:
case cCRNFmtDXT5A:
case cCRNFmtDXT5_CCxY:
case cCRNFmtDXT5_xGxR:
case cCRNFmtDXT5_xGBR:
case cCRNFmtDXT5_AGBR:
return true;
default:
break;
}
return false;
}
inline uint get_bpp(pixel_format fmt)
{
switch (fmt)
{
case PIXEL_FMT_DXT1: return 4;
case PIXEL_FMT_DXT1A: return 4;
case PIXEL_FMT_ETC1: return 4;
case PIXEL_FMT_DXT2: return 8;
case PIXEL_FMT_DXT3: return 8;
case PIXEL_FMT_DXT4: return 8;
case PIXEL_FMT_DXT5: return 8;
case PIXEL_FMT_3DC: return 8;
case PIXEL_FMT_DXT5A: return 4;
case PIXEL_FMT_R8G8B8: return 24;
case PIXEL_FMT_A8R8G8B8: return 32;
case PIXEL_FMT_A8: return 8;
case PIXEL_FMT_L8: return 8;
case PIXEL_FMT_A8L8: return 16;
case PIXEL_FMT_DXN: return 8;
case PIXEL_FMT_DXT5_CCxY: return 8;
case PIXEL_FMT_DXT5_xGxR: return 8;
case PIXEL_FMT_DXT5_xGBR: return 8;
case PIXEL_FMT_DXT5_AGBR: return 8;
default: break;
}
CRNLIB_ASSERT(false);
return 0;
};
inline uint get_bpp(pixel_format fmt) {
switch (fmt) {
case PIXEL_FMT_DXT1:
return 4;
case PIXEL_FMT_DXT1A:
return 4;
case PIXEL_FMT_ETC1:
return 4;
case PIXEL_FMT_DXT2:
return 8;
case PIXEL_FMT_DXT3:
return 8;
case PIXEL_FMT_DXT4:
return 8;
case PIXEL_FMT_DXT5:
return 8;
case PIXEL_FMT_3DC:
return 8;
case PIXEL_FMT_DXT5A:
return 4;
case PIXEL_FMT_R8G8B8:
return 24;
case PIXEL_FMT_A8R8G8B8:
return 32;
case PIXEL_FMT_A8:
return 8;
case PIXEL_FMT_L8:
return 8;
case PIXEL_FMT_A8L8:
return 16;
case PIXEL_FMT_DXN:
return 8;
case PIXEL_FMT_DXT5_CCxY:
return 8;
case PIXEL_FMT_DXT5_xGxR:
return 8;
case PIXEL_FMT_DXT5_xGBR:
return 8;
case PIXEL_FMT_DXT5_AGBR:
return 8;
default:
break;
}
CRNLIB_ASSERT(false);
return 0;
};
inline uint get_dxt_bytes_per_block(pixel_format fmt)
{
switch (fmt)
{
case PIXEL_FMT_DXT1: return 8;
case PIXEL_FMT_DXT1A: return 8;
case PIXEL_FMT_DXT5A: return 8;
case PIXEL_FMT_ETC1: return 8;
case PIXEL_FMT_DXT2: return 16;
case PIXEL_FMT_DXT3: return 16;
case PIXEL_FMT_DXT4: return 16;
case PIXEL_FMT_DXT5: return 16;
case PIXEL_FMT_3DC: return 16;
case PIXEL_FMT_DXN: return 16;
case PIXEL_FMT_DXT5_CCxY: return 16;
case PIXEL_FMT_DXT5_xGxR: return 16;
case PIXEL_FMT_DXT5_xGBR: return 16;
case PIXEL_FMT_DXT5_AGBR: return 16;
default: break;
}
CRNLIB_ASSERT(false);
return 0;
}
inline uint get_dxt_bytes_per_block(pixel_format fmt) {
switch (fmt) {
case PIXEL_FMT_DXT1:
return 8;
case PIXEL_FMT_DXT1A:
return 8;
case PIXEL_FMT_DXT5A:
return 8;
case PIXEL_FMT_ETC1:
return 8;
case PIXEL_FMT_DXT2:
return 16;
case PIXEL_FMT_DXT3:
return 16;
case PIXEL_FMT_DXT4:
return 16;
case PIXEL_FMT_DXT5:
return 16;
case PIXEL_FMT_3DC:
return 16;
case PIXEL_FMT_DXN:
return 16;
case PIXEL_FMT_DXT5_CCxY:
return 16;
case PIXEL_FMT_DXT5_xGxR:
return 16;
case PIXEL_FMT_DXT5_xGBR:
return 16;
case PIXEL_FMT_DXT5_AGBR:
return 16;
default:
break;
}
CRNLIB_ASSERT(false);
return 0;
}
enum component_flags
{
cCompFlagRValid = 1,
cCompFlagGValid = 2,
cCompFlagBValid = 4,
cCompFlagAValid = 8,
enum component_flags {
cCompFlagRValid = 1,
cCompFlagGValid = 2,
cCompFlagBValid = 4,
cCompFlagAValid = 8,
cCompFlagGrayscale = 16,
cCompFlagNormalMap = 32,
cCompFlagLumaChroma = 64,
cCompFlagGrayscale = 16,
cCompFlagNormalMap = 32,
cCompFlagLumaChroma = 64,
cDefaultCompFlags = cCompFlagRValid | cCompFlagGValid | cCompFlagBValid | cCompFlagAValid
};
cDefaultCompFlags = cCompFlagRValid | cCompFlagGValid | cCompFlagBValid | cCompFlagAValid
};
component_flags get_component_flags(pixel_format fmt);
component_flags get_component_flags(pixel_format fmt);
crn_format convert_pixel_format_to_best_crn_format(pixel_format crn_fmt);
crn_format convert_pixel_format_to_best_crn_format(pixel_format crn_fmt);
pixel_format convert_crn_format_to_pixel_format(crn_format fmt);
pixel_format convert_crn_format_to_pixel_format(crn_format fmt);
} // namespace pixel_format_helpers
} // namespace crnlib
} // namespace pixel_format_helpers
} // namespace crnlib
+45 -56
View File
@@ -6,87 +6,76 @@
#include "crn_winhdr.h"
#endif
#ifndef _MSC_VER
int sprintf_s(char *buffer, size_t sizeOfBuffer, const char *format, ...)
{
if (!sizeOfBuffer)
return 0;
int sprintf_s(char* buffer, size_t sizeOfBuffer, const char* format, ...) {
if (!sizeOfBuffer)
return 0;
va_list args;
va_start(args, format);
int c = vsnprintf(buffer, sizeOfBuffer, format, args);
va_end(args);
va_list args;
va_start(args, format);
int c = vsnprintf(buffer, sizeOfBuffer, format, args);
va_end(args);
buffer[sizeOfBuffer - 1] = '\0';
buffer[sizeOfBuffer - 1] = '\0';
if (c < 0)
return sizeOfBuffer - 1;
if (c < 0)
return sizeOfBuffer - 1;
return CRNLIB_MIN(c, (int)sizeOfBuffer - 1);
return CRNLIB_MIN(c, (int)sizeOfBuffer - 1);
}
int vsprintf_s(char *buffer, size_t sizeOfBuffer, const char *format, va_list args)
{
if (!sizeOfBuffer)
return 0;
int vsprintf_s(char* buffer, size_t sizeOfBuffer, const char* format, va_list args) {
if (!sizeOfBuffer)
return 0;
int c = vsnprintf(buffer, sizeOfBuffer, format, args);
int c = vsnprintf(buffer, sizeOfBuffer, format, args);
buffer[sizeOfBuffer - 1] = '\0';
buffer[sizeOfBuffer - 1] = '\0';
if (c < 0)
return sizeOfBuffer - 1;
if (c < 0)
return sizeOfBuffer - 1;
return CRNLIB_MIN(c, (int)sizeOfBuffer - 1);
return CRNLIB_MIN(c, (int)sizeOfBuffer - 1);
}
char* strlwr(char* p)
{
char *q = p;
while (*q)
{
char c = *q;
*q++ = tolower(c);
}
return p;
char* strlwr(char* p) {
char* q = p;
while (*q) {
char c = *q;
*q++ = tolower(c);
}
return p;
}
char* strupr(char *p)
{
char *q = p;
while (*q)
{
char c = *q;
*q++ = toupper(c);
}
return p;
char* strupr(char* p) {
char* q = p;
while (*q) {
char c = *q;
*q++ = toupper(c);
}
return p;
}
#endif // __GNUC__
#endif // __GNUC__
void crnlib_debug_break(void)
{
CRNLIB_BREAKPOINT
void crnlib_debug_break(void) {
CRNLIB_BREAKPOINT
}
#if CRNLIB_USE_WIN32_API
#include "crn_winhdr.h"
bool crnlib_is_debugger_present(void)
{
return IsDebuggerPresent() != 0;
bool crnlib_is_debugger_present(void) {
return IsDebuggerPresent() != 0;
}
void crnlib_output_debug_string(const char* p)
{
OutputDebugStringA(p);
void crnlib_output_debug_string(const char* p) {
OutputDebugStringA(p);
}
#else
bool crnlib_is_debugger_present(void)
{
return false;
bool crnlib_is_debugger_present(void) {
return false;
}
void crnlib_output_debug_string(const char* p)
{
puts(p);
void crnlib_output_debug_string(const char* p) {
puts(p);
}
#endif // CRNLIB_USE_WIN32_API
#endif // CRNLIB_USE_WIN32_API
+45 -44
View File
@@ -11,86 +11,87 @@ void crnlib_assert(const char* pExp, const char* pFile, unsigned line);
void crnlib_fail(const char* pExp, const char* pFile, unsigned line);
#if CRNLIB_LITTLE_ENDIAN_CPU
const bool c_crnlib_little_endian_platform = true;
const bool c_crnlib_little_endian_platform = true;
#else
const bool c_crnlib_little_endian_platform = false;
const bool c_crnlib_little_endian_platform = false;
#endif
const bool c_crnlib_big_endian_platform = !c_crnlib_little_endian_platform;
#ifdef __GNUC__
#define crn_fopen(pDstFile, f, m) *(pDstFile) = fopen64(f, m)
#define crn_fseek fseeko64
#define crn_ftell ftello64
#elif defined( _MSC_VER )
#define crn_fopen(pDstFile, f, m) fopen_s(pDstFile, f, m)
#define crn_fseek _fseeki64
#define crn_ftell _ftelli64
#define crn_fopen(pDstFile, f, m) *(pDstFile) = fopen64(f, m)
#define crn_fseek fseeko64
#define crn_ftell ftello64
#elif defined(_MSC_VER)
#define crn_fopen(pDstFile, f, m) fopen_s(pDstFile, f, m)
#define crn_fseek _fseeki64
#define crn_ftell _ftelli64
#else
#define crn_fopen(pDstFile, f, m) *(pDstFile) = fopen(f, m)
#define crn_fseek(s, o, w) fseek(s, static_cast<long>(o), w)
#define crn_ftell ftell
#define crn_fopen(pDstFile, f, m) *(pDstFile) = fopen(f, m)
#define crn_fseek(s, o, w) fseek(s, static_cast<long>(o), w)
#define crn_ftell ftell
#endif
#if CRNLIB_USE_WIN32_API
#define CRNLIB_BREAKPOINT DebugBreak();
#define CRNLIB_BUILTIN_EXPECT(c, v) c
#define CRNLIB_BREAKPOINT DebugBreak();
#define CRNLIB_BUILTIN_EXPECT(c, v) c
#elif defined(__GNUC__)
#define CRNLIB_BREAKPOINT asm("int $3");
#define CRNLIB_BUILTIN_EXPECT(c, v) __builtin_expect(c, v)
#define CRNLIB_BREAKPOINT asm("int $3");
#define CRNLIB_BUILTIN_EXPECT(c, v) __builtin_expect(c, v)
#else
#define CRNLIB_BREAKPOINT
#define CRNLIB_BUILTIN_EXPECT(c, v) c
#define CRNLIB_BREAKPOINT
#define CRNLIB_BUILTIN_EXPECT(c, v) c
#endif
#if defined(__GNUC__)
#define CRNLIB_ALIGNED(x) __attribute__((aligned(x)))
#define CRNLIB_NOINLINE __attribute__((noinline))
#define CRNLIB_ALIGNED(x) __attribute__((aligned(x)))
#define CRNLIB_NOINLINE __attribute__((noinline))
#elif defined(_MSC_VER)
#define CRNLIB_ALIGNED(x) __declspec(align(x))
#define CRNLIB_NOINLINE __declspec(noinline)
#define CRNLIB_ALIGNED(x) __declspec(align(x))
#define CRNLIB_NOINLINE __declspec(noinline)
#else
#define CRNLIB_ALIGNED(x)
#define CRNLIB_NOINLINE
#define CRNLIB_ALIGNED(x)
#define CRNLIB_NOINLINE
#endif
#define CRNLIB_GET_ALIGNMENT(v) ((!sizeof(v)) ? 1 : (__alignof(v) ? __alignof(v) : sizeof(uint32)))
#ifndef _MSC_VER
int sprintf_s(char *buffer, size_t sizeOfBuffer, const char *format, ...);
int vsprintf_s(char *buffer, size_t sizeOfBuffer, const char *format, va_list args);
char* strlwr(char* p);
char* strupr(char *p);
#define _stricmp strcasecmp
#define _strnicmp strncasecmp
int sprintf_s(char* buffer, size_t sizeOfBuffer, const char* format, ...);
int vsprintf_s(char* buffer, size_t sizeOfBuffer, const char* format, va_list args);
char* strlwr(char* p);
char* strupr(char* p);
#define _stricmp strcasecmp
#define _strnicmp strncasecmp
#endif
inline bool crnlib_is_little_endian() { return c_crnlib_little_endian_platform; }
inline bool crnlib_is_big_endian() { return c_crnlib_big_endian_platform; }
inline bool crnlib_is_little_endian() {
return c_crnlib_little_endian_platform;
}
inline bool crnlib_is_big_endian() {
return c_crnlib_big_endian_platform;
}
inline bool crnlib_is_pc()
{
inline bool crnlib_is_pc() {
#ifdef CRNLIB_PLATFORM_PC
return true;
return true;
#else
return false;
return false;
#endif
}
inline bool crnlib_is_x86()
{
inline bool crnlib_is_x86() {
#ifdef CRNLIB_PLATFORM_PC_X86
return true;
return true;
#else
return false;
return false;
#endif
}
inline bool crnlib_is_x64()
{
inline bool crnlib_is_x64() {
#ifdef CRNLIB_PLATFORM_PC_X64
return true;
return true;
#else
return false;
return false;
#endif
}
+284 -327
View File
@@ -5,352 +5,309 @@
//#include "rand.h"
#ifdef CRNLIB_BUILD_DEBUG
//#define TEST_DECODER_TABLES
//#define TEST_DECODER_TABLES
#endif
namespace crnlib
{
namespace crnlib {
namespace prefix_coding
{
bool limit_max_code_size(uint num_syms, uint8* pCodesizes, uint max_code_size)
{
const uint cMaxEverCodeSize = 34;
if ((!num_syms) || (num_syms > cMaxSupportedSyms) || (max_code_size < 1) || (max_code_size > cMaxEverCodeSize))
return false;
uint num_codes[cMaxEverCodeSize + 1];
utils::zero_object(num_codes);
namespace prefix_coding {
bool limit_max_code_size(uint num_syms, uint8* pCodesizes, uint max_code_size) {
const uint cMaxEverCodeSize = 34;
bool should_limit = false;
for (uint i = 0; i < num_syms; i++)
{
uint c = pCodesizes[i];
if (c)
{
CRNLIB_ASSERT(c <= cMaxEverCodeSize);
num_codes[c]++;
if (c > max_code_size)
should_limit = true;
}
}
if (!should_limit)
return true;
uint ofs = 0;
uint next_sorted_ofs[cMaxEverCodeSize + 1];
for (uint i = 1; i <= cMaxEverCodeSize; i++)
{
next_sorted_ofs[i] = ofs;
ofs += num_codes[i];
}
if ((ofs < 2) || (ofs > cMaxSupportedSyms))
return true;
if (ofs > (1U << max_code_size))
return false;
for (uint i = max_code_size + 1; i <= cMaxEverCodeSize; i++)
num_codes[max_code_size] += num_codes[i];
// Technique of adjusting tree to enforce maximum code size from LHArc.
uint total = 0;
for (uint i = max_code_size; i; --i)
total += (num_codes[i] << (max_code_size - i));
if ((!num_syms) || (num_syms > cMaxSupportedSyms) || (max_code_size < 1) || (max_code_size > cMaxEverCodeSize))
return false;
if (total == (1U << max_code_size))
return true;
do
{
num_codes[max_code_size]--;
uint num_codes[cMaxEverCodeSize + 1];
utils::zero_object(num_codes);
uint i;
for (i = max_code_size - 1; i; --i)
{
if (!num_codes[i])
continue;
num_codes[i]--;
num_codes[i + 1] += 2;
break;
}
if (!i)
return false;
bool should_limit = false;
total--;
} while (total != (1U << max_code_size));
uint8 new_codesizes[cMaxSupportedSyms];
uint8* p = new_codesizes;
for (uint i = 1; i <= max_code_size; i++)
{
uint n = num_codes[i];
if (n)
{
memset(p, i, n);
p += n;
}
}
for (uint i = 0; i < num_syms; i++)
{
const uint c = pCodesizes[i];
if (c)
{
uint ofs = next_sorted_ofs[c];
next_sorted_ofs[c] = ofs + 1;
pCodesizes[i] = static_cast<uint8>(new_codesizes[ofs]);
}
}
return true;
for (uint i = 0; i < num_syms; i++) {
uint c = pCodesizes[i];
if (c) {
CRNLIB_ASSERT(c <= cMaxEverCodeSize);
num_codes[c]++;
if (c > max_code_size)
should_limit = true;
}
}
if (!should_limit)
return true;
uint ofs = 0;
uint next_sorted_ofs[cMaxEverCodeSize + 1];
for (uint i = 1; i <= cMaxEverCodeSize; i++) {
next_sorted_ofs[i] = ofs;
ofs += num_codes[i];
}
if ((ofs < 2) || (ofs > cMaxSupportedSyms))
return true;
if (ofs > (1U << max_code_size))
return false;
for (uint i = max_code_size + 1; i <= cMaxEverCodeSize; i++)
num_codes[max_code_size] += num_codes[i];
// Technique of adjusting tree to enforce maximum code size from LHArc.
uint total = 0;
for (uint i = max_code_size; i; --i)
total += (num_codes[i] << (max_code_size - i));
if (total == (1U << max_code_size))
return true;
do {
num_codes[max_code_size]--;
uint i;
for (i = max_code_size - 1; i; --i) {
if (!num_codes[i])
continue;
num_codes[i]--;
num_codes[i + 1] += 2;
break;
}
if (!i)
return false;
total--;
} while (total != (1U << max_code_size));
uint8 new_codesizes[cMaxSupportedSyms];
uint8* p = new_codesizes;
for (uint i = 1; i <= max_code_size; i++) {
uint n = num_codes[i];
if (n) {
memset(p, i, n);
p += n;
}
}
for (uint i = 0; i < num_syms; i++) {
const uint c = pCodesizes[i];
if (c) {
uint ofs = next_sorted_ofs[c];
next_sorted_ofs[c] = ofs + 1;
pCodesizes[i] = static_cast<uint8>(new_codesizes[ofs]);
}
}
return true;
}
bool generate_codes(uint num_syms, const uint8* pCodesizes, uint16* pCodes) {
uint num_codes[cMaxExpectedCodeSize + 1];
utils::zero_object(num_codes);
for (uint i = 0; i < num_syms; i++) {
uint c = pCodesizes[i];
if (c) {
CRNLIB_ASSERT(c <= cMaxExpectedCodeSize);
num_codes[c]++;
}
}
uint code = 0;
uint next_code[cMaxExpectedCodeSize + 1];
next_code[0] = 0;
for (uint i = 1; i <= cMaxExpectedCodeSize; i++) {
next_code[i] = code;
code = (code + num_codes[i]) << 1;
}
if (code != (1 << (cMaxExpectedCodeSize + 1))) {
uint t = 0;
for (uint i = 1; i <= cMaxExpectedCodeSize; i++) {
t += num_codes[i];
if (t > 1)
return false;
}
}
for (uint i = 0; i < num_syms; i++) {
uint c = pCodesizes[i];
if (c) {
CRNLIB_ASSERT(next_code[c] <= cUINT16_MAX);
pCodes[i] = static_cast<uint16>(next_code[c]++);
CRNLIB_ASSERT(math::total_bits(pCodes[i]) <= pCodesizes[i]);
}
}
return true;
}
bool generate_decoder_tables(uint num_syms, const uint8* pCodesizes, decoder_tables* pTables, uint table_bits) {
uint min_codes[cMaxExpectedCodeSize];
if ((!num_syms) || (table_bits > cMaxTableBits))
return false;
pTables->m_num_syms = num_syms;
uint num_codes[cMaxExpectedCodeSize + 1];
utils::zero_object(num_codes);
for (uint i = 0; i < num_syms; i++) {
uint c = pCodesizes[i];
if (c)
num_codes[c]++;
}
uint sorted_positions[cMaxExpectedCodeSize + 1];
uint code = 0;
uint total_used_syms = 0;
uint max_code_size = 0;
uint min_code_size = UINT_MAX;
for (uint i = 1; i <= cMaxExpectedCodeSize; i++) {
const uint n = num_codes[i];
if (!n)
pTables->m_max_codes[i - 1] = 0; //UINT_MAX;
else {
min_code_size = math::minimum(min_code_size, i);
max_code_size = math::maximum(max_code_size, i);
min_codes[i - 1] = code;
pTables->m_max_codes[i - 1] = code + n - 1;
pTables->m_max_codes[i - 1] = 1 + ((pTables->m_max_codes[i - 1] << (16 - i)) | ((1 << (16 - i)) - 1));
pTables->m_val_ptrs[i - 1] = total_used_syms;
sorted_positions[i] = total_used_syms;
code += n;
total_used_syms += n;
}
code <<= 1;
}
pTables->m_total_used_syms = total_used_syms;
if (total_used_syms > pTables->m_cur_sorted_symbol_order_size) {
pTables->m_cur_sorted_symbol_order_size = total_used_syms;
if (!math::is_power_of_2(total_used_syms))
pTables->m_cur_sorted_symbol_order_size = math::minimum<uint>(num_syms, math::next_pow2(total_used_syms));
if (pTables->m_sorted_symbol_order) {
crnlib_delete_array(pTables->m_sorted_symbol_order);
pTables->m_sorted_symbol_order = NULL;
}
pTables->m_sorted_symbol_order = crnlib_new_array<uint16>(pTables->m_cur_sorted_symbol_order_size);
}
pTables->m_min_code_size = static_cast<uint8>(min_code_size);
pTables->m_max_code_size = static_cast<uint8>(max_code_size);
for (uint i = 0; i < num_syms; i++) {
uint c = pCodesizes[i];
if (c) {
CRNLIB_ASSERT(num_codes[c]);
uint sorted_pos = sorted_positions[c]++;
CRNLIB_ASSERT(sorted_pos < total_used_syms);
pTables->m_sorted_symbol_order[sorted_pos] = static_cast<uint16>(i);
}
}
if (table_bits <= pTables->m_min_code_size)
table_bits = 0;
pTables->m_table_bits = table_bits;
if (table_bits) {
uint table_size = 1 << table_bits;
if (table_size > pTables->m_cur_lookup_size) {
pTables->m_cur_lookup_size = table_size;
if (pTables->m_lookup) {
crnlib_delete_array(pTables->m_lookup);
pTables->m_lookup = NULL;
}
bool generate_codes(uint num_syms, const uint8* pCodesizes, uint16* pCodes)
{
uint num_codes[cMaxExpectedCodeSize + 1];
utils::zero_object(num_codes);
for (uint i = 0; i < num_syms; i++)
{
uint c = pCodesizes[i];
if (c)
{
CRNLIB_ASSERT(c <= cMaxExpectedCodeSize);
num_codes[c]++;
}
}
pTables->m_lookup = crnlib_new_array<uint32>(table_size);
}
uint code = 0;
memset(pTables->m_lookup, 0xFF, static_cast<uint>(sizeof(pTables->m_lookup[0])) * (1UL << table_bits));
uint next_code[cMaxExpectedCodeSize + 1];
next_code[0] = 0;
for (uint i = 1; i <= cMaxExpectedCodeSize; i++)
{
next_code[i] = code;
code = (code + num_codes[i]) << 1;
}
for (uint codesize = 1; codesize <= table_bits; codesize++) {
if (!num_codes[codesize])
continue;
if (code != (1 << (cMaxExpectedCodeSize + 1)))
{
uint t = 0;
for (uint i = 1; i <= cMaxExpectedCodeSize; i++)
{
t += num_codes[i];
if (t > 1)
return false;
}
}
const uint fillsize = table_bits - codesize;
const uint fillnum = 1 << fillsize;
for (uint i = 0; i < num_syms; i++)
{
uint c = pCodesizes[i];
if (c)
{
CRNLIB_ASSERT(next_code[c] <= cUINT16_MAX);
pCodes[i] = static_cast<uint16>(next_code[c]++);
CRNLIB_ASSERT(math::total_bits(pCodes[i]) <= pCodesizes[i]);
}
}
return true;
const uint min_code = min_codes[codesize - 1];
const uint max_code = pTables->get_unshifted_max_code(codesize);
const uint val_ptr = pTables->m_val_ptrs[codesize - 1];
for (uint code = min_code; code <= max_code; code++) {
const uint sym_index = pTables->m_sorted_symbol_order[val_ptr + code - min_code];
CRNLIB_ASSERT(pCodesizes[sym_index] == codesize);
for (uint j = 0; j < fillnum; j++) {
const uint t = j + (code << fillsize);
CRNLIB_ASSERT(t < (1U << table_bits));
CRNLIB_ASSERT(pTables->m_lookup[t] == cUINT32_MAX);
pTables->m_lookup[t] = sym_index | (codesize << 16U);
}
}
bool generate_decoder_tables(uint num_syms, const uint8* pCodesizes, decoder_tables* pTables, uint table_bits)
{
uint min_codes[cMaxExpectedCodeSize];
if ((!num_syms) || (table_bits > cMaxTableBits))
return false;
pTables->m_num_syms = num_syms;
uint num_codes[cMaxExpectedCodeSize + 1];
utils::zero_object(num_codes);
}
}
for (uint i = 0; i < num_syms; i++)
{
uint c = pCodesizes[i];
if (c)
num_codes[c]++;
}
for (uint i = 0; i < cMaxExpectedCodeSize; i++)
pTables->m_val_ptrs[i] -= min_codes[i];
uint sorted_positions[cMaxExpectedCodeSize + 1];
uint code = 0;
pTables->m_table_max_code = 0;
pTables->m_decode_start_code_size = pTables->m_min_code_size;
uint total_used_syms = 0;
uint max_code_size = 0;
uint min_code_size = UINT_MAX;
for (uint i = 1; i <= cMaxExpectedCodeSize; i++)
{
const uint n = num_codes[i];
if (!n)
pTables->m_max_codes[i - 1] = 0;//UINT_MAX;
else
{
min_code_size = math::minimum(min_code_size, i);
max_code_size = math::maximum(max_code_size, i);
min_codes[i - 1] = code;
pTables->m_max_codes[i - 1] = code + n - 1;
pTables->m_max_codes[i - 1] = 1 + ((pTables->m_max_codes[i - 1] << (16 - i)) | ((1 << (16 - i)) - 1));
pTables->m_val_ptrs[i - 1] = total_used_syms;
sorted_positions[i] = total_used_syms;
code += n;
total_used_syms += n;
}
code <<= 1;
}
pTables->m_total_used_syms = total_used_syms;
if (total_used_syms > pTables->m_cur_sorted_symbol_order_size)
{
pTables->m_cur_sorted_symbol_order_size = total_used_syms;
if (!math::is_power_of_2(total_used_syms))
pTables->m_cur_sorted_symbol_order_size = math::minimum<uint>(num_syms, math::next_pow2(total_used_syms));
if (pTables->m_sorted_symbol_order)
{
crnlib_delete_array(pTables->m_sorted_symbol_order);
pTables->m_sorted_symbol_order = NULL;
}
pTables->m_sorted_symbol_order = crnlib_new_array<uint16>(pTables->m_cur_sorted_symbol_order_size);
}
pTables->m_min_code_size = static_cast<uint8>(min_code_size);
pTables->m_max_code_size = static_cast<uint8>(max_code_size);
for (uint i = 0; i < num_syms; i++)
{
uint c = pCodesizes[i];
if (c)
{
CRNLIB_ASSERT(num_codes[c]);
uint sorted_pos = sorted_positions[c]++;
CRNLIB_ASSERT(sorted_pos < total_used_syms);
pTables->m_sorted_symbol_order[sorted_pos] = static_cast<uint16>(i);
}
}
if (table_bits <= pTables->m_min_code_size)
table_bits = 0;
pTables->m_table_bits = table_bits;
if (table_bits)
{
uint table_size = 1 << table_bits;
if (table_size > pTables->m_cur_lookup_size)
{
pTables->m_cur_lookup_size = table_size;
if (pTables->m_lookup)
{
crnlib_delete_array(pTables->m_lookup);
pTables->m_lookup = NULL;
}
pTables->m_lookup = crnlib_new_array<uint32>(table_size);
}
memset(pTables->m_lookup, 0xFF, static_cast<uint>(sizeof(pTables->m_lookup[0])) * (1UL << table_bits));
for (uint codesize = 1; codesize <= table_bits; codesize++)
{
if (!num_codes[codesize])
continue;
const uint fillsize = table_bits - codesize;
const uint fillnum = 1 << fillsize;
const uint min_code = min_codes[codesize - 1];
const uint max_code = pTables->get_unshifted_max_code(codesize);
const uint val_ptr = pTables->m_val_ptrs[codesize - 1];
for (uint code = min_code; code <= max_code; code++)
{
const uint sym_index = pTables->m_sorted_symbol_order[ val_ptr + code - min_code ];
CRNLIB_ASSERT( pCodesizes[sym_index] == codesize );
for (uint j = 0; j < fillnum; j++)
{
const uint t = j + (code << fillsize);
CRNLIB_ASSERT(t < (1U << table_bits));
CRNLIB_ASSERT(pTables->m_lookup[t] == cUINT32_MAX);
pTables->m_lookup[t] = sym_index | (codesize << 16U);
}
}
}
}
for (uint i = 0; i < cMaxExpectedCodeSize; i++)
pTables->m_val_ptrs[i] -= min_codes[i];
pTables->m_table_max_code = 0;
pTables->m_decode_start_code_size = pTables->m_min_code_size;
if (table_bits)
{
uint i;
for (i = table_bits; i >= 1; i--)
{
if (num_codes[i])
{
pTables->m_table_max_code = pTables->m_max_codes[i - 1];
break;
}
}
if (i >= 1)
{
pTables->m_decode_start_code_size = table_bits + 1;
for (uint i = table_bits + 1; i <= max_code_size; i++)
{
if (num_codes[i])
{
pTables->m_decode_start_code_size = i;
break;
}
}
}
}
// sentinels
pTables->m_max_codes[cMaxExpectedCodeSize] = UINT_MAX;
pTables->m_val_ptrs[cMaxExpectedCodeSize] = 0xFFFFF;
pTables->m_table_shift = 32 - pTables->m_table_bits;
return true;
if (table_bits) {
uint i;
for (i = table_bits; i >= 1; i--) {
if (num_codes[i]) {
pTables->m_table_max_code = pTables->m_max_codes[i - 1];
break;
}
} // namespace prefix_codig
}
if (i >= 1) {
pTables->m_decode_start_code_size = table_bits + 1;
for (uint i = table_bits + 1; i <= max_code_size; i++) {
if (num_codes[i]) {
pTables->m_decode_start_code_size = i;
break;
}
}
}
}
// sentinels
pTables->m_max_codes[cMaxExpectedCodeSize] = UINT_MAX;
pTables->m_val_ptrs[cMaxExpectedCodeSize] = 0xFFFFF;
} // namespace crnlib
pTables->m_table_shift = 32 - pTables->m_table_bits;
return true;
}
} // namespace prefix_codig
} // namespace crnlib
+75 -88
View File
@@ -2,115 +2,102 @@
// See Copyright Notice and license at the end of inc/crnlib.h
#pragma once
namespace crnlib
{
namespace prefix_coding
{
const uint cMaxExpectedCodeSize = 16;
const uint cMaxSupportedSyms = 8192;
const uint cMaxTableBits = 11;
namespace crnlib {
namespace prefix_coding {
const uint cMaxExpectedCodeSize = 16;
const uint cMaxSupportedSyms = 8192;
const uint cMaxTableBits = 11;
bool limit_max_code_size(uint num_syms, uint8* pCodesizes, uint max_code_size);
bool limit_max_code_size(uint num_syms, uint8* pCodesizes, uint max_code_size);
bool generate_codes(uint num_syms, const uint8* pCodesizes, uint16* pCodes);
bool generate_codes(uint num_syms, const uint8* pCodesizes, uint16* pCodes);
class decoder_tables
{
public:
inline decoder_tables() :
m_table_shift(0), m_table_max_code(0), m_decode_start_code_size(0), m_cur_lookup_size(0), m_lookup(NULL), m_cur_sorted_symbol_order_size(0), m_sorted_symbol_order(NULL)
{
}
class decoder_tables {
public:
inline decoder_tables()
: m_table_shift(0), m_table_max_code(0), m_decode_start_code_size(0), m_cur_lookup_size(0), m_lookup(NULL), m_cur_sorted_symbol_order_size(0), m_sorted_symbol_order(NULL) {
}
inline decoder_tables(const decoder_tables& other) :
m_table_shift(0), m_table_max_code(0), m_decode_start_code_size(0), m_cur_lookup_size(0), m_lookup(NULL), m_cur_sorted_symbol_order_size(0), m_sorted_symbol_order(NULL)
{
*this = other;
}
inline decoder_tables(const decoder_tables& other)
: m_table_shift(0), m_table_max_code(0), m_decode_start_code_size(0), m_cur_lookup_size(0), m_lookup(NULL), m_cur_sorted_symbol_order_size(0), m_sorted_symbol_order(NULL) {
*this = other;
}
decoder_tables& operator= (const decoder_tables& other)
{
if (this == &other)
return *this;
decoder_tables& operator=(const decoder_tables& other) {
if (this == &other)
return *this;
clear();
clear();
memcpy(this, &other, sizeof(*this));
memcpy(this, &other, sizeof(*this));
if (other.m_lookup)
{
m_lookup = crnlib_new_array<uint32>(m_cur_lookup_size);
memcpy(m_lookup, other.m_lookup, sizeof(m_lookup[0]) * m_cur_lookup_size);
}
if (other.m_lookup) {
m_lookup = crnlib_new_array<uint32>(m_cur_lookup_size);
memcpy(m_lookup, other.m_lookup, sizeof(m_lookup[0]) * m_cur_lookup_size);
}
if (other.m_sorted_symbol_order)
{
m_sorted_symbol_order = crnlib_new_array<uint16>(m_cur_sorted_symbol_order_size);
memcpy(m_sorted_symbol_order, other.m_sorted_symbol_order, sizeof(m_sorted_symbol_order[0]) * m_cur_sorted_symbol_order_size);
}
if (other.m_sorted_symbol_order) {
m_sorted_symbol_order = crnlib_new_array<uint16>(m_cur_sorted_symbol_order_size);
memcpy(m_sorted_symbol_order, other.m_sorted_symbol_order, sizeof(m_sorted_symbol_order[0]) * m_cur_sorted_symbol_order_size);
}
return *this;
}
return *this;
}
inline void clear()
{
if (m_lookup)
{
crnlib_delete_array(m_lookup);
m_lookup = 0;
m_cur_lookup_size = 0;
}
inline void clear() {
if (m_lookup) {
crnlib_delete_array(m_lookup);
m_lookup = 0;
m_cur_lookup_size = 0;
}
if (m_sorted_symbol_order)
{
crnlib_delete_array(m_sorted_symbol_order);
m_sorted_symbol_order = NULL;
m_cur_sorted_symbol_order_size = 0;
}
}
if (m_sorted_symbol_order) {
crnlib_delete_array(m_sorted_symbol_order);
m_sorted_symbol_order = NULL;
m_cur_sorted_symbol_order_size = 0;
}
}
inline ~decoder_tables()
{
if (m_lookup)
crnlib_delete_array(m_lookup);
inline ~decoder_tables() {
if (m_lookup)
crnlib_delete_array(m_lookup);
if (m_sorted_symbol_order)
crnlib_delete_array(m_sorted_symbol_order);
}
if (m_sorted_symbol_order)
crnlib_delete_array(m_sorted_symbol_order);
}
// DO NOT use any complex classes here - it is bitwise copied.
// DO NOT use any complex classes here - it is bitwise copied.
uint m_num_syms;
uint m_total_used_syms;
uint m_table_bits;
uint m_table_shift;
uint m_table_max_code;
uint m_decode_start_code_size;
uint m_num_syms;
uint m_total_used_syms;
uint m_table_bits;
uint m_table_shift;
uint m_table_max_code;
uint m_decode_start_code_size;
uint8 m_min_code_size;
uint8 m_max_code_size;
uint8 m_min_code_size;
uint8 m_max_code_size;
uint m_max_codes[cMaxExpectedCodeSize + 1];
int m_val_ptrs[cMaxExpectedCodeSize + 1];
uint m_max_codes[cMaxExpectedCodeSize + 1];
int m_val_ptrs[cMaxExpectedCodeSize + 1];
uint m_cur_lookup_size;
uint32* m_lookup;
uint m_cur_lookup_size;
uint32* m_lookup;
uint m_cur_sorted_symbol_order_size;
uint16* m_sorted_symbol_order;
uint m_cur_sorted_symbol_order_size;
uint16* m_sorted_symbol_order;
inline uint get_unshifted_max_code(uint len) const
{
CRNLIB_ASSERT( (len >= 1) && (len <= cMaxExpectedCodeSize) );
uint k = m_max_codes[len - 1];
if (!k)
return UINT_MAX;
return (k - 1) >> (16 - len);
}
};
inline uint get_unshifted_max_code(uint len) const {
CRNLIB_ASSERT((len >= 1) && (len <= cMaxExpectedCodeSize));
uint k = m_max_codes[len - 1];
if (!k)
return UINT_MAX;
return (k - 1) >> (16 - len);
}
};
bool generate_decoder_tables(uint num_syms, const uint8* pCodesizes, decoder_tables* pTables, uint table_bits);
bool generate_decoder_tables(uint num_syms, const uint8* pCodesizes, decoder_tables* pTables, uint table_bits);
} // namespace prefix_coding
} // namespace prefix_coding
} // namespace crnlib
} // namespace crnlib
+685 -754
View File
File diff suppressed because it is too large Load Diff
+120 -133
View File
@@ -8,178 +8,165 @@
#include "crn_threaded_clusterizer.h"
#include "crn_dxt_image.h"
namespace crnlib
{
struct qdxt1_params
{
qdxt1_params()
{
clear();
}
namespace crnlib {
struct qdxt1_params {
qdxt1_params() {
clear();
}
void clear()
{
m_quality_level = cMaxQuality;
m_dxt_quality = cCRNDXTQualityUber;
m_perceptual = true;
m_dxt1a_alpha_threshold = 0;
m_use_alpha_blocks = true;
m_pProgress_func = NULL;
m_pProgress_data = NULL;
m_num_mips = 0;
m_hierarchical = true;
utils::zero_object(m_mip_desc);
m_progress_start = 0;
m_progress_range = 100;
}
void clear() {
m_quality_level = cMaxQuality;
m_dxt_quality = cCRNDXTQualityUber;
m_perceptual = true;
m_dxt1a_alpha_threshold = 0;
m_use_alpha_blocks = true;
m_pProgress_func = NULL;
m_pProgress_data = NULL;
m_num_mips = 0;
m_hierarchical = true;
utils::zero_object(m_mip_desc);
m_progress_start = 0;
m_progress_range = 100;
}
void init(const dxt_image::pack_params &pp, int quality_level, bool hierarchical)
{
m_dxt_quality = pp.m_quality;
m_hierarchical = hierarchical;
m_perceptual = pp.m_perceptual;
m_use_alpha_blocks = pp.m_use_both_block_types;
m_quality_level = quality_level;
m_dxt1a_alpha_threshold = pp.m_dxt1a_alpha_threshold;
}
void init(const dxt_image::pack_params& pp, int quality_level, bool hierarchical) {
m_dxt_quality = pp.m_quality;
m_hierarchical = hierarchical;
m_perceptual = pp.m_perceptual;
m_use_alpha_blocks = pp.m_use_both_block_types;
m_quality_level = quality_level;
m_dxt1a_alpha_threshold = pp.m_dxt1a_alpha_threshold;
}
enum { cMaxQuality = cCRNMaxQualityLevel };
uint m_quality_level;
enum { cMaxQuality = cCRNMaxQualityLevel };
uint m_quality_level;
uint m_dxt1a_alpha_threshold;
crn_dxt_quality m_dxt_quality;
bool m_perceptual;
bool m_use_alpha_blocks;
bool m_hierarchical;
uint m_dxt1a_alpha_threshold;
crn_dxt_quality m_dxt_quality;
bool m_perceptual;
bool m_use_alpha_blocks;
bool m_hierarchical;
struct mip_desc
{
uint m_first_block;
uint m_block_width;
uint m_block_height;
};
struct mip_desc {
uint m_first_block;
uint m_block_width;
uint m_block_height;
};
uint m_num_mips;
enum { cMaxMips = 128 };
mip_desc m_mip_desc[cMaxMips];
uint m_num_mips;
enum { cMaxMips = 128 };
mip_desc m_mip_desc[cMaxMips];
typedef bool (*progress_callback_func)(uint percentage_completed, void* pProgress_data);
progress_callback_func m_pProgress_func;
void* m_pProgress_data;
uint m_progress_start;
uint m_progress_range;
};
typedef bool (*progress_callback_func)(uint percentage_completed, void* pProgress_data);
progress_callback_func m_pProgress_func;
void* m_pProgress_data;
uint m_progress_start;
uint m_progress_range;
};
class qdxt1
{
CRNLIB_NO_COPY_OR_ASSIGNMENT_OP(qdxt1);
class qdxt1 {
CRNLIB_NO_COPY_OR_ASSIGNMENT_OP(qdxt1);
public:
qdxt1(task_pool& task_pool);
~qdxt1();
public:
qdxt1(task_pool& task_pool);
~qdxt1();
void clear();
void clear();
bool init(uint n, const dxt_pixel_block* pBlocks, const qdxt1_params& params);
bool init(uint n, const dxt_pixel_block* pBlocks, const qdxt1_params& params);
uint get_num_blocks() const { return m_num_blocks; }
const dxt_pixel_block* get_blocks() const { return m_pBlocks; }
uint get_num_blocks() const { return m_num_blocks; }
const dxt_pixel_block* get_blocks() const { return m_pBlocks; }
bool pack(dxt1_block* pDst_elements, uint elements_per_block, const qdxt1_params& params, float quality_power_mul);
bool pack(dxt1_block* pDst_elements, uint elements_per_block, const qdxt1_params& params, float quality_power_mul);
private:
task_pool* m_pTask_pool;
crn_thread_id_t m_main_thread_id;
bool m_canceled;
private:
task_pool* m_pTask_pool;
crn_thread_id_t m_main_thread_id;
bool m_canceled;
uint m_progress_start;
uint m_progress_range;
uint m_progress_start;
uint m_progress_range;
uint m_num_blocks;
const dxt_pixel_block* m_pBlocks;
uint m_num_blocks;
const dxt_pixel_block* m_pBlocks;
dxt1_block* m_pDst_elements;
uint m_elements_per_block;
qdxt1_params m_params;
dxt1_block* m_pDst_elements;
uint m_elements_per_block;
qdxt1_params m_params;
uint m_max_selector_clusters;
uint m_max_selector_clusters;
int m_prev_percentage_complete;
int m_prev_percentage_complete;
typedef vec<6, float> vec6F;
typedef clusterizer<vec6F> vec6F_clusterizer;
vec6F_clusterizer m_endpoint_clusterizer;
typedef vec<6, float> vec6F;
typedef clusterizer<vec6F> vec6F_clusterizer;
vec6F_clusterizer m_endpoint_clusterizer;
crnlib::vector< crnlib::vector<uint> > m_endpoint_cluster_indices;
crnlib::vector<crnlib::vector<uint> > m_endpoint_cluster_indices;
typedef vec<16, float> vec16F;
typedef threaded_clusterizer<vec16F> vec16F_clusterizer;
typedef vec<16, float> vec16F;
typedef threaded_clusterizer<vec16F> vec16F_clusterizer;
typedef vec16F_clusterizer::weighted_vec weighted_selector_vec;
typedef vec16F_clusterizer::weighted_vec_array weighted_selector_vec_array;
typedef vec16F_clusterizer::weighted_vec weighted_selector_vec;
typedef vec16F_clusterizer::weighted_vec_array weighted_selector_vec_array;
vec16F_clusterizer m_selector_clusterizer;
vec16F_clusterizer m_selector_clusterizer;
crnlib::vector< crnlib::vector<uint> > m_cached_selector_cluster_indices[qdxt1_params::cMaxQuality + 1];
crnlib::vector<crnlib::vector<uint> > m_cached_selector_cluster_indices[qdxt1_params::cMaxQuality + 1];
struct cluster_id
{
cluster_id() : m_hash(0)
{
struct cluster_id {
cluster_id()
: m_hash(0) {
}
}
cluster_id(const crnlib::vector<uint>& indices) {
set(indices);
}
cluster_id(const crnlib::vector<uint>& indices)
{
set(indices);
}
void set(const crnlib::vector<uint>& indices) {
m_cells.resize(indices.size());
void set(const crnlib::vector<uint>& indices)
{
m_cells.resize(indices.size());
for (uint i = 0; i < indices.size(); i++)
m_cells[i] = static_cast<uint32>(indices[i]);
for (uint i = 0; i < indices.size(); i++)
m_cells[i] = static_cast<uint32>(indices[i]);
std::sort(m_cells.begin(), m_cells.end());
std::sort(m_cells.begin(), m_cells.end());
m_hash = fast_hash(&m_cells[0], sizeof(m_cells[0]) * m_cells.size());
}
m_hash = fast_hash(&m_cells[0], sizeof(m_cells[0]) * m_cells.size());
}
bool operator<(const cluster_id& rhs) const {
return m_cells < rhs.m_cells;
}
bool operator< (const cluster_id& rhs) const
{
return m_cells < rhs.m_cells;
}
bool operator==(const cluster_id& rhs) const {
if (m_hash != rhs.m_hash)
return false;
bool operator== (const cluster_id& rhs) const
{
if (m_hash != rhs.m_hash)
return false;
return m_cells == rhs.m_cells;
}
return m_cells == rhs.m_cells;
}
crnlib::vector<uint32> m_cells;
crnlib::vector<uint32> m_cells;
size_t m_hash;
size_t m_hash;
operator size_t() const { return m_hash; }
};
operator size_t() const { return m_hash; }
};
typedef crnlib::hash_map<cluster_id, uint> cluster_hash;
cluster_hash m_cluster_hash;
spinlock m_cluster_hash_lock;
typedef crnlib::hash_map<cluster_id, uint> cluster_hash;
cluster_hash m_cluster_hash;
spinlock m_cluster_hash_lock;
static bool generate_codebook_dummy_progress_callback(uint percentage_completed, void* pData);
static bool generate_codebook_progress_callback(uint percentage_completed, void* pData);
bool update_progress(uint value, uint max_value);
void pack_endpoints_task(uint64 data, void* pData_ptr);
void optimize_selectors_task(uint64 data, void* pData_ptr);
bool create_selector_clusters(uint max_selector_clusters, crnlib::vector<crnlib::vector<uint> >& selector_cluster_indices);
static bool generate_codebook_dummy_progress_callback(uint percentage_completed, void* pData);
static bool generate_codebook_progress_callback(uint percentage_completed, void* pData);
bool update_progress(uint value, uint max_value);
void pack_endpoints_task(uint64 data, void* pData_ptr);
void optimize_selectors_task(uint64 data, void* pData_ptr);
bool create_selector_clusters(uint max_selector_clusters, crnlib::vector< crnlib::vector<uint> >& selector_cluster_indices);
inline dxt1_block& get_block(uint index) const { return m_pDst_elements[index * m_elements_per_block]; }
};
inline dxt1_block& get_block(uint index) const { return m_pDst_elements[index * m_elements_per_block]; }
};
CRNLIB_DEFINE_BITWISE_MOVABLE(qdxt1::cluster_id);
CRNLIB_DEFINE_BITWISE_MOVABLE(qdxt1::cluster_id);
} // namespace crnlib
} // namespace crnlib
+600 -679
View File
File diff suppressed because it is too large Load Diff
+116 -139
View File
@@ -8,187 +8,164 @@
#include "crn_dxt.h"
#include "crn_dxt_image.h"
namespace crnlib
{
struct qdxt5_params
{
qdxt5_params()
{
clear();
}
namespace crnlib {
struct qdxt5_params {
qdxt5_params() {
clear();
}
void clear()
{
m_quality_level = cMaxQuality;
m_dxt_quality = cCRNDXTQualityUber;
void clear() {
m_quality_level = cMaxQuality;
m_dxt_quality = cCRNDXTQualityUber;
m_pProgress_func = NULL;
m_pProgress_data = NULL;
m_num_mips = 0;
m_hierarchical = true;
utils::zero_object(m_mip_desc);
m_pProgress_func = NULL;
m_pProgress_data = NULL;
m_num_mips = 0;
m_hierarchical = true;
utils::zero_object(m_mip_desc);
m_comp_index = 3;
m_progress_start = 0;
m_progress_range = 100;
m_comp_index = 3;
m_progress_start = 0;
m_progress_range = 100;
m_use_both_block_types = true;
}
m_use_both_block_types = true;
}
void init(const dxt_image::pack_params &pp, int quality_level, bool hierarchical, int comp_index = 3)
{
m_dxt_quality = pp.m_quality;
m_hierarchical = hierarchical;
m_comp_index = comp_index;
m_use_both_block_types = pp.m_use_both_block_types;
m_quality_level = quality_level;
}
void init(const dxt_image::pack_params& pp, int quality_level, bool hierarchical, int comp_index = 3) {
m_dxt_quality = pp.m_quality;
m_hierarchical = hierarchical;
m_comp_index = comp_index;
m_use_both_block_types = pp.m_use_both_block_types;
m_quality_level = quality_level;
}
enum { cMaxQuality = cCRNMaxQualityLevel };
uint m_quality_level;
crn_dxt_quality m_dxt_quality;
bool m_hierarchical;
enum { cMaxQuality = cCRNMaxQualityLevel };
uint m_quality_level;
crn_dxt_quality m_dxt_quality;
bool m_hierarchical;
struct mip_desc
{
uint m_first_block;
uint m_block_width;
uint m_block_height;
};
struct mip_desc {
uint m_first_block;
uint m_block_width;
uint m_block_height;
};
uint m_num_mips;
enum { cMaxMips = 128 };
mip_desc m_mip_desc[cMaxMips];
uint m_num_mips;
enum { cMaxMips = 128 };
mip_desc m_mip_desc[cMaxMips];
typedef bool (*progress_callback_func)(uint percentage_completed, void* pProgress_data);
progress_callback_func m_pProgress_func;
void* m_pProgress_data;
uint m_progress_start;
uint m_progress_range;
typedef bool (*progress_callback_func)(uint percentage_completed, void* pProgress_data);
progress_callback_func m_pProgress_func;
void* m_pProgress_data;
uint m_progress_start;
uint m_progress_range;
uint m_comp_index;
uint m_comp_index;
bool m_use_both_block_types;
};
bool m_use_both_block_types;
};
class qdxt5
{
CRNLIB_NO_COPY_OR_ASSIGNMENT_OP(qdxt5);
class qdxt5 {
CRNLIB_NO_COPY_OR_ASSIGNMENT_OP(qdxt5);
public:
qdxt5(task_pool& task_pool);
~qdxt5();
public:
qdxt5(task_pool& task_pool);
~qdxt5();
void clear();
void clear();
bool init(uint n, const dxt_pixel_block* pBlocks, const qdxt5_params& params);
bool init(uint n, const dxt_pixel_block* pBlocks, const qdxt5_params& params);
uint get_num_blocks() const { return m_num_blocks; }
const dxt_pixel_block* get_blocks() const { return m_pBlocks; }
uint get_num_blocks() const { return m_num_blocks; }
const dxt_pixel_block* get_blocks() const { return m_pBlocks; }
bool pack(dxt5_block* pDst_elements, uint elements_per_block, const qdxt5_params& params);
bool pack(dxt5_block* pDst_elements, uint elements_per_block, const qdxt5_params& params);
private:
task_pool* m_pTask_pool;
crn_thread_id_t m_main_thread_id;
bool m_canceled;
private:
task_pool* m_pTask_pool;
crn_thread_id_t m_main_thread_id;
bool m_canceled;
uint m_progress_start;
uint m_progress_range;
uint m_progress_start;
uint m_progress_range;
uint m_num_blocks;
const dxt_pixel_block* m_pBlocks;
uint m_num_blocks;
const dxt_pixel_block* m_pBlocks;
dxt5_block* m_pDst_elements;
uint m_elements_per_block;
qdxt5_params m_params;
dxt5_block* m_pDst_elements;
uint m_elements_per_block;
qdxt5_params m_params;
uint m_max_selector_clusters;
uint m_max_selector_clusters;
int m_prev_percentage_complete;
int m_prev_percentage_complete;
typedef vec<2, float> vec2F;
typedef clusterizer<vec2F> vec2F_clusterizer;
vec2F_clusterizer m_endpoint_clusterizer;
typedef vec<2, float> vec2F;
typedef clusterizer<vec2F> vec2F_clusterizer;
vec2F_clusterizer m_endpoint_clusterizer;
crnlib::vector< crnlib::vector<uint> > m_endpoint_cluster_indices;
crnlib::vector<crnlib::vector<uint> > m_endpoint_cluster_indices;
typedef vec<16, float> vec16F;
typedef threaded_clusterizer<vec16F> vec16F_clusterizer;
typedef vec<16, float> vec16F;
typedef threaded_clusterizer<vec16F> vec16F_clusterizer;
typedef vec16F_clusterizer::weighted_vec weighted_selector_vec;
typedef vec16F_clusterizer::weighted_vec_array weighted_selector_vec_array;
typedef vec16F_clusterizer::weighted_vec weighted_selector_vec;
typedef vec16F_clusterizer::weighted_vec_array weighted_selector_vec_array;
vec16F_clusterizer m_selector_clusterizer;
vec16F_clusterizer m_selector_clusterizer;
crnlib::vector< crnlib::vector<uint> > m_cached_selector_cluster_indices[qdxt5_params::cMaxQuality + 1];
crnlib::vector<crnlib::vector<uint> > m_cached_selector_cluster_indices[qdxt5_params::cMaxQuality + 1];
struct cluster_id
{
cluster_id() : m_hash(0)
{
struct cluster_id {
cluster_id()
: m_hash(0) {
}
}
cluster_id(const crnlib::vector<uint>& indices) {
set(indices);
}
cluster_id(const crnlib::vector<uint>& indices)
{
set(indices);
}
void set(const crnlib::vector<uint>& indices) {
m_cells.resize(indices.size());
void set(const crnlib::vector<uint>& indices)
{
m_cells.resize(indices.size());
for (uint i = 0; i < indices.size(); i++)
m_cells[i] = static_cast<uint32>(indices[i]);
for (uint i = 0; i < indices.size(); i++)
m_cells[i] = static_cast<uint32>(indices[i]);
std::sort(m_cells.begin(), m_cells.end());
std::sort(m_cells.begin(), m_cells.end());
m_hash = fast_hash(&m_cells[0], sizeof(m_cells[0]) * m_cells.size());
}
bool operator< (const cluster_id& rhs) const
{
return m_cells < rhs.m_cells;
}
bool operator== (const cluster_id& rhs) const
{
if (m_hash != rhs.m_hash)
return false;
return m_cells == rhs.m_cells;
}
crnlib::vector<uint32> m_cells;
size_t m_hash;
operator size_t() const { return m_hash; }
};
typedef crnlib::hash_map<cluster_id, uint> cluster_hash;
cluster_hash m_cluster_hash;
spinlock m_cluster_hash_lock;
static bool generate_codebook_dummy_progress_callback(uint percentage_completed, void* pData);
static bool generate_codebook_progress_callback(uint percentage_completed, void* pData);
bool update_progress(uint value, uint max_value);
void pack_endpoints_task(uint64 data, void* pData_ptr);
void optimize_selectors_task(uint64 data, void* pData_ptr);
bool create_selector_clusters(uint max_selector_clusters, crnlib::vector< crnlib::vector<uint> >& selector_cluster_indices);
inline dxt5_block& get_block(uint index) const { return m_pDst_elements[index * m_elements_per_block]; }
};
} // namespace crnlib
m_hash = fast_hash(&m_cells[0], sizeof(m_cells[0]) * m_cells.size());
}
bool operator<(const cluster_id& rhs) const {
return m_cells < rhs.m_cells;
}
bool operator==(const cluster_id& rhs) const {
if (m_hash != rhs.m_hash)
return false;
return m_cells == rhs.m_cells;
}
crnlib::vector<uint32> m_cells;
size_t m_hash;
operator size_t() const { return m_hash; }
};
typedef crnlib::hash_map<cluster_id, uint> cluster_hash;
cluster_hash m_cluster_hash;
spinlock m_cluster_hash_lock;
static bool generate_codebook_dummy_progress_callback(uint percentage_completed, void* pData);
static bool generate_codebook_progress_callback(uint percentage_completed, void* pData);
bool update_progress(uint value, uint max_value);
void pack_endpoints_task(uint64 data, void* pData_ptr);
void optimize_selectors_task(uint64 data, void* pData_ptr);
bool create_selector_clusters(uint max_selector_clusters, crnlib::vector<crnlib::vector<uint> >& selector_cluster_indices);
inline dxt5_block& get_block(uint index) const { return m_pDst_elements[index * m_elements_per_block]; }
};
} // namespace crnlib
+262 -307
View File
@@ -2,344 +2,299 @@
// See Copyright Notice and license at the end of inc/crnlib.h
#pragma once
namespace crnlib
{
// Returns pointer to sorted array.
template<typename T>
T* radix_sort(uint num_vals, T* pBuf0, T* pBuf1, uint key_ofs, uint key_size)
{
CRNLIB_ASSERT_OPEN_RANGE(key_ofs, 0, sizeof(T));
CRNLIB_ASSERT_CLOSED_RANGE(key_size, 1, 4);
namespace crnlib {
// Returns pointer to sorted array.
template <typename T>
T* radix_sort(uint num_vals, T* pBuf0, T* pBuf1, uint key_ofs, uint key_size) {
CRNLIB_ASSERT_OPEN_RANGE(key_ofs, 0, sizeof(T));
CRNLIB_ASSERT_CLOSED_RANGE(key_size, 1, 4);
uint hist[256 * 4];
uint hist[256 * 4];
memset(hist, 0, sizeof(hist[0]) * 256 * key_size);
memset(hist, 0, sizeof(hist[0]) * 256 * key_size);
#define CRNLIB_GET_KEY(p) (*(uint*)((uint8*)(p) + key_ofs))
if (key_size == 4)
{
T* p = pBuf0;
T* q = pBuf0 + num_vals;
for ( ; p != q; p++)
{
const uint key = CRNLIB_GET_KEY(p);
if (key_size == 4) {
T* p = pBuf0;
T* q = pBuf0 + num_vals;
for (; p != q; p++) {
const uint key = CRNLIB_GET_KEY(p);
hist[ key & 0xFF]++;
hist[256 + ((key >> 8) & 0xFF)]++;
hist[512 + ((key >> 16) & 0xFF)]++;
hist[768 + ((key >> 24) & 0xFF)]++;
}
hist[key & 0xFF]++;
hist[256 + ((key >> 8) & 0xFF)]++;
hist[512 + ((key >> 16) & 0xFF)]++;
hist[768 + ((key >> 24) & 0xFF)]++;
}
} else if (key_size == 3) {
T* p = pBuf0;
T* q = pBuf0 + num_vals;
for (; p != q; p++) {
const uint key = CRNLIB_GET_KEY(p);
hist[key & 0xFF]++;
hist[256 + ((key >> 8) & 0xFF)]++;
hist[512 + ((key >> 16) & 0xFF)]++;
}
} else if (key_size == 2) {
T* p = pBuf0;
T* q = pBuf0 + (num_vals >> 1) * 2;
for (; p != q; p += 2) {
const uint key0 = CRNLIB_GET_KEY(p);
const uint key1 = CRNLIB_GET_KEY(p + 1);
hist[key0 & 0xFF]++;
hist[256 + ((key0 >> 8) & 0xFF)]++;
hist[key1 & 0xFF]++;
hist[256 + ((key1 >> 8) & 0xFF)]++;
}
if (num_vals & 1) {
const uint key = CRNLIB_GET_KEY(p);
hist[key & 0xFF]++;
hist[256 + ((key >> 8) & 0xFF)]++;
}
} else {
CRNLIB_ASSERT(key_size == 1);
if (key_size != 1)
return NULL;
T* p = pBuf0;
T* q = pBuf0 + (num_vals >> 1) * 2;
for (; p != q; p += 2) {
const uint key0 = CRNLIB_GET_KEY(p);
const uint key1 = CRNLIB_GET_KEY(p + 1);
hist[key0 & 0xFF]++;
hist[key1 & 0xFF]++;
}
if (num_vals & 1) {
const uint key = CRNLIB_GET_KEY(p);
hist[key & 0xFF]++;
}
}
T* pCur = pBuf0;
T* pNew = pBuf1;
for (uint pass = 0; pass < key_size; pass++) {
const uint* pHist = &hist[pass << 8];
uint offsets[256];
uint cur_ofs = 0;
for (uint i = 0; i < 256; i += 2) {
offsets[i] = cur_ofs;
cur_ofs += pHist[i];
offsets[i + 1] = cur_ofs;
cur_ofs += pHist[i + 1];
}
const uint pass_shift = pass << 3;
T* p = pCur;
T* q = pCur + (num_vals >> 1) * 2;
for (; p != q; p += 2) {
uint c0 = (CRNLIB_GET_KEY(p) >> pass_shift) & 0xFF;
uint c1 = (CRNLIB_GET_KEY(p + 1) >> pass_shift) & 0xFF;
if (c0 == c1) {
uint dst_offset0 = offsets[c0];
offsets[c0] = dst_offset0 + 2;
pNew[dst_offset0] = p[0];
pNew[dst_offset0 + 1] = p[1];
} else {
uint dst_offset0 = offsets[c0]++;
uint dst_offset1 = offsets[c1]++;
pNew[dst_offset0] = p[0];
pNew[dst_offset1] = p[1];
}
else if (key_size == 3)
{
T* p = pBuf0;
T* q = pBuf0 + num_vals;
for ( ; p != q; p++)
{
const uint key = CRNLIB_GET_KEY(p);
}
hist[ key & 0xFF]++;
hist[256 + ((key >> 8) & 0xFF)]++;
hist[512 + ((key >> 16) & 0xFF)]++;
}
}
else if (key_size == 2)
{
T* p = pBuf0;
T* q = pBuf0 + (num_vals >> 1) * 2;
if (num_vals & 1) {
uint c = (CRNLIB_GET_KEY(p) >> pass_shift) & 0xFF;
for ( ; p != q; p += 2)
{
const uint key0 = CRNLIB_GET_KEY(p);
const uint key1 = CRNLIB_GET_KEY(p+1);
uint dst_offset = offsets[c];
offsets[c] = dst_offset + 1;
hist[ key0 & 0xFF]++;
hist[256 + ((key0 >> 8) & 0xFF)]++;
pNew[dst_offset] = *p;
}
hist[ key1 & 0xFF]++;
hist[256 + ((key1 >> 8) & 0xFF)]++;
}
T* t = pCur;
pCur = pNew;
pNew = t;
}
if (num_vals & 1)
{
const uint key = CRNLIB_GET_KEY(p);
hist[ key & 0xFF]++;
hist[256 + ((key >> 8) & 0xFF)]++;
}
}
else
{
CRNLIB_ASSERT(key_size == 1);
if (key_size != 1)
return NULL;
T* p = pBuf0;
T* q = pBuf0 + (num_vals >> 1) * 2;
for ( ; p != q; p += 2)
{
const uint key0 = CRNLIB_GET_KEY(p);
const uint key1 = CRNLIB_GET_KEY(p+1);
hist[key0 & 0xFF]++;
hist[key1 & 0xFF]++;
}
if (num_vals & 1)
{
const uint key = CRNLIB_GET_KEY(p);
hist[key & 0xFF]++;
}
}
T* pCur = pBuf0;
T* pNew = pBuf1;
for (uint pass = 0; pass < key_size; pass++)
{
const uint* pHist = &hist[pass << 8];
uint offsets[256];
uint cur_ofs = 0;
for (uint i = 0; i < 256; i += 2)
{
offsets[i] = cur_ofs;
cur_ofs += pHist[i];
offsets[i+1] = cur_ofs;
cur_ofs += pHist[i+1];
}
const uint pass_shift = pass << 3;
T* p = pCur;
T* q = pCur + (num_vals >> 1) * 2;
for ( ; p != q; p += 2)
{
uint c0 = (CRNLIB_GET_KEY(p) >> pass_shift) & 0xFF;
uint c1 = (CRNLIB_GET_KEY(p+1) >> pass_shift) & 0xFF;
if (c0 == c1)
{
uint dst_offset0 = offsets[c0];
offsets[c0] = dst_offset0 + 2;
pNew[dst_offset0] = p[0];
pNew[dst_offset0 + 1] = p[1];
}
else
{
uint dst_offset0 = offsets[c0]++;
uint dst_offset1 = offsets[c1]++;
pNew[dst_offset0] = p[0];
pNew[dst_offset1] = p[1];
}
}
if (num_vals & 1)
{
uint c = (CRNLIB_GET_KEY(p) >> pass_shift) & 0xFF;
uint dst_offset = offsets[c];
offsets[c] = dst_offset + 1;
pNew[dst_offset] = *p;
}
T* t = pCur;
pCur = pNew;
pNew = t;
}
return pCur;
}
return pCur;
}
#undef CRNLIB_GET_KEY
// Returns pointer to sorted array.
template<typename T, typename Q>
T* indirect_radix_sort(uint num_indices, T* pIndices0, T* pIndices1, const Q* pKeys, uint key_ofs, uint key_size, bool init_indices)
{
CRNLIB_ASSERT_OPEN_RANGE(key_ofs, 0, sizeof(T));
CRNLIB_ASSERT_CLOSED_RANGE(key_size, 1, 4);
// Returns pointer to sorted array.
template <typename T, typename Q>
T* indirect_radix_sort(uint num_indices, T* pIndices0, T* pIndices1, const Q* pKeys, uint key_ofs, uint key_size, bool init_indices) {
CRNLIB_ASSERT_OPEN_RANGE(key_ofs, 0, sizeof(T));
CRNLIB_ASSERT_CLOSED_RANGE(key_size, 1, 4);
if (init_indices)
{
T* p = pIndices0;
T* q = pIndices0 + (num_indices >> 1) * 2;
uint i;
for (i = 0; p != q; p += 2, i += 2)
{
p[0] = static_cast<T>(i);
p[1] = static_cast<T>(i + 1);
}
if (init_indices) {
T* p = pIndices0;
T* q = pIndices0 + (num_indices >> 1) * 2;
uint i;
for (i = 0; p != q; p += 2, i += 2) {
p[0] = static_cast<T>(i);
p[1] = static_cast<T>(i + 1);
}
if (num_indices & 1)
*p = static_cast<T>(i);
}
if (num_indices & 1)
*p = static_cast<T>(i);
}
uint hist[256 * 4];
uint hist[256 * 4];
memset(hist, 0, sizeof(hist[0]) * 256 * key_size);
memset(hist, 0, sizeof(hist[0]) * 256 * key_size);
#define CRNLIB_GET_KEY(p) (*(const uint*)((const uint8*)(pKeys + *(p)) + key_ofs))
#define CRNLIB_GET_KEY_FROM_INDEX(i) (*(const uint*)((const uint8*)(pKeys + (i)) + key_ofs))
if (key_size == 4)
{
T* p = pIndices0;
T* q = pIndices0 + num_indices;
for ( ; p != q; p++)
{
const uint key = CRNLIB_GET_KEY(p);
if (key_size == 4) {
T* p = pIndices0;
T* q = pIndices0 + num_indices;
for (; p != q; p++) {
const uint key = CRNLIB_GET_KEY(p);
hist[ key & 0xFF]++;
hist[256 + ((key >> 8) & 0xFF)]++;
hist[512 + ((key >> 16) & 0xFF)]++;
hist[768 + ((key >> 24) & 0xFF)]++;
}
hist[key & 0xFF]++;
hist[256 + ((key >> 8) & 0xFF)]++;
hist[512 + ((key >> 16) & 0xFF)]++;
hist[768 + ((key >> 24) & 0xFF)]++;
}
} else if (key_size == 3) {
T* p = pIndices0;
T* q = pIndices0 + num_indices;
for (; p != q; p++) {
const uint key = CRNLIB_GET_KEY(p);
hist[key & 0xFF]++;
hist[256 + ((key >> 8) & 0xFF)]++;
hist[512 + ((key >> 16) & 0xFF)]++;
}
} else if (key_size == 2) {
T* p = pIndices0;
T* q = pIndices0 + (num_indices >> 1) * 2;
for (; p != q; p += 2) {
const uint key0 = CRNLIB_GET_KEY(p);
const uint key1 = CRNLIB_GET_KEY(p + 1);
hist[key0 & 0xFF]++;
hist[256 + ((key0 >> 8) & 0xFF)]++;
hist[key1 & 0xFF]++;
hist[256 + ((key1 >> 8) & 0xFF)]++;
}
if (num_indices & 1) {
const uint key = CRNLIB_GET_KEY(p);
hist[key & 0xFF]++;
hist[256 + ((key >> 8) & 0xFF)]++;
}
} else {
CRNLIB_ASSERT(key_size == 1);
if (key_size != 1)
return NULL;
T* p = pIndices0;
T* q = pIndices0 + (num_indices >> 1) * 2;
for (; p != q; p += 2) {
const uint key0 = CRNLIB_GET_KEY(p);
const uint key1 = CRNLIB_GET_KEY(p + 1);
hist[key0 & 0xFF]++;
hist[key1 & 0xFF]++;
}
if (num_indices & 1) {
const uint key = CRNLIB_GET_KEY(p);
hist[key & 0xFF]++;
}
}
T* pCur = pIndices0;
T* pNew = pIndices1;
for (uint pass = 0; pass < key_size; pass++) {
const uint* pHist = &hist[pass << 8];
uint offsets[256];
uint cur_ofs = 0;
for (uint i = 0; i < 256; i += 2) {
offsets[i] = cur_ofs;
cur_ofs += pHist[i];
offsets[i + 1] = cur_ofs;
cur_ofs += pHist[i + 1];
}
const uint pass_shift = pass << 3;
T* p = pCur;
T* q = pCur + (num_indices >> 1) * 2;
for (; p != q; p += 2) {
uint index0 = p[0];
uint index1 = p[1];
uint c0 = (CRNLIB_GET_KEY_FROM_INDEX(index0) >> pass_shift) & 0xFF;
uint c1 = (CRNLIB_GET_KEY_FROM_INDEX(index1) >> pass_shift) & 0xFF;
if (c0 == c1) {
uint dst_offset0 = offsets[c0];
offsets[c0] = dst_offset0 + 2;
pNew[dst_offset0] = static_cast<T>(index0);
pNew[dst_offset0 + 1] = static_cast<T>(index1);
} else {
uint dst_offset0 = offsets[c0]++;
uint dst_offset1 = offsets[c1]++;
pNew[dst_offset0] = static_cast<T>(index0);
pNew[dst_offset1] = static_cast<T>(index1);
}
else if (key_size == 3)
{
T* p = pIndices0;
T* q = pIndices0 + num_indices;
for ( ; p != q; p++)
{
const uint key = CRNLIB_GET_KEY(p);
}
hist[ key & 0xFF]++;
hist[256 + ((key >> 8) & 0xFF)]++;
hist[512 + ((key >> 16) & 0xFF)]++;
}
}
else if (key_size == 2)
{
T* p = pIndices0;
T* q = pIndices0 + (num_indices >> 1) * 2;
if (num_indices & 1) {
uint index = *p;
uint c = (CRNLIB_GET_KEY_FROM_INDEX(index) >> pass_shift) & 0xFF;
for ( ; p != q; p += 2)
{
const uint key0 = CRNLIB_GET_KEY(p);
const uint key1 = CRNLIB_GET_KEY(p+1);
uint dst_offset = offsets[c];
offsets[c] = dst_offset + 1;
hist[ key0 & 0xFF]++;
hist[256 + ((key0 >> 8) & 0xFF)]++;
pNew[dst_offset] = static_cast<T>(index);
}
hist[ key1 & 0xFF]++;
hist[256 + ((key1 >> 8) & 0xFF)]++;
}
T* t = pCur;
pCur = pNew;
pNew = t;
}
if (num_indices & 1)
{
const uint key = CRNLIB_GET_KEY(p);
hist[ key & 0xFF]++;
hist[256 + ((key >> 8) & 0xFF)]++;
}
}
else
{
CRNLIB_ASSERT(key_size == 1);
if (key_size != 1)
return NULL;
T* p = pIndices0;
T* q = pIndices0 + (num_indices >> 1) * 2;
for ( ; p != q; p += 2)
{
const uint key0 = CRNLIB_GET_KEY(p);
const uint key1 = CRNLIB_GET_KEY(p+1);
hist[key0 & 0xFF]++;
hist[key1 & 0xFF]++;
}
if (num_indices & 1)
{
const uint key = CRNLIB_GET_KEY(p);
hist[key & 0xFF]++;
}
}
T* pCur = pIndices0;
T* pNew = pIndices1;
for (uint pass = 0; pass < key_size; pass++)
{
const uint* pHist = &hist[pass << 8];
uint offsets[256];
uint cur_ofs = 0;
for (uint i = 0; i < 256; i += 2)
{
offsets[i] = cur_ofs;
cur_ofs += pHist[i];
offsets[i+1] = cur_ofs;
cur_ofs += pHist[i+1];
}
const uint pass_shift = pass << 3;
T* p = pCur;
T* q = pCur + (num_indices >> 1) * 2;
for ( ; p != q; p += 2)
{
uint index0 = p[0];
uint index1 = p[1];
uint c0 = (CRNLIB_GET_KEY_FROM_INDEX(index0) >> pass_shift) & 0xFF;
uint c1 = (CRNLIB_GET_KEY_FROM_INDEX(index1) >> pass_shift) & 0xFF;
if (c0 == c1)
{
uint dst_offset0 = offsets[c0];
offsets[c0] = dst_offset0 + 2;
pNew[dst_offset0] = static_cast<T>(index0);
pNew[dst_offset0 + 1] = static_cast<T>(index1);
}
else
{
uint dst_offset0 = offsets[c0]++;
uint dst_offset1 = offsets[c1]++;
pNew[dst_offset0] = static_cast<T>(index0);
pNew[dst_offset1] = static_cast<T>(index1);
}
}
if (num_indices & 1)
{
uint index = *p;
uint c = (CRNLIB_GET_KEY_FROM_INDEX(index) >> pass_shift) & 0xFF;
uint dst_offset = offsets[c];
offsets[c] = dst_offset + 1;
pNew[dst_offset] = static_cast<T>(index);
}
T* t = pCur;
pCur = pNew;
pNew = t;
}
return pCur;
}
return pCur;
}
#undef CRNLIB_GET_KEY
#undef CRNLIB_GET_KEY_FROM_INDEX
} // namespace crnlib
} // namespace crnlib
+253 -289
View File
@@ -9,240 +9,217 @@
#include "crn_rand.h"
#include "crn_hash.h"
#define znew (z=36969*(z&65535)+(z>>16))
#define wnew (w=18000*(w&65535)+(w>>16))
#define MWC ((znew<<16)+wnew )
#define SHR3 (jsr^=(jsr<<17), jsr^=(jsr>>13), jsr^=(jsr<<5))
#define CONG (jcong=69069*jcong+1234567)
#define FIB ((b=a+b),(a=b-a))
#define KISS ((MWC^CONG)+SHR3)
#define LFIB4 (c++,t[c]=t[c]+t[UC(c+58)]+t[UC(c+119)]+t[UC(c+178)])
#define SWB (c++,bro=(x<y),t[c]=(x=t[UC(c+34)])-(y=t[UC(c+19)]+bro))
#define UNI (KISS*2.328306e-10)
#define VNI ((long) KISS)*4.656613e-10
#define UC (unsigned char) /*a cast operation*/
#define znew (z = 36969 * (z & 65535) + (z >> 16))
#define wnew (w = 18000 * (w & 65535) + (w >> 16))
#define MWC ((znew << 16) + wnew)
#define SHR3 (jsr ^= (jsr << 17), jsr ^= (jsr >> 13), jsr ^= (jsr << 5))
#define CONG (jcong = 69069 * jcong + 1234567)
#define FIB ((b = a + b), (a = b - a))
#define KISS ((MWC ^ CONG) + SHR3)
#define LFIB4 (c++, t[c] = t[c] + t[UC(c + 58)] + t[UC(c + 119)] + t[UC(c + 178)])
#define SWB (c++, bro = (x < y), t[c] = (x = t[UC(c + 34)]) - (y = t[UC(c + 19)] + bro))
#define UNI (KISS * 2.328306e-10)
#define VNI ((long)KISS) * 4.656613e-10
#define UC (unsigned char)/*a cast operation*/
//#define rot(x,k) (((x)<<(k))|((x)>>(32-(k))))
#define rot(x,k) CRNLIB_ROTATE_LEFT(x,k)
#define rot(x, k) CRNLIB_ROTATE_LEFT(x, k)
namespace crnlib
{
static const double cNorm = 1.0 / (double)0x100000000ULL;
namespace crnlib {
static const double cNorm = 1.0 / (double)0x100000000ULL;
kiss99::kiss99()
{
x = 123456789;
y = 362436000;
z = 521288629;
c = 7654321;
}
kiss99::kiss99() {
x = 123456789;
y = 362436000;
z = 521288629;
c = 7654321;
}
void kiss99::seed(uint32 i, uint32 j, uint32 k)
{
x = i;
y = j;
z = k;
c = 7654321;
}
void kiss99::seed(uint32 i, uint32 j, uint32 k) {
x = i;
y = j;
z = k;
c = 7654321;
}
inline uint32 kiss99::next()
{
x = 69069*x+12345;
inline uint32 kiss99::next() {
x = 69069 * x + 12345;
y ^= (y<<13);
y ^= (y>>17);
y ^= (y<<5);
y ^= (y << 13);
y ^= (y >> 17);
y ^= (y << 5);
uint64 t = c;
t += (698769069ULL*z);
c = static_cast<uint32>(t >> 32);
z = static_cast<uint32>(t);
uint64 t = c;
t += (698769069ULL * z);
c = static_cast<uint32>(t >> 32);
z = static_cast<uint32>(t);
return (x+y+z);
}
return (x + y + z);
}
inline uint32 ranctx::next()
{
uint32 e = a - rot(b, 27);
a = b ^ rot(c, 17);
b = c + d;
c = d + e;
d = e + a;
return d;
}
inline uint32 ranctx::next() {
uint32 e = a - rot(b, 27);
a = b ^ rot(c, 17);
b = c + d;
c = d + e;
d = e + a;
return d;
}
void ranctx::seed(uint32 seed)
{
a = 0xf1ea5eed, b = c = d = seed;
for (uint32 i=0; i<20; ++i)
next();
}
void ranctx::seed(uint32 seed) {
a = 0xf1ea5eed, b = c = d = seed;
for (uint32 i = 0; i < 20; ++i)
next();
}
well512::well512()
{
seed(0xDEADBE3F);
}
well512::well512() {
seed(0xDEADBE3F);
}
void well512::seed(uint32 seed[well512::cStateSize])
{
memcpy(m_state, seed, sizeof(m_state));
m_index = 0;
}
void well512::seed(uint32 seed[well512::cStateSize]) {
memcpy(m_state, seed, sizeof(m_state));
m_index = 0;
}
void well512::seed(uint32 seed)
{
uint32 jsr = utils::swap32(seed) ^ 0xAAC29377;
void well512::seed(uint32 seed) {
uint32 jsr = utils::swap32(seed) ^ 0xAAC29377;
for (uint i = 0; i < cStateSize; i++)
{
SHR3;
seed = bitmix32c(seed);
for (uint i = 0; i < cStateSize; i++) {
SHR3;
seed = bitmix32c(seed);
m_state[i] = seed ^ jsr;
}
m_index = 0;
}
m_state[i] = seed ^ jsr;
}
m_index = 0;
}
void well512::seed(uint32 seed1, uint32 seed2, uint32 seed3)
{
uint32 jsr = seed2;
uint32 jcong = seed3;
void well512::seed(uint32 seed1, uint32 seed2, uint32 seed3) {
uint32 jsr = seed2;
uint32 jcong = seed3;
for (uint i = 0; i < cStateSize; i++)
{
SHR3;
seed1 = bitmix32c(seed1);
CONG;
for (uint i = 0; i < cStateSize; i++) {
SHR3;
seed1 = bitmix32c(seed1);
CONG;
m_state[i] = seed1 ^ jsr ^ jcong;
}
m_index = 0;
}
m_state[i] = seed1 ^ jsr ^ jcong;
}
m_index = 0;
}
inline uint32 well512::next()
{
uint32 a, b, c, d;
a = m_state[m_index];
c = m_state[(m_index+13)&15];
b = a^c^(a<<16)^(c<<15);
c = m_state[(m_index+9)&15];
c ^= (c>>11);
a = m_state[m_index] = b^c;
d = a^((a<<5)&0xDA442D20UL);
m_index = (m_index + 15)&15;
a = m_state[m_index];
m_state[m_index] = a^b^d^(a<<2)^(b<<18)^(c<<28);
return m_state[m_index];
}
inline uint32 well512::next() {
uint32 a, b, c, d;
a = m_state[m_index];
c = m_state[(m_index + 13) & 15];
b = a ^ c ^ (a << 16) ^ (c << 15);
c = m_state[(m_index + 9) & 15];
c ^= (c >> 11);
a = m_state[m_index] = b ^ c;
d = a ^ ((a << 5) & 0xDA442D20UL);
m_index = (m_index + 15) & 15;
a = m_state[m_index];
m_state[m_index] = a ^ b ^ d ^ (a << 2) ^ (b << 18) ^ (c << 28);
return m_state[m_index];
}
random::random()
{
seed(12345,65435,34221);
}
random::random() {
seed(12345, 65435, 34221);
}
random::random(uint32 i)
{
seed(i);
}
random::random(uint32 i) {
seed(i);
}
void random::seed(uint32 i1, uint32 i2, uint32 i3)
{
m_ranctx.seed(i1^i2^i3);
void random::seed(uint32 i1, uint32 i2, uint32 i3) {
m_ranctx.seed(i1 ^ i2 ^ i3);
m_kiss99.seed(i1, i2, i3);
m_kiss99.seed(i1, i2, i3);
m_well512.seed(i1, i2, i3);
m_well512.seed(i1, i2, i3);
for (uint i = 0; i < 100; i++)
urand32();
}
for (uint i = 0; i < 100; i++)
urand32();
}
void random::seed(uint32 i)
{
uint32 jsr = i;
SHR3; SHR3;
uint32 jcong = utils::swap32(~jsr);
CONG; CONG;
uint32 i1 = SHR3 ^ CONG;
uint32 i2 = SHR3 ^ CONG;
uint32 i3 = SHR3 + CONG;
seed(i1, i2, i3);
}
void random::seed(uint32 i) {
uint32 jsr = i;
SHR3;
SHR3;
uint32 jcong = utils::swap32(~jsr);
CONG;
CONG;
uint32 i1 = SHR3 ^ CONG;
uint32 i2 = SHR3 ^ CONG;
uint32 i3 = SHR3 + CONG;
seed(i1, i2, i3);
}
uint32 random::urand32()
{
return m_kiss99.next() ^ (m_ranctx.next() + m_well512.next());
}
uint32 random::urand32() {
return m_kiss99.next() ^ (m_ranctx.next() + m_well512.next());
}
uint64 random::urand64()
{
uint64 result = urand32();
result <<= 32ULL;
result |= urand32();
return result;
}
uint32 random::fast_urand32()
{
return m_well512.next();
}
uint64 random::urand64() {
uint64 result = urand32();
result <<= 32ULL;
result |= urand32();
return result;
}
uint32 random::fast_urand32() {
return m_well512.next();
}
uint32 random::bit()
{
uint32 k = urand32();
return (k ^ (k >> 6) ^ (k >> 10) ^ (k >> 30)) & 1;
}
uint32 random::bit() {
uint32 k = urand32();
return (k ^ (k >> 6) ^ (k >> 10) ^ (k >> 30)) & 1;
}
double random::drand(double l, double h)
{
CRNLIB_ASSERT(l <= h);
if (l >= h)
return l;
double random::drand(double l, double h) {
CRNLIB_ASSERT(l <= h);
if (l >= h)
return l;
return math::clamp(l + (h - l) * (urand32() * cNorm), l, h);
}
return math::clamp(l + (h - l) * (urand32() * cNorm), l, h);
}
float random::frand(float l, float h)
{
CRNLIB_ASSERT(l <= h);
if (l >= h)
return l;
float random::frand(float l, float h) {
CRNLIB_ASSERT(l <= h);
if (l >= h)
return l;
float r = static_cast<float>(l + (h - l) * (urand32() * cNorm));
float r = static_cast<float>(l + (h - l) * (urand32() * cNorm));
return math::clamp<float>(r, l, h);
}
int random::irand(int l, int h)
{
CRNLIB_ASSERT(l < h);
if (l >= h)
return l;
return math::clamp<float>(r, l, h);
}
uint32 range = static_cast<uint32>(h - l);
int random::irand(int l, int h) {
CRNLIB_ASSERT(l < h);
if (l >= h)
return l;
uint32 rnd = urand32();
uint32 range = static_cast<uint32>(h - l);
uint32 rnd = urand32();
#if defined(_M_IX86) && defined(_MSC_VER)
//uint32 rnd_range = static_cast<uint32>(__emulu(range, rnd) >> 32U);
uint32 x[2];
*reinterpret_cast<uint64*>(x) = __emulu(range, rnd);
uint32 rnd_range = x[1];
//uint32 rnd_range = static_cast<uint32>(__emulu(range, rnd) >> 32U);
uint32 x[2];
*reinterpret_cast<uint64*>(x) = __emulu(range, rnd);
uint32 rnd_range = x[1];
#else
uint32 rnd_range = static_cast<uint32>((((uint64)range) * ((uint64)rnd)) >> 32U);
uint32 rnd_range = static_cast<uint32>((((uint64)range) * ((uint64)rnd)) >> 32U);
#endif
int result = l + rnd_range;
CRNLIB_ASSERT((result >= l) && (result < h));
return result;
}
int result = l + rnd_range;
CRNLIB_ASSERT((result >= l) && (result < h));
return result;
}
int random::irand_inclusive(int l, int h)
{
CRNLIB_ASSERT(h < cINT32_MAX);
return irand(l, h + 1);
}
int random::irand_inclusive(int l, int h) {
CRNLIB_ASSERT(h < cINT32_MAX);
return irand(l, h + 1);
}
/*
/*
ALGORITHM 712, COLLECTED ALGORITHMS FROM ACM.
THIS WORK PUBLISHED IN TRANSACTIONS ON MATHEMATICAL SOFTWARE,
VOL. 18, NO. 4, DECEMBER, 1992, PP. 434-435.
@@ -253,133 +230,120 @@ namespace crnlib
The algorithm uses the ratio of uniforms method of A.J. Kinderman
and J.F. Monahan augmented with quadratic bounding curves.
*/
double random::gaussian(double mean, double stddev)
{
double q,u,v,x,y;
double random::gaussian(double mean, double stddev) {
double q, u, v, x, y;
/*
/*
Generate P = (u,v) uniform in rect. enclosing acceptance region
Make sure that any random numbers <= 0 are rejected, since
gaussian() requires uniforms > 0, but RandomUniform() delivers >= 0.
*/
do {
u = drand(0, 1);
v = drand(0, 1);
if (u <= 0.0 || v <= 0.0) {
u = 1.0;
v = 1.0;
}
v = 1.7156 * (v - 0.5);
do {
u = drand(0, 1);
v = drand(0, 1);
if (u <= 0.0 || v <= 0.0) {
u = 1.0;
v = 1.0;
}
v = 1.7156 * (v - 0.5);
/* Evaluate the quadratic form */
x = u - 0.449871;
y = fabs(v) + 0.386595;
q = x * x + y * (0.19600 * y - 0.25472 * x);
/* Evaluate the quadratic form */
x = u - 0.449871;
y = fabs(v) + 0.386595;
q = x * x + y * (0.19600 * y - 0.25472 * x);
/* Accept P if inside inner ellipse */
if (q < 0.27597)
break;
/* Accept P if inside inner ellipse */
if (q < 0.27597)
break;
/* Reject P if outside outer ellipse, or outside acceptance region */
} while ((q > 0.27846) || (v * v > -4.0 * log(u) * u * u));
/* Reject P if outside outer ellipse, or outside acceptance region */
} while ((q > 0.27846) || (v * v > -4.0 * log(u) * u * u));
/* Return ratio of P's coordinates as the normal deviate */
return (mean + stddev * v / u);
}
/* Return ratio of P's coordinates as the normal deviate */
return (mean + stddev * v / u);
}
void random::test()
{
}
void random::test() {
}
fast_random::fast_random() :
jsr(0xABCD917A),
jcong(0x17F3DEAD)
{
}
fast_random::fast_random()
: jsr(0xABCD917A),
jcong(0x17F3DEAD) {
}
fast_random::fast_random(const fast_random& other) :
jsr(other.jsr), jcong(other.jcong)
{
}
fast_random::fast_random(const fast_random& other)
: jsr(other.jsr), jcong(other.jcong) {
}
fast_random::fast_random(uint32 i)
{
seed(i);
}
fast_random::fast_random(uint32 i) {
seed(i);
}
fast_random& fast_random::operator=(const fast_random& other)
{
jsr = other.jsr;
jcong = other.jcong;
return *this;
}
fast_random& fast_random::operator=(const fast_random& other) {
jsr = other.jsr;
jcong = other.jcong;
return *this;
}
void fast_random::seed(uint32 i)
{
jsr = i;
SHR3;
SHR3;
jcong = (~i) ^ 0xDEADBEEF;
void fast_random::seed(uint32 i) {
jsr = i;
SHR3;
SHR3;
jcong = (~i) ^ 0xDEADBEEF;
SHR3;
CONG;
}
SHR3;
CONG;
}
uint32 fast_random::urand32()
{
return SHR3 ^ CONG;
}
uint32 fast_random::urand32() {
return SHR3 ^ CONG;
}
uint64 fast_random::urand64()
{
uint64 result = urand32();
result <<= 32ULL;
result |= urand32();
return result;
}
int fast_random::irand(int l, int h)
{
CRNLIB_ASSERT(l < h);
if (l >= h)
return l;
uint64 fast_random::urand64() {
uint64 result = urand32();
result <<= 32ULL;
result |= urand32();
return result;
}
int fast_random::irand(int l, int h) {
CRNLIB_ASSERT(l < h);
if (l >= h)
return l;
uint32 range = static_cast<uint32>(h - l);
uint32 range = static_cast<uint32>(h - l);
uint32 rnd = urand32();
uint32 rnd = urand32();
#if defined(_M_IX86) && defined(_MSC_VER)
//uint32 rnd_range = static_cast<uint32>(__emulu(range, rnd) >> 32U);
uint32 x[2];
*reinterpret_cast<uint64*>(x) = __emulu(range, rnd);
uint32 rnd_range = x[1];
//uint32 rnd_range = static_cast<uint32>(__emulu(range, rnd) >> 32U);
uint32 x[2];
*reinterpret_cast<uint64*>(x) = __emulu(range, rnd);
uint32 rnd_range = x[1];
#else
uint32 rnd_range = static_cast<uint32>((((uint64)range) * ((uint64)rnd)) >> 32U);
uint32 rnd_range = static_cast<uint32>((((uint64)range) * ((uint64)rnd)) >> 32U);
#endif
int result = l + rnd_range;
CRNLIB_ASSERT((result >= l) && (result < h));
return result;
}
int result = l + rnd_range;
CRNLIB_ASSERT((result >= l) && (result < h));
return result;
}
double fast_random::drand(double l, double h)
{
CRNLIB_ASSERT(l <= h);
if (l >= h)
return l;
double fast_random::drand(double l, double h) {
CRNLIB_ASSERT(l <= h);
if (l >= h)
return l;
return math::clamp(l + (h - l) * (urand32() * cNorm), l, h);
}
return math::clamp(l + (h - l) * (urand32() * cNorm), l, h);
}
float fast_random::frand(float l, float h)
{
CRNLIB_ASSERT(l <= h);
if (l >= h)
return l;
float fast_random::frand(float l, float h) {
CRNLIB_ASSERT(l <= h);
if (l >= h)
return l;
float r = static_cast<float>(l + (h - l) * (urand32() * cNorm));
float r = static_cast<float>(l + (h - l) * (urand32() * cNorm));
return math::clamp<float>(r, l, h);
}
} // namespace crnlib
return math::clamp<float>(r, l, h);
}
} // namespace crnlib
+106 -112
View File
@@ -1,119 +1,113 @@
// File: crn_rand.h
// See Copyright Notice and license at the end of inc/crnlib.h
#pragma once
#pragma once
namespace crnlib
{
class kiss99
{
public:
kiss99();
void seed(uint32 i, uint32 j, uint32 k);
inline uint32 next();
private:
uint32 x;
uint32 y;
uint32 z;
uint32 c;
};
class well512
{
public:
well512();
enum { cStateSize = 16 };
void seed(uint32 seed[cStateSize]);
void seed(uint32 seed);
void seed(uint32 seed1, uint32 seed2, uint32 seed3);
inline uint32 next();
private:
uint32 m_state[cStateSize];
uint32 m_index;
};
class ranctx
{
public:
ranctx() { seed(0xDE149737); }
void seed(uint32 seed);
inline uint32 next();
private:
uint32 a;
uint32 b;
uint32 c;
uint32 d;
};
class random
{
public:
random();
random(uint32 i);
void seed(uint32 i);
void seed(uint32 i1, uint32 i2, uint32 i3);
uint32 urand32();
uint64 urand64();
// "Fast" variant uses no multiplies.
uint32 fast_urand32();
uint32 bit();
// Returns random between [0, 1)
double drand(double l, double h);
float frand(float l, float h);
// Returns random between [l, h)
int irand(int l, int h);
namespace crnlib {
class kiss99 {
public:
kiss99();
// Returns random between [l, h]
int irand_inclusive(int l, int h);
double gaussian(double mean, double stddev);
void test();
void seed(uint32 i, uint32 j, uint32 k);
private:
ranctx m_ranctx;
kiss99 m_kiss99;
well512 m_well512;
};
// Simpler, minimal state PRNG
class fast_random
{
public:
fast_random();
fast_random(uint32 i);
fast_random(const fast_random& other);
fast_random& operator=(const fast_random& other);
void seed(uint32 i);
uint32 urand32();
uint64 urand64();
int irand(int l, int h);
double drand(double l, double h);
inline uint32 next();
float frand(float l, float h);
private:
uint32 jsr;
uint32 jcong;
};
private:
uint32 x;
uint32 y;
uint32 z;
uint32 c;
};
} // namespace crnlib
class well512 {
public:
well512();
enum { cStateSize = 16 };
void seed(uint32 seed[cStateSize]);
void seed(uint32 seed);
void seed(uint32 seed1, uint32 seed2, uint32 seed3);
inline uint32 next();
private:
uint32 m_state[cStateSize];
uint32 m_index;
};
class ranctx {
public:
ranctx() { seed(0xDE149737); }
void seed(uint32 seed);
inline uint32 next();
private:
uint32 a;
uint32 b;
uint32 c;
uint32 d;
};
class random {
public:
random();
random(uint32 i);
void seed(uint32 i);
void seed(uint32 i1, uint32 i2, uint32 i3);
uint32 urand32();
uint64 urand64();
// "Fast" variant uses no multiplies.
uint32 fast_urand32();
uint32 bit();
// Returns random between [0, 1)
double drand(double l, double h);
float frand(float l, float h);
// Returns random between [l, h)
int irand(int l, int h);
// Returns random between [l, h]
int irand_inclusive(int l, int h);
double gaussian(double mean, double stddev);
void test();
private:
ranctx m_ranctx;
kiss99 m_kiss99;
well512 m_well512;
};
// Simpler, minimal state PRNG
class fast_random {
public:
fast_random();
fast_random(uint32 i);
fast_random(const fast_random& other);
fast_random& operator=(const fast_random& other);
void seed(uint32 i);
uint32 urand32();
uint64 urand64();
int irand(int l, int h);
double drand(double l, double h);
float frand(float l, float h);
private:
uint32 jsr;
uint32 jcong;
};
} // namespace crnlib
+33 -37
View File
@@ -3,50 +3,46 @@
#pragma once
#include "crn_vec.h"
namespace crnlib
{
template<typename vector_type>
class ray
{
public:
typedef vector_type vector_t;
typedef typename vector_type::scalar_type scalar_type;
namespace crnlib {
template <typename vector_type>
class ray {
public:
typedef vector_type vector_t;
typedef typename vector_type::scalar_type scalar_type;
inline ray() { }
inline ray(eClear) { clear(); }
inline ray(const vector_type& origin, const vector_type& direction) : m_origin(origin), m_direction(direction) { }
inline ray() {}
inline ray(eClear) { clear(); }
inline ray(const vector_type& origin, const vector_type& direction)
: m_origin(origin), m_direction(direction) {}
inline void clear()
{
m_origin.clear();
m_direction.clear();
}
inline void clear() {
m_origin.clear();
m_direction.clear();
}
inline const vector_type& get_origin(void) const { return m_origin; }
inline void set_origin(const vector_type& origin) { m_origin = origin; }
inline const vector_type& get_origin(void) const { return m_origin; }
inline void set_origin(const vector_type& origin) { m_origin = origin; }
inline const vector_type& get_direction(void) const { return m_direction; }
inline void set_direction(const vector_type& direction) { m_direction = direction; }
inline const vector_type& get_direction(void) const { return m_direction; }
inline void set_direction(const vector_type& direction) { m_direction = direction; }
inline scalar_type set_endpoints(const vector_type& start, const vector_type& end, const vector_type& def)
{
m_origin = start;
inline scalar_type set_endpoints(const vector_type& start, const vector_type& end, const vector_type& def) {
m_origin = start;
m_direction = end - start;
return m_direction.normalize(&def);
}
m_direction = end - start;
return m_direction.normalize(&def);
}
inline vector_type eval(scalar_type t) const
{
return m_origin + m_direction * t;
}
inline vector_type eval(scalar_type t) const {
return m_origin + m_direction * t;
}
private:
vector_type m_origin;
vector_type m_direction;
};
private:
vector_type m_origin;
vector_type m_direction;
};
typedef ray<vec2F> ray2F;
typedef ray<vec3F> ray3F;
typedef ray<vec2F> ray2F;
typedef ray<vec3F> ray3F;
} // namespace crnlib
} // namespace crnlib
+142 -162
View File
@@ -4,183 +4,163 @@
#include "crn_vec.h"
#include "crn_hash.h"
namespace crnlib
{
class rect
{
public:
inline rect()
{
}
inline rect(eClear)
{
clear();
}
namespace crnlib {
class rect {
public:
inline rect() {
}
// up to, but not including right/bottom
inline rect(int left, int top, int right, int bottom)
{
set(left, top, right, bottom);
}
inline rect(const vec2I& lo, const vec2I& hi)
{
m_corner[0] = lo;
m_corner[1] = hi;
}
inline rect(const vec2I& point)
{
m_corner[0] = point;
m_corner[1].set(point[0] + 1, point[1] + 1);
}
inline rect(eClear) {
clear();
}
inline bool operator== (const rect& r) const
{
return (m_corner[0] == r.m_corner[0]) && (m_corner[1] == r.m_corner[1]);
}
// up to, but not including right/bottom
inline rect(int left, int top, int right, int bottom) {
set(left, top, right, bottom);
}
inline bool operator< (const rect& r) const
{
for (uint i = 0; i < 2; i++)
{
if (m_corner[i] < r.m_corner[i])
return true;
else if (!(m_corner[i] == r.m_corner[i]))
return false;
}
inline rect(const vec2I& lo, const vec2I& hi) {
m_corner[0] = lo;
m_corner[1] = hi;
}
return false;
}
inline void clear()
{
m_corner[0].clear();
m_corner[1].clear();
}
inline void set(int left, int top, int right, int bottom)
{
m_corner[0].set(left, top);
m_corner[1].set(right, bottom);
}
inline rect(const vec2I& point) {
m_corner[0] = point;
m_corner[1].set(point[0] + 1, point[1] + 1);
}
inline void set(const vec2I& lo, const vec2I& hi)
{
m_corner[0] = lo;
m_corner[1] = hi;
}
inline void set(const vec2I& point)
{
m_corner[0] = point;
m_corner[1].set(point[0] + 1, point[1] + 1);
}
inline uint get_width() const { return m_corner[1][0] - m_corner[0][0]; }
inline uint get_height() const { return m_corner[1][1] - m_corner[0][1]; }
inline int get_left() const { return m_corner[0][0]; }
inline int get_top() const { return m_corner[0][1]; }
inline int get_right() const { return m_corner[1][0]; }
inline int get_bottom() const { return m_corner[1][1]; }
inline bool is_empty() const { return (m_corner[1][0] <= m_corner[0][0]) || (m_corner[1][1] <= m_corner[0][1]); }
inline uint get_dimension(uint axis) const { return m_corner[1][axis] - m_corner[0][axis]; }
inline uint get_area() const { return get_dimension(0) * get_dimension(1); }
inline const vec2I& operator[] (uint i) const { CRNLIB_ASSERT(i < 2); return m_corner[i]; }
inline vec2I& operator[] (uint i) { CRNLIB_ASSERT(i < 2); return m_corner[i]; }
inline bool operator==(const rect& r) const {
return (m_corner[0] == r.m_corner[0]) && (m_corner[1] == r.m_corner[1]);
}
inline rect& translate(int x_ofs, int y_ofs)
{
m_corner[0][0] += x_ofs;
m_corner[0][1] += y_ofs;
m_corner[1][0] += x_ofs;
m_corner[1][1] += y_ofs;
return *this;
}
inline bool operator<(const rect& r) const {
for (uint i = 0; i < 2; i++) {
if (m_corner[i] < r.m_corner[i])
return true;
else if (!(m_corner[i] == r.m_corner[i]))
return false;
}
inline rect& init_expand()
{
m_corner[0].set(INT_MAX);
m_corner[1].set(INT_MIN);
return *this;
}
return false;
}
inline rect& expand(int x, int y)
{
m_corner[0][0] = math::minimum(m_corner[0][0], x);
m_corner[0][1] = math::minimum(m_corner[0][1], y);
m_corner[1][0] = math::maximum(m_corner[1][0], x + 1);
m_corner[1][1] = math::maximum(m_corner[1][1], y + 1);
return *this;
}
inline void clear() {
m_corner[0].clear();
m_corner[1].clear();
}
inline rect& expand(const rect& r)
{
m_corner[0][0] = math::minimum(m_corner[0][0], r[0][0]);
m_corner[0][1] = math::minimum(m_corner[0][1], r[0][1]);
m_corner[1][0] = math::maximum(m_corner[1][0], r[1][0]);
m_corner[1][1] = math::maximum(m_corner[1][1], r[1][1]);
return *this;
}
inline bool touches(const rect& r) const
{
for (uint i = 0; i < 2; i++)
{
if (r[1][i] <= m_corner[0][i])
return false;
else if (r[0][i] >= m_corner[1][i])
return false;
}
inline void set(int left, int top, int right, int bottom) {
m_corner[0].set(left, top);
m_corner[1].set(right, bottom);
}
return true;
}
inline void set(const vec2I& lo, const vec2I& hi) {
m_corner[0] = lo;
m_corner[1] = hi;
}
inline bool within(const rect& r) const
{
for (uint i = 0; i < 2; i++)
{
if (m_corner[0][i] < r[0][i])
return false;
else if (m_corner[1][i] > r[1][i])
return false;
}
inline void set(const vec2I& point) {
m_corner[0] = point;
m_corner[1].set(point[0] + 1, point[1] + 1);
}
return true;
}
inline uint get_width() const { return m_corner[1][0] - m_corner[0][0]; }
inline uint get_height() const { return m_corner[1][1] - m_corner[0][1]; }
inline bool intersect(const rect& r)
{
if (!touches(r))
{
clear();
return false;
}
inline int get_left() const { return m_corner[0][0]; }
inline int get_top() const { return m_corner[0][1]; }
inline int get_right() const { return m_corner[1][0]; }
inline int get_bottom() const { return m_corner[1][1]; }
for (uint i = 0; i < 2; i++)
{
m_corner[0][i] = math::maximum<int>(m_corner[0][i], r[0][i]);
m_corner[1][i] = math::minimum<int>(m_corner[1][i], r[1][i]);
}
inline bool is_empty() const { return (m_corner[1][0] <= m_corner[0][0]) || (m_corner[1][1] <= m_corner[0][1]); }
return true;
}
inline uint get_dimension(uint axis) const { return m_corner[1][axis] - m_corner[0][axis]; }
inline uint get_area() const { return get_dimension(0) * get_dimension(1); }
inline bool contains(int x, int y) const
{
return (x >= m_corner[0][0]) && (x < m_corner[1][0]) &&
(y >= m_corner[0][1]) && (y < m_corner[1][1]);
}
inline const vec2I& operator[](uint i) const {
CRNLIB_ASSERT(i < 2);
return m_corner[i];
}
inline vec2I& operator[](uint i) {
CRNLIB_ASSERT(i < 2);
return m_corner[i];
}
inline bool contains(const vec2I& p) const { return contains(p[0], p[1]); }
inline rect& translate(int x_ofs, int y_ofs) {
m_corner[0][0] += x_ofs;
m_corner[0][1] += y_ofs;
m_corner[1][0] += x_ofs;
m_corner[1][1] += y_ofs;
return *this;
}
private:
vec2I m_corner[2];
};
} // namespace crnlib
inline rect& init_expand() {
m_corner[0].set(INT_MAX);
m_corner[1].set(INT_MIN);
return *this;
}
inline rect& expand(int x, int y) {
m_corner[0][0] = math::minimum(m_corner[0][0], x);
m_corner[0][1] = math::minimum(m_corner[0][1], y);
m_corner[1][0] = math::maximum(m_corner[1][0], x + 1);
m_corner[1][1] = math::maximum(m_corner[1][1], y + 1);
return *this;
}
inline rect& expand(const rect& r) {
m_corner[0][0] = math::minimum(m_corner[0][0], r[0][0]);
m_corner[0][1] = math::minimum(m_corner[0][1], r[0][1]);
m_corner[1][0] = math::maximum(m_corner[1][0], r[1][0]);
m_corner[1][1] = math::maximum(m_corner[1][1], r[1][1]);
return *this;
}
inline bool touches(const rect& r) const {
for (uint i = 0; i < 2; i++) {
if (r[1][i] <= m_corner[0][i])
return false;
else if (r[0][i] >= m_corner[1][i])
return false;
}
return true;
}
inline bool within(const rect& r) const {
for (uint i = 0; i < 2; i++) {
if (m_corner[0][i] < r[0][i])
return false;
else if (m_corner[1][i] > r[1][i])
return false;
}
return true;
}
inline bool intersect(const rect& r) {
if (!touches(r)) {
clear();
return false;
}
for (uint i = 0; i < 2; i++) {
m_corner[0][i] = math::maximum<int>(m_corner[0][i], r[0][i]);
m_corner[1][i] = math::minimum<int>(m_corner[1][i], r[1][i]);
}
return true;
}
inline bool contains(int x, int y) const {
return (x >= m_corner[0][0]) && (x < m_corner[1][0]) &&
(y >= m_corner[0][1]) && (y < m_corner[1][1]);
}
inline bool contains(const vec2I& p) const { return contains(p[0], p[1]); }
private:
vec2I m_corner[2];
};
} // namespace crnlib
+230 -265
View File
@@ -3,335 +3,300 @@
#include "crn_core.h"
#include "crn_resample_filters.h"
namespace crnlib
{
#define M_PI 3.14159265358979323846
namespace crnlib {
#define M_PI 3.14159265358979323846
// To add your own filter, insert the new function below and update the filter table.
// There is no need to make the filter function particularly fast, because it's
// only called during initializing to create the X and Y axis contributor tables.
// To add your own filter, insert the new function below and update the filter table.
// There is no need to make the filter function particularly fast, because it's
// only called during initializing to create the X and Y axis contributor tables.
#define BOX_FILTER_SUPPORT (0.5f)
static float box_filter(float t) /* pulse/Fourier window */
{
// make_clist() calls the filter function with t inverted (pos = left, neg = right)
if ((t >= -0.5f) && (t < 0.5f))
return 1.0f;
else
return 0.0f;
}
static float box_filter(float t) /* pulse/Fourier window */
{
// make_clist() calls the filter function with t inverted (pos = left, neg = right)
if ((t >= -0.5f) && (t < 0.5f))
return 1.0f;
else
return 0.0f;
}
#define TENT_FILTER_SUPPORT (1.0f)
static float tent_filter(float t) /* box (*) box, bilinear/triangle */
{
if (t < 0.0f)
t = -t;
static float tent_filter(float t) /* box (*) box, bilinear/triangle */
{
if (t < 0.0f)
t = -t;
if (t < 1.0f)
return 1.0f - t;
else
return 0.0f;
}
if (t < 1.0f)
return 1.0f - t;
else
return 0.0f;
}
#define BELL_SUPPORT (1.5f)
static float bell_filter(float t) /* box (*) box (*) box */
{
if (t < 0.0f)
t = -t;
static float bell_filter(float t) /* box (*) box (*) box */
{
if (t < 0.0f)
t = -t;
if (t < .5f)
return (.75f - (t * t));
if (t < .5f)
return (.75f - (t * t));
if (t < 1.5f)
{
t = (t - 1.5f);
return (.5f * (t * t));
}
if (t < 1.5f) {
t = (t - 1.5f);
return (.5f * (t * t));
}
return (0.0f);
}
return (0.0f);
}
#define B_SPLINE_SUPPORT (2.0f)
static float B_spline_filter(float t) /* box (*) box (*) box (*) box */
{
float tt;
static float B_spline_filter(float t) /* box (*) box (*) box (*) box */
{
float tt;
if (t < 0.0f)
t = -t;
if (t < 0.0f)
t = -t;
if (t < 1.0f)
{
tt = t * t;
return ((.5f * tt * t) - tt + (2.0f / 3.0f));
}
else if (t < 2.0f)
{
t = 2.0f - t;
return ((1.0f / 6.0f) * (t * t * t));
}
if (t < 1.0f) {
tt = t * t;
return ((.5f * tt * t) - tt + (2.0f / 3.0f));
} else if (t < 2.0f) {
t = 2.0f - t;
return ((1.0f / 6.0f) * (t * t * t));
}
return (0.0f);
}
return (0.0f);
}
// Dodgson, N., "Quadratic Interpolation for Image Resampling"
// Dodgson, N., "Quadratic Interpolation for Image Resampling"
#define QUADRATIC_SUPPORT 1.5f
static float quadratic(float t, const float R)
{
if (t < 0.0f)
t = -t;
if (t < QUADRATIC_SUPPORT)
{
float tt = t * t;
if (t <= .5f)
return (-2.0f * R) * tt + .5f * (R + 1.0f);
else
return (R * tt) + (-2.0f * R - .5f) * t + (3.0f / 4.0f) * (R + 1.0f);
}
else
return 0.0f;
}
static float quadratic(float t, const float R) {
if (t < 0.0f)
t = -t;
if (t < QUADRATIC_SUPPORT) {
float tt = t * t;
if (t <= .5f)
return (-2.0f * R) * tt + .5f * (R + 1.0f);
else
return (R * tt) + (-2.0f * R - .5f) * t + (3.0f / 4.0f) * (R + 1.0f);
} else
return 0.0f;
}
static float quadratic_interp_filter(float t)
{
return quadratic(t, 1.0f);
}
static float quadratic_interp_filter(float t) {
return quadratic(t, 1.0f);
}
static float quadratic_approx_filter(float t)
{
return quadratic(t, .5f);
}
static float quadratic_approx_filter(float t) {
return quadratic(t, .5f);
}
static float quadratic_mix_filter(float t)
{
return quadratic(t, .8f);
}
static float quadratic_mix_filter(float t) {
return quadratic(t, .8f);
}
// Mitchell, D. and A. Netravali, "Reconstruction Filters in Computer Graphics."
// Computer Graphics, Vol. 22, No. 4, pp. 221-228.
// (B, C)
// (1/3, 1/3) - Defaults recommended by Mitchell and Netravali
// (1, 0) - Equivalent to the Cubic B-Spline
// (0, 0.5) - Equivalent to the Catmull-Rom Spline
// (0, C) - The family of Cardinal Cubic Splines
// (B, 0) - Duff's tensioned B-Splines.
static float mitchell(float t, const float B, const float C)
{
float tt;
// Mitchell, D. and A. Netravali, "Reconstruction Filters in Computer Graphics."
// Computer Graphics, Vol. 22, No. 4, pp. 221-228.
// (B, C)
// (1/3, 1/3) - Defaults recommended by Mitchell and Netravali
// (1, 0) - Equivalent to the Cubic B-Spline
// (0, 0.5) - Equivalent to the Catmull-Rom Spline
// (0, C) - The family of Cardinal Cubic Splines
// (B, 0) - Duff's tensioned B-Splines.
static float mitchell(float t, const float B, const float C) {
float tt;
tt = t * t;
tt = t * t;
if(t < 0.0f)
t = -t;
if (t < 0.0f)
t = -t;
if(t < 1.0f)
{
t = (((12.0f - 9.0f * B - 6.0f * C) * (t * tt))
+ ((-18.0f + 12.0f * B + 6.0f * C) * tt)
+ (6.0f - 2.0f * B));
if (t < 1.0f) {
t = (((12.0f - 9.0f * B - 6.0f * C) * (t * tt)) + ((-18.0f + 12.0f * B + 6.0f * C) * tt) + (6.0f - 2.0f * B));
return (t / 6.0f);
}
else if (t < 2.0f)
{
t = (((-1.0f * B - 6.0f * C) * (t * tt))
+ ((6.0f * B + 30.0f * C) * tt)
+ ((-12.0f * B - 48.0f * C) * t)
+ (8.0f * B + 24.0f * C));
return (t / 6.0f);
} else if (t < 2.0f) {
t = (((-1.0f * B - 6.0f * C) * (t * tt)) + ((6.0f * B + 30.0f * C) * tt) + ((-12.0f * B - 48.0f * C) * t) + (8.0f * B + 24.0f * C));
return (t / 6.0f);
}
return (t / 6.0f);
}
return (0.0f);
}
return (0.0f);
}
#define MITCHELL_SUPPORT (2.0f)
static float mitchell_filter(float t)
{
return mitchell(t, 1.0f / 3.0f, 1.0f / 3.0f);
}
static float mitchell_filter(float t) {
return mitchell(t, 1.0f / 3.0f, 1.0f / 3.0f);
}
#define CATMULL_ROM_SUPPORT (2.0f)
static float catmull_rom_filter(float t)
{
return mitchell(t, 0.0f, .5f);
}
static float catmull_rom_filter(float t) {
return mitchell(t, 0.0f, .5f);
}
static double sinc(double x)
{
x = (x * M_PI);
static double sinc(double x) {
x = (x * M_PI);
if ((x < 0.01f) && (x > -0.01f))
return 1.0f + x*x*(-1.0f/6.0f + x*x*1.0f/120.0f);
if ((x < 0.01f) && (x > -0.01f))
return 1.0f + x * x * (-1.0f / 6.0f + x * x * 1.0f / 120.0f);
return sin(x) / x;
}
return sin(x) / x;
}
static float clean(double t)
{
const float EPSILON = .0000125f;
if (fabs(t) < EPSILON)
return 0.0f;
return (float)t;
}
static float clean(double t) {
const float EPSILON = .0000125f;
if (fabs(t) < EPSILON)
return 0.0f;
return (float)t;
}
//static double blackman_window(double x)
//{
// return .42f + .50f * cos(M_PI*x) + .08f * cos(2.0f*M_PI*x);
//}
//static double blackman_window(double x)
//{
// return .42f + .50f * cos(M_PI*x) + .08f * cos(2.0f*M_PI*x);
//}
static double blackman_exact_window(double x)
{
return 0.42659071f + 0.49656062f * cos(M_PI*x) + 0.07684867f * cos(2.0f*M_PI*x);
}
static double blackman_exact_window(double x) {
return 0.42659071f + 0.49656062f * cos(M_PI * x) + 0.07684867f * cos(2.0f * M_PI * x);
}
#define BLACKMAN_SUPPORT (3.0f)
static float blackman_filter(float t)
{
if (t < 0.0f)
t = -t;
static float blackman_filter(float t) {
if (t < 0.0f)
t = -t;
if (t < 3.0f)
//return clean(sinc(t) * blackman_window(t / 3.0f));
return clean(sinc(t) * blackman_exact_window(t / 3.0f));
else
return (0.0f);
}
if (t < 3.0f)
//return clean(sinc(t) * blackman_window(t / 3.0f));
return clean(sinc(t) * blackman_exact_window(t / 3.0f));
else
return (0.0f);
}
#define GAUSSIAN_SUPPORT (1.25f)
static float gaussian_filter(float t) // with blackman window
{
if (t < 0)
t = -t;
if (t < GAUSSIAN_SUPPORT)
return clean(exp(-2.0f * t * t) * sqrt(2.0f / M_PI) * blackman_exact_window(t / GAUSSIAN_SUPPORT));
else
return 0.0f;
}
static float gaussian_filter(float t) // with blackman window
{
if (t < 0)
t = -t;
if (t < GAUSSIAN_SUPPORT)
return clean(exp(-2.0f * t * t) * sqrt(2.0f / M_PI) * blackman_exact_window(t / GAUSSIAN_SUPPORT));
else
return 0.0f;
}
// Windowed sinc -- see "Jimm Blinn's Corner: Dirty Pixels" pg. 26.
// Windowed sinc -- see "Jimm Blinn's Corner: Dirty Pixels" pg. 26.
#define LANCZOS3_SUPPORT (3.0f)
static float lanczos3_filter(float t)
{
if (t < 0.0f)
t = -t;
static float lanczos3_filter(float t) {
if (t < 0.0f)
t = -t;
if (t < 3.0f)
return clean(sinc(t) * sinc(t / 3.0f));
else
return (0.0f);
}
if (t < 3.0f)
return clean(sinc(t) * sinc(t / 3.0f));
else
return (0.0f);
}
#define LANCZOS4_SUPPORT (4.0f)
static float lanczos4_filter(float t)
{
if (t < 0.0f)
t = -t;
static float lanczos4_filter(float t) {
if (t < 0.0f)
t = -t;
if (t < 4.0f)
return clean(sinc(t) * sinc(t / 4.0f));
else
return (0.0f);
}
if (t < 4.0f)
return clean(sinc(t) * sinc(t / 4.0f));
else
return (0.0f);
}
#define LANCZOS6_SUPPORT (6.0f)
static float lanczos6_filter(float t)
{
if (t < 0.0f)
t = -t;
static float lanczos6_filter(float t) {
if (t < 0.0f)
t = -t;
if (t < 6.0f)
return clean(sinc(t) * sinc(t / 6.0f));
else
return (0.0f);
}
if (t < 6.0f)
return clean(sinc(t) * sinc(t / 6.0f));
else
return (0.0f);
}
#define LANCZOS12_SUPPORT (12.0f)
static float lanczos12_filter(float t)
{
if (t < 0.0f)
t = -t;
static float lanczos12_filter(float t) {
if (t < 0.0f)
t = -t;
if (t < 12.0f)
return clean(sinc(t) * sinc(t / 12.0f));
else
return (0.0f);
}
if (t < 12.0f)
return clean(sinc(t) * sinc(t / 12.0f));
else
return (0.0f);
}
static double bessel0(double x)
{
const double EPSILON_RATIO = 1E-16;
double xh, sum, pow, ds;
int k;
static double bessel0(double x) {
const double EPSILON_RATIO = 1E-16;
double xh, sum, pow, ds;
int k;
xh = 0.5 * x;
sum = 1.0;
pow = 1.0;
k = 0;
ds = 1.0;
while (ds > sum * EPSILON_RATIO) // FIXME: Shouldn't this stop after X iterations for max. safety?
{
++k;
pow = pow * (xh / k);
ds = pow * pow;
sum = sum + ds;
}
xh = 0.5 * x;
sum = 1.0;
pow = 1.0;
k = 0;
ds = 1.0;
while (ds > sum * EPSILON_RATIO) // FIXME: Shouldn't this stop after X iterations for max. safety?
{
++k;
pow = pow * (xh / k);
ds = pow * pow;
sum = sum + ds;
}
return sum;
}
return sum;
}
static const float KAISER_ALPHA = 4.0;
static double kaiser(double alpha, double half_width, double x)
{
const double ratio = (x / half_width);
return bessel0(alpha * sqrt(1 - ratio * ratio)) / bessel0(alpha);
}
static const float KAISER_ALPHA = 4.0;
static double kaiser(double alpha, double half_width, double x) {
const double ratio = (x / half_width);
return bessel0(alpha * sqrt(1 - ratio * ratio)) / bessel0(alpha);
}
#define KAISER_SUPPORT 3
static float kaiser_filter(float t)
{
if (t < 0.0f)
t = -t;
static float kaiser_filter(float t) {
if (t < 0.0f)
t = -t;
if (t < KAISER_SUPPORT)
{
// db atten
const float att = 40.0f;
const float alpha = (float)(exp(log((double)0.58417 * (att - 20.96)) * 0.4) + 0.07886 * (att - 20.96));
//const float alpha = KAISER_ALPHA;
return (float)clean(sinc(t) * kaiser(alpha, KAISER_SUPPORT, t));
}
if (t < KAISER_SUPPORT) {
// db atten
const float att = 40.0f;
const float alpha = (float)(exp(log((double)0.58417 * (att - 20.96)) * 0.4) + 0.07886 * (att - 20.96));
//const float alpha = KAISER_ALPHA;
return (float)clean(sinc(t) * kaiser(alpha, KAISER_SUPPORT, t));
}
return 0.0f;
}
return 0.0f;
}
const resample_filter g_resample_filters[] =
{
{ "box", box_filter, BOX_FILTER_SUPPORT },
{ "tent", tent_filter, TENT_FILTER_SUPPORT },
{ "bell", bell_filter, BELL_SUPPORT },
{ "b-spline", B_spline_filter, B_SPLINE_SUPPORT },
{ "mitchell", mitchell_filter, MITCHELL_SUPPORT },
{ "lanczos3", lanczos3_filter, LANCZOS3_SUPPORT },
{ "blackman", blackman_filter, BLACKMAN_SUPPORT },
{ "lanczos4", lanczos4_filter, LANCZOS4_SUPPORT },
{ "lanczos6", lanczos6_filter, LANCZOS6_SUPPORT },
{ "lanczos12", lanczos12_filter, LANCZOS12_SUPPORT },
{ "kaiser", kaiser_filter, KAISER_SUPPORT },
{ "gaussian", gaussian_filter, GAUSSIAN_SUPPORT },
{ "catmullrom", catmull_rom_filter, CATMULL_ROM_SUPPORT },
{ "quadratic_interp", quadratic_interp_filter, QUADRATIC_SUPPORT },
{ "quadratic_approx", quadratic_approx_filter, QUADRATIC_SUPPORT },
{ "quadratic_mix", quadratic_mix_filter, QUADRATIC_SUPPORT },
};
const resample_filter g_resample_filters[] =
{
{"box", box_filter, BOX_FILTER_SUPPORT},
{"tent", tent_filter, TENT_FILTER_SUPPORT},
{"bell", bell_filter, BELL_SUPPORT},
{"b-spline", B_spline_filter, B_SPLINE_SUPPORT},
{"mitchell", mitchell_filter, MITCHELL_SUPPORT},
{"lanczos3", lanczos3_filter, LANCZOS3_SUPPORT},
{"blackman", blackman_filter, BLACKMAN_SUPPORT},
{"lanczos4", lanczos4_filter, LANCZOS4_SUPPORT},
{"lanczos6", lanczos6_filter, LANCZOS6_SUPPORT},
{"lanczos12", lanczos12_filter, LANCZOS12_SUPPORT},
{"kaiser", kaiser_filter, KAISER_SUPPORT},
{"gaussian", gaussian_filter, GAUSSIAN_SUPPORT},
{"catmullrom", catmull_rom_filter, CATMULL_ROM_SUPPORT},
{"quadratic_interp", quadratic_interp_filter, QUADRATIC_SUPPORT},
{"quadratic_approx", quadratic_approx_filter, QUADRATIC_SUPPORT},
{"quadratic_mix", quadratic_mix_filter, QUADRATIC_SUPPORT},
};
const int g_num_resample_filters = sizeof(g_resample_filters) / sizeof(g_resample_filters[0]);
const int g_num_resample_filters = sizeof(g_resample_filters) / sizeof(g_resample_filters[0]);
int find_resample_filter(const char* pName)
{
for (int i = 0; i < g_num_resample_filters; i++)
if (_stricmp(pName, g_resample_filters[i].name) == 0)
return i;
return cInvalidIndex;
}
int find_resample_filter(const char* pName) {
for (int i = 0; i < g_num_resample_filters; i++)
if (_stricmp(pName, g_resample_filters[i].name) == 0)
return i;
return cInvalidIndex;
}
} // namespace crnlib
} // namespace crnlib
+15 -17
View File
@@ -2,20 +2,18 @@
// RG: This is public domain code, originally derived from Graphics Gems 3, see: http://code.google.com/p/imageresampler/
#pragma once
namespace crnlib
{
typedef float (*resample_filter_func)(float t);
struct resample_filter
{
char name[32];
resample_filter_func func;
float support;
};
extern const resample_filter g_resample_filters[];
extern const int g_num_resample_filters;
int find_resample_filter(const char* pName);
} // namespace crnlib
namespace crnlib {
typedef float (*resample_filter_func)(float t);
struct resample_filter {
char name[32];
resample_filter_func func;
float support;
};
extern const resample_filter g_resample_filters[];
extern const int g_num_resample_filters;
int find_resample_filter(const char* pName);
} // namespace crnlib
+592 -670
View File
File diff suppressed because it is too large Load Diff

Some files were not shown because too many files have changed in this diff Show More