1 Commits

Author SHA1 Message Date
richgel99@gmail.com 97b7cb25e5 2012-04-16 00:53:29 +00:00
248 changed files with 63598 additions and 77212 deletions
-17
View File
@@ -1,17 +0,0 @@
*.o
*.2010.vcxproj.user
*.2010.suo
/crnlib/crunch
/crnlib/Win32
/crnlib/x64
/crunch/Win32
/crunch/x64
/example1/Win32
/example1/x64
/example2/Win32
/example2/x64
/example3/Win32
/example3/x64
/lib
/bin/*
!bin/crunch_x64.exe
-17
View File
@@ -1,17 +0,0 @@
# Change Log
## [0.1.4] - 2012-11-24
### Added
* KTX file format
* Basic ETC1 support
* Simple makefile
### Fixed
* Various DDS format fixes
## [0.1.3] - 2012-04-26
### Added
* Ported to Linux (tested on Ubuntu x86 w/Codeblocks). Note that a few features of the cmd line tool don't work yet (eg. -timestamp)
[0.1.4]: https://github.com/BinomialLLC/crunch
[0.1.3]: https://github.com/BinomialLLC/crunch
Binary file not shown.
+7 -4
View File
@@ -1,9 +1,12 @@
 
Microsoft Visual Studio Solution File, Format Version 11.00 Microsoft Visual Studio Solution File, Format Version 10.00
# Visual Studio 2010 # Visual Studio 2008
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "crunch", "crunch\crunch.2010.vcxproj", "{8F645BA1-B996-49EB-859B-970A671DE05D}" Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "crunch", "crunch\crunch.2008.vcproj", "{8F645BA1-B996-49EB-859B-970A671DE05D}"
ProjectSection(ProjectDependencies) = postProject
{CF2E70E8-7133-4D96-92C7-68BB406C0664} = {CF2E70E8-7133-4D96-92C7-68BB406C0664}
EndProjectSection
EndProject EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "crnlib", "crnlib\crnlib.2010.vcxproj", "{CF2E70E8-7133-4D96-92C7-68BB406C0664}" Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "crnlib", "crnlib\crnlib.2008.vcproj", "{CF2E70E8-7133-4D96-92C7-68BB406C0664}"
EndProject EndProject
Global Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution GlobalSection(SolutionConfigurationPlatforms) = preSolution
@@ -1,11 +1,11 @@
 
Microsoft Visual Studio Solution File, Format Version 11.00 Microsoft Visual Studio Solution File, Format Version 10.00
# Visual Studio 2010 # Visual Studio 2008
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "example1", "example1\example1.2010.vcxproj", "{8F745B42-F996-49EB-859B-970A671DE05D}" Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "example1", "example1\example1.2008.vcproj", "{8F745B42-F996-49EB-859B-970A671DE05D}"
EndProject EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "example2", "example2\example2.2010.vcxproj", "{AF745B42-F996-49EB-859B-970A671DEF5E}" Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "example2", "example2\example2.2008.vcproj", "{AF745B42-F996-49EB-859B-970A671DEF5E}"
EndProject EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "example3", "example3\example3.2010.vcxproj", "{AF745B42-E296-46EB-859B-970A671DEF5E}" Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "example3", "example3\example3.2008.vcproj", "{AF745B42-E296-46EB-859B-970A671DEF5E}"
EndProject EndProject
Global Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution GlobalSection(SolutionConfigurationPlatforms) = preSolution
-9
View File
@@ -1,9 +0,0 @@
<?xml version="1.0" encoding="UTF-8" standalone="yes" ?>
<CodeBlocks_workspace_file>
<Workspace title="Workspace">
<Project filename="crunch/crunch_linux.cbp" active="1">
<Depends filename="crnlib/crnlib_linux.cbp" />
</Project>
<Project filename="crnlib/crnlib_linux.cbp" />
</Workspace>
</CodeBlocks_workspace_file>
-96
View File
@@ -1,96 +0,0 @@
COMPILE_OPTIONS = -O3 -fomit-frame-pointer -ffast-math -fno-math-errno -g -fno-strict-aliasing -Wall -Wno-unused-value -Wno-unused -march=core2
LINKER_OPTIONS = -lpthread -g
OBJECTS = \
crn_arealist.o \
crn_assert.o \
crn_checksum.o \
crn_colorized_console.o \
crn_command_line_params.o \
crn_comp.o \
crn_console.o \
crn_core.o \
crn_data_stream.o \
crn_mipmapped_texture.o \
crn_decomp.o \
crn_dxt1.o \
crn_dxt5a.o \
crn_dxt.o \
crn_dxt_endpoint_refiner.o \
crn_dxt_fast.o \
crn_dxt_hc_common.o \
crn_dxt_hc.o \
crn_dxt_image.o \
crn_dynamic_string.o \
crn_file_utils.o \
crn_find_files.o \
crn_hash.o \
crn_hash_map.o \
crn_huffman_codes.o \
crn_image_utils.o \
crnlib.o \
crn_math.o \
crn_mem.o \
crn_pixel_format.o \
crn_platform.o \
crn_prefix_coding.o \
crn_qdxt1.o \
crn_qdxt5.o \
crn_rand.o \
crn_resample_filters.o \
crn_resampler.o \
crn_ryg_dxt.o \
crn_sparse_bit_array.o \
crn_stb_image.o \
crn_strutils.o \
crn_symbol_codec.o \
crn_texture_file_types.o \
crn_threaded_resampler.o \
crn_threading_pthreads.o \
crn_timer.o \
crn_utils.o \
crn_value.o \
crn_vector.o \
crn_zeng.o \
crn_texture_comp.o \
crn_texture_conversion.o \
crn_dds_comp.o \
crn_lzma_codec.o \
crn_ktx_texture.o \
crn_etc.o \
crn_rg_etc1.o \
crn_miniz.o \
crn_jpge.o \
crn_jpgd.o \
lzma_7zBuf2.o \
lzma_7zBuf.o \
lzma_7zCrc.o \
lzma_7zFile.o \
lzma_7zStream.o \
lzma_Alloc.o \
lzma_Bcj2.o \
lzma_Bra86.o \
lzma_Bra.o \
lzma_BraIA64.o \
lzma_LzFind.o \
lzma_LzmaDec.o \
lzma_LzmaEnc.o \
lzma_LzmaLib.o
all: crunch
%.o: %.cpp
g++ $< -o $@ -c $(COMPILE_OPTIONS)
crunch.o: ../crunch/crunch.cpp
g++ $< -o $@ -c -I../inc -I../crnlib $(COMPILE_OPTIONS)
corpus_gen.o: ../crunch/corpus_gen.cpp
g++ $< -o $@ -c -I../inc -I../crnlib $(COMPILE_OPTIONS)
corpus_test.o: ../crunch/corpus_test.cpp
g++ $< -o $@ -c -I../inc -I../crnlib $(COMPILE_OPTIONS)
crunch: $(OBJECTS) crunch.o corpus_gen.o corpus_test.o
g++ $(OBJECTS) crunch.o corpus_gen.o corpus_test.o -o crunch $(LINKER_OPTIONS)
+529 -455
View File
File diff suppressed because it is too large Load Diff
+50 -47
View File
@@ -2,70 +2,73 @@
// See Copyright Notice and license at the end of inc/crnlib.h // See Copyright Notice and license at the end of inc/crnlib.h
#pragma once #pragma once
namespace crnlib { namespace crnlib
struct Area { {
struct Area *Pprev, *Pnext; struct Area
{
struct Area *Pprev, *Pnext;
int x1, y1, x2, y2; int x1, y1, x2, y2;
uint get_width() const { return x2 - x1 + 1; } uint get_width() const { return x2 - x1 + 1; }
uint get_height() const { return y2 - y1 + 1; } uint get_height() const { return y2 - y1 + 1; }
uint get_area() const { return get_width() * get_height(); } uint get_area() const { return get_width() * get_height(); }
}; };
typedef Area* Area_Ptr; typedef Area * Area_Ptr;
struct Area_List { struct Area_List
int total_areas; {
int next_free; int total_areas;
int next_free;
Area *Phead, *Ptail, *Pfree; Area *Phead, *Ptail, *Pfree;
}; };
typedef Area_List* Area_List_Ptr; typedef Area_List * Area_List_Ptr;
Area_List* Area_List_init(int max_areas); Area_List * Area_List_init(int max_areas);
void Area_List_deinit(Area_List* Pobj_base); void Area_List_deinit(Area_List* Pobj_base);
void Area_List_print(Area_List* Plist); void Area_List_print(Area_List *Plist);
Area_List* Area_List_dup_new(Area_List* Plist, Area_List * Area_List_dup_new(Area_List *Plist,
int x_ofs, int y_ofs); int x_ofs, int y_ofs);
uint Area_List_get_num(Area_List* Plist); uint Area_List_get_num(Area_List* Plist);
// src and dst area lists must have the same number of total areas. // src and dst area lists must have the same number of total areas.
void Area_List_dup(Area_List* Psrc_list, void Area_List_dup(Area_List *Psrc_list,
Area_List* Pdst_list, Area_List *Pdst_list,
int x_ofs, int y_ofs); int x_ofs, int y_ofs);
void Area_List_copy(Area_List* Psrc_list, void Area_List_copy(Area_List *Psrc_list,
Area_List* Pdst_list, Area_List *Pdst_list,
int x_ofs, int y_ofs); int x_ofs, int y_ofs);
void Area_List_clear(Area_List* Plist); void Area_List_clear(Area_List *Plist);
void Area_List_set(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); int x1, int y1, int x2, int y2);
// logical: x or y // logical: x and (not y)
void Area_List_insert(Area_List* Plist, void Area_List_remove(Area_List *Plist,
int x1, int y1, int x2, int y2, int x1, int y1, int x2, int y2);
bool combine);
// logical: x and y // logical: x or y
void Area_List_intersect_area(Area_List* Plist, void Area_List_insert(Area_List *Plist,
int x1, int y1, int x2, int y2); int x1, int y1, int x2, int y2,
bool combine);
// logical: x and y // logical: x and y
void Area_List_intersect_Area_List(Area_List* Pouter_list, void Area_List_intersect_area(Area_List *Plist,
Area_List* Pinner_list, int x1, int y1, int x2, int y2);
Area_List* Pdst_list);
Area_List_Ptr Area_List_create_optimal(Area_List_Ptr Plist); // logical: x and y
void Area_List_intersect_Area_List(Area_List *Pouter_list,
Area_List *Pinner_list,
Area_List *Pdst_list);
} // namespace crnlib Area_List_Ptr Area_List_create_optimal(Area_List_Ptr Plist);
} // namespace crnlib
+59 -45
View File
@@ -1,63 +1,77 @@
// File: crn_assert.cpp // File: crn_assert.cpp
// See Copyright Notice and license at the end of inc/crnlib.h // See Copyright Notice and license at the end of inc/crnlib.h
#include "crn_core.h" #include "crn_core.h"
#if CRNLIB_USE_WIN32_API
#include "crn_winhdr.h" #include "crn_winhdr.h"
#endif #include <stdio.h>
static bool g_fail_exceptions; static bool g_fail_exceptions;
static bool g_exit_on_failure = true; static bool g_exit_on_failure = true;
void crnlib_enable_fail_exceptions(bool enabled) { void crnlib_enable_fail_exceptions(bool enabled)
g_fail_exceptions = enabled; {
g_fail_exceptions = enabled;
} }
void crnlib_assert(const char* pExp, const char* pFile, unsigned line) { void crnlib_assert(const char* pExp, const char* pFile, unsigned line)
char buf[512]; {
char buf[512];
sprintf_s(buf, sizeof(buf), "%s(%u): Assertion failed: \"%s\"\n", pFile, line, pExp); #if defined(WIN32) && defined(_MSC_VER)
sprintf_s(buf, sizeof(buf), "%s(%u): Assertion failed: \"%s\"\n", pFile, line, pExp);
crnlib_output_debug_string(buf); #else
sprintf(buf, "%s(%u): Assertion failed: \"%s\"\n", pFile, line, pExp);
fputs(buf, stderr);
if (crnlib_is_debugger_present())
crnlib_debug_break();
}
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);
crnlib_output_debug_string(buf);
fputs(buf, stderr);
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
#endif #endif
if (g_exit_on_failure)
exit(EXIT_FAILURE); crnlib_output_debug_string(buf);
printf(buf);
if (crnlib_is_debugger_present())
crnlib_debug_break();
} }
void trace(const char* pFmt, va_list args) { void crnlib_fail(const char* pExp, const char* pFile, unsigned line)
if (crnlib_is_debugger_present()) { {
char buf[512]; char buf[512];
vsprintf_s(buf, sizeof(buf), pFmt, args);
crnlib_output_debug_string(buf); #if defined(WIN32) && defined(_MSC_VER)
} sprintf_s(buf, sizeof(buf), "%s(%u): Failure: \"%s\"\n", pFile, line, pExp);
#else
sprintf(buf, "%s(%u): Failure: \"%s\"\n", pFile, line, pExp);
#endif
crnlib_output_debug_string(buf);
printf(buf);
if (crnlib_is_debugger_present())
crnlib_debug_break();
if (g_fail_exceptions)
RaiseException(CRNLIB_FAIL_EXCEPTION_CODE, 0, 0, NULL);
else if (g_exit_on_failure)
exit(EXIT_FAILURE);
}
void trace(const char* pFmt, va_list args)
{
if (crnlib_is_debugger_present())
{
char buf[512];
#if defined(WIN32) && defined(_MSC_VER)
vsprintf_s(buf, sizeof(buf), pFmt, args);
#else
vsprintf(buf, pFmt, args);
#endif
crnlib_output_debug_string(buf);
}
}; };
void trace(const char* pFmt, ...) { void trace(const char* pFmt, ...)
va_list args; {
va_start(args, pFmt); va_list args;
trace(pFmt, args); va_start(args, pFmt);
va_end(args); trace(pFmt, args);
va_end(args);
}; };
+26 -32
View File
@@ -9,19 +9,16 @@ void crnlib_assert(const char* pExp, const char* pFile, unsigned line);
void crnlib_fail(const char* pExp, const char* pFile, unsigned line); void crnlib_fail(const char* pExp, const char* pFile, unsigned line);
#ifdef NDEBUG #ifdef NDEBUG
#define CRNLIB_ASSERT(x) ((void)0) #define CRNLIB_ASSERT(x) ((void)0)
#undef CRNLIB_ASSERTS_ENABLED #undef CRNLIB_ASSERTS_ENABLED
#else #else
#define CRNLIB_ASSERT(_exp) (void)((!!(_exp)) || (crnlib_assert(#_exp, __FILE__, __LINE__), 0)) #define CRNLIB_ASSERT(_exp) (void)( (!!(_exp)) || (crnlib_assert(#_exp, __FILE__, __LINE__), 0) )
#define CRNLIB_ASSERTS_ENABLED #define CRNLIB_ASSERTS_ENABLED
#endif #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) \ #define CRNLIB_FAIL(msg) do { crnlib_fail(#msg, __FILE__, __LINE__); } while(0)
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_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)) #define CRNLIB_ASSERT_CLOSED_RANGE(x, l, h) CRNLIB_ASSERT((x >= l) && (x <= h))
@@ -30,38 +27,35 @@ void trace(const char* pFmt, va_list args);
void trace(const char* pFmt, ...); void trace(const char* pFmt, ...);
// Borrowed from boost libraries. // Borrowed from boost libraries.
template <bool x> template <bool x> struct crnlib_assume_failure;
struct crnlib_assume_failure; template <> struct crnlib_assume_failure<true> { enum { blah = 1 }; };
template <> template<int x> struct crnlib_assume_try { };
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_FINAL(a, b) a##b
#define CRNLIB_JOINER(a, b) CRNLIB_JOINER_FINAL(a, b) #define CRNLIB_JOINER(a, b) CRNLIB_JOINER_FINAL(a, b)
#define CRNLIB_JOIN(a, b) CRNLIB_JOINER(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 #ifdef NDEBUG
template <typename T> template<typename T> inline T crnlib_assert_range(T i, T m)
inline T crnlib_assert_range(T i, T) { {
return i; m;
return i;
} }
template <typename T> template<typename T> inline T crnlib_assert_range_incl(T i, T m)
inline T crnlib_assert_range_incl(T i, T) { {
return i; m;
return i;
} }
#else #else
template <typename T> template<typename T> inline T crnlib_assert_range(T i, T m)
inline T crnlib_assert_range(T i, T m) { {
CRNLIB_ASSERT((i >= 0) && (i < m)); CRNLIB_ASSERT((i >= 0) && (i < m));
return i; return i;
} }
template <typename T> template<typename T> inline T crnlib_assert_range_incl(T i, T m)
inline T crnlib_assert_range_incl(T i, T m) { {
CRNLIB_ASSERT((i >= 0) && (i <= m)); CRNLIB_ASSERT((i >= 0) && (i <= m));
return i; return i;
} }
#endif #endif
-184
View File
@@ -1,184 +0,0 @@
// File: crn_atomics.h
#ifndef CRN_ATOMICS_H
#define CRN_ATOMICS_H
#ifdef WIN32
#pragma once
#endif
#ifdef WIN32
#include "crn_winhdr.h"
#endif
#if defined(__GNUC__) && CRNLIB_PLATFORM_PC
extern __inline__ __attribute__((__always_inline__, __gnu_inline__)) void crnlib_yield_processor() {
__asm__ __volatile__("pause");
}
#else
CRNLIB_FORCE_INLINE void crnlib_yield_processor() {
#if CRNLIB_USE_MSVC_INTRINSICS
#if CRNLIB_PLATFORM_PC_X64
_mm_pause();
#else
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
namespace crnlib {
#if CRNLIB_USE_WIN32_ATOMIC_FUNCTIONS
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 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 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 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);
}
#elif CRNLIB_USE_GCC_ATOMIC_BUILTINS
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 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 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 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);
}
#else
#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;
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 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_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_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
#endif // CRN_ATOMICS_H
+143 -125
View File
@@ -3,176 +3,194 @@
#pragma once #pragma once
#include "crn_data_stream.h" #include "crn_data_stream.h"
namespace crnlib { namespace crnlib
class buffer_stream : public data_stream { {
public: class buffer_stream : public data_stream
buffer_stream() {
: data_stream(), public:
m_pBuf(NULL), buffer_stream() :
m_size(0), data_stream(),
m_ofs(0) { m_pBuf(NULL),
} m_size(0),
m_ofs(0)
{
}
buffer_stream(void* p, uint size) buffer_stream(void* p, uint size) :
: data_stream(), data_stream(),
m_pBuf(NULL), m_pBuf(NULL),
m_size(0), m_size(0),
m_ofs(0) { m_ofs(0)
open(p, size); {
} open(p, size);
}
buffer_stream(const void* p, uint size) buffer_stream(const void* p, uint size) :
: data_stream(), data_stream(),
m_pBuf(NULL), m_pBuf(NULL),
m_size(0), m_size(0),
m_ofs(0) { m_ofs(0)
open(p, size); {
} open(p, size);
}
virtual ~buffer_stream() { virtual ~buffer_stream()
} {
}
bool open(const void* p, uint size) { bool open(const void* p, uint size)
CRNLIB_ASSERT(p); {
CRNLIB_ASSERT(p);
close(); close();
if ((!p) || (!size)) if ((!p) || (!size))
return false; return false;
m_opened = true; m_opened = true;
m_pBuf = (uint8*)(p); m_pBuf = (uint8*)(p);
m_size = size; m_size = size;
m_ofs = 0; m_ofs = 0;
m_attribs = cDataStreamSeekable | cDataStreamReadable; m_attribs = cDataStreamSeekable | cDataStreamReadable;
return true; return true;
} }
bool open(void* p, uint size) { bool open(void* p, uint size)
CRNLIB_ASSERT(p); {
CRNLIB_ASSERT(p);
close(); close();
if ((!p) || (!size)) if ((!p) || (!size))
return false; return false;
m_opened = true; m_opened = true;
m_pBuf = static_cast<uint8*>(p); m_pBuf = static_cast<uint8*>(p);
m_size = size; m_size = size;
m_ofs = 0; m_ofs = 0;
m_attribs = cDataStreamSeekable | cDataStreamWritable | cDataStreamReadable; m_attribs = cDataStreamSeekable | cDataStreamWritable | cDataStreamReadable;
return true; return true;
} }
virtual bool close() { virtual bool close()
if (m_opened) { {
m_opened = false; if (m_opened)
m_pBuf = NULL; {
m_size = 0; m_opened = false;
m_ofs = 0; m_pBuf = NULL;
return true; m_size = 0;
} m_ofs = 0;
return true;
}
return false; return false;
} }
const void* get_buf() const { return m_pBuf; } const void* get_buf() const { return m_pBuf; }
void* get_buf() { 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) { virtual uint read(void* pBuf, uint len)
CRNLIB_ASSERT(pBuf && (len <= 0x7FFFFFFF)); {
CRNLIB_ASSERT(pBuf && (len <= 0x7FFFFFFF));
if ((!m_opened) || (!is_readable()) || (!len)) if ((!m_opened) || (!is_readable()) || (!len))
return 0; 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) if (len)
memcpy(pBuf, &m_pBuf[m_ofs], 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) { virtual uint write(const void* pBuf, uint len)
CRNLIB_ASSERT(pBuf && (len <= 0x7FFFFFFF)); {
CRNLIB_ASSERT(pBuf && (len <= 0x7FFFFFFF));
if ((!m_opened) || (!is_writable()) || (!len)) if ((!m_opened) || (!is_writable()) || (!len))
return 0; 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) if (len)
memcpy(&m_pBuf[m_ofs], pBuf, len); memcpy(&m_pBuf[m_ofs], pBuf, len);
m_ofs += len; m_ofs += len;
return len; return len;
} }
virtual bool flush() { virtual bool flush()
if (!m_opened) {
return false; if (!m_opened)
return false;
return true; return true;
} }
virtual uint64 get_size() { virtual uint64 get_size()
if (!m_opened) {
return 0; if (!m_opened)
return 0;
return m_size; return m_size;
} }
virtual uint64 get_remaining() { virtual uint64 get_remaining()
if (!m_opened) {
return 0; 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() { virtual uint64 get_ofs()
if (!m_opened) {
return 0; if (!m_opened)
return 0;
return m_ofs; return m_ofs;
} }
virtual bool seek(int64 ofs, bool relative) { virtual bool seek(int64 ofs, bool relative)
if ((!m_opened) || (!is_seekable())) {
return false; 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) if (new_ofs < 0)
return false; return false;
else if (new_ofs > m_size) else if (new_ofs > m_size)
return false; 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: private:
uint8* m_pBuf; uint8* m_pBuf;
uint m_size; uint m_size;
uint m_ofs; uint m_ofs;
}; };
} // namespace crnlib
} // namespace crnlib
+232 -201
View File
@@ -2,214 +2,245 @@
// See Copyright Notice and license at the end of inc/crnlib.h // See Copyright Notice and license at the end of inc/crnlib.h
#pragma once #pragma once
#include "crn_data_stream.h" #include "crn_data_stream.h"
#include <stdio.h>
namespace crnlib { namespace crnlib
class cfile_stream : public data_stream { {
public: class cfile_stream : public data_stream
cfile_stream() {
: data_stream(), m_pFile(NULL), m_size(0), m_ofs(0), m_has_ownership(false) { 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;
} }
m_pFile = NULL; cfile_stream(FILE* pFile, const wchar_t* pFilename, uint attribs, bool has_ownership) :
m_opened = false; data_stream(), m_pFile(NULL), m_size(0), m_ofs(0), m_has_ownership(false)
m_size = 0; {
m_ofs = 0; open(pFile, pFilename, attribs, has_ownership);
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;
} }
m_ofs = new_ofs; cfile_stream(const wchar_t* 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);
}
return true; virtual ~cfile_stream()
} {
close();
}
static bool read_file_into_array(const char* pFilename, vector<uint8>& buf) { virtual bool close()
cfile_stream in_stream(pFilename); {
if (!in_stream.is_opened()) clear_error();
return false;
return in_stream.read_array(buf);
}
static bool write_array_to_file(const char* pFilename, const vector<uint8>& buf) { if (m_opened)
cfile_stream out_stream(pFilename, cDataStreamWritable | cDataStreamSeekable); {
if (!out_stream.is_opened()) bool status = true;
return false; if (m_has_ownership)
return out_stream.write_array(buf); {
} if (EOF == fclose(m_pFile))
status = false;
}
private: m_pFile = NULL;
FILE* m_pFile; m_opened = false;
uint64 m_size, m_ofs; m_size = 0;
bool m_has_ownership; m_ofs = 0;
}; m_has_ownership = false;
} // namespace crnlib return status;
}
return false;
}
bool open(FILE* pFile, const wchar_t* 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 = _ftelli64(m_pFile);
_fseeki64(m_pFile, 0, SEEK_END);
m_size = _ftelli64(m_pFile);
_fseeki64(m_pFile, m_ofs, SEEK_SET);
m_opened = true;
return true;
}
bool open(const wchar_t* pFilename, uint attribs = cDataStreamReadable | cDataStreamSeekable, bool open_existing = false)
{
CRNLIB_ASSERT(pFilename);
close();
m_attribs = static_cast<uint16>(attribs);
const wchar_t* pMode;
if ((is_readable()) && (is_writable()))
pMode = open_existing ? L"r+b" : L"w+b";
else if (is_writable())
pMode = open_existing ? L"ab" : L"wb";
else if (is_readable())
pMode = L"rb";
else
{
set_error();
return false;
}
FILE* pFile = NULL;
#ifdef _MSC_VER
_wfopen_s(&pFile, pFilename, pMode);
#else
pFile = _wfopen(pFilename, pMode);
#endif
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 (_fseeki64(m_pFile, new_ofs, SEEK_SET) != 0)
{
set_error();
return false;
}
m_ofs = new_ofs;
}
return true;
}
static bool read_file_into_array(const wchar_t* 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 wchar_t* 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
+51 -46
View File
@@ -1,58 +1,63 @@
// File: crn_checksum.cpp // File: crn_checksum.cpp
#include "crn_core.h" #include "crn_core.h"
namespace crnlib { namespace crnlib
// From the public domain stb.h header. {
uint adler32(const void* pBuf, size_t buflen, uint adler32) { // From the public domain stb.h header.
const uint8* buffer = static_cast<const uint8*>(pBuf); uint adler32(const void* pBuf, size_t buflen, uint adler32)
{
const uint8* buffer = static_cast<const uint8*>(pBuf);
const unsigned long ADLER_MOD = 65521; const unsigned long ADLER_MOD = 65521;
unsigned long s1 = adler32 & 0xffff, s2 = adler32 >> 16; unsigned long s1 = adler32 & 0xffff, s2 = adler32 >> 16;
size_t blocklen; size_t blocklen;
unsigned long i; unsigned long i;
blocklen = buflen % 5552; blocklen = buflen % 5552;
while (buflen) { while (buflen) {
for (i = 0; i + 7 < blocklen; i += 8) { for (i=0; i + 7 < blocklen; i += 8) {
s1 += buffer[0], s2 += s1; s1 += buffer[0], s2 += s1;
s1 += buffer[1], s2 += s1; s1 += buffer[1], s2 += s1;
s1 += buffer[2], s2 += s1; s1 += buffer[2], s2 += s1;
s1 += buffer[3], s2 += s1; s1 += buffer[3], s2 += s1;
s1 += buffer[4], s2 += s1; s1 += buffer[4], s2 += s1;
s1 += buffer[5], s2 += s1; s1 += buffer[5], s2 += s1;
s1 += buffer[6], s2 += s1; s1 += buffer[6], s2 += s1;
s1 += buffer[7], s2 += s1; s1 += buffer[7], s2 += s1;
buffer += 8; buffer += 8;
} }
for (; i < blocklen; ++i) for (; i < blocklen; ++i)
s1 += *buffer++, s2 += s1; s1 += *buffer++, s2 += s1;
s1 %= ADLER_MOD, s2 %= ADLER_MOD; s1 %= ADLER_MOD, s2 %= ADLER_MOD;
buflen -= blocklen; buflen -= blocklen;
blocklen = 5552; blocklen = 5552;
} }
return (s2 << 16) + s1; return (s2 << 16) + s1;
} }
uint16 crc16(const void* pBuf, size_t len, uint16 crc) { uint16 crc16(const void* pBuf, size_t len, uint16 crc)
crc = ~crc; {
crc = ~crc;
const uint8* p = reinterpret_cast<const uint8*>(pBuf); const uint8* p = reinterpret_cast<const uint8*>(pBuf);
while (len) { while (len)
const uint16 q = *p++ ^ (crc >> 8); {
crc <<= 8U; const uint16 q = *p++ ^ (crc >> 8);
uint16 r = (q >> 4) ^ q; crc <<= 8U;
crc ^= r; uint16 r = (q >> 4) ^ q;
r <<= 5U; crc ^= r;
crc ^= r; r <<= 5U;
r <<= 7U; crc ^= r;
crc ^= r; r <<= 7U;
len--; crc ^= r;
} len--;
}
return static_cast<uint16>(~crc); return static_cast<uint16>(~crc);
} }
} // namespace crnlib
} // namespace crnlib
+7 -6
View File
@@ -1,12 +1,13 @@
// File: crn_checksum.h // File: crn_checksum.h
#pragma once #pragma once
namespace crnlib { namespace crnlib
const uint cInitAdler32 = 1U; {
uint adler32(const void* pBuf, size_t buflen, uint adler32 = cInitAdler32); 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. // crc16() intended for small buffers - doesn't use an acceleration table.
const uint cInitCRC16 = 0; const uint cInitCRC16 = 0;
uint16 crc16(const void* pBuf, size_t len, uint16 crc = cInitCRC16); uint16 crc16(const void* pBuf, size_t len, uint16 crc = cInitCRC16);
} // namespace crnlib } // namespace crnlib
+592 -528
View File
File diff suppressed because it is too large Load Diff
+663 -869
View File
File diff suppressed because it is too large Load Diff
-109
View File
@@ -1,109 +0,0 @@
// File: crn_colorized_console.cpp
// See Copyright Notice and license at the end of inc/crnlib.h
#include "crn_core.h"
#include "crn_colorized_console.h"
#ifdef CRNLIB_USE_WIN32_API
#include "crn_winhdr.h"
#endif
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::tick() {
}
#ifdef CRNLIB_USE_WIN32_API
bool colorized_console::console_output_func(eConsoleMessageType type, const char* pMsg, void*) {
if (console::get_output_disabled())
return true;
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;
}
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_crlf())
printf("\n");
if (INVALID_HANDLE_VALUE != cons)
SetConsoleTextAttribute(cons, FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE);
return true;
}
#else
bool colorized_console::console_output_func(eConsoleMessageType type, const char* pMsg, void*) {
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_crlf())
printf("\n");
return true;
}
#endif
} // namespace crnlib
-17
View File
@@ -1,17 +0,0 @@
// File: crn_colorized_console.h
// See Copyright Notice and license at the end of inc/crnlib.h
#pragma once
#include "crn_console.h"
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);
};
} // namespace crnlib
+361 -332
View File
@@ -5,406 +5,435 @@
#include "crn_console.h" #include "crn_console.h"
#include "crn_cfile_stream.h" #include "crn_cfile_stream.h"
#ifdef WIN32 namespace crnlib
#define CRNLIB_CMD_LINE_ALLOW_SLASH_PARAMS 1 {
#endif command_line_params::command_line_params()
{
}
#if CRNLIB_USE_WIN32_API void command_line_params::clear()
#include "crn_winhdr.h" {
#endif m_params.clear();
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());
#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;
}
#endif
}
command_line_params::command_line_params() { m_param_map.clear();
} }
void command_line_params::clear() { bool command_line_params::split_params(const wchar_t* p, dynamic_wstring_array& params)
m_params.clear(); {
bool within_param = false;
bool within_quote = false;
m_param_map.clear(); uint ofs = 0;
} dynamic_wstring str;
bool command_line_params::split_params(const char* p, dynamic_string_array& params) { while (p[ofs])
bool within_param = false; {
bool within_quote = false; const wchar_t c = p[ofs];
uint ofs = 0; if (within_param)
dynamic_string str; {
if (within_quote)
{
if (c == L'"')
within_quote = false;
while (p[ofs]) { str.append_char(c);
const char c = p[ofs]; }
else if ((c == L' ') || (c == L'\t'))
{
if (!str.is_empty())
{
params.push_back(str);
str.clear();
}
within_param = false;
}
else
{
if (c == L'"')
within_quote = true;
if (within_param) { str.append_char(c);
if (within_quote) { }
if (c == '"') }
within_quote = false; else if ((c != L' ') && (c != L'\t'))
{
within_param = true;
str.append_char(c); if (c == L'"')
} else if ((c == ' ') || (c == '\t')) { within_quote = true;
if (!str.is_empty()) {
params.push_back(str);
str.clear();
}
within_param = false;
} else {
if (c == '"')
within_quote = true;
str.append_char(c); str.append_char(c);
} }
} else if ((c != ' ') && (c != '\t')) {
within_param = true;
if (c == '"') ofs++;
within_quote = true;
str.append_char(c);
}
ofs++;
}
if (within_quote) {
console::error("Unmatched quote in command line \"%s\"", p);
return false;
}
if (!str.is_empty())
params.push_back(str);
return true;
}
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;
}
dynamic_string ansi_str;
for (;;) {
if (!in_stream.read_line(ansi_str))
break;
ansi_str.trim();
if (ansi_str.is_empty())
continue;
strings.push_back(dynamic_string(ansi_str.get_ptr()));
}
return true;
}
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] == '-'))
#else
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); if (within_quote)
{
key_str.right(1); console::error(L"Unmatched quote in command line \"%s\"", p);
return false;
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]; if (!str.is_empty())
params.push_back(str);
const uint cMaxValues = 16; return true;
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()) { bool command_line_params::load_string_file(const wchar_t* pFilename, dynamic_wstring_array& strings)
console::error("Expected %u value(s) after command line parameter: \"%s\"", desc.m_num_values, src_param.get_ptr()); {
return false; cfile_stream in_stream;
} if (!in_stream.open(pFilename, cDataStreamReadable | cDataStreamSeekable))
{
for (uint v = 0; v < desc.m_num_values; v++) console::error(L"Unable to open file \"%s\" for reading!", pFilename);
val_str[num_val_strs++] = params[arg_index++]; return false;
} }
dynamic_string_array strings; dynamic_string ansi_str;
if ((desc.m_support_listing_file) && (val_str[0].get_len() >= 2) && (val_str[0][0] == '@')) { for ( ; ; )
dynamic_string filename(val_str[0]); {
filename.right(1); if (!in_stream.read_line(ansi_str))
filename.unquote(); break;
if (!load_string_file(filename.get_ptr(), strings)) { ansi_str.trim();
console::error("Failed loading listing file \"%s\"!", filename.get_ptr()); if (ansi_str.is_empty())
return false; continue;
}
} else { strings.push_back(dynamic_wstring(ansi_str.get_ptr()));
for (uint v = 0; v < num_val_strs; v++) {
val_str[v].unquote();
strings.push_back(val_str[v]);
}
} }
param_value pv; return true;
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 dynamic_wstring_array& params, uint n, const param_desc* pParam_desc)
} {
CRNLIB_ASSERT(n && pParam_desc);
bool command_line_params::parse(const char* pCmd_line, uint n, const param_desc* pParam_desc, bool skip_first_param) { m_params = params;
CRNLIB_ASSERT(n && pParam_desc);
dynamic_string_array p; uint arg_index = 0;
if (!split_params(pCmd_line, p)) while (arg_index < params.size())
return 0; {
const uint cur_arg_index = arg_index;
const dynamic_wstring& src_param = params[arg_index++];
if (p.empty()) if (src_param.is_empty())
return 0; continue;
if (skip_first_param) if ((src_param[0] == L'/') || (src_param[0] == L'-'))
p.erase(0U); {
if (src_param.get_len() < 2)
{
console::error(L"Invalid command line parameter: \"%s\"", src_param.get_ptr());
return false;
}
return parse(p, n, pParam_desc); dynamic_wstring key_str(src_param);
}
bool command_line_params::is_param(uint index) const { key_str.right(1);
CRNLIB_ASSERT(index < m_params.size());
if (index >= m_params.size())
return false;
const dynamic_string& w = m_params[index]; int modifier = 0;
if (w.is_empty()) wchar_t c = key_str[key_str.get_len() - 1];
return false; if (c == L'+')
modifier = 1;
else if (c == L'-')
modifier = -1;
#if CRNLIB_CMD_LINE_ALLOW_SLASH_PARAMS if (modifier)
return (w.get_len() >= 2) && ((w[0] == '-') || (w[0] == '/')); key_str.left(key_str.get_len() - 1);
#else
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 { uint param_index;
CRNLIB_ASSERT(ppKeys); for (param_index = 0; param_index < n; param_index++)
if (key_str == pParam_desc[param_index].m_pName)
break;
if (pUnmatched_indices) { if (param_index == n)
pUnmatched_indices->resize(m_params.size()); {
for (uint i = 0; i < m_params.size(); i++) console::error(L"Unrecognized command line parameter: \"%s\"", src_param.get_ptr());
(*pUnmatched_indices)[i] = i; return false;
} }
uint n = 0; const param_desc& desc = pParam_desc[param_index];
for (uint i = 0; i < num_keys; i++) {
const char* pKey = ppKeys[i];
param_map_const_iterator begin, end; const uint cMaxValues = 16;
find(pKey, begin, end); dynamic_wstring val_str[cMaxValues];
uint num_val_strs = 0;
if (desc.m_num_values)
{
CRNLIB_ASSERT(desc.m_num_values <= cMaxValues);
while (begin != end) { if ((arg_index + desc.m_num_values) > params.size())
if (pIterators) {
pIterators->push_back(begin); console::error(L"Expected %u value(s) after command line parameter: \"%s\"", desc.m_num_values, src_param.get_ptr());
return false;
}
if (pUnmatched_indices) { for (uint v = 0; v < desc.m_num_values; v++)
int k = pUnmatched_indices->find(begin->second.m_index); val_str[num_val_strs++] = params[arg_index++];
if (k >= 0) }
pUnmatched_indices->erase_unordered(k);
dynamic_wstring_array strings;
if ((desc.m_support_listing_file) && (val_str[0].get_len() >= 2) && (val_str[0][0] == L'@'))
{
dynamic_wstring filename(val_str[0]);
filename.right(1);
filename.unquote();
if (!load_string_file(filename.get_ptr(), strings))
{
console::error(L"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_wstring, pv));
}
} }
n++; return true;
begin++; }
}
}
return n; bool command_line_params::parse(const wchar_t* pCmd_line, uint n, const param_desc* pParam_desc, bool skip_first_param)
} {
CRNLIB_ASSERT(n && pParam_desc);
void command_line_params::find(const char* pKey, param_map_const_iterator& begin, param_map_const_iterator& end) const { dynamic_wstring_array p;
dynamic_string key(pKey); if (!split_params(pCmd_line, p))
begin = m_param_map.lower_bound(key); return 0;
end = m_param_map.upper_bound(key);
}
uint command_line_params::get_count(const char* pKey) const { if (p.empty())
param_map_const_iterator begin, end; return 0;
find(pKey, begin, end);
uint n = 0; if (skip_first_param)
p.erase(0U);
while (begin != end) { return parse(p, n, pParam_desc);
n++; }
begin++;
}
return n; bool command_line_params::is_param(uint index) const
} {
CRNLIB_ASSERT(index < m_params.size());
if (index >= m_params.size())
return false;
command_line_params::param_map_const_iterator command_line_params::get_param(const char* pKey, uint index) const { const dynamic_wstring& w = m_params[index];
param_map_const_iterator begin, end; if (w.is_empty())
find(pKey, begin, end); return false;
if (begin == end) return (w.get_len() >= 2) && ((w[0] == L'-') || (w[0] == L'/'));
return m_param_map.end(); }
uint n = 0; uint command_line_params::find(uint num_keys, const wchar_t** ppKeys, crnlib::vector<param_map_const_iterator>* pIterators, crnlib::vector<uint>* pUnmatched_indices) const
{
CRNLIB_ASSERT(ppKeys);
while ((begin != end) && (n != index)) { if (pUnmatched_indices)
n++; {
begin++; pUnmatched_indices->resize(m_params.size());
} for (uint i = 0; i < m_params.size(); i++)
(*pUnmatched_indices)[i] = i;
}
if (begin == end) uint n = 0;
return m_param_map.end(); for (uint i = 0; i < num_keys; i++)
{
const wchar_t* pKey = ppKeys[i];
return begin; param_map_const_iterator begin, end;
} find(pKey, begin, end);
bool command_line_params::has_value(const char* pKey, uint index) const { while (begin != end)
return get_num_values(pKey, index) != 0; {
} if (pIterators)
pIterators->push_back(begin);
uint command_line_params::get_num_values(const char* pKey, uint index) const { if (pUnmatched_indices)
param_map_const_iterator it = get_param(pKey, index); {
int k = pUnmatched_indices->find(begin->second.m_index);
if (k >= 0)
pUnmatched_indices->erase_unordered(k);
}
if (it == end()) n++;
return 0; begin++;
}
}
return it->second.m_values.size(); return n;
} }
bool command_line_params::get_value_as_bool(const char* pKey, uint index, bool def) const { void command_line_params::find(const wchar_t* pKey, param_map_const_iterator& begin, param_map_const_iterator& end) const
param_map_const_iterator it = get_param(pKey, index); {
if (it == end()) dynamic_wstring key(pKey);
return def; begin = m_param_map.lower_bound(key);
end = m_param_map.upper_bound(key);
}
if (it->second.m_modifier) uint command_line_params::get_count(const wchar_t* pKey) const
return it->second.m_modifier > 0; {
else param_map_const_iterator begin, end;
return true; find(pKey, begin, end);
}
int command_line_params::get_value_as_int(const char* pKey, uint index, int def, int l, int h, uint value_index) const { uint n = 0;
param_map_const_iterator it = get_param(pKey, index);
if ((it == end()) || (value_index >= it->second.m_values.size()))
return def;
int val; while (begin != end)
const char* p = it->second.m_values[value_index].get_ptr(); {
if (!string_to_int(p, val)) { n++;
crnlib::console::warning("Invalid value specified for parameter \"%s\", using default value of %i", pKey, def); begin++;
return def; }
}
if (val < l) { return n;
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;
}
return val; command_line_params::param_map_const_iterator command_line_params::get_param(const wchar_t* pKey, uint index) const
} {
param_map_const_iterator begin, end;
find(pKey, begin, end);
float command_line_params::get_value_as_float(const char* pKey, uint index, float def, float l, float h, uint value_index) const { if (begin == end)
param_map_const_iterator it = get_param(pKey, index); return m_param_map.end();
if ((it == end()) || (value_index >= it->second.m_values.size()))
return def;
float val; uint n = 0;
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) { while ((begin != end) && (n != index))
crnlib::console::warning("Value %f for parameter \"%s\" is out of range, clamping to %f", val, pKey, l); {
val = l; n++;
} else if (val > h) { begin++;
crnlib::console::warning("Value %f for parameter \"%s\" is out of range, clamping to %f", val, pKey, h); }
val = h;
}
return val; if (begin == end)
} return m_param_map.end();
bool command_line_params::get_value_as_string(const char* pKey, uint index, dynamic_string& value, uint value_index) const { return begin;
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]; bool command_line_params::has_value(const wchar_t* pKey, uint index) const
return true; {
} return get_num_values(pKey, index) != 0;
}
const dynamic_string& command_line_params::get_value_as_string_or_empty(const char* pKey, uint index, uint value_index) const { uint command_line_params::get_num_values(const wchar_t* pKey, uint index) const
param_map_const_iterator it = get_param(pKey, index); {
if ((it == end()) || (value_index >= it->second.m_values.size())) param_map_const_iterator it = get_param(pKey, index);
return g_empty_dynamic_string;
return it->second.m_values[value_index]; if (it == end())
} return 0;
return it->second.m_values.size();
}
bool command_line_params::get_value_as_bool(const wchar_t* pKey, uint index, bool def) const
{
param_map_const_iterator it = get_param(pKey, index);
if (it == end())
return def;
if (it->second.m_modifier)
return it->second.m_modifier > 0;
else
return true;
}
int command_line_params::get_value_as_int(const wchar_t* 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;
int val;
const wchar_t* p = it->second.m_values[value_index].get_ptr();
if (!string_to_int(p, val))
{
crnlib::console::warning(L"Invalid value specified for parameter \"%s\", using default value of %i", pKey, def);
return def;
}
if (val < l)
{
crnlib::console::warning(L"Value %i for parameter \"%s\" is out of range, clamping to %i", val, pKey, l);
val = l;
}
else if (val > h)
{
crnlib::console::warning(L"Value %i for parameter \"%s\" is out of range, clamping to %i", val, pKey, h);
val = h;
}
return val;
}
float command_line_params::get_value_as_float(const wchar_t* 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;
float val;
const wchar_t* p = it->second.m_values[value_index].get_ptr();
if (!string_to_float(p, val))
{
crnlib::console::warning(L"Invalid value specified for float parameter \"%s\", using default value of %f", pKey, def);
return def;
}
if (val < l)
{
crnlib::console::warning(L"Value %f for parameter \"%s\" is out of range, clamping to %f", val, pKey, l);
val = l;
}
else if (val > h)
{
crnlib::console::warning(L"Value %f for parameter \"%s\" is out of range, clamping to %f", val, pKey, h);
val = h;
}
return val;
}
bool command_line_params::get_value_as_string(const wchar_t* pKey, uint index, dynamic_wstring& 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_wstring& command_line_params::get_value_as_string_or_empty(const wchar_t* 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_wstring;
return it->second.m_values[value_index];
}
} // namespace crnlib
} // namespace crnlib
+51 -52
View File
@@ -4,80 +4,79 @@
#include "crn_value.h" #include "crn_value.h"
#include <map> #include <map>
namespace crnlib { 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. class command_line_params
void get_command_line_as_single_string(dynamic_string& cmd_line, int argc, char* argv[]); {
public:
struct param_value
{
param_value() : m_index(0), m_modifier(0) { }
class command_line_params { dynamic_wstring_array m_values;
public: uint m_index;
struct param_value { int8 m_modifier;
inline param_value() };
: m_index(0), m_modifier(0) {}
dynamic_string_array m_values; typedef std::multimap<dynamic_wstring, param_value> param_map;
uint m_index; typedef param_map::const_iterator param_map_const_iterator;
int8 m_modifier; typedef param_map::iterator param_map_iterator;
};
typedef std::multimap<dynamic_string, param_value> param_map; command_line_params();
typedef param_map::const_iterator param_map_const_iterator;
typedef param_map::iterator param_map_iterator;
command_line_params(); void clear();
void clear(); static bool split_params(const wchar_t* p, dynamic_wstring_array& params);
static bool split_params(const char* p, dynamic_string_array& params); struct param_desc
{
const wchar_t* m_pName;
uint m_num_values;
bool m_support_listing_file;
};
struct param_desc { bool parse(const dynamic_wstring_array& params, uint n, const param_desc* pParam_desc);
const char* m_pName; bool parse(const wchar_t* pCmd_line, uint n, const param_desc* pParam_desc, bool skip_first_param = true);
uint m_num_values;
bool m_support_listing_file;
};
bool parse(const dynamic_string_array& params, uint n, const param_desc* pParam_desc); const dynamic_wstring_array& get_array() const { return m_params; }
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; } 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(); } uint find(uint num_keys, const wchar_t** ppKeys, crnlib::vector<param_map_const_iterator>* pIterators, crnlib::vector<uint>* pUnmatched_indices) const;
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; void find(const wchar_t* 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 wchar_t* 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 wchar_t* pKey, uint index) const;
// Returns end() if param cannot be found, or index is out of range. bool has_key(const wchar_t* pKey) const { return get_param(pKey, 0) != end(); }
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_value(const wchar_t* pKey, uint index) const;
uint get_num_values(const wchar_t* pKey, uint index) const;
bool has_value(const char* pKey, uint index) const; bool get_value_as_bool(const wchar_t* pKey, uint index = 0, bool def = false) 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; int get_value_as_int(const wchar_t* pKey, uint index, int def, int l = INT_MIN, int h = INT_MAX, uint value_index = 0) const;
float get_value_as_float(const wchar_t* 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; bool get_value_as_string(const wchar_t* pKey, uint index, dynamic_wstring& value, 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; const dynamic_wstring& get_value_as_string_or_empty(const wchar_t* 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; private:
const dynamic_string& get_value_as_string_or_empty(const char* pKey, uint index = 0, uint value_index = 0) const; dynamic_wstring_array m_params;
private: param_map m_param_map;
dynamic_string_array m_params;
param_map m_param_map; static bool load_string_file(const wchar_t* pFilename, dynamic_wstring_array& strings);
};
static bool load_string_file(const char* pFilename, dynamic_string_array& strings); } // namespace crnlib
};
} // namespace crnlib
+2099 -1250
View File
File diff suppressed because it is too large Load Diff
+145 -89
View File
@@ -2,7 +2,9 @@
// See Copyright Notice and license at the end of inc/crnlib.h // See Copyright Notice and license at the end of inc/crnlib.h
#pragma once #pragma once
#include "../inc/crn_defs.h" #define CRND_HEADER_FILE_ONLY
#include "../inc/crn_decomp.h"
#undef CRND_HEADER_FILE_ONLY
#include "../inc/crnlib.h" #include "../inc/crnlib.h"
#include "crn_symbol_codec.h" #include "crn_symbol_codec.h"
@@ -11,115 +13,169 @@
#include "crn_image_utils.h" #include "crn_image_utils.h"
#include "crn_texture_comp.h" #include "crn_texture_comp.h"
namespace crnlib { namespace crnlib
class crn_comp : public itexture_comp { {
CRNLIB_NO_COPY_OR_ASSIGNMENT_OP(crn_comp); class crn_comp : public itexture_comp
{
CRNLIB_NO_COPY_OR_ASSIGNMENT_OP(crn_comp);
public: public:
crn_comp(); crn_comp();
virtual ~crn_comp(); virtual ~crn_comp();
virtual const char* get_ext() const { return "CRN"; } virtual const wchar_t *get_ext() const { return L"CRN"; }
virtual bool compress_init(const crn_comp_params&) { return true; }; virtual bool compress_init(const crn_comp_params& params);
virtual bool compress_pass(const crn_comp_params& params, float* pEffective_bitrate); virtual bool compress_pass(const crn_comp_params& params, float *pEffective_bitrate);
virtual void compress_deinit(); virtual void compress_deinit();
virtual const crnlib::vector<uint8>& get_comp_data() const { 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; } virtual crnlib::vector<uint8>& get_comp_data() { return m_comp_data; }
uint get_comp_data_size() const { return m_comp_data.size(); } 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; } const uint8* get_comp_data_ptr() const { return m_comp_data.size() ? &m_comp_data[0] : NULL; }
private: private:
task_pool m_task_pool; task_pool m_task_pool;
const crn_comp_params* m_pParams; const crn_comp_params* m_pParams;
image_u8 m_images[cCRNMaxFaces][cCRNMaxLevels]; image_u8 m_images[cCRNMaxFaces][cCRNMaxLevels];
enum comp { struct
cColor, {
cAlpha0, uint m_width, m_height;
cAlpha1, uint m_chunk_width, m_chunk_height;
cNumComps uint m_group_index;
}; uint m_num_chunks;
uint m_first_chunk;
uint m_group_first_chunk;
} m_levels[cCRNMaxLevels];
bool m_has_comp[cNumComps]; struct mip_group
bool m_has_etc_color_blocks; {
bool m_has_subblocks; mip_group() : m_first_chunk(0), m_num_chunks(0) { }
struct level_details { uint m_first_chunk;
uint first_block; uint m_num_chunks;
uint num_blocks; };
uint block_width; crnlib::vector<mip_group> m_mip_groups;
};
crnlib::vector<level_details> m_levels;
uint m_total_blocks; enum comp
crnlib::vector<uint32> m_color_endpoints; {
crnlib::vector<uint32> m_alpha_endpoints; cColor,
crnlib::vector<uint32> m_color_selectors; cAlpha0,
crnlib::vector<uint64> m_alpha_selectors; cAlpha1,
crnlib::vector<dxt_hc::endpoint_indices_details> m_endpoint_indices; cNumComps
crnlib::vector<dxt_hc::selector_indices_details> m_selector_indices; };
crnd::crn_header m_crn_header; bool m_has_comp[cNumComps];
crnlib::vector<uint8> m_comp_data;
dxt_hc m_hvq; struct chunk_detail
{
chunk_detail() { utils::zero_object(*this); }
symbol_histogram m_reference_hist; uint m_first_endpoint_index;
static_huffman_data_model m_reference_dm; uint m_first_selector_index;
};
typedef crnlib::vector<chunk_detail> chunk_detail_vec;
chunk_detail_vec m_chunk_details;
crnlib::vector<uint16> m_endpoint_remaping[2]; crnlib::vector<uint> m_endpoint_indices[cNumComps];
symbol_histogram m_endpoint_index_hist[2]; crnlib::vector<uint> m_selector_indices[cNumComps];
static_huffman_data_model m_endpoint_index_dm[2];
crnlib::vector<uint16> m_selector_remaping[2]; uint m_total_chunks;
symbol_histogram m_selector_index_hist[2]; dxt_hc::pixel_chunk_vec m_chunks;
static_huffman_data_model m_selector_index_dm[2];
crnlib::vector<uint8> m_packed_blocks[cCRNMaxLevels]; crnd::crn_header m_crn_header;
crnlib::vector<uint8> m_packed_data_models; crnlib::vector<uint8> m_comp_data;
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;
bool pack_color_endpoints(crnlib::vector<uint8>& packed_data, const crnlib::vector<uint16>& remapping); dxt_hc m_hvq;
bool pack_color_endpoints_etc(crnlib::vector<uint8>& packed_data, const crnlib::vector<uint16>& remapping);
bool pack_color_selectors(crnlib::vector<uint8>& packed_data, const crnlib::vector<uint16>& remapping);
bool pack_alpha_endpoints(crnlib::vector<uint8>& packed_data, const crnlib::vector<uint16>& remapping);
bool pack_alpha_selectors(crnlib::vector<uint8>& packed_data, const crnlib::vector<uint16>& remapping);
bool pack_blocks(
uint group,
bool clear_histograms,
symbol_codec* pCodec,
const crnlib::vector<uint16>* pColor_endpoint_remap,
const crnlib::vector<uint16>* pColor_selector_remap,
const crnlib::vector<uint16>* pAlpha_endpoint_remap,
const crnlib::vector<uint16>* pAlpha_selector_remap
);
bool alias_images(); symbol_histogram m_chunk_encoding_hist;
void clear(); static_huffman_data_model m_chunk_encoding_dm;
bool quantize_images();
void optimize_color_endpoints_task(uint64 data, void* pData_ptr); symbol_histogram m_endpoint_index_hist[2];
void optimize_color_selectors(); static_huffman_data_model m_endpoint_index_dm[2]; // color, alpha
void optimize_color();
void optimize_alpha_endpoints_task(uint64 data, void* pData_ptr); symbol_histogram m_selector_index_hist[2];
void optimize_alpha_selectors(); static_huffman_data_model m_selector_index_dm[2]; // color, alpha
void optimize_alpha();
bool pack_data_models(); crnlib::vector<uint8> m_packed_chunks[cCRNMaxLevels];
static void append_vec(crnlib::vector<uint8>& a, const void* p, uint size); crnlib::vector<uint8> m_packed_data_models;
static void append_vec(crnlib::vector<uint8>& a, const crnlib::vector<uint8>& b); crnlib::vector<uint8> m_packed_color_endpoints;
bool create_comp_data(); crnlib::vector<uint8> m_packed_color_selectors;
crnlib::vector<uint8> m_packed_alpha_endpoints;
crnlib::vector<uint8> m_packed_alpha_selectors;
bool update_progress(uint phase_index, uint subphase_index, uint subphase_total); void clear();
bool compress_internal();
};
} // namespace crnlib 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);
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);
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 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);
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_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);
bool create_comp_data();
bool pack_data_models();
bool update_progress(uint phase_index, uint subphase_index, uint subphase_total);
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);
};
} // namespace crnlib
+431
View File
@@ -0,0 +1,431 @@
// File: crn_condition_var.cpp
// See Copyright Notice and license at the end of inc/crnlib.h
#include "crn_core.h"
#include "crn_condition_var.h"
#include "crn_spinlock.h"
#include "crn_winhdr.h"
namespace crnlib
{
void spinlock::lock(uint32 max_spins, bool yielding, bool memoryBarrier)
{
if (g_number_of_processors <= 1)
max_spins = 1;
uint32 spinCount = 0;
uint32 yieldCount = 0;
for ( ; ; )
{
CRNLIB_ASSUME(sizeof(long) == sizeof(int32));
if (!InterlockedExchange((volatile long*)&m_flag, TRUE))
break;
YieldProcessor();
YieldProcessor();
YieldProcessor();
YieldProcessor();
YieldProcessor();
YieldProcessor();
YieldProcessor();
YieldProcessor();
spinCount++;
if ((yielding) && (spinCount >= max_spins))
{
switch (yieldCount)
{
case 0:
{
spinCount = 0;
Sleep(0);
yieldCount++;
break;
}
case 1:
{
if (g_number_of_processors <= 1)
spinCount = 0;
else
spinCount = max_spins / 2;
Sleep(1);
yieldCount++;
break;
}
case 2:
{
if (g_number_of_processors <= 1)
spinCount = 0;
else
spinCount = max_spins;
Sleep(2);
break;
}
}
}
}
if (memoryBarrier)
{
#ifdef _MSC_VER
MemoryBarrier();
#elif defined(__MINGW32__) && defined(__MINGW64__)
__sync_synchronize();
#endif
}
}
void spinlock::unlock()
{
#ifdef _MSC_VER
MemoryBarrier();
#elif defined(__MINGW32__) && defined(__MINGW64__)
__sync_synchronize();
#endif
m_flag = FALSE;
}
mutex::mutex(unsigned int spin_count)
{
CRNLIB_ASSUME(sizeof(mutex) >= sizeof(CRITICAL_SECTION));
void *p = m_buf;
CRITICAL_SECTION &m_cs = *static_cast<CRITICAL_SECTION *>(p);
BOOL status = true;
#ifdef _XBOX
InitializeCriticalSectionAndSpinCount(&m_cs, spin_count);
#else
status = InitializeCriticalSectionAndSpinCount(&m_cs, spin_count);
#endif
if (!status)
crnlib_fail("mutex::mutex: InitializeCriticalSectionAndSpinCount failed", __FILE__, __LINE__);
#ifdef CRNLIB_BUILD_DEBUG
m_lock_count = 0;
#endif
}
mutex::~mutex()
{
void *p = m_buf;
CRITICAL_SECTION &m_cs = *static_cast<CRITICAL_SECTION *>(p);
#ifdef CRNLIB_BUILD_DEBUG
if (m_lock_count)
crnlib_assert("mutex::~mutex: mutex is still locked", __FILE__, __LINE__);
#endif
DeleteCriticalSection(&m_cs);
}
void mutex::lock()
{
void *p = m_buf;
CRITICAL_SECTION &m_cs = *static_cast<CRITICAL_SECTION *>(p);
EnterCriticalSection(&m_cs);
#ifdef CRNLIB_BUILD_DEBUG
m_lock_count++;
#endif
}
void mutex::unlock()
{
void *p = m_buf;
CRITICAL_SECTION &m_cs = *static_cast<CRITICAL_SECTION *>(p);
#ifdef CRNLIB_BUILD_DEBUG
if (!m_lock_count)
crnlib_assert("mutex::unlock: mutex is not locked", __FILE__, __LINE__);
m_lock_count--;
#endif
LeaveCriticalSection(&m_cs);
}
void mutex::set_spin_count(unsigned int count)
{
void *p = m_buf;
CRITICAL_SECTION &m_cs = *static_cast<CRITICAL_SECTION *>(p);
SetCriticalSectionSpinCount(&m_cs, count);
}
semaphore::semaphore(int32 initialCount, int32 maximumCount, const char* pName)
{
m_handle = CreateSemaphoreA(NULL, initialCount, maximumCount, pName);
if (NULL == m_handle)
{
CRNLIB_FAIL("semaphore: CreateSemaphore() failed");
}
}
semaphore::~semaphore()
{
if (m_handle)
{
CloseHandle(m_handle);
m_handle = NULL;
}
}
void semaphore::release(int32 releaseCount, int32 *pPreviousCount)
{
CRNLIB_ASSUME(sizeof(LONG) == sizeof(int32));
if (0 == ReleaseSemaphore(m_handle, releaseCount, (LPLONG)pPreviousCount))
{
CRNLIB_FAIL("semaphore: ReleaseSemaphore() failed");
}
}
bool semaphore::wait(uint32 milliseconds)
{
uint32 result = WaitForSingleObject(m_handle, milliseconds);
if (WAIT_FAILED == result)
{
CRNLIB_FAIL("semaphore: WaitForSingleObject() failed");
}
return WAIT_OBJECT_0 == result;
}
event::event(bool manual_reset, bool initial_state, const char* pName)
{
m_handle = CreateEventA(NULL, manual_reset, initial_state, pName);
if (NULL == m_handle)
CRNLIB_FAIL("event: CreateEvent() failed");
}
event::~event()
{
if (m_handle)
{
CloseHandle(m_handle);
m_handle = NULL;
}
}
void event::set(void)
{
SetEvent(m_handle);
}
void event::reset(void)
{
ResetEvent(m_handle);
}
void event::pulse(void)
{
PulseEvent(m_handle);
}
bool event::wait(uint32 milliseconds)
{
uint32 result = WaitForSingleObject(m_handle, milliseconds);
if (result == WAIT_FAILED)
{
CRNLIB_FAIL("event: WaitForSingleObject() failed");
}
return (result == WAIT_OBJECT_0);
}
condition_var::condition_var(uint spin_count) :
m_condition_var_lock(1, 1),
m_tls(TlsAlloc()),
m_cur_age(0),
m_max_waiter_array_index(-1)
{
CRNLIB_ASSERT(TLS_OUT_OF_INDEXES != m_tls);
m_waiters_array_lock.set_spin_count(spin_count);
m_waiters_array_lock.lock();
for (uint i = 0; i < cMaxWaitingThreads; i++)
m_waiters[i].clear();
m_waiters_array_lock.unlock();
}
condition_var::~condition_var()
{
TlsFree(m_tls);
}
void condition_var::lock()
{
uint32 cur_count = get_cur_lock_count();
CRNLIB_ASSERT(cur_count != 0xFFFFFFFF);
cur_count++;
set_cur_lock_count(cur_count);
if (1 == cur_count)
m_condition_var_lock.wait();
}
void condition_var::unlock()
{
uint32 cur_count = get_cur_lock_count();
CRNLIB_ASSERT(cur_count);
cur_count--;
set_cur_lock_count(cur_count);
if (!cur_count)
leave_and_scan();
}
void condition_var::leave_and_scan(int index_to_ignore)
{
m_waiters_array_lock.lock();
uint best_age = 0;
int best_index = -1;
for (int i = 0; i <= m_max_waiter_array_index; i++)
{
waiting_thread& waiter = m_waiters[i];
if ((i != index_to_ignore) && (waiter.m_occupied) && (!waiter.m_satisfied))
{
uint age = m_cur_age - waiter.m_age;
if ((age > best_age) || (best_index < 0))
{
if ((!waiter.m_callback_func) || (waiter.m_callback_func(waiter.m_pCallback_ptr, waiter.m_callback_data)))
{
best_age = age;
best_index = i;
}
}
}
}
if (best_index >= 0)
{
waiting_thread& waiter = m_waiters[best_index];
waiter.m_satisfied = true;
waiter.m_event.set();
m_waiters_array_lock.unlock();
}
else
{
m_waiters_array_lock.unlock();
m_condition_var_lock.release();
}
}
uint32 condition_var::get_cur_lock_count() const
{
return (uint32)((intptr_t)TlsGetValue(m_tls));
}
int condition_var::wait(
pCondition_func pCallback, void* pCallback_data_ptr, uint64 callback_data,
uint num_wait_handles, const void** pWait_handles, uint32 max_time_to_wait)
{
CRNLIB_ASSERT(get_cur_lock_count());
// First, see if the calling thread's condition function is satisfied. If so, there's no need to wait.
if ((pCallback) && (pCallback(pCallback_data_ptr, callback_data)))
return 0;
// Add this thread to the list of waiters.
m_waiters_array_lock.lock();
uint i;
for (i = 0; i < cMaxWaitingThreads; i++)
if (!m_waiters[i].m_occupied)
break;
CRNLIB_VERIFY(i != cMaxWaitingThreads);
m_max_waiter_array_index = math::maximum<int>(m_max_waiter_array_index, i);
waiting_thread& waiter = m_waiters[i];
waiter.m_callback_func = pCallback;
waiter.m_pCallback_ptr = pCallback_data_ptr;
waiter.m_callback_data = callback_data;
waiter.m_satisfied = false;
waiter.m_occupied = true;
waiter.m_age = m_cur_age++;
waiter.m_event.reset();
m_waiters_array_lock.unlock();
// Now leave the condition_var and scan to see if there are any satisfied waiters.
leave_and_scan(i);
// Let's wait for this thread's condition to be satisfied, or until timeout, or until one of the user supplied handles is signaled.
int return_index = 0;
const uint cMaxWaitHandles = 64;
CRNLIB_ASSERT(num_wait_handles < cMaxWaitHandles);
HANDLE handles[cMaxWaitHandles];
handles[0] = waiter.m_event.get_handle();
uint total_handles = 1;
if (num_wait_handles)
{
CRNLIB_ASSERT(pWait_handles);
memcpy(handles + total_handles, pWait_handles, sizeof(HANDLE) * num_wait_handles);
total_handles += num_wait_handles;
}
uint32 result;
if (max_time_to_wait == UINT32_MAX)
{
do
{
result = WaitForMultipleObjects(total_handles, handles, FALSE, 2000);
} while (result == WAIT_TIMEOUT);
}
else
result = WaitForMultipleObjects(total_handles, handles, FALSE, max_time_to_wait);
if ((result == WAIT_ABANDONED) || (result == WAIT_TIMEOUT))
return_index = -1;
else
return_index = result - WAIT_OBJECT_0;
// See if our condition was satisfied, and remove this thread from the waiter list.
m_waiters_array_lock.lock();
const bool was_satisfied = waiter.m_satisfied;
waiter.m_occupied = false;
m_waiters_array_lock.unlock();
if (0 == return_index)
{
CRNLIB_ASSERT(was_satisfied);
}
else
{
// Enter the condition_var if a user supplied handle was signaled. This guarantees that on exit of this function we're still inside the condition_var, no matter
// what happened during the WaitForMultipleObjects() call.
if (!was_satisfied)
m_condition_var_lock.wait();
}
return return_index;
}
void condition_var::set_cur_lock_count(uint32 newCount)
{
TlsSetValue(m_tls, (void*)newCount);
}
} // namespace crnlib
+91
View File
@@ -0,0 +1,91 @@
// File: crn_condition_var.h
// See Copyright Notice and license at the end of inc/crnlib.h
// Inspired by the "monitor" class in "Win32 Multithreaded Programming" by Cohen and Woodring.
// Also see http://en.wikipedia.org/wiki/Monitor_(synchronization)
#pragma once
#include "crn_mutex.h"
#include "crn_event.h"
#include "crn_semaphore.h"
namespace crnlib
{
class condition_var
{
CRNLIB_NO_COPY_OR_ASSIGNMENT_OP(condition_var);
public:
condition_var(uint spin_count = 4096U);
~condition_var();
// Locks the condition_var.
// Recursive locks are supported.
void lock();
// Returns TRUE if the thread owning this condition function should stop waiting.
// This function will always be called from within the condition_var, but it may be called from several different threads!
typedef bool (*pCondition_func)(void* pCallback_data_ptr, uint64 callback_data);
// Temporarily leaves the lock and waits for a condition to be satisfied.
// If pCallback is NULL, this method will return after another thread enters and exits the lock (like a Vista-style condition variable).
// Otherwise, this method will only return when the specified condition function returns TRUE when another thread exits the lock.
// When this method returns, the calling thread will be inside the lock.
// Returns -1 on timeout or error, 0 if the wait was satisfied, or 1 or higher if one of the extra wait handles became signaled.
// It is highly recommended you use a non-null condition callback. If you don't be sure to check for race conditions!
int wait(pCondition_func pCallback = NULL, void* pCallback_data_ptr = NULL, uint64 callback_data = 0,
uint num_wait_handles = 0, const void** pWait_handles = NULL, uint32 max_time_to_wait = UINT32_MAX);
// Unlocks the condition_var. Another thread may be woken up if its condition function has become satisfied.
void unlock();
uint32 get_cur_lock_count() const;
private:
enum { cMaxWaitingThreads = 16, cMaxWaitingThreadsMask = cMaxWaitingThreads - 1 };
semaphore m_condition_var_lock;
mutex m_waiters_array_lock;
uint32 m_tls;
uint m_cur_age;
struct waiting_thread
{
uint64 m_callback_data;
void* m_pCallback_ptr;
pCondition_func m_callback_func;
uint m_age;
bool m_satisfied;
bool m_occupied;
event m_event;
void clear()
{
m_callback_data = 0;
m_pCallback_ptr = NULL;
m_callback_func = NULL;
m_age = 0;
m_satisfied = false;
m_occupied = false;
}
};
waiting_thread m_waiters[cMaxWaitingThreads];
int m_max_waiter_array_index;
void set_cur_lock_count(uint32 newCount);
void leave_and_scan(int index_to_ignore = -1);
};
class scoped_condition_var
{
CRNLIB_NO_COPY_OR_ASSIGNMENT_OP(scoped_condition_var);
public:
inline scoped_condition_var(condition_var& m) : m_condition_var(m) { m_condition_var.lock(); }
inline ~scoped_condition_var() { m_condition_var.unlock(); }
private:
condition_var& m_condition_var;
};
} // namespace crnlib
+186 -155
View File
@@ -3,198 +3,229 @@
#include "crn_core.h" #include "crn_core.h"
#include "crn_console.h" #include "crn_console.h"
#include "crn_data_stream.h" #include "crn_data_stream.h"
#include "crn_threading.h"
namespace crnlib { namespace crnlib
eConsoleMessageType console::m_default_category = cInfoConsoleMessage; {
crnlib::vector<console::console_func> console::m_output_funcs; eConsoleMessageType console::m_default_category = cInfoConsoleMessage;
bool console::m_crlf = true; crnlib::vector<console::console_func> console::m_output_funcs;
bool console::m_prefixes = true; bool console::m_crlf = true;
bool console::m_output_disabled; bool console::m_prefixes = true;
data_stream* console::m_pLog_stream; bool console::m_output_disabled;
mutex* console::m_pMutex; data_stream* console::m_pLog_stream;
uint console::m_num_messages[cCMTTotal]; mutex* console::m_pMutex;
bool console::m_at_beginning_of_line = true; uint console::m_num_messages[cCMTTotal];
const uint cConsoleBufSize = 4096; const uint cConsoleBufSize = 4096;
void console::init() { void console::init()
if (!m_pMutex) { {
m_pMutex = crnlib_new<mutex>(); if (!m_pMutex)
} {
} m_pMutex = crnlib_new<mutex>();
}
}
void console::deinit() { void console::deinit()
if (m_pMutex) { {
crnlib_delete(m_pMutex); if (m_pMutex)
m_pMutex = NULL; {
} crnlib_delete(m_pMutex);
} m_pMutex = NULL;
}
}
void console::disable_crlf() { void console::disable_crlf()
init(); {
init();
m_crlf = false; m_crlf = false;
} }
void console::enable_crlf() { void console::enable_crlf()
init(); {
init();
m_crlf = true; m_crlf = true;
} }
void console::vprintf(eConsoleMessageType type, const char* p, va_list args) { void console::vprintf(eConsoleMessageType type, const wchar_t* p, va_list args)
init(); {
init();
scoped_mutex lock(*m_pMutex); scoped_mutex lock(*m_pMutex);
m_num_messages[type]++; m_num_messages[type]++;
char buf[cConsoleBufSize]; wchar_t buf[cConsoleBufSize];
vsprintf_s(buf, cConsoleBufSize, p, args); #ifdef _MSC_VER
vswprintf_s(buf, cConsoleBufSize, p, args);
#else
vswprintf(buf, p, args);
#endif
bool handled = false; bool handled = false;
if (m_output_funcs.size()) { 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)) for (uint i = 0; i < m_output_funcs.size(); i++)
handled = true; if (m_output_funcs[i].m_func(type, buf, m_output_funcs[i].m_pData))
} handled = true;
}
const char* pPrefix = NULL; const wchar_t* pPrefix = NULL;
if ((m_prefixes) && (m_at_beginning_of_line)) { if (m_prefixes)
switch (type) { {
case cDebugConsoleMessage: switch (type)
pPrefix = "Debug: "; {
break; case cDebugConsoleMessage: pPrefix = L"Debug: "; break;
case cWarningConsoleMessage: case cWarningConsoleMessage: pPrefix = L"Warning: "; break;
pPrefix = "Warning: "; case cErrorConsoleMessage: pPrefix = L"Error: "; break;
break; default: break;
case cErrorConsoleMessage: }
pPrefix = "Error: "; }
break;
default:
break;
}
}
if ((!m_output_disabled) && (!handled)) { if ((!m_output_disabled) && (!handled))
if (pPrefix) {
::printf("%s", pPrefix); #ifdef _XBOX
::printf(m_crlf ? "%s\n" : "%s", buf); if (pPrefix)
} OutputDebugStringW(pPrefix);
OutputDebugStringW(buf);
if (m_crlf)
OutputDebugStringW(L"\n");
#else
if (pPrefix)
::wprintf(pPrefix);
::wprintf(m_crlf ? L"%s\n" : L"%s", buf);
#endif
}
uint n = strlen(buf); if ((type != cProgressConsoleMessage) && (m_pLog_stream))
m_at_beginning_of_line = (m_crlf) || ((n) && (buf[n - 1] == '\n')); {
// Yes this is bad.
dynamic_wstring utf16_buf(buf);
if ((type != cProgressConsoleMessage) && (m_pLog_stream)) { dynamic_string ansi_buf;
// Yes this is bad. utf16_buf.as_ansi(ansi_buf);
dynamic_string tmp_buf(buf); ansi_buf.translate_lf_to_crlf();
tmp_buf.translate_lf_to_crlf(); m_pLog_stream->printf(m_crlf ? "%s\r\n" : "%s", ansi_buf.get_ptr());
m_pLog_stream->flush();
}
}
m_pLog_stream->printf(m_crlf ? "%s\r\n" : "%s", tmp_buf.get_ptr()); void console::printf(eConsoleMessageType type, const wchar_t* p, ...)
m_pLog_stream->flush(); {
} va_list args;
} va_start(args, p);
vprintf(type, p, args);
va_end(args);
}
void console::printf(eConsoleMessageType type, const char* p, ...) { void console::printf(const wchar_t* p, ...)
va_list args; {
va_start(args, p); va_list args;
vprintf(type, p, args); va_start(args, p);
va_end(args); vprintf(m_default_category, p, args);
} va_end(args);
}
void console::printf(const char* p, ...) { void console::set_default_category(eConsoleMessageType category)
va_list args; {
va_start(args, p); init();
vprintf(m_default_category, p, args);
va_end(args);
}
void console::set_default_category(eConsoleMessageType category) { m_default_category = category;
init(); }
m_default_category = category; eConsoleMessageType console::get_default_category()
} {
init();
eConsoleMessageType console::get_default_category() { return m_default_category;
init(); }
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) { scoped_mutex lock(*m_pMutex);
init();
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) { scoped_mutex lock(*m_pMutex);
init();
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.size())
if (m_output_funcs[i].m_func == pFunc) { {
m_output_funcs.erase(m_output_funcs.begin() + i); m_output_funcs.clear();
} }
} }
if (!m_output_funcs.size()) { void console::progress(const wchar_t* p, ...)
m_output_funcs.clear(); {
} va_list args;
} va_start(args, p);
vprintf(cProgressConsoleMessage, p, args);
va_end(args);
}
void console::progress(const char* p, ...) { void console::info(const wchar_t* p, ...)
va_list args; {
va_start(args, p); va_list args;
vprintf(cProgressConsoleMessage, p, args); va_start(args, p);
va_end(args); vprintf(cInfoConsoleMessage, p, args);
} va_end(args);
}
void console::info(const char* p, ...) { void console::message(const wchar_t* p, ...)
va_list args; {
va_start(args, p); va_list args;
vprintf(cInfoConsoleMessage, p, args); va_start(args, p);
va_end(args); vprintf(cMessageConsoleMessage, p, args);
} va_end(args);
}
void console::message(const char* p, ...) { void console::cons(const wchar_t* p, ...)
va_list args; {
va_start(args, p); va_list args;
vprintf(cMessageConsoleMessage, p, args); va_start(args, p);
va_end(args); vprintf(cConsoleConsoleMessage, p, args);
} va_end(args);
}
void console::cons(const char* p, ...) { void console::debug(const wchar_t* p, ...)
va_list args; {
va_start(args, p); va_list args;
vprintf(cConsoleConsoleMessage, p, args); va_start(args, p);
va_end(args); vprintf(cDebugConsoleMessage, p, args);
} va_end(args);
}
void console::debug(const char* p, ...) { void console::warning(const wchar_t* p, ...)
va_list args; {
va_start(args, p); va_list args;
vprintf(cDebugConsoleMessage, p, args); va_start(args, p);
va_end(args); vprintf(cWarningConsoleMessage, p, args);
} va_end(args);
}
void console::warning(const char* p, ...) { void console::error(const wchar_t* p, ...)
va_list args; {
va_start(args, p); va_list args;
vprintf(cWarningConsoleMessage, p, args); va_start(args, p);
va_end(args); vprintf(cErrorConsoleMessage, p, args);
} va_end(args);
}
void console::error(const char* p, ...) { } // namespace crnlib
va_list args;
va_start(args, p);
vprintf(cErrorConsoleMessage, p, args);
va_end(args);
}
} // namespace crnlib
+65 -92
View File
@@ -3,119 +3,92 @@
#pragma once #pragma once
#include "crn_dynamic_string.h" #include "crn_dynamic_string.h"
#ifdef WIN32 namespace crnlib
#include <tchar.h> {
#include <conio.h> class dynamic_string;
#endif class data_stream;
namespace crnlib { class mutex;
class dynamic_string;
class data_stream;
class mutex;
enum eConsoleMessageType { enum eConsoleMessageType
cDebugConsoleMessage, // debugging messages {
cProgressConsoleMessage, // progress messages cDebugConsoleMessage, // debugging messages
cInfoConsoleMessage, // ordinary messages cProgressConsoleMessage, // progress messages
cConsoleConsoleMessage, // user console output cInfoConsoleMessage, // ordinary messages
cMessageConsoleMessage, // high importance messages cConsoleConsoleMessage, // user console output
cWarningConsoleMessage, // warnings cMessageConsoleMessage, // high importance messages
cErrorConsoleMessage, // errors 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 wchar_t* pMsg, void* pData);
class console { class console
public: {
static void init(); public:
static void deinit(); 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 void set_default_category(eConsoleMessageType category);
static eConsoleMessageType get_default_category(); static eConsoleMessageType get_default_category();
static void add_console_output_func(console_output_func pFunc, void* pData); static void add_console_output_func(console_output_func pFunc, void* pData);
static void remove_console_output_func(console_output_func pFunc); static void remove_console_output_func(console_output_func pFunc);
static void printf(const char* p, ...); static void printf(const wchar_t* p, ...);
static void vprintf(eConsoleMessageType type, const char* p, va_list args); static void vprintf(eConsoleMessageType type, const wchar_t* p, va_list args);
static void printf(eConsoleMessageType type, const char* p, ...); static void printf(eConsoleMessageType type, const wchar_t* p, ...);
static void cons(const char* p, ...); static void cons(const wchar_t* p, ...);
static void debug(const char* p, ...); static void debug(const wchar_t* p, ...);
static void progress(const char* p, ...); static void progress(const wchar_t* p, ...);
static void info(const char* p, ...); static void info(const wchar_t* p, ...);
static void message(const char* p, ...); static void message(const wchar_t* p, ...);
static void warning(const char* p, ...); static void warning(const wchar_t* p, ...);
static void error(const char* p, ...); static void error(const wchar_t* p, ...);
// FIXME: All console state is currently global! // FIXME: All console state is currently global!
static void disable_prefixes(); static void disable_prefixes();
static void enable_prefixes(); static void enable_prefixes();
static bool get_prefixes() { return m_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 disable_crlf();
static void enable_crlf(); static void enable_crlf();
static bool get_crlf() { return m_crlf; } static bool get_crlf() { return m_crlf; }
static void disable_output() { m_output_disabled = true; } static void disable_output() { m_output_disabled = true; }
static void enable_output() { m_output_disabled = false; } static void enable_output() { m_output_disabled = false; }
static bool get_output_disabled() { return m_output_disabled; } static bool get_output_disabled() { return m_output_disabled; }
static void set_log_stream(data_stream* pStream) { m_pLog_stream = pStream; } static void set_log_stream(data_stream* pStream) { m_pLog_stream = pStream; }
static data_stream* get_log_stream() { return m_pLog_stream; } 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: private:
static eConsoleMessageType m_default_category; static eConsoleMessageType m_default_category;
struct console_func { struct console_func
console_func(console_output_func func = NULL, void* pData = NULL) {
: m_func(func), m_pData(pData) {} console_func(console_output_func func = NULL, void* pData = NULL) : m_func(func), m_pData(pData) { }
console_output_func m_func; console_output_func m_func;
void* m_pData; void* m_pData;
}; };
static crnlib::vector<console_func> m_output_funcs; 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; } // namespace crnlib
};
#if defined(WIN32)
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;
}
#endif
} // namespace crnlib
+2 -8
View File
@@ -1,13 +1,7 @@
// File: crn_core.cpp // File: crn_core.cpp
// See Copyright Notice and license at the end of inc/crnlib.h // See Copyright Notice and license at the end of inc/crnlib.h
#include "crn_core.h" #include "crn_core.h"
#if CRNLIB_USE_WIN32_API
#include "crn_winhdr.h" #include "crn_winhdr.h"
#endif
namespace crnlib { char *g_copyright_str = "Copyright (c) 2010-2011 Tenacious Software LLC";
const char* g_copyright_str = "Copyright (c) 2010-2016 Richard Geldreich, Jr. and Binomial LLC"; char *g_sig_str = "C8cfRlaorj0wLtnMSxrBJxTC85rho2L9hUZKHcBL";
const char* g_sig_str = "C8cfRlaorj0wLtnMSxrBJxTC85rho2L9hUZKHcBL";
} // namespace crnlib
+57 -132
View File
@@ -3,147 +3,67 @@
#pragma once #pragma once
#if defined(WIN32) && defined(_MSC_VER) #if defined(WIN32) && defined(_MSC_VER)
#pragma warning(disable : 4201) // nonstandard extension used : nameless struct/union #pragma warning (disable: 4201) // nonstandard extension used : nameless struct/union
#pragma warning(disable : 4127) // conditional expression is constant #pragma warning (disable: 4127) // conditional expression is constant
#pragma warning(disable : 4793) // function compiled as native #pragma warning (disable: 4793) // function compiled as native
#pragma warning(disable : 4324) // structure was padded due to __declspec(align())
#endif #endif
#if defined(WIN32) && !defined(CRNLIB_ANSI_CPLUSPLUS) #if defined(WIN32)
// 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 #if 0
#ifdef NDEBUG
// Ensure checked iterators are disabled.
#define _SECURE_SCL 0
#define _HAS_ITERATOR_DEBUGGING 0
#endif
#if defined(__MINGW32__) || defined(__MINGW64__) #ifndef _DLL
#define CRNLIB_USE_GCC_ATOMIC_BUILTINS 1 // 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.
#else // Otherwise, we disable exceptions for a small (up to 5%) speed boost.
#define CRNLIB_USE_WIN32_ATOMIC_FUNCTIONS 1 #define _HAS_EXCEPTIONS 0
#endif
#endif #endif
#define CRNLIB_PLATFORM_PC 1 //#define _CRT_SECURE_NO_WARNINGS
#define NOMINMAX
#if defined(_WIN64) || defined(__MINGW64__) || defined(_LP64) || defined(__LP64__) #define CRNLIB_PLATFORM_PC 1
#define CRNLIB_PLATFORM_PC_X64 1
#define CRNLIB_64BIT_POINTERS 1 #ifdef _WIN64
#define CRNLIB_CPU_HAS_64BIT_REGISTERS 1 #define CRNLIB_PLATFORM_PC_X64 1
#define CRNLIB_LITTLE_ENDIAN_CPU 1 #else
#else #define CRNLIB_PLATFORM_PC_X86 1
#define CRNLIB_PLATFORM_PC_X86 1 #endif
#define CRNLIB_64BIT_POINTERS 0
#define CRNLIB_CPU_HAS_64BIT_REGISTERS 0 #define CRNLIB_USE_WIN32_API 1
#define CRNLIB_LITTLE_ENDIAN_CPU 1
#ifdef _WIN64
#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
#endif #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
#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
#include <stdlib.h> #include <stdlib.h>
#include <stdio.h>
#include <limits.h> #include <limits.h>
#include <math.h> #include <math.h>
#include <stdarg.h> #include <stdarg.h>
#include <string.h> #include <string.h>
#include <algorithm> #include <algorithm>
#include <locale> #include <locale>
#include <memory.h>
#include <limits.h>
#include <algorithm>
#include <errno.h>
#ifdef min #ifdef min
#undef min #undef min
#endif #endif
#ifdef max #ifdef max
#undef max #undef max
#endif #endif
#define CRNLIB_FALSE (0) #define CRNLIB_FALSE (0)
@@ -151,22 +71,23 @@
#define CRNLIB_MAX_PATH (260) #define CRNLIB_MAX_PATH (260)
#ifdef _DEBUG #ifdef _DEBUG
#define CRNLIB_BUILD_DEBUG #define CRNLIB_BUILD_DEBUG
#else #else
#define CRNLIB_BUILD_RELEASE #define CRNLIB_BUILD_RELEASE
#ifndef NDEBUG #ifndef NDEBUG
#define NDEBUG #define NDEBUG
#endif
#endif #endif
#ifdef DEBUG
#error DEBUG cannot be defined in CRNLIB_BUILD_RELEASE
#endif
#endif
#include "crn_types.h"
#include "crn_assert.h"
#include "crn_platform.h" #include "crn_platform.h"
#if defined(WIN32)
#include "crn_mutex.h"
#endif
#include "crn_assert.h"
#include "crn_types.h"
#include "crn_helpers.h" #include "crn_helpers.h"
#include "crn_traits.h" #include "crn_traits.h"
#include "crn_mem.h" #include "crn_mem.h"
@@ -174,5 +95,9 @@
#include "crn_utils.h" #include "crn_utils.h"
#include "crn_hash.h" #include "crn_hash.h"
#include "crn_vector.h" #include "crn_vector.h"
#include "crn_timer.h" #include "crn_win32_timer.h"
#include "crn_win32_threading.h"
#include "crn_dynamic_string.h" #include "crn_dynamic_string.h"
#include "crn_dynamic_wstring.h"
+127 -87
View File
@@ -2,113 +2,153 @@
// See Copyright Notice and license at the end of inc/crnlib.h // See Copyright Notice and license at the end of inc/crnlib.h
#include "crn_core.h" #include "crn_core.h"
#include "crn_data_stream.h" #include "crn_data_stream.h"
#include <stdio.h>
namespace crnlib { namespace crnlib
data_stream::data_stream() {
: m_attribs(0), data_stream::data_stream() :
m_opened(false), m_attribs(0),
m_error(false), m_opened(false), m_error(false), m_got_cr(false)
m_got_cr(false) { {
} }
data_stream::data_stream(const char* pName, uint attribs) data_stream::data_stream(const wchar_t* pName, uint attribs) :
: m_name(pName), m_name(pName),
m_attribs(static_cast<uint16>(attribs)), m_attribs(static_cast<uint16>(attribs)),
m_opened(false), m_opened(false), m_error(false), m_got_cr(false)
m_error(false), {
m_got_cr(false) { }
}
uint64 data_stream::skip(uint64 len) { uint64 data_stream::skip(uint64 len)
uint64 total_bytes_read = 0; {
uint64 total_bytes_read = 0;
const uint cBufSize = 1024; const uint cBufSize = 1024;
uint8 buf[cBufSize]; uint8 buf[cBufSize];
while (len) { 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)); const uint64 bytes_to_read = math::minimum<uint64>(sizeof(buf), len);
total_bytes_read += bytes_read; const uint64 bytes_read = read(buf, static_cast<uint>(bytes_to_read));
total_bytes_read += bytes_read;
if (bytes_read != bytes_to_read) if (bytes_read != bytes_to_read)
break; break;
len -= bytes_read; len -= bytes_read;
} }
return total_bytes_read; return total_bytes_read;
} }
bool data_stream::read_line(dynamic_string& str) { bool data_stream::read_line(dynamic_string& str)
str.empty(); {
str.empty();
for (;;) { for ( ; ; )
const int c = read_byte(); {
const int c = read_byte();
const bool prev_got_cr = m_got_cr; const bool prev_got_cr = m_got_cr;
m_got_cr = false; m_got_cr = false;
if (c < 0) { 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);
char buf[4096];
#ifdef _MSC_VER
int l = vsprintf_s(buf, sizeof(buf), p, args);
#else
int l = vsprintf(buf, p, args);
#endif
va_end(args);
if (l < 0)
return false;
return write(buf, l) == static_cast<uint>(l);
}
bool data_stream::printf(const wchar_t* p, ...)
{
va_list args;
va_start(args, p);
dynamic_wstring buf;
buf.format_args(p, args);
va_end(args);
return write(buf.get_ptr(), buf.get_len() * sizeof(wchar_t)) == buf.get_len() * sizeof(wchar_t);
}
bool data_stream::write_line(const dynamic_string& str)
{
if (!str.is_empty()) if (!str.is_empty())
break; return write(str.get_ptr(), str.get_len()) == str.get_len();
return false; return true;
} 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; bool data_stream::write_line(const dynamic_wstring& str)
} {
if (!str.is_empty())
return write(str.get_ptr(), str.get_len() * sizeof(wchar_t)) == str.get_len() * sizeof(wchar_t);
str.append_char(static_cast<char>(c)); return true;
} }
return true; bool data_stream::read_array(vector<uint8>& buf)
} {
if (buf.size() < get_remaining())
{
if (get_remaining() > 1024U*1024U*1024U)
return false;
bool data_stream::printf(const char* p, ...) { buf.resize((uint)get_remaining());
va_list args; }
va_start(args, p); if (!get_remaining())
dynamic_string buf; {
buf.format_args(p, args); buf.resize(0);
va_end(args); return true;
}
return write(buf.get_ptr(), buf.get_len() * sizeof(char)) == buf.get_len() * sizeof(char); return read(&buf[0], buf.size()) == buf.size();
} }
bool data_stream::write_line(const dynamic_string& str) { bool data_stream::write_array(const vector<uint8>& buf)
if (!str.is_empty()) {
return write(str.get_ptr(), str.get_len()) == str.get_len(); if (!buf.empty())
return write(&buf[0], buf.size()) == buf.size();
return true;
}
return true; } // namespace crnlib
}
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
+62 -69
View File
@@ -2,97 +2,90 @@
// See Copyright Notice and license at the end of inc/crnlib.h // See Copyright Notice and license at the end of inc/crnlib.h
#pragma once #pragma once
namespace crnlib { namespace crnlib
enum data_stream_attribs { {
cDataStreamReadable = 1, enum data_stream_attribs
cDataStreamWritable = 2, {
cDataStreamSeekable = 4 cDataStreamReadable = 1,
}; cDataStreamWritable = 2,
cDataStreamSeekable = 4
};
const int64 DATA_STREAM_SIZE_UNKNOWN = cINT64_MAX; const int64 DATA_STREAM_SIZE_UNKNOWN = INT64_MAX;
const int64 DATA_STREAM_SIZE_INFINITE = cUINT64_MAX; const int64 DATA_STREAM_SIZE_INFINITE = UINT64_MAX;
class data_stream { class data_stream
data_stream(const data_stream&); {
data_stream& operator=(const data_stream&); data_stream(const data_stream&);
data_stream& operator= (const data_stream&);
public: public:
data_stream(); data_stream();
data_stream(const char* pName, uint attribs); data_stream(const wchar_t* 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() { virtual bool close() { m_opened = false; m_error = false; m_got_cr = false; return true; }
m_opened = false;
m_error = false;
m_got_cr = false;
return true;
}
typedef uint16 attribs_t; typedef uint16 attribs_t;
inline attribs_t get_attribs() const { return m_attribs; } 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_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_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_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 const dynamic_wstring& get_name() const { return m_name; }
inline void set_name(const char* pName) { m_name.set(pName); } inline void set_name(const wchar_t* pName) { m_name.set(pName); }
virtual uint read(void* pBuf, uint len) = 0; virtual uint read(void* pBuf, uint len) = 0;
virtual uint64 skip(uint64 len); virtual uint64 skip(uint64 len);
virtual uint write(const void* pBuf, uint len) = 0; virtual uint write(const void* pBuf, uint len) = 0;
virtual bool flush() = 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. // 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_size() = 0;
virtual uint64 get_remaining() = 0; virtual uint64 get_remaining() = 0;
virtual uint64 get_ofs() = 0; virtual uint64 get_ofs() = 0;
virtual bool seek(int64 ofs, bool relative) = 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() { inline int read_byte() { uint8 c; if (read(&c, 1) != 1) return -1; return c; }
uint8 c; inline bool write_byte(uint8 c) { return write(&c, 1) == 1; }
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 read_line(dynamic_string& str);
bool printf(const char* p, ...); bool printf(const char* p, ...);
bool write_line(const dynamic_string& str); bool printf(const wchar_t* p, ...);
bool write_bom() { bool write_line(const dynamic_string& str);
uint16 bom = 0xFEFF; bool write_line(const dynamic_wstring& str);
return write(&bom, sizeof(bom)) == sizeof(bom); bool write_bom() { uint16 bom = 0xFEFF; return write(&bom, sizeof(bom)) == sizeof(bom); }
}
bool read_array(vector<uint8>& buf); bool read_array(vector<uint8>& buf);
bool write_array(const vector<uint8>& buf); bool write_array(const vector<uint8>& buf);
protected: protected:
dynamic_string m_name; dynamic_wstring m_name;
attribs_t m_attribs; attribs_t m_attribs;
bool m_opened : 1; bool m_opened : 1;
bool m_error : 1; bool m_error : 1;
bool m_got_cr : 1; bool m_got_cr : 1;
inline void set_error() { m_error = true; } inline void set_error() { m_error = true; }
inline void clear_error() { m_error = false; } inline void clear_error() { m_error = false; }
inline void post_seek() { m_got_cr = false; } inline void post_seek() { m_got_cr = false; }
}; };
} // namespace crnlib
} // namespace crnlib
+405 -468
View File
@@ -3,493 +3,430 @@
#pragma once #pragma once
#include "crn_data_stream.h" #include "crn_data_stream.h"
namespace crnlib { namespace crnlib
// Defaults to little endian mode. {
class data_stream_serializer { // Defaults to little endian mode.
public: class data_stream_serializer
data_stream_serializer() {
: m_pStream(NULL), m_little_endian(true) {} public:
data_stream_serializer(data_stream* pStream) data_stream_serializer() : m_pStream(NULL), m_little_endian(true) { }
: m_pStream(pStream), m_little_endian(true) {} data_stream_serializer(data_stream* pStream) : m_pStream(pStream), m_little_endian(true) { }
data_stream_serializer(data_stream& stream) data_stream_serializer(data_stream& stream) : m_pStream(&stream), m_little_endian(true) { }
: 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(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) { data_stream_serializer& operator= (const data_stream_serializer& rhs) { m_pStream = rhs.m_pStream; m_little_endian = rhs.m_little_endian; return *this; }
m_pStream = rhs.m_pStream;
m_little_endian = rhs.m_little_endian;
return *this;
}
data_stream* get_stream() const { return m_pStream; } data_stream* get_stream() const { return m_pStream; }
void set_stream(data_stream* pStream) { m_pStream = pStream; } void set_stream(data_stream* pStream) { m_pStream = pStream; }
const dynamic_string& get_name() const { return m_pStream ? m_pStream->get_name() : g_empty_dynamic_string; } bool get_error() { return m_pStream ? m_pStream->get_error() : false; }
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 get_little_endian() const { return m_little_endian; } bool write(const void* pBuf, uint len)
void set_little_endian(bool little_endian) { m_little_endian = little_endian; } {
return m_pStream->write(pBuf, len) == len;
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;
} }
}
return true; bool read(void* pBuf, uint len)
} {
return m_pStream->read(pBuf, len) == len;
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;
}
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); bool write_chars(const char* pBuf, uint len)
return true; {
} return write(pBuf, len);
// 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;
}
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;
}
} }
}
va_end(v); bool read_chars(char* pBuf, uint len)
return true; {
} return read(pBuf, len);
}
private: bool skip(uint len)
data_stream* m_pStream; {
return m_pStream->skip(len) == len;
}
bool m_little_endian; 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);
// Write operators return write(buf, sizeof(T));
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) { template<typename T>
serializer.write_string(str); bool read_object(T& obj)
return serializer; {
} 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;
}
}
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;
}
// 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);
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;
}
}
}
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
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
+224 -192
View File
@@ -5,223 +5,255 @@
#include "crn_dynamic_stream.h" #include "crn_dynamic_stream.h"
#include "crn_lzma_codec.h" #include "crn_lzma_codec.h"
namespace crnlib { namespace crnlib
dds_comp::dds_comp() {
: m_pParams(NULL), dds_comp::dds_comp() :
m_pParams(NULL),
m_pixel_fmt(PIXEL_FMT_INVALID), m_pixel_fmt(PIXEL_FMT_INVALID),
m_pQDXT_state(NULL) { m_pQDXT_state(NULL)
} {
}
dds_comp::~dds_comp() { dds_comp::~dds_comp()
crnlib_delete(m_pQDXT_state); {
} crnlib_delete(m_pQDXT_state);
}
void dds_comp::clear() { void dds_comp::clear()
m_src_tex.clear(); {
m_packed_tex.clear(); m_src_tex.clear();
m_comp_data.clear(); m_packed_tex.clear();
m_pParams = NULL; m_comp_data.clear();
m_pixel_fmt = PIXEL_FMT_INVALID; m_pParams = NULL;
m_task_pool.deinit(); m_pixel_fmt = PIXEL_FMT_INVALID;
if (m_pQDXT_state) { m_task_pool.deinit();
crnlib_delete(m_pQDXT_state); if (m_pQDXT_state)
m_pQDXT_state = NULL; {
} 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);
} }
} }
}
face_vec faces(m_pParams->m_faces); bool dds_comp::create_dds_tex(dds_texture &dds_tex)
{
image_u8 images[cCRNMaxFaces][cCRNMaxLevels];
for (uint face_index = 0; face_index < m_pParams->m_faces; face_index++) { bool has_alpha = false;
for (uint level_index = 0; level_index < m_pParams->m_levels; level_index++) { for (uint face_index = 0; face_index < m_pParams->m_faces; face_index++)
mip_level* pMip = crnlib_new<mip_level>(); {
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);
image_u8* pImage = crnlib_new<image_u8>(); if (!m_pParams->m_pImages[face_index][level_index])
pImage->swap(images[face_index][level_index]); return false;
pMip->assign(pImage);
faces[face_index].push_back(pMip); 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]);
}
}
dds_tex.assign(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++)
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);
}
}
}
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);
#ifdef CRNLIB_BUILD_DEBUG #ifdef CRNLIB_BUILD_DEBUG
CRNLIB_ASSERT(dds_tex.check()); CRNLIB_ASSERT(dds_tex.check());
#endif #endif
return true; return true;
} }
static bool progress_callback_func(uint percentage_complete, void* pUser_data_ptr) { 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; 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) { 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; 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) { 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; 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) { 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 ((params.m_quality_level == cCRNMaxQualityLevel) || (params.m_format == cCRNFmtDXT3))
if (!m_packed_tex.convert(m_pixel_fmt, false, m_pack_params)) {
return false; m_packed_tex = m_src_tex;
} else { if (!m_packed_tex.convert(m_pixel_fmt, false, m_pack_params))
const bool hierarchical = (params.m_flags & cCRNCompFlagHierarchical) != 0; 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_quality_level = params.m_quality_level;
m_q1_params.m_hierarchical = hierarchical; m_q1_params.m_hierarchical = hierarchical;
m_q5_params.m_quality_level = params.m_quality_level; m_q5_params.m_quality_level = params.m_quality_level;
m_q5_params.m_hierarchical = hierarchical; m_q5_params.m_hierarchical = hierarchical;
if (!m_pQDXT_state) { if (!m_pQDXT_state)
m_pQDXT_state = crnlib_new<mipmapped_texture::qdxt_state>(m_task_pool); {
m_pQDXT_state = crnlib_new<dds_texture::qdxt_state>(m_task_pool);
if (params.m_pProgress_func) { 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_q1_params.m_pProgress_func = progress_callback_func_phase_0;
m_q5_params.m_pProgress_func = progress_callback_func_phase_0; m_q1_params.m_pProgress_data = (void*)&params;
m_q5_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;
}
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_src_tex.qdxt_pack(*m_pQDXT_state, m_packed_tex, m_q1_params, m_q5_params))
return false;
} }
if (!m_src_tex.qdxt_pack_init(*m_pQDXT_state, m_packed_tex, m_q1_params, m_q5_params, m_pixel_fmt, false)) return true;
return false; }
if (params.m_pProgress_func) { bool dds_comp::compress_init(const crn_comp_params& params)
m_q1_params.m_pProgress_func = progress_callback_func_phase_1; {
m_q5_params.m_pProgress_func = progress_callback_func_phase_1; 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;
} }
} else {
if (params.m_pProgress_func) { m_pixel_fmt = pixel_format_helpers::convert_crn_format_to_pixel_format(static_cast<crn_format>(m_pParams->m_format));
m_q1_params.m_pProgress_func = progress_callback_func; if (m_pixel_fmt == PIXEL_FMT_INVALID)
m_q1_params.m_pProgress_data = (void*)&params; return false;
m_q5_params.m_pProgress_func = progress_callback_func; 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_q5_params.m_pProgress_data = (void*)&params; 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 (!m_src_tex.qdxt_pack(*m_pQDXT_state, m_packed_tex, m_q1_params, m_q5_params)) return true;
return false; }
}
return true; void dds_comp::compress_deinit()
} {
clear();
}
bool dds_comp::compress_init(const crn_comp_params& params) { } // namespace crnlib
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
+31 -29
View File
@@ -2,45 +2,47 @@
// See Copyright Notice and license at the end of inc/crnlib.h // See Copyright Notice and license at the end of inc/crnlib.h
#pragma once #pragma once
#include "crn_comp.h" #include "crn_comp.h"
#include "crn_mipmapped_texture.h" #include "crn_dds_texture.h"
#include "crn_texture_comp.h" #include "crn_texture_comp.h"
namespace crnlib { namespace crnlib
class dds_comp : public itexture_comp { {
CRNLIB_NO_COPY_OR_ASSIGNMENT_OP(dds_comp); class dds_comp : public itexture_comp
{
CRNLIB_NO_COPY_OR_ASSIGNMENT_OP(dds_comp);
public: public:
dds_comp(); dds_comp();
virtual ~dds_comp(); virtual ~dds_comp();
virtual const char* get_ext() const { return "DDS"; } virtual const wchar_t *get_ext() const { return L"DDS"; }
virtual bool compress_init(const crn_comp_params& params); virtual bool compress_init(const crn_comp_params& params);
virtual bool compress_pass(const crn_comp_params& params, float* pEffective_bitrate); virtual bool compress_pass(const crn_comp_params& params, float *pEffective_bitrate);
virtual void compress_deinit(); virtual void compress_deinit();
virtual const crnlib::vector<uint8>& get_comp_data() const { 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; } virtual crnlib::vector<uint8>& get_comp_data() { return m_comp_data; }
private: private:
mipmapped_texture m_src_tex; dds_texture m_src_tex;
mipmapped_texture m_packed_tex; dds_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; pixel_format m_pixel_fmt;
dxt_image::pack_params m_pack_params; dxt_image::pack_params m_pack_params;
task_pool m_task_pool; task_pool m_task_pool;
qdxt1_params m_q1_params; qdxt1_params m_q1_params;
qdxt5_params m_q5_params; qdxt5_params m_q5_params;
mipmapped_texture::qdxt_state* m_pQDXT_state; dds_texture::qdxt_state *m_pQDXT_state;
void clear(); void clear();
bool create_dds_tex(mipmapped_texture& dds_tex); bool create_dds_tex(dds_texture &dds_tex);
bool convert_to_dxt(const crn_comp_params& params); bool convert_to_dxt(const crn_comp_params& params);
}; };
} // namespace crnlib } // namespace crnlib
File diff suppressed because it is too large Load Diff
+292
View File
@@ -0,0 +1,292 @@
// File: crn_dds_texture.h
// See Copyright Notice and license at the end of inc/crnlib.h
#pragma once
#include "crn_dxt_image.h"
#include "../inc/dds_defs.h"
#include "crn_pixel_format.h"
#include "crn_image.h"
#include "crn_resampler.h"
#include "crn_data_stream_serializer.h"
#include "crn_qdxt1.h"
#include "crn_qdxt5.h"
#include "crn_texture_file_types.h"
#include "crn_image_utils.h"
namespace crnlib
{
extern const vec2I g_vertical_cross_image_offsets[6];
class mip_level
{
friend class dds_texture;
public:
mip_level();
~mip_level();
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);
void assign(dxt_image* p, pixel_format fmt = PIXEL_FMT_INVALID);
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; }
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, bool uncook) const;
inline bool is_packed() const { return m_pDXTImage != NULL; }
inline bool is_valid() const { return (m_pImage != NULL) || (m_pDXTImage != NULL); }
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 pixel_format get_format() const { return m_format; }
inline void set_format(pixel_format fmt) { m_format = fmt; }
bool convert(pixel_format fmt, bool cook, const dxt_image::pack_params& p);
bool pack_to_dxt(const image_u8& img, pixel_format fmt, bool cook, const dxt_image::pack_params& p);
bool pack_to_dxt(pixel_format fmt, bool cook, const dxt_image::pack_params& p);
bool unpack_from_dxt(bool uncook = true);
bool set_alpha_to_luma();
bool convert(image_utils::conversion_type conv_type);
private:
uint m_width;
uint m_height;
pixel_format_helpers::component_flags m_comp_flags;
pixel_format m_format;
image_u8* m_pImage;
dxt_image* m_pDXTImage;
void cook_image(image_u8& img) const;
void uncook_image(image_u8& img) const;
};
// A face is an array of mip_level ptr's.
typedef crnlib::vector<mip_level*> mip_ptr_vec;
// And an array of one, six, or N faces make up a texture.
typedef crnlib::vector<mip_ptr_vec> face_vec;
class dds_texture
{
public:
// Construction/destruction
dds_texture();
~dds_texture();
dds_texture(const dds_texture& other);
dds_texture& operator= (const dds_texture& rhs);
void clear();
void init(uint width, uint height, uint levels, uint faces, pixel_format fmt, const wchar_t* pName);
// Assumes ownership.
void assign(face_vec& faces);
void assign(mip_level* pLevel);
void assign(image_u8* p, pixel_format fmt = PIXEL_FMT_INVALID);
void assign(dxt_image* p, pixel_format fmt = PIXEL_FMT_INVALID);
void set(texture_file_types::format source_file_type, const dds_texture& dds_texture);
// Accessors
image_u8* get_level_image(uint face, uint level, image_u8& img, bool uncook = true) const;
inline bool is_valid() const { return m_faces.size() > 0; }
const dynamic_wstring& get_name() const { return m_name; }
void set_name(const dynamic_wstring& name) { m_name = name; }
const dynamic_wstring& 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_wstring& get_last_error() const { return m_last_error; }
void clear_last_error() { m_last_error.clear(); }
// Loading/saving
bool read_dds(const wchar_t* pFilename);
bool read_dds(data_stream_serializer& serializer);
bool write_dds(const wchar_t* pFilename) const;
bool write_dds(data_stream_serializer& serializer) const;
bool load_crn_from_memory(const wchar_t* pFilename, const void *pData, uint data_size);
// If file_format is texture_file_types::cFormatInvalid, the format will be determined from the filename's extension.
bool load_from_file(const wchar_t* pFilename, texture_file_types::format file_format);
bool write_to_file(
const wchar_t* pFilename,
texture_file_types::format file_format,
crn_comp_params* pCRN_comp_params,
uint32 *pActual_quality_level, float *pActual_bitrate);
// 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, dds_texture& dst_tex, const qdxt1_params& dxt1_params, const qdxt5_params& dxt5_params, pixel_format fmt, bool cook);
bool qdxt_pack(qdxt_state& state, dds_texture& dst_tex, const qdxt1_params& dxt1_params, const qdxt5_params& dxt5_params);
void swap(dds_texture& img);
bool check() const;
private:
dynamic_wstring 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_wstring m_last_error;
inline void clear_last_error() const { m_last_error.clear(); }
inline void set_last_error(const wchar_t* p) const { m_last_error = p; }
void free_all_mips();
bool read_dds_internal(data_stream_serializer& serializer);
bool load_regular(const wchar_t* pFilename, texture_file_types::format file_format);
bool load_dds(const wchar_t* pFilename);
bool load_crn(const wchar_t* pFilename);
void print_crn_comp_params(const crn_comp_params& p);
bool save_regular(const wchar_t* pFilename);
bool save_dds(const wchar_t* pFilename);
bool save_comp_texture(const wchar_t* pFilename, const crn_comp_params &comp_params, uint32 *pActual_quality_level, float *pActual_bitrate);
};
inline void swap(dds_texture& a, dds_texture& b)
{
a.swap(b);
}
} // namespace crnlib
+356 -352
View File
@@ -7,371 +7,375 @@
#include "crn_dxt_fast.h" #include "crn_dxt_fast.h"
#include "crn_intersect.h" #include "crn_intersect.h"
namespace crnlib { 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_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_from_linear[cDXT1SelectorValues] = { 0U, 2U, 3U, 1U };
const uint8 g_dxt1_to_linear[cDXT1SelectorValues] = {0U, 3U, 1U, 2U}; 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_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_eight_alpha_invert_table[cDXT5SelectorValues] = { 1, 0, 7, 6, 5, 4, 3, 2 };
const char* get_dxt_format_string(dxt_format fmt) { const wchar_t* get_dxt_format_string(dxt_format fmt)
switch (fmt) { {
case cDXT1: switch (fmt)
return "DXT1"; {
case cDXT1A: case cDXT1: return L"DXT1";
return "DXT1A"; case cDXT1A: return L"DXT1A";
case cDXT3: case cDXT3: return L"DXT3";
return "DXT3"; case cDXT5: return L"DXT5";
case cDXT5: case cDXT5A: return L"DXT5A";
return "DXT5"; case cDXN_XY: return L"DXN_XY";
case cDXT5A: case cDXN_YX: return L"DXN_YX";
return "DXT5A"; default: break;
case cDXN_XY: }
return "DXN_XY"; CRNLIB_ASSERT(false);
case cDXN_YX: return L"?";
return "DXN_YX"; }
case cETC1:
return "ETC1";
case cETC2:
return "ETC2";
case cETC2A:
return "ETC2A";
case cETC1S:
return "ETC1S";
case cETC2AS:
return "ETC2AS";
default:
break;
}
CRNLIB_ASSERT(false);
return "?";
}
const char* get_dxt_compressor_name(crn_dxt_compressor_type c) { const wchar_t* get_dxt_compressor_name(crn_dxt_compressor_type c)
switch (c) { {
case cCRNDXTCompressorCRN: switch (c)
return "CRN"; {
case cCRNDXTCompressorCRNF: case cCRNDXTCompressorCRN: return L"CRN";
return "CRNF"; case cCRNDXTCompressorCRNF: return L"CRNF";
case cCRNDXTCompressorRYG: case cCRNDXTCompressorRYG: return L"RYG";
return "RYG"; default: break;
#if CRNLIB_SUPPORT_ATI_COMPRESS }
case cCRNDXTCompressorATI: CRNLIB_ASSERT(false);
return "ATI"; return L"?";
#endif }
default:
break; uint get_dxt_format_bits_per_pixel(dxt_format fmt)
} {
CRNLIB_ASSERT(false); switch (fmt)
return "?"; {
} case cDXT1:
case cDXT1A:
case cDXT5A:
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);
uint get_dxt_format_bits_per_pixel(dxt_format fmt) {
switch (fmt) {
case cDXT1:
case cDXT1A:
case cDXT5A:
case cETC1:
case cETC2:
case cETC1S:
return 4; return 4;
case cDXT3: }
case cDXT5:
case cDXN_XY: uint dxt1_block::get_block_colors3_round(color_quad_u8* pDst, uint16 color0, uint16 color1)
case cDXN_YX: {
case cETC2A: color_quad_u8 c0(unpack_color(color0, true));
case cETC2AS: 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; return 8;
default: }
break;
}
CRNLIB_ASSERT(false);
return 0;
}
bool get_dxt_format_has_alpha(dxt_format fmt) { uint dxt5_block::get_block_values(color_quad_u8* pDst, uint l, uint h)
switch (fmt) { {
case cDXT1A: if (l > h)
case cDXT3: return get_block_values8(pDst, l, h);
case cDXT5: else
case cDXT5A: return get_block_values6(pDst, l, h);
case cETC2A: }
case cETC2AS:
return true;
default:
break;
}
return false;
}
uint16 dxt1_block::pack_color(const color_quad_u8& color, bool scaled, uint bias) { uint dxt5_block::get_block_values6(uint* pDst, uint l, uint h)
uint r = color.r; {
uint g = color.g; pDst[0] = l;
uint b = color.b; 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;
}
if (scaled) { uint dxt5_block::get_block_values8(uint* pDst, uint l, uint h)
r = (r * 31U + bias) / 255U; {
g = (g * 63U + bias) / 255U; pDst[0] = l;
b = (b * 31U + bias) / 255U; 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;
}
r = math::minimum(r, 31U); uint dxt5_block::unpack_endpoint(uint packed, uint index)
g = math::minimum(g, 63U); {
b = math::minimum(b, 31U); CRNLIB_ASSERT(index < 2);
return (packed >> (8 * index)) & 0xFF;
}
return static_cast<uint16>(b | (g << 5U) | (r << 11U)); uint dxt5_block::pack_endpoints(uint lo, uint hi)
} {
CRNLIB_ASSERT((lo <= 0xFF) && (hi <= 0xFF));
return lo | (hi << 8U);
}
uint16 dxt1_block::pack_color(uint r, uint g, uint b, bool scaled, uint bias) { uint dxt5_block::get_block_values(uint* pDst, uint l, uint h)
return pack_color(color_quad_u8(r, g, b, 0), scaled, bias); {
} if (l > h)
return get_block_values8(pDst, l, h);
else
return get_block_values6(pDst, l, h);
}
color_quad_u8 dxt1_block::unpack_color(uint16 packed_color, bool scaled, uint alpha) { } // namespace crnlib
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
+227 -271
View File
@@ -11,315 +11,271 @@
#define CRNLIB_DXT_ALT_ROUNDING 1 #define CRNLIB_DXT_ALT_ROUNDING 1
namespace crnlib { namespace crnlib
enum dxt_constants { {
cDXT1BytesPerBlock = 8U, enum dxt_constants
cDXT5NBytesPerBlock = 16U, {
cDXT1BytesPerBlock = 8U,
cDXT5NBytesPerBlock = 16U,
cDXT5SelectorBits = 3U, cDXT5SelectorBits = 3U,
cDXT5SelectorValues = 1U << cDXT5SelectorBits, cDXT5SelectorValues = 1U << cDXT5SelectorBits,
cDXT5SelectorMask = cDXT5SelectorValues - 1U, cDXT5SelectorMask = cDXT5SelectorValues - 1U,
cDXT1SelectorBits = 2U, cDXT1SelectorBits = 2U,
cDXT1SelectorValues = 1U << cDXT1SelectorBits, cDXT1SelectorValues = 1U << cDXT1SelectorBits,
cDXT1SelectorMask = cDXT1SelectorValues - 1U, cDXT1SelectorMask = cDXT1SelectorValues - 1U,
cDXTBlockShift = 2U, cDXTBlockShift = 2U,
cDXTBlockSize = 1U << cDXTBlockShift cDXTBlockSize = 1U << cDXTBlockShift
}; };
enum dxt_format { enum dxt_format
cDXTInvalid = -1, {
cDXTInvalid = -1,
// cDXT1/1A must appear first! // cDXT1/1A must appear first!
cDXT1, cDXT1,
cDXT1A, cDXT1A,
cDXT3, cDXT3,
cDXT5, cDXT5,
cDXT5A, cDXT5A,
cDXN_XY, // inverted relative to standard ATI2, 360's DXN cDXN_XY, // inverted relative to standard ATI2, 360's DXN
cDXN_YX, // standard ATI2, cDXN_YX // standard ATI2
};
cETC1, const float cDXT1MaxLinearValue = 3.0f;
cETC2, const float cDXT1InvMaxLinearValue = 1.0f/3.0f;
cETC2A,
cETC1S,
cETC2AS,
};
const float cDXT1MaxLinearValue = 3.0f; const float cDXT5MaxLinearValue = 7.0f;
const float cDXT1InvMaxLinearValue = 1.0f / 3.0f; const float cDXT5InvMaxLinearValue = 1.0f/7.0f;
const float cDXT5MaxLinearValue = 7.0f; // Converts DXT1 raw color selector index to a linear value.
const float cDXT5InvMaxLinearValue = 1.0f / 7.0f; extern const uint8 g_dxt1_to_linear[cDXT1SelectorValues];
// Converts DXT1 raw color selector index to a linear value. // Converts DXT5 raw alpha selector index to a linear value.
extern const uint8 g_dxt1_to_linear[cDXT1SelectorValues]; extern const uint8 g_dxt5_to_linear[cDXT5SelectorValues];
// Converts DXT5 raw alpha selector index to a linear value. // Converts DXT1 linear color selector index to a raw value (inverse of g_dxt1_to_linear).
extern const uint8 g_dxt5_to_linear[cDXT5SelectorValues]; extern const uint8 g_dxt1_from_linear[cDXT1SelectorValues];
// Converts DXT1 linear color selector index to a raw value (inverse of g_dxt1_to_linear). // Converts DXT5 linear alpha selector index to a raw value (inverse of g_dxt5_to_linear).
extern const uint8 g_dxt1_from_linear[cDXT1SelectorValues]; 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_alpha6_to_linear[cDXT5SelectorValues];
extern const uint8 g_dxt5_from_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]; const wchar_t* get_dxt_format_string(dxt_format fmt);
extern const uint8 g_eight_alpha_invert_table[cDXT5SelectorValues]; 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); const wchar_t* get_dxt_quality_string(crn_dxt_quality q);
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 wchar_t* 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 { enum { cNumSelectorBytes = 4 };
uint8 m_low_color[2]; uint8 m_selectors[cNumSelectorBytes];
uint8 m_high_color[2];
enum { cNumSelectorBytes = 4 }; inline void clear()
uint8 m_selectors[cNumSelectorBytes]; {
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);
} }
}
}
inline void flip_y(uint w = 4, uint h = 4) { // These methods assume the in-memory rep is in LE byte order.
for (uint y = 0; y < (h / 2); y++) { inline uint get_low_color() const
for (uint x = 0; x < w; x++) { {
const uint c = get_selector(x, y); return m_low_color[0] | (m_low_color[1] << 8U);
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); inline uint get_high_color() const
static uint16 pack_color(uint r, uint g, uint b, bool scaled, uint bias = 127U); {
return m_high_color[0] | (m_high_color[1] << 8U);
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 flip_y(uint w = 4, uint h = 4) { inline void set_low_color(uint16 c)
for (uint y = 0; y < (h / 2); y++) { {
for (uint x = 0; x < w; x++) { m_low_color[0] = static_cast<uint8>(c & 0xFF);
const uint c = get_alpha(x, y, false); m_low_color[1] = static_cast<uint8>((c >> 8) & 0xFF);
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); inline void set_high_color(uint16 c)
{
struct dxt5_block { m_high_color[0] = static_cast<uint8>(c & 0xFF);
uint8 m_endpoints[2]; m_high_color[1] = static_cast<uint8>((c >> 8) & 0xFF);
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) { inline bool is_constant_color_block() const { return get_low_color() == get_high_color(); }
for (uint y = 0; y < (h / 2); y++) { inline bool is_alpha_block() const { return get_low_color() <= get_high_color(); }
for (uint x = 0; x < w; x++) { inline bool is_non_alpha_block() const { return !is_alpha_block(); }
const uint c = get_selector(x, y);
set_selector(x, y, get_selector(x, (h - 1) - y)); inline uint get_selector(uint x, uint y) const
set_selector(x, (h - 1) - y, c); {
CRNLIB_ASSERT((x < 4U) && (y < 4U));
return (m_selectors[y] >> (x * cDXT1SelectorBits)) & cDXT1SelectorMask;
} }
}
}
enum { cMaxSelectorValues = 8 }; inline void set_selector(uint x, uint y, uint val)
{
CRNLIB_ASSERT((x < 4U) && (y < 4U) && (val < 4U));
// Results written to alpha channel. m_selectors[y] &= (~(cDXT1SelectorMask << (x * cDXT1SelectorBits)));
static uint get_block_values6(color_quad_u8* pDst, uint l, uint h); m_selectors[y] |= (val << (x * cDXT1SelectorBits));
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 uint16 pack_color(const color_quad_u8& color, bool scaled, uint bias = 127U);
static uint get_block_values8(uint* pDst, uint l, uint h); static uint16 pack_color(uint r, uint g, uint b, bool scaled, uint bias = 127U);
// 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 color_quad_u8 unpack_color(uint16 packed_color, bool scaled, uint alpha = 255U);
static uint pack_endpoints(uint lo, uint hi); 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);
struct dxt_pixel_block { static uint get_block_colors4(color_quad_u8* pDst, uint16 color0, uint16 color1);
color_quad_u8 m_pixels[cDXTBlockSize][cDXTBlockSize]; // [y][x] 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;
};
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 <= UINT8_MAX);
m_endpoints[0] = static_cast<uint8>(i);
}
inline void set_high_alpha(uint i)
{
CRNLIB_ASSERT(i <= UINT8_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);
}
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
inline void clear() {
utils::zero_object(*this);
}
};
CRNLIB_DEFINE_BITWISE_COPYABLE(dxt_pixel_block);
} // namespace crnlib
+2053 -1733
View File
File diff suppressed because it is too large Load Diff
+282 -206
View File
@@ -3,274 +3,350 @@
#pragma once #pragma once
#include "crn_dxt.h" #include "crn_dxt.h"
namespace crnlib { namespace crnlib
struct dxt1_solution_coordinates { {
inline dxt1_solution_coordinates() struct dxt1_solution_coordinates
: m_low_color(0), m_high_color(0) {} {
inline dxt1_solution_coordinates() : m_low_color(0), m_high_color(0){ }
inline dxt1_solution_coordinates(uint16 l, uint16 h) inline dxt1_solution_coordinates(uint16 l, uint16 h) : m_low_color(l), m_high_color(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) 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_low_color(dxt1_block::pack_color(l, scaled)),
m_high_color(dxt1_block::pack_color(h, 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 #if CRNLIB_DXT_ALT_ROUNDING
// Umm, wtf? // Umm, wtf?
nl.clamp(0.0f, .999f); nl.clamp(0.0f, .999f);
nh.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 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); color_quad_u8 h( (int)floor(nh[0] * 32.0f), (int)floor(nh[1] * 64.0f), (int)floor(nh[2] * 32.0f), 255);
#else #else
// Fixes the bins // 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 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); 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 #endif
m_low_color = dxt1_block::pack_color(l, false); m_low_color = dxt1_block::pack_color(l, false);
m_high_color = dxt1_block::pack_color(h, false); m_high_color = dxt1_block::pack_color(h, false);
} }
uint16 m_low_color; uint16 m_low_color;
uint16 m_high_color; uint16 m_high_color;
inline void clear() { inline void clear()
m_low_color = 0; {
m_high_color = 0; m_low_color = 0;
} m_high_color = 0;
}
inline dxt1_solution_coordinates& canonicalize() { inline dxt1_solution_coordinates& canonicalize()
if (m_low_color < m_high_color) {
utils::swap(m_low_color, m_high_color); if (m_low_color < m_high_color)
return *this; utils::swap(m_low_color, m_high_color);
} return *this;
}
inline operator size_t() const { return fast_hash(this, sizeof(*this)); } inline operator size_t() const { return fast_hash(this, sizeof(*this)); }
inline bool operator==(const dxt1_solution_coordinates& other) const { 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 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 l1 = math::minimum(other.m_low_color, other.m_high_color);
uint16 h1 = math::maximum(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); return (l0 == l1) && (h0 == h1);
} }
inline bool operator!=(const dxt1_solution_coordinates& other) const { inline bool operator!= (const dxt1_solution_coordinates& other) const
return !(*this == other); {
} return !(*this == other);
}
inline bool operator<(const dxt1_solution_coordinates& other) const { 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 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 l1 = math::minimum(other.m_low_color, other.m_high_color);
uint16 h1 = math::maximum(other.m_low_color, other.m_high_color); uint16 h1 = math::maximum(other.m_low_color, other.m_high_color);
if (l0 < l1) if (l0 < l1)
return true; return true;
else if (l0 == l1) { else if (l0 == l1)
if (h0 < h1) {
return true; if (h0 < h1)
} return true;
}
return false; return false;
} }
}; };
typedef crnlib::vector<dxt1_solution_coordinates> dxt1_solution_coordinates_vec; typedef crnlib::vector<dxt1_solution_coordinates> dxt1_solution_coordinates_vec;
CRNLIB_DEFINE_BITWISE_COPYABLE(dxt1_solution_coordinates); CRNLIB_DEFINE_BITWISE_COPYABLE(dxt1_solution_coordinates);
struct unique_color { struct unique_color
inline unique_color() {} {
inline unique_color(const color_quad_u8& color, uint weight) inline unique_color() { }
: m_color(color), m_weight(weight) {} inline unique_color(const color_quad_u8& color, uint weight) : m_color(color), m_weight(weight) { }
color_quad_u8 m_color; color_quad_u8 m_color;
uint m_weight; uint m_weight;
inline bool operator<(const unique_color& c) const { inline bool operator< (const unique_color& c) const
return *reinterpret_cast<const uint32*>(&m_color) < *reinterpret_cast<const uint32*>(&c.m_color); {
} return *reinterpret_cast<const uint32*>(&m_color) < *reinterpret_cast<const uint32*>(&c.m_color);
}
inline bool operator==(const unique_color& c) const { inline bool operator== (const unique_color& c) const
return *reinterpret_cast<const uint32*>(&m_color) == *reinterpret_cast<const uint32*>(&c.m_color); {
} return *reinterpret_cast<const uint32*>(&m_color) == *reinterpret_cast<const uint32*>(&c.m_color);
}; }
};
CRNLIB_DEFINE_BITWISE_COPYABLE(unique_color); CRNLIB_DEFINE_BITWISE_COPYABLE(unique_color);
class dxt1_endpoint_optimizer { class dxt1_endpoint_optimizer
public: {
dxt1_endpoint_optimizer(); public:
dxt1_endpoint_optimizer();
struct params { struct params
params() {
: m_block_index(0), params() :
m_pPixels(NULL), m_block_index(0),
m_num_pixels(0), m_pPixels(NULL),
m_dxt1a_alpha_threshold(128U), m_num_pixels(0),
m_quality(cCRNDXTQualityUber), m_dxt1a_alpha_threshold(128U),
m_pixels_have_alpha(false), m_quality(cCRNDXTQualityUber),
m_use_alpha_blocks(true), m_pixels_have_alpha(false),
m_perceptual(true), m_use_alpha_blocks(true),
m_grayscale_sampling(false), m_perceptual(true),
m_endpoint_caching(true), m_grayscale_sampling(false),
m_use_transparent_indices_for_black(false), m_endpoint_caching(true),
m_force_alpha_blocks(false) { 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; uint m_block_index;
const color_quad_u8* m_pPixels; const color_quad_u8* m_pPixels;
uint m_num_pixels; uint m_num_pixels;
uint m_dxt1a_alpha_threshold; uint m_dxt1a_alpha_threshold;
crn_dxt_quality m_quality; crn_dxt_quality m_quality;
bool m_pixels_have_alpha; bool m_pixels_have_alpha;
bool m_use_alpha_blocks; bool m_use_alpha_blocks;
bool m_perceptual; bool m_perceptual;
bool m_grayscale_sampling; bool m_grayscale_sampling;
bool m_endpoint_caching; bool m_endpoint_caching;
bool m_use_transparent_indices_for_black; bool m_use_transparent_indices_for_black;
bool m_force_alpha_blocks; bool m_force_alpha_blocks;
}; int m_color_weights[3];
};
struct results { struct results
inline results() {
: m_pSelectors(NULL) {} inline results() : m_pSelectors(NULL) { }
uint64 m_error; uint64 m_error;
uint16 m_low_color; uint16 m_low_color;
uint16 m_high_color; uint16 m_high_color;
uint8* m_pSelectors; uint8* m_pSelectors;
bool m_alpha_block; bool m_alpha_block;
bool m_reordered; };
bool m_alternate_rounding;
bool m_enforce_selector;
uint8 m_enforced_selector;
};
bool compute(const params& p, results& r); struct solution
{
solution() { }
private: solution(const solution& other)
const params* m_pParams; {
results* m_pResults; m_results = other.m_results;
m_selectors = other.m_selectors;
m_results.m_pSelectors = m_selectors.begin();
}
bool m_perceptual; solution& operator= (const solution& rhs)
bool m_evaluate_hc; {
if (this == &rhs)
return *this;
typedef crnlib::vector<unique_color> unique_color_vec; m_results = rhs.m_results;
m_selectors = rhs.m_selectors;
m_results.m_pSelectors = m_selectors.begin();
//typedef crnlib::hash_map<uint32, uint32, bit_hasher<uint32> > unique_color_hash_map; return *this;
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! results m_results;
unique_color_vec m_evaluated_colors; crnlib::vector<uint8> m_selectors;
unique_color_vec m_temp_unique_colors;
struct { inline bool operator< (const solution& other) const
uint64 low, high; {
} m_rDist[32], m_gDist[64], m_bDist[32]; 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;
uint m_total_unique_color_weight; bool compute(const params& p, results& r, solution_vec* pSolutions = NULL);
bool m_has_transparent_pixels; private:
const params* m_pParams;
results* m_pResults;
solution_vec* m_pSolutions;
vec3F_array m_norm_unique_colors; bool m_perceptual;
vec3F m_mean_norm_color; bool m_has_color_weighting;
vec3F_array m_norm_unique_colors_weighted; typedef crnlib::vector<unique_color> unique_color_vec;
vec3F m_mean_norm_color_weighted;
vec3F m_principle_axis; //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;
crnlib::vector<uint16> m_unique_packed_colors; unique_color_vec m_unique_colors; // excludes transparent colors!
crnlib::vector<uint8> m_trial_selectors; unique_color_vec m_temp_unique_colors;
crnlib::vector<vec3F> m_low_coords; uint m_total_unique_color_weight;
crnlib::vector<vec3F> m_high_coords;
enum { cMaxPrevResults = 4 }; bool m_has_transparent_pixels;
dxt1_solution_coordinates m_prev_results[cMaxPrevResults];
uint m_num_prev_results;
crnlib::vector<vec3I> m_lo_cells; vec3F_array m_norm_unique_colors;
crnlib::vector<vec3I> m_hi_cells; vec3F m_mean_norm_color;
struct potential_solution { vec3F_array m_norm_unique_colors_weighted;
potential_solution() vec3F m_mean_norm_color_weighted;
: m_coords(), m_error(cUINT64_MAX), m_alpha_block(false) {
}
dxt1_solution_coordinates m_coords; vec3F m_principle_axis;
crnlib::vector<uint8> m_selectors;
uint64 m_error;
bool m_alpha_block;
bool m_alternate_rounding;
bool m_enforce_selector;
uint8 m_enforced_selector;
void clear() { bool m_all_pixels_grayscale;
m_coords.clear();
m_selectors.resize(0);
m_error = cUINT64_MAX;
m_alpha_block = false;
}
bool are_selectors_all_equal() const { crnlib::vector<uint16> m_unique_packed_colors;
if (m_selectors.empty()) crnlib::vector<uint8> m_trial_selectors;
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; crnlib::vector<vec3F> m_low_coords;
potential_solution m_best_solution; crnlib::vector<vec3F> m_high_coords;
typedef crnlib::hash_map<uint, empty_type> solution_hash_map; enum { cMaxPrevResults = 4 };
solution_hash_map m_solutions_tried; dxt1_solution_coordinates m_prev_results[cMaxPrevResults];
uint m_num_prev_results;
bool refine_solution(int refinement_level = 0); crnlib::vector<vec3I> m_lo_cells;
crnlib::vector<vec3I> m_hi_cells;
bool evaluate_solution(const dxt1_solution_coordinates& coords, bool alternate_rounding = false); uint m_total_evals;
bool evaluate_solution_uber(const dxt1_solution_coordinates& coords, bool alternate_rounding);
bool evaluate_solution_fast(const dxt1_solution_coordinates& coords, bool alternate_rounding);
bool evaluate_solution_hc_perceptual(const dxt1_solution_coordinates& coords, bool alternate_rounding);
bool evaluate_solution_hc_uniform(const dxt1_solution_coordinates& coords, bool alternate_rounding);
void compute_selectors();
void compute_selectors_hc();
void find_unique_colors(); struct potential_solution
void handle_multicolor_block(); {
void compute_pca(vec3F& axis, const vec3F_array& norm_colors, const vec3F& def); potential_solution() : m_coords(), m_error(UINT64_MAX), m_alpha_block(false), m_valid(false)
void compute_vectors(const vec3F& perceptual_weights); {
void return_solution(); }
void try_combinatorial_encoding();
void compute_endpoint_component_errors(uint comp_index, uint64 (&error)[4][256], uint64 (&best_remaining_error)[4]);
void optimize_endpoint_comps();
void 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);
void compute_internal(const params& p, results& r); dxt1_solution_coordinates m_coords;
crnlib::vector<uint8> m_selectors;
uint64 m_error;
bool m_alpha_block;
bool m_valid;
unique_color lerp_color(const color_quad_u8& a, const color_quad_u8& b, float f, int rounding = 1); void clear()
{
m_coords.clear();
m_selectors.resize(0);
m_error = UINT64_MAX;
m_alpha_block = false;
m_valid = false;
}
inline uint color_distance(bool perceptual, const color_quad_u8& e1, const color_quad_u8& e2, bool alpha); 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;
}
};
} // namespace crnlib 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
+185 -165
View File
@@ -6,184 +6,204 @@
#include "crn_dxt_fast.h" #include "crn_dxt_fast.h"
#include "crn_intersect.h" #include "crn_intersect.h"
namespace crnlib { namespace crnlib
dxt5_endpoint_optimizer::dxt5_endpoint_optimizer() {
: m_pParams(NULL), dxt5_endpoint_optimizer::dxt5_endpoint_optimizer() :
m_pResults(NULL) { m_pParams(NULL),
m_unique_values.reserve(16); m_pResults(NULL)
m_unique_value_weights.reserve(16); {
} m_unique_values.reserve(16);
m_unique_value_weights.reserve(16);
}
bool dxt5_endpoint_optimizer::compute(const params& p, results& r) { bool dxt5_endpoint_optimizer::compute(const params& p, results& r)
m_pParams = &p; {
m_pResults = &r; m_pParams = &p;
m_pResults = &r;
if ((!p.m_num_pixels) || (!p.m_pPixels)) if ((!p.m_num_pixels) || (!p.m_pPixels))
return false; return false;
m_unique_values.resize(0); m_unique_values.resize(0);
m_unique_value_weights.resize(0); m_unique_value_weights.resize(0);
for (uint i = 0; i < 256; i++) for (uint i = 0; i < 256; i++)
m_unique_value_map[i] = -1; m_unique_value_map[i] = -1;
for (uint i = 0; i < p.m_num_pixels; i++) { for (uint i = 0; i < p.m_num_pixels; i++)
uint alpha = p.m_pPixels[i][p.m_comp_index]; {
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) { if (index == -1)
index = m_unique_values.size(); {
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_values.push_back(static_cast<uint8>(alpha));
m_unique_value_weights.push_back(0); 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_reordered = false;
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));
}
}
}
m_pResults->m_reordered = false;
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);
m_pResults->m_reordered = true;
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);
m_pResults->m_reordered = true;
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); if (m_unique_values.size() == 1)
trial_error += best_selector_error; {
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 (trial_error > m_pResults->m_error) m_trial_selectors.resize(m_unique_values.size());
break; m_best_selectors.resize(m_unique_values.size());
}
if (trial_error < m_pResults->m_error) { r.m_error = UINT64_MAX;
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) for (uint i = 0; i < m_unique_values.size() - 1; i++)
break; {
} const uint low_endpoint = m_unique_values[i];
}
}
} // namespace crnlib 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[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
+45 -41
View File
@@ -3,60 +3,64 @@
#pragma once #pragma once
#include "crn_dxt.h" #include "crn_dxt.h"
namespace crnlib { namespace crnlib
class dxt5_endpoint_optimizer { {
public: class dxt5_endpoint_optimizer
dxt5_endpoint_optimizer(); {
public:
dxt5_endpoint_optimizer();
struct params { struct params
params() {
: m_block_index(0), params() :
m_pPixels(NULL), m_block_index(0),
m_num_pixels(0), m_pPixels(NULL),
m_comp_index(3), m_num_pixels(0),
m_quality(cCRNDXTQualityUber), m_comp_index(3),
m_use_both_block_types(true) { m_quality(cCRNDXTQualityUber),
} m_use_both_block_types(true)
{
}
uint m_block_index; uint m_block_index;
const color_quad_u8* m_pPixels; const color_quad_u8* m_pPixels;
uint m_num_pixels; uint m_num_pixels;
uint m_comp_index; 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 { struct results
uint8* m_pSelectors; {
uint8* m_pSelectors;
uint64 m_error; uint64 m_error;
uint8 m_first_endpoint; uint8 m_first_endpoint;
uint8 m_second_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 m_reordered; };
};
bool compute(const params& p, results& r); bool compute(const params& p, results& r);
private: private:
const params* m_pParams; const params* m_pParams;
results* m_pResults; results* m_pResults;
crnlib::vector<uint8> m_unique_values; crnlib::vector<uint8> m_unique_values;
crnlib::vector<uint> m_unique_value_weights; crnlib::vector<uint> m_unique_value_weights;
crnlib::vector<uint8> m_trial_selectors; crnlib::vector<uint8> m_trial_selectors;
crnlib::vector<uint8> m_best_selectors; crnlib::vector<uint8> m_best_selectors;
int m_unique_value_map[256]; 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
+341 -188
View File
@@ -4,206 +4,359 @@
#include "crn_dxt_endpoint_refiner.h" #include "crn_dxt_endpoint_refiner.h"
#include "crn_dxt1.h" #include "crn_dxt1.h"
namespace crnlib { namespace crnlib
dxt_endpoint_refiner::dxt_endpoint_refiner() {
: m_pParams(NULL), dxt_endpoint_refiner::dxt_endpoint_refiner() :
m_pResults(NULL) { m_pParams(NULL),
} m_pResults(NULL)
{
}
bool dxt_endpoint_refiner::refine(const params& p, results& r) { bool dxt_endpoint_refiner::refine(const params& p, results& r)
if (!p.m_num_pixels) {
return false; if (!p.m_num_pixels)
return false;
m_pParams = &p; m_pParams = &p;
m_pResults = &r; m_pResults = &r;
r.m_error = cUINT64_MAX; r.m_error = UINT64_MAX;
r.m_low_color = 0; r.m_low_color = 0;
r.m_high_color = 0; r.m_high_color = 0;
double alpha2_sum = 0.0f; double alpha2_sum = 0.0f;
double beta2_sum = 0.0f; double beta2_sum = 0.0f;
double alphabeta_sum = 0.0f; double alphabeta_sum = 0.0f;
vec<3, double> alphax_sum(0.0f); vec<3, double> alphax_sum( 0.0f );
vec<3, double> betax_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. // This linear solver is from Squish.
for (uint i = 0; i < p.m_num_pixels; ++i) { for( uint i = 0; i < p.m_num_pixels; ++i )
uint8 c = p.m_pSelectors[i]; {
uint8 c = p.m_pSelectors[i];
double k; double k;
if (p.m_dxt1_selectors) if (p.m_dxt1_selectors)
k = g_dxt1_to_linear[c] * 1.0f / 3.0f; k = g_dxt1_to_linear[c] * 1.0f/3.0f;
else else
k = g_dxt5_to_linear[c] * 1.0f / 7.0f; k = g_dxt5_to_linear[c] * 1.0f/7.0f;
double alpha = 1.0f - k; double alpha = 1.0f - k;
double beta = k; double beta = k;
vec<3, double> x; vec<3, double> x;
if (p.m_dxt1_selectors) 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); 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 else
x.set(p.m_pPixels[i][p.m_alpha_comp_index] / 255.0f); x.set( p.m_pPixels[i][p.m_alpha_comp_index]/255.0f );
if (!i) if (!i)
first_color = x; first_color = x;
alpha2_sum += alpha * alpha; alpha2_sum += alpha*alpha;
beta2_sum += beta * beta; beta2_sum += beta*beta;
alphabeta_sum += alpha * beta; alphabeta_sum += alpha*beta;
alphax_sum += alpha * x; alphax_sum += alpha*x;
betax_sum += beta * 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;
}
}
vec3F l(0.0f), h(0.0f);
l = a;
h = b;
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);
return r.m_error < p.m_error_to_beat;
}
void dxt_endpoint_refiner::optimize_dxt5(vec3F low_color, vec3F high_color) {
uint8 L0 = math::clamp<int>(low_color[0] * 256.0f, 0, 255);
uint8 H0 = math::clamp<int>(high_color[0] * 256.0f, 0, 255);
uint64 hist[8] = {}, D2[8] = {}, DD[8] = {};
for (uint c = m_pParams->m_alpha_comp_index, i = 0; i < m_pParams->m_num_pixels; i++) {
uint8 a = m_pParams->m_pPixels[i][c];
uint8 s = m_pParams->m_pSelectors[i];
hist[s]++;
D2[s] += a * 2;
DD[s] += a * a;
}
uint16 solutions[529];
uint solutions_count = 0;
solutions[solutions_count++] = L0 == H0 ? H0 ? H0 - 1 << 8 | L0 : 1 : L0 > H0 ? H0 << 8 | L0 : L0 << 8 | H0;
uint8 minL = L0 <= 11 ? 0 : L0 - 11, maxL = L0 >= 244 ? 255 : L0 + 11;
uint8 minH = H0 <= 11 ? 0 : H0 - 11, maxH = H0 >= 244 ? 255 : H0 + 11;
for (uint16 L = minL; L <= maxL; L++) {
for (uint16 H = minH; H <= maxH; H++) {
if ((maxH < L || L <= H || H < minL) && (L != L0 || H != H0) && (L != H0 || H != L0))
solutions[solutions_count++] = L == H ? H ? H - 1 << 8 | L : 1 : L > H ? H << 8 | L : L << 8 | H;
}
}
for (uint i = 0; i < solutions_count; i++) {
uint8 L = solutions[i] & 0xFF;
uint8 H = solutions[i] >> 8;
uint values[8];
dxt5_block::get_block_values8(values, L, H);
uint64 error = 0;
for (uint64 s = 0; s < 8; s++)
error += hist[s] * values[s] * values[s] - D2[s] * values[s] + DD[s];
if (error < m_pResults->m_error) {
m_pResults->m_low_color = L;
m_pResults->m_high_color = H;
m_pResults->m_error = error;
if (!m_pResults->m_error)
return;
}
}
}
void dxt_endpoint_refiner::optimize_dxt1(vec3F low_color, vec3F high_color) {
uint16 L0 = math::clamp<int>(low_color[0] * 32.0f, 0, 31) << 11 | math::clamp<int>(low_color[1] * 64.0f, 0, 63) << 5 | math::clamp<int>(low_color[2] * 32.0f, 0, 31);
uint16 H0 = math::clamp<int>(high_color[0] * 32.0f, 0, 31) << 11 | math::clamp<int>(high_color[1] * 64.0f, 0, 63) << 5 | math::clamp<int>(high_color[2] * 32.0f, 0, 31);
uint64 hist[4] = {}, D2[4][3] = {}, DD[4][3] = {};
for (uint i = 0; i < m_pParams->m_num_pixels; i++) {
const color_quad_u8& pixel = m_pParams->m_pPixels[i];
uint8 s = m_pParams->m_pSelectors[i];
hist[s]++;
for (uint c = 0; c < 3; c++) {
D2[s][c] += pixel[c] * 2;
DD[s][c] += pixel[c] * pixel[c];
}
}
crnlib::vector<uint> solutions(54);
bool preserveL = hist[0] + hist[2] > hist[1] + hist[3];
bool improved = true;
for (uint iterations = 8; improved && iterations; iterations--) {
improved = false;
uint solutions_count = 0;
for (uint16 b0 = L0 & 31, g0 = L0 >> 5 & 63, r0 = L0 >> 11 & 31, b = b0 ? b0 - 1 : b0; b <= b0 + 1 && b <= 31; b++) {
for (uint16 g = g0 ? g0 - 1 : g0; g <= g0 + 1 && g <= 63; g++) {
for (uint16 r = r0 ? r0 - 1 : r0; r <= r0 + 1 && r <= 31; r++) {
uint16 L = r << 11 | g << 5 | b;
if (L != L0)
solutions[solutions_count++] = L > H0 ? L | H0 << 16 : H0 | L << 16;
}
} }
}
for (uint16 b0 = H0 & 31, g0 = H0 >> 5 & 63, r0 = H0 >> 11 & 31, b = b0 ? b0 - 1 : b0; b <= b0 + 1 && b <= 31; b++) {
for (uint16 g = g0 ? g0 - 1 : g0; g <= g0 + 1 && g <= 63; g++) {
for (uint16 r = r0 ? r0 - 1 : r0; r <= r0 + 1 && r <= 31; r++) {
uint16 H = r << 11 | g << 5 | b;
if (H != H0)
solutions[solutions_count++] = H > L0 ? H | L0 << 16 : L0 | H << 16;
}
}
}
std::sort(solutions.begin(), solutions.begin() + solutions_count);
for (uint i = 0; i < solutions_count; i++) {
if (i && solutions[i] == solutions[i - 1])
continue;
uint16 L = solutions[i] & 0xFFFF;
uint16 H = solutions[i] >> 16;
if (L == H) {
L += !preserveL ? ~L & 0x1F ? 0x1 : ~L & 0xF800 ? 0x800 : ~L & 0x7E0 ? 0x20 : 0 : !L ? 0x1 : 0;
H -= preserveL ? H & 0x1F ? 0x1 : H & 0xF800 ? 0x800 : H & 0x7E0 ? 0x20 : 0 : H == 0xFFFF ? 0x1 : 0;
}
color_quad_u8 block_colors[4];
dxt1_block::get_block_colors4(block_colors, L, H);
uint64 error = 0;
for (uint64 s = 0, d[3]; s < 4; s++) {
for (uint c = 0; c < 3; c++)
d[c] = hist[s] * block_colors[s][c] * block_colors[s][c] - D2[s][c] * block_colors[s][c] + DD[s][c];
error += m_pParams->m_perceptual ? d[0] * 8 + d[1] * 25 + d[2] : d[0] + d[1] + d[2];
}
if (error < m_pResults->m_error) {
m_pResults->m_low_color = L0 = L;
m_pResults->m_high_color = H0 = H;
m_pResults->m_error = error;
if (!m_pResults->m_error)
return;
improved = true;
}
}
}
}
} // namespace crnlib // 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;
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 (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;
}
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);
#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);
#endif
crnlib::vector<uint> trial_solutions;
trial_solutions.reserve(256);
trial_solutions.push_back(il | (ih << 8));
sparse_bit_array flags;
flags.resize(256 * 256);
flags.set_bit((il * 256) + ih);
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;
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;
if ((flags.get_bit(bit_index + h)) || (flags.get_bit(h * 256 + l)))
continue;
flags.set_bit(bit_index + h);
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);
}
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;
}
}
} // namespace crnlib
+45 -40
View File
@@ -3,55 +3,60 @@
#pragma once #pragma once
#include "crn_dxt.h" #include "crn_dxt.h"
namespace crnlib { namespace crnlib
// TODO: Experimental/Not fully implemented {
class dxt_endpoint_refiner { // TODO: Experimental/Not fully implemented
public: class dxt_endpoint_refiner
dxt_endpoint_refiner(); {
public:
dxt_endpoint_refiner();
struct params { struct params
params() {
: m_block_index(0), params() :
m_pPixels(NULL), m_block_index(0),
m_num_pixels(0), m_pPixels(NULL),
m_pSelectors(NULL), m_num_pixels(0),
m_alpha_comp_index(0), m_pSelectors(NULL),
m_error_to_beat(cUINT64_MAX), m_alpha_comp_index(0),
m_dxt1_selectors(true), m_error_to_beat(UINT64_MAX),
m_perceptual(true), m_dxt1_selectors(true),
m_highest_quality(true) { m_perceptual(true),
} m_highest_quality(true)
{
}
uint m_block_index; uint m_block_index;
const color_quad_u8* m_pPixels; const color_quad_u8* m_pPixels;
uint m_num_pixels; 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_dxt1_selectors;
bool m_perceptual; bool m_perceptual;
bool m_highest_quality; bool m_highest_quality;
}; };
struct results { struct results
uint16 m_low_color; {
uint16 m_high_color; uint16 m_low_color;
uint64 m_error; uint16 m_high_color;
}; uint64 m_error;
};
bool refine(const params& p, results& r); bool refine(const params& p, results& r);
private: private:
const params* m_pParams; const params* m_pParams;
results* m_pResults; results* m_pResults;
void optimize_dxt1(vec3F low_color, vec3F high_color); void optimize_dxt1(vec3F low_color, vec3F high_color);
void optimize_dxt5(vec3F low_color, vec3F high_color); void optimize_dxt5(vec3F low_color, vec3F high_color);
}; };
} // namespace crnlib } // namespace crnlib
+805 -725
View File
File diff suppressed because it is too large Load Diff
+11 -9
View File
@@ -4,16 +4,18 @@
#include "crn_color.h" #include "crn_color.h"
#include "crn_dxt.h" #include "crn_dxt.h"
namespace crnlib { 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); namespace dxt_fast
void compress_color_block(dxt1_block* pDXT1_block, const color_quad_u8* pBlock, bool refine = false); {
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(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 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); void find_representative_colors(uint n, const color_quad_u8* pBlock, color_quad_u8& lo, color_quad_u8& hi);
} // namespace dxt_fast } // namespace dxt_fast
} // namespace crnlib } // namespace crnlib
+2451 -1223
View File
File diff suppressed because it is too large Load Diff
+396 -169
View File
@@ -9,205 +9,432 @@
#include "crn_image.h" #include "crn_image.h"
#include "crn_dxt_hc_common.h" #include "crn_dxt_hc_common.h"
#include "crn_tree_clusterizer.h" #include "crn_tree_clusterizer.h"
#include "crn_threading.h" #include "crn_task_pool.h"
#include "crn_spinlock.h"
#define CRN_NO_FUNCTION_DEFINITIONS #define CRN_NO_FUNCTION_DEFINITIONS
#include "../inc/crnlib.h" #include "../inc/crnlib.h"
namespace crnlib { namespace crnlib
const uint cTotalCompressionPhases = 25; {
const uint cTotalCompressionPhases = 25;
class dxt_hc { class dxt_hc
public: {
dxt_hc(); public:
~dxt_hc(); dxt_hc();
~dxt_hc();
struct endpoint_indices_details { struct pixel_chunk
union { {
struct { pixel_chunk() { clear(); }
uint16 color;
uint16 alpha0; dxt_pixel_block m_blocks[cChunkBlockHeight][cChunkBlockWidth];
uint16 alpha1;
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;
}; };
uint16 component[3];
};
uint8 reference;
endpoint_indices_details() { utils::zero_object(*this); }
};
struct selector_indices_details { typedef crnlib::vector<pixel_chunk> pixel_chunk_vec;
union {
struct { struct params
uint16 color; {
uint16 alpha0; params() :
uint16 alpha1; 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;
}; };
uint16 component[3];
};
selector_indices_details() { utils::zero_object(*this); }
};
struct tile_details { void clear();
crnlib::vector<color_quad_u8> pixels;
float weight;
vec<6, float> color_endpoint;
vec<2, float> alpha_endpoints[2];
uint16 cluster_indices[3];
};
crnlib::vector<tile_details> m_tiles;
uint m_num_tiles;
float m_color_derating[cCRNMaxLevels][8];
float m_alpha_derating[8];
float m_uint8_to_float[256];
color_quad_u8 (*m_blocks)[16]; // Main compression function
uint m_num_blocks; bool compress(const params& p, uint num_chunks, const pixel_chunk* pChunks, task_pool& task_pool);
crnlib::vector<float> m_block_weights;
crnlib::vector<uint8> m_block_encodings;
crnlib::vector<uint64> m_block_selectors[3];
crnlib::vector<uint32> m_color_selectors;
crnlib::vector<uint64> m_alpha_selectors;
crnlib::vector<bool> m_color_selectors_used;
crnlib::vector<bool> m_alpha_selectors_used;
crnlib::vector<uint> m_tile_indices;
crnlib::vector<endpoint_indices_details> m_endpoint_indices;
crnlib::vector<selector_indices_details> m_selector_indices;
struct params { // Output accessors
params() inline uint get_num_chunks() const { return m_num_chunks; }
: m_num_blocks(0),
m_num_levels(0),
m_num_faces(0),
m_format(cDXT1),
m_perceptual(true),
m_hierarchical(true),
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),
m_adaptive_tile_alpha_psnr_derating(2.0f),
m_adaptive_tile_color_alpha_weighting_ratio(3.0f),
m_debugging(false),
m_pProgress_func(0),
m_pProgress_func_data(0) {
m_alpha_component_indices[0] = 3;
m_alpha_component_indices[1] = 0;
for (uint i = 0; i < cCRNMaxLevels; i++) {
m_levels[i].m_first_block = 0;
m_levels[i].m_num_blocks = 0;
m_levels[i].m_block_width = 0;
}
}
uint m_num_blocks; struct chunk_encoding
uint m_num_levels; {
uint m_num_faces; chunk_encoding() { utils::zero_object(*this); };
struct { // Index into g_chunk_encodings.
uint m_first_block; uint8 m_encoding_index;
uint m_num_blocks;
uint m_block_width;
float m_weight;
} m_levels[cCRNMaxLevels];
dxt_format m_format; // Number of tiles, endpoint indices.
bool m_perceptual; uint8 m_num_tiles;
bool m_hierarchical;
uint m_color_endpoint_codebook_size; // Color, alpha0, alpha1
uint m_color_selector_codebook_size; enum { cColorIndex = 0, cAlpha0Index = 1, cAlpha1Index = 2 };
uint m_alpha_endpoint_codebook_size; uint16 m_endpoint_indices[3][cChunkMaxTiles];
uint m_alpha_selector_codebook_size; uint16 m_selector_indices[3][cChunkBlockHeight][cChunkBlockWidth]; // [block_y][block_x]
};
float m_adaptive_tile_color_psnr_derating; typedef crnlib::vector<chunk_encoding> chunk_encoding_vec;
float m_adaptive_tile_alpha_psnr_derating;
float m_adaptive_tile_color_alpha_weighting_ratio;
uint m_alpha_component_indices[2];
task_pool* m_pTask_pool; inline const chunk_encoding& get_chunk_encoding(uint chunk_index) const { return m_chunk_encoding[chunk_index]; }
bool m_debugging; inline const chunk_encoding_vec& get_chunk_encoding_vec() const { return m_chunk_encoding; }
crn_progress_callback_func m_pProgress_func;
void* m_pProgress_func_data;
};
void clear(); struct selectors
bool compress( {
color_quad_u8 (*blocks)[16], selectors() { utils::zero_object(*this); }
crnlib::vector<endpoint_indices_details>& endpoint_indices,
crnlib::vector<selector_indices_details>& selector_indices,
crnlib::vector<uint32>& color_endpoints,
crnlib::vector<uint32>& alpha_endpoints,
crnlib::vector<uint32>& color_selectors,
crnlib::vector<uint64>& alpha_selectors,
const params& p
);
private: uint8 m_selectors[cBlockPixelHeight][cBlockPixelWidth];
params m_params;
uint m_num_alpha_blocks; uint8 get_by_index(uint i) const { CRNLIB_ASSERT(i < (cBlockPixelWidth * cBlockPixelHeight)); return *(&m_selectors[0][0] + i); }
bool m_has_color_blocks; void set_by_index(uint i, uint v) { CRNLIB_ASSERT(i < (cBlockPixelWidth * cBlockPixelHeight)); *(&m_selectors[0][0] + i) = static_cast<uint8>(v); }
bool m_has_etc_color_blocks; };
bool m_has_subblocks; typedef crnlib::vector<selectors> selectors_vec;
enum { // Color endpoints
cColor = 0, inline uint get_color_endpoint_codebook_size() const { return m_color_endpoints.size(); }
cAlpha0 = 1, inline uint get_color_endpoint(uint codebook_index) const { return m_color_endpoints[codebook_index]; }
cAlpha1 = 2, const crnlib::vector<uint>& get_color_endpoint_vec() const { return m_color_endpoints; }
cNumComps = 3
};
struct color_cluster { // Color selectors
color_cluster() : first_endpoint(0), second_endpoint(0) {} uint get_color_selector_codebook_size() const { return m_color_selectors.size(); }
crnlib::vector<uint> blocks[3]; const selectors& get_color_selectors(uint codebook_index) const { return m_color_selectors[codebook_index]; }
crnlib::vector<color_quad_u8> pixels; const crnlib::vector<selectors>& get_color_selectors_vec() const { return m_color_selectors; }
uint first_endpoint;
uint second_endpoint;
color_quad_u8 color_values[4];
};
crnlib::vector<color_cluster> m_color_clusters;
struct alpha_cluster { // Alpha endpoints
alpha_cluster() : first_endpoint(0), second_endpoint(0) {} inline uint get_alpha_endpoint_codebook_size() const { return m_alpha_endpoints.size(); }
crnlib::vector<uint> blocks[3]; inline uint get_alpha_endpoint(uint codebook_index) const { return m_alpha_endpoints[codebook_index]; }
crnlib::vector<color_quad_u8> pixels; const crnlib::vector<uint>& get_alpha_endpoint_vec() const { return m_alpha_endpoints; }
uint first_endpoint;
uint second_endpoint;
uint alpha_values[8];
bool refined_alpha;
uint refined_alpha_values[8];
};
crnlib::vector<alpha_cluster> m_alpha_clusters;
crn_thread_id_t m_main_thread_id; // Alpha selectors
bool m_canceled; uint get_alpha_selector_codebook_size() const { return m_alpha_selectors.size(); }
task_pool* m_pTask_pool; 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; }
int m_prev_phase_index; // Debug images
int m_prev_percentage_complete; 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; }
vec<6, float> palettize_color(color_quad_u8* pixels, uint pixels_count); const pixel_chunk_vec& get_compressed_chunk_pixels_orig_color_selectors() const { return m_dbg_chunk_pixels_orig_color_selectors; }
vec<2, float> palettize_alpha(color_quad_u8* pixels, uint pixels_count, uint comp_index); const pixel_chunk_vec& get_compressed_chunk_pixels_quantized_color_selectors() const { return m_dbg_chunk_pixels_quantized_color_selectors; }
void determine_tiles_task(uint64 data, void* pData_ptr); const pixel_chunk_vec& get_compressed_chunk_pixels_final_color_selectors() const { return m_dbg_chunk_pixels_final_color_selectors; }
void determine_tiles_task_etc(uint64 data, void* pData_ptr);
void determine_color_endpoint_codebook_task(uint64 data, void* pData_ptr); const pixel_chunk_vec& get_compressed_chunk_pixels_orig_alpha_selectors() const { return m_dbg_chunk_pixels_orig_alpha_selectors; }
void determine_color_endpoint_codebook_task_etc(uint64 data, void* pData_ptr); const pixel_chunk_vec& get_compressed_chunk_pixels_quantized_alpha_selectors() const { return m_dbg_chunk_pixels_quantized_alpha_selectors; }
void determine_color_endpoint_clusters_task(uint64 data, void* pData_ptr); const pixel_chunk_vec& get_compressed_chunk_pixels_final_alpha_selectors() const { return m_dbg_chunk_pixels_final_alpha_selectors; }
void determine_color_endpoints();
void determine_alpha_endpoint_codebook_task(uint64 data, void* pData_ptr); 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);
void determine_alpha_endpoint_clusters_task(uint64 data, void* pData_ptr);
void determine_alpha_endpoints();
void create_color_selector_codebook_task(uint64 data, void* pData_ptr); private:
void create_color_selector_codebook(); params m_params;
void create_alpha_selector_codebook_task(uint64 data, void* pData_ptr); uint m_num_chunks;
void create_alpha_selector_codebook(); const pixel_chunk* m_pChunks;
bool update_progress(uint phase_index, uint subphase_index, uint subphase_total); chunk_encoding_vec m_chunk_encoding;
};
} // namespace crnlib uint m_num_alpha_blocks; // 0, 1, or 2
bool m_has_color_blocks;
bool m_has_alpha0_blocks;
bool m_has_alpha1_blocks;
struct compressed_tile
{
uint m_endpoint_cluster_index;
uint m_first_endpoint;
uint m_second_endpoint;
uint8 m_selectors[cChunkPixelWidth * cChunkPixelHeight];
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);
}
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];
}
uint8 m_pixel_width;
uint8 m_pixel_height;
uint8 m_layout_index;
bool m_alpha_encoding;
};
struct compressed_chunk
{
compressed_chunk() { utils::zero_object(*this); }
uint8 m_encoding_index;
uint8 m_num_tiles;
compressed_tile m_tiles[cChunkMaxTiles];
compressed_tile m_quantized_tiles[cChunkMaxTiles];
uint16 m_endpoint_cluster_index[cChunkMaxTiles];
uint16 m_selector_cluster_index[cChunkBlockHeight][cChunkBlockWidth];
};
typedef crnlib::vector<compressed_chunk> compressed_chunk_vec;
enum
{
cColorChunks = 0,
cAlpha0Chunks = 1,
cAlpha1Chunks = 2,
cNumCompressedChunkVecs = 3
};
compressed_chunk_vec m_compressed_chunks[cNumCompressedChunkVecs];
int32 m_encoding_hist[cNumChunkEncodings];
int32 m_total_tiles;
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);
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);
void determine_compressed_chunks_task(uint64 data, void* pData_ptr);
bool determine_compressed_chunks();
struct tile_cluster
{
tile_cluster() : m_first_endpoint(0), m_second_endpoint(0), m_error(0), m_alpha_encoding(false) { }
// 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;
uint m_first_endpoint;
uint m_second_endpoint;
uint64 m_error;
bool m_alpha_encoding;
};
typedef crnlib::vector<tile_cluster> tile_cluster_vec;
tile_cluster_vec m_color_clusters;
tile_cluster_vec m_alpha_clusters;
selectors_vec m_color_selectors;
selectors_vec m_alpha_selectors;
// 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;
uint32 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
+33 -27
View File
@@ -3,39 +3,45 @@
#include "crn_core.h" #include "crn_core.h"
#include "crn_dxt_hc_common.h" #include "crn_dxt_hc_common.h"
namespace crnlib { namespace crnlib
chunk_encoding_desc g_chunk_encodings[cNumChunkEncodings] = {
{ chunk_encoding_desc g_chunk_encodings[cNumChunkEncodings] =
{1, {{0, 0, 8, 8, 0}}}, {
{ 1, { { 0, 0, 8, 8, 0 } } },
{2, {{0, 0, 8, 4, 1}, {0, 4, 8, 4, 2}}}, { 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, 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, 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, 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, { { 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, { { 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] = chunk_tile_desc g_chunk_tile_layouts[cNumChunkTileLayouts] =
{ {
// 2x2 // 2x2
{0, 0, 8, 8, 0}, { 0, 0, 8, 8, 0 },
// 2x1 // 2x1
{0, 0, 8, 4, 1}, { 0, 0, 8, 4, 1 },
{0, 4, 8, 4, 2}, { 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
// 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
+31 -28
View File
@@ -2,39 +2,42 @@
// See Copyright Notice and license at the end of inc/crnlib.h // See Copyright Notice and license at the end of inc/crnlib.h
#pragma once #pragma once
namespace crnlib { namespace crnlib
struct chunk_tile_desc { {
// These values are in pixels, and always a multiple of cBlockPixelWidth/cBlockPixelHeight. struct chunk_tile_desc
uint m_x_ofs; {
uint m_y_ofs; // These values are in pixels, and always a multiple of cBlockPixelWidth/cBlockPixelHeight.
uint m_width; uint m_x_ofs;
uint m_height; uint m_y_ofs;
uint m_layout_index; uint m_width;
}; uint m_height;
uint m_layout_index;
};
struct chunk_encoding_desc { struct chunk_encoding_desc
uint m_num_tiles; {
chunk_tile_desc m_tiles[4]; uint m_num_tiles;
}; chunk_tile_desc m_tiles[4];
};
const uint cChunkPixelWidth = 8; const uint cChunkPixelWidth = 8;
const uint cChunkPixelHeight = 8; const uint cChunkPixelHeight = 8;
const uint cChunkBlockWidth = 2; const uint cChunkBlockWidth = 2;
const uint cChunkBlockHeight = 2; const uint cChunkBlockHeight = 2;
const uint cChunkMaxTiles = 4; const uint cChunkMaxTiles = 4;
const uint cBlockPixelWidthShift = 2; const uint cBlockPixelWidthShift = 2;
const uint cBlockPixelHeightShift = 2; const uint cBlockPixelHeightShift = 2;
const uint cBlockPixelWidth = 4; const uint cBlockPixelWidth = 4;
const uint cBlockPixelHeight = 4; const uint cBlockPixelHeight = 4;
const uint cNumChunkEncodings = 8; const uint cNumChunkEncodings = 8;
extern chunk_encoding_desc g_chunk_encodings[cNumChunkEncodings]; extern chunk_encoding_desc g_chunk_encodings[cNumChunkEncodings];
const uint cNumChunkTileLayouts = 9; const uint cNumChunkTileLayouts = 9;
const uint cFirst4x4ChunkTileLayout = 5; const uint cFirst4x4ChunkTileLayout = 5;
extern chunk_tile_desc g_chunk_tile_layouts[cNumChunkTileLayouts]; extern chunk_tile_desc g_chunk_tile_layouts[cNumChunkTileLayouts];
} // namespace crnlib } // namespace crnlib
+1192 -1563
View File
File diff suppressed because it is too large Load Diff
+149 -187
View File
@@ -3,254 +3,216 @@
#pragma once #pragma once
#include "crn_dxt1.h" #include "crn_dxt1.h"
#include "crn_dxt5a.h" #include "crn_dxt5a.h"
#include "crn_etc.h"
#if CRNLIB_SUPPORT_ETC_A1
#include "crn_etc_a1.h"
#endif
#include "crn_image.h" #include "crn_image.h"
#define CRNLIB_SUPPORT_ATI_COMPRESS 0 #define CRNLIB_SUPPORT_ATI_COMPRESS 0
namespace crnlib { namespace crnlib
class task_pool; {
class task_pool;
class dxt_image { class dxt_image
public: {
dxt_image(); public:
dxt_image(const dxt_image& other); dxt_image();
dxt_image& operator=(const dxt_image& rhs); dxt_image(const dxt_image& other);
dxt_image& operator= (const dxt_image& rhs);
void clear(); void clear();
inline bool is_valid() const { return m_blocks_x > 0; } inline bool is_valid() const { return m_blocks_x > 0; }
uint get_width() const { return m_width; } uint get_width() const { return m_width; }
uint get_height() const { return m_height; } uint get_height() const { return m_height; }
uint get_blocks_x() const { return m_blocks_x; } uint get_blocks_x() const { return m_blocks_x; }
uint get_blocks_y() const { return m_blocks_y; } uint get_blocks_y() const { return m_blocks_y; }
uint get_total_blocks() const { return m_blocks_x * 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_elements_per_block() const { return m_num_elements_per_block; }
uint get_bytes_per_block() const { return m_bytes_per_block; } uint get_bytes_per_block() const { return m_bytes_per_block; }
dxt_format get_format() const { return m_format; } 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) || (m_format == cETC2) || (m_format == cETC2A) || (m_format == cETC1S) || (m_format == cETC2AS); } bool has_color() const { return (m_format == cDXT1) || (m_format == cDXT1A) || (m_format == cDXT3) || (m_format == cDXT5); }
// Will be pretty slow if the image is DXT1, as this method scans for alpha blocks/selectors. // Will be pretty slow if the image is DXT1, as this method scans for alpha blocks/selectors.
bool has_alpha() const; bool has_alpha() const;
enum element_type { enum element_type
cUnused = 0, {
cUnused = 0,
cColorDXT1, // DXT1 color block cColor,
cAlphaDXT3, // DXT3 alpha block (only) cAlpha3,
cAlphaDXT5, // DXT5 alpha block (only) cAlpha5,
};
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]; }
cColorETC2, // ETC2 color block
cAlphaETC2, // ETC2 alpha block (only) //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]; }
element_type get_element_type(uint element_index) const { struct element
CRNLIB_ASSERT(element_index < m_num_elements_per_block); {
return m_element_type[element_index]; uint8 m_bytes[8];
}
//Returns -1 for RGB, or [0,3] uint get_le_word(uint index) const { CRNLIB_ASSERT(index < 4); return m_bytes[index*2] | (m_bytes[index * 2 + 1] << 8); }
int8 get_element_component_index(uint element_index) const { uint get_be_word(uint index) const { CRNLIB_ASSERT(index < 4); return m_bytes[index*2 + 1] | (m_bytes[index * 2] << 8); }
CRNLIB_ASSERT(element_index < m_num_elements_per_block);
return m_element_component_index[element_index];
}
struct element { void set_le_word(uint index, uint val) { CRNLIB_ASSERT((index < 4) && (val <= UINT16_MAX)); m_bytes[index*2] = static_cast<uint8>(val & 0xFF); m_bytes[index * 2 + 1] = static_cast<uint8>((val >> 8) & 0xFF); }
uint8 m_bytes[8]; void set_be_word(uint index, uint val) { CRNLIB_ASSERT((index < 4) && (val <= UINT16_MAX)); m_bytes[index*2+1] = static_cast<uint8>(val & 0xFF); m_bytes[index * 2] = static_cast<uint8>((val >> 8) & 0xFF); }
uint get_le_word(uint index) const { void clear()
CRNLIB_ASSERT(index < 4); {
return m_bytes[index * 2] | (m_bytes[index * 2 + 1] << 8); memset(this, 0, sizeof(*this));
} }
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) { typedef crnlib::vector<element> element_vec;
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() { bool init(dxt_format fmt, uint width, uint height, bool clear_elements);
memset(this, 0, sizeof(*this)); bool init(dxt_format fmt, uint width, uint height, uint num_elements, element* pElements, bool create_copy);
}
};
typedef crnlib::vector<element> element_vec; struct pack_params
{
pack_params()
{
clear();
}
bool init(dxt_format fmt, uint width, uint height, bool clear_elements); void clear()
bool init(dxt_format fmt, uint width, uint height, uint num_elements, element* pElements, bool create_copy); {
m_quality = cCRNDXTQualityUber;
m_perceptual = true;
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;
}
struct pack_params { void init(const crn_comp_params &params)
pack_params() { {
clear(); 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;
}
void clear() { uint m_dxt1a_alpha_threshold;
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;
}
void init(const crn_comp_params& params) { uint m_num_helper_threads;
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; crn_dxt_quality m_quality;
uint m_num_helper_threads; crn_dxt_compressor_type m_compressor;
crn_dxt_quality m_quality; bool m_perceptual;
bool m_grayscale_sampling;
bool m_use_both_block_types;
bool m_endpoint_caching;
bool m_use_transparent_indices_for_black;
crn_dxt_compressor_type m_compressor; 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;
bool m_perceptual; uint m_progress_start;
bool m_dithering; uint m_progress_range;
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); task_pool *m_pTask_pool;
progress_callback_func m_pProgress_callback;
void* m_pProgress_callback_user_data_ptr;
uint m_progress_start; int m_color_weights[3];
uint m_progress_range; };
task_pool* m_pTask_pool; bool init(dxt_format fmt, const image_u8& img, const pack_params& p = dxt_image::pack_params());
};
bool init(dxt_format fmt, const image_u8& img, const pack_params& p = dxt_image::pack_params()); bool unpack(image_u8& img) const;
bool unpack(image_u8& img) const; void endian_swap();
void endian_swap(); uint get_num_elements() const { return m_elements.size(); }
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_vec& get_element_vec() const { return m_elements; } const element& get_element(uint block_x, uint block_y, uint element_index) const;
element_vec& get_element_vec() { return m_elements; } 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; const element* get_element_ptr() const { return m_pElements; }
element& get_element(uint block_x, uint block_y, uint element_index); element* get_element_ptr() { return m_pElements; }
const element* get_element_ptr() const { return m_pElements; } uint get_size_in_bytes() const { return m_elements.size() * sizeof(element); }
element* get_element_ptr() { return m_pElements; } uint get_row_pitch_in_bytes() const { return m_blocks_x * m_bytes_per_block; }
uint get_size_in_bytes() const { return m_elements.size() * sizeof(element); } color_quad_u8 get_pixel(uint x, uint y) const;
uint get_row_pitch_in_bytes() const { return m_blocks_x * m_bytes_per_block; } uint get_pixel_alpha(uint x, uint y, uint element_index) const;
color_quad_u8 get_pixel(uint x, uint y) const; void set_pixel(uint x, uint y, const color_quad_u8& c, bool perceptual = true);
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!
void get_block_pixels(uint block_x, uint block_y, color_quad_u8* pPixels) const;
// get_block_pixels() only sets those components stored in the image! void set_block_pixels(uint block_x, uint block_y, const color_quad_u8* pPixels, const pack_params& p, dxt1_endpoint_optimizer& dxt1_optimizer, dxt5_endpoint_optimizer& dxt5_optimizer);
bool get_block_pixels(uint block_x, uint block_y, color_quad_u8* pPixels) const; void set_block_pixels(uint block_x, uint block_y, const color_quad_u8* pPixels, const pack_params& p);
struct set_block_pixels_context { void get_block_endpoints(uint block_x, uint block_y, uint element_index, uint& packed_low_endpoint, uint& packed_high_endpoint) const;
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;
#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); // Returns a value representing the component(s) that where actually set, where -1 = RGB.
void set_block_pixels(uint block_x, uint block_y, const color_quad_u8* pPixels, const pack_params& p); // 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 get_block_endpoints(uint block_x, uint block_y, uint element_index, uint& packed_low_endpoint, uint& packed_high_endpoint) 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);
// Returns a value representing the component(s) that where actually set, where -1 = RGB. uint get_selector(uint x, uint y, uint element_index) const;
// 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. void change_dxt1_to_dxt1a();
// 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; private:
uint get_total_subblocks(uint element_index) const; element_vec m_elements;
element* m_pElements;
uint get_selector(uint x, uint y, uint element_index) const; uint m_width;
uint m_height;
void change_dxt1_to_dxt1a(); uint m_blocks_x;
uint m_blocks_y;
uint m_total_blocks;
uint m_total_elements;
bool can_flip(uint axis_index); uint m_num_elements_per_block; // 1 or 2
uint m_bytes_per_block; // 8 or 16
// Returns true if the texture can actually be flipped. int8 m_element_component_index[2];
bool flip_x(); element_type m_element_type[2];
bool flip_y();
private: dxt_format m_format; // DXT1, 1A, 3, 5, N/3DC, or A
element_vec m_elements;
element* m_pElements;
uint m_width; bool init_internal(dxt_format fmt, uint width, uint height);
uint m_height; void init_task(uint64 data, void* pData_ptr);
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 #if CRNLIB_SUPPORT_ATI_COMPRESS
bool init_ati_compress(dxt_format fmt, const image_u8& img, const pack_params& p); bool init_ati_compress(dxt_format fmt, const image_u8& img, const pack_params& p);
#endif #endif
};
void flip_col(uint x); } // namespace crnlib
void flip_row(uint y);
};
} // namespace crnlib
+163 -139
View File
@@ -3,180 +3,204 @@
#pragma once #pragma once
#include "crn_data_stream.h" #include "crn_data_stream.h"
namespace crnlib { namespace crnlib
class dynamic_stream : public data_stream { {
public: class dynamic_stream : public data_stream
dynamic_stream(uint initial_size, const char* pName = "dynamic_stream", uint attribs = cDataStreamSeekable | cDataStreamWritable | cDataStreamReadable) {
: data_stream(pName, attribs), public:
m_ofs(0) { dynamic_stream(uint initial_size, const wchar_t* pName = L"dynamic_stream", uint attribs = cDataStreamSeekable | cDataStreamWritable | cDataStreamReadable) :
open(initial_size, pName, attribs); data_stream(pName, attribs),
} m_ofs(0)
{
dynamic_stream(const void* pBuf, uint size, const char* pName = "dynamic_stream", uint attribs = cDataStreamSeekable | cDataStreamWritable | cDataStreamReadable) open(initial_size, pName, attribs);
: 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;
}
return false; dynamic_stream(const void* pBuf, uint size, const wchar_t* pName = L"dynamic_stream", uint attribs = cDataStreamSeekable | cDataStreamWritable | cDataStreamReadable) :
} data_stream(pName, attribs),
m_ofs(0)
{
open(pBuf, size, pName, attribs);
}
virtual bool close() { dynamic_stream() :
if (m_opened) { data_stream(),
m_opened = false; m_ofs(0)
m_buf.clear(); {
m_ofs = 0; open();
return true; }
}
return false; virtual ~dynamic_stream()
} {
}
const crnlib::vector<uint8>& get_buf() const { return m_buf; } bool open(uint initial_size = 0, const wchar_t* pName = L"dynamic_stream", uint attribs = cDataStreamSeekable | cDataStreamWritable | cDataStreamReadable)
crnlib::vector<uint8>& get_buf() { return m_buf; } {
close();
void reserve(uint size) { m_opened = true;
if (m_opened) { m_buf.clear();
m_buf.reserve(size); m_buf.resize(initial_size);
} m_ofs = 0;
} m_name.set(pName ? pName : L"dynamic_stream");
m_attribs = static_cast<attribs_t>(attribs);
return true;
}
virtual const void* get_ptr() const { return m_buf.empty() ? NULL : &m_buf[0]; } bool reopen(const wchar_t* pName, uint attribs)
{
if (!m_opened)
{
return open(0, pName, attribs);
}
virtual uint read(void* pBuf, uint len) { m_name.set(pName ? pName : L"dynamic_stream");
CRNLIB_ASSERT(pBuf && (len <= 0x7FFFFFFF)); m_attribs = static_cast<attribs_t>(attribs);
return true;
}
if ((!m_opened) || (!is_readable()) || (!len)) bool open(const void* pBuf, uint size, const wchar_t* pName = L"dynamic_stream", uint attribs = cDataStreamSeekable | cDataStreamWritable | cDataStreamReadable)
return 0; {
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 : L"dynamic_stream");
m_attribs = static_cast<attribs_t>(attribs);
return true;
}
CRNLIB_ASSERT(m_ofs <= m_buf.size()); return false;
}
uint bytes_left = m_buf.size() - m_ofs; virtual bool close()
{
if (m_opened)
{
m_opened = false;
m_buf.clear();
m_ofs = 0;
return true;
}
len = math::minimum<uint>(len, bytes_left); return false;
}
if (len) const crnlib::vector<uint8>& get_buf() const { return m_buf; }
memcpy(pBuf, &m_buf[m_ofs], len); crnlib::vector<uint8>& get_buf() { return m_buf; }
m_ofs += len; void reserve(uint size)
{
if (m_opened)
{
m_buf.reserve(size);
}
}
return len; virtual const void* get_ptr() const { return m_buf.empty() ? NULL : &m_buf[0]; }
}
virtual uint write(const void* pBuf, uint len) { virtual uint read(void* pBuf, uint len)
CRNLIB_ASSERT(pBuf && (len <= 0x7FFFFFFF)); {
CRNLIB_ASSERT(pBuf && (len <= 0x7FFFFFFF));
if ((!m_opened) || (!is_writable()) || (!len)) if ((!m_opened) || (!is_readable()) || (!len))
return 0; return 0;
CRNLIB_ASSERT(m_ofs <= m_buf.size()); CRNLIB_ASSERT(m_ofs <= m_buf.size());
uint new_ofs = m_ofs + len; uint bytes_left = m_buf.size() - m_ofs;
if (new_ofs > m_buf.size())
m_buf.resize(new_ofs);
memcpy(&m_buf[m_ofs], pBuf, len); len = math::minimum<uint>(len, bytes_left);
m_ofs = new_ofs;
return len; if (len)
} memcpy(pBuf, &m_buf[m_ofs], len);
virtual bool flush() { m_ofs += len;
if (!m_opened)
return false;
return true; return len;
} }
virtual uint64 get_size() { virtual uint write(const void* pBuf, uint len)
if (!m_opened) {
return 0; CRNLIB_ASSERT(pBuf && (len <= 0x7FFFFFFF));
return m_buf.size(); if ((!m_opened) || (!is_writable()) || (!len))
} return 0;
virtual uint64 get_remaining() { CRNLIB_ASSERT(m_ofs <= m_buf.size());
if (!m_opened)
return 0;
CRNLIB_ASSERT(m_ofs <= m_buf.size()); uint new_ofs = m_ofs + len;
if (new_ofs > m_buf.size())
m_buf.resize(new_ofs);
return m_buf.size() - m_ofs; memcpy(&m_buf[m_ofs], pBuf, len);
} m_ofs = new_ofs;
virtual uint64 get_ofs() { return len;
if (!m_opened) }
return 0;
return m_ofs; virtual bool flush()
} {
if (!m_opened)
return false;
virtual bool seek(int64 ofs, bool relative) { return true;
if ((!m_opened) || (!is_seekable())) }
return false;
int64 new_ofs = relative ? (m_ofs + ofs) : ofs; virtual uint64 get_size()
{
if (!m_opened)
return 0;
if (new_ofs < 0) return m_buf.size();
return false; }
else if (new_ofs > m_buf.size())
return false;
m_ofs = static_cast<uint>(new_ofs); virtual uint64 get_remaining()
{
if (!m_opened)
return 0;
post_seek(); CRNLIB_ASSERT(m_ofs <= m_buf.size());
return true; return m_buf.size() - m_ofs;
} }
private: virtual uint64 get_ofs()
crnlib::vector<uint8> m_buf; {
uint m_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
} // namespace crnlib
File diff suppressed because it is too large Load Diff
+108 -130
View File
@@ -2,184 +2,162 @@
// See Copyright Notice and license at the end of inc/crnlib.h // See Copyright Notice and license at the end of inc/crnlib.h
#pragma once #pragma once
namespace crnlib { namespace crnlib
enum { cMaxDynamicStringLen = cUINT16_MAX - 1 }; {
class dynamic_string { class dynamic_wstring;
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() { class dynamic_string
if (m_pStr) {
crnlib_delete_array(m_pStr); friend class dynamic_wstring;
}
// Truncates the string to 0 chars and frees the buffer. public:
void clear(); inline dynamic_string() : m_buf_size(0), m_len(0), m_pStr(NULL) { }
void optimize(); 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);
// Truncates the string to 0 chars, but does not free the buffer. inline ~dynamic_string() { if (m_pStr) crnlib_delete_array(m_pStr); }
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; } explicit dynamic_string(const wchar_t* pStr);
inline bool is_empty() const { return !m_len; } dynamic_string& set(const wchar_t *pStr);
dynamic_wstring& as_utf16(dynamic_wstring &buf);
inline const char* get_ptr() const { return m_pStr ? m_pStr : ""; } // Truncates the string to 0 chars and frees the buffer.
inline const char* c_str() const { return get_ptr(); } void clear();
void optimize();
inline const char* get_ptr_raw() const { return m_pStr; } // Truncates the string to 0 chars, but does not free the buffer.
inline char* get_ptr_raw() { return m_pStr; } void empty();
inline char front() const { return m_len ? m_pStr[0] : '\0'; } inline uint get_len() const { return m_len; }
inline char back() const { return m_len ? m_pStr[m_len - 1] : '\0'; } inline bool is_empty() const { return !m_len; }
inline char operator[](uint i) const { inline const char* get_ptr() const { return m_pStr ? m_pStr : ""; }
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 const char* get_ptr_raw() const { return m_pStr; }
inline char* get_ptr_raw() { return m_pStr; }
int compare(const char* p, bool case_sensitive = false) const; inline char operator[] (uint i) const { CRNLIB_ASSERT(i <= m_len); return get_ptr()[i]; }
int compare(const dynamic_string& rhs, bool case_sensitive = false) const;
inline bool operator==(const dynamic_string& rhs) const { return compare(rhs) == 0; } inline operator size_t() const { return fast_hash(get_ptr(), m_len) ^ fast_hash(&m_len, sizeof(m_len)); }
inline bool operator==(const char* p) const { return compare(p) == 0; }
inline bool operator!=(const dynamic_string& rhs) const { return compare(rhs) != 0; } int compare(const char* p, bool case_sensitive = false) const;
inline bool operator!=(const char* p) const { return compare(p) != 0; } 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 dynamic_string& rhs) const { return compare(rhs) == 0; }
inline bool operator<(const char* p) const { return compare(p) < 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 dynamic_string& rhs) const { return compare(rhs) != 0; }
inline bool operator>(const char* p) const { return compare(p) > 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 dynamic_string& rhs) const { return compare(rhs) < 0; }
inline bool operator<=(const char* p) const { return compare(p) <= 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 dynamic_string& rhs) const { return compare(rhs) > 0; }
inline bool operator>=(const char* p) const { return compare(p) >= 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; } inline bool operator<= (const dynamic_string& rhs) const { return compare(rhs) <= 0; }
inline bool operator<= (const char* p) const { return compare(p) <= 0; }
dynamic_string& set(const char* p, uint max_len = UINT_MAX); inline bool operator>= (const dynamic_string& rhs) const { return compare(rhs) >= 0; }
dynamic_string& set(const dynamic_string& other, uint max_len = UINT_MAX); inline bool operator>= (const char* p) const { return compare(p) >= 0; }
bool set_len(uint new_len, char fill_char = ' '); friend inline bool operator== (const char* p, const dynamic_string& rhs) { return rhs.compare(p) == 0; }
// Set from non-zero terminated buffer. dynamic_string& set(const char* p, uint max_len = UINT_MAX);
dynamic_string& set_from_buf(const void* pBuf, uint buf_size); dynamic_string& set(const dynamic_string& other, uint max_len = UINT_MAX);
dynamic_string& operator=(const dynamic_string& rhs) { return set(rhs); } bool set_len(uint new_len, char fill_char = ' ');
dynamic_string& operator=(const char* p) { return set(p); }
dynamic_string& set_char(uint index, char c); // Set from non-zero terminated buffer.
dynamic_string& append_char(char c); dynamic_string& set_from_buf(const void* pBuf, uint buf_size);
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& operator= (const dynamic_string& rhs) { return set(rhs); }
dynamic_string& append(const dynamic_string& other); dynamic_string& operator= (const dynamic_wstring& rhs);
dynamic_string& operator+=(const char* p) { return append(p); } dynamic_string& operator= (const char* p) { return set(p); }
dynamic_string& operator+=(const dynamic_string& other) { return append(other); }
friend dynamic_string operator+(const char* p, const dynamic_string& a); dynamic_string& set_char(uint index, char c);
friend dynamic_string operator+(const dynamic_string& a, const char* p); dynamic_string& append_char(char c);
friend dynamic_string operator+(const dynamic_string& a, const dynamic_string& b); 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& format_args(const char* p, va_list args); dynamic_string& append(const char* p);
dynamic_string& format(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& crop(uint start, uint len); friend dynamic_string operator+ (const char* p, const dynamic_string& a);
dynamic_string& substring(uint start, uint end); friend dynamic_string operator+ (const dynamic_string& a, const char* p);
dynamic_string& left(uint len); friend dynamic_string operator+ (const dynamic_string& a, const dynamic_string& b);
dynamic_string& mid(uint start, uint len);
dynamic_string& right(uint start);
dynamic_string& tail(uint num);
dynamic_string& unquote(); dynamic_string& format_args(const char* p, va_list args);
dynamic_string& format(const char* p, ...);
uint count_char(char c) const; 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);
int find_left(const char* p, bool case_sensitive = false) const; dynamic_string& unquote();
int find_left(char c) const;
int find_right(char c) const; uint count_char(char c) const;
int find_right(const char* p, bool case_sensitive = false) const;
bool contains(const char* p, bool case_sensitive = false) const; int find_left(const char* p, bool case_sensitive = false) const;
int find_left(char c) const;
dynamic_string& trim(); int find_right(char c) const;
dynamic_string& trim_crlf(); int find_right(const char* p, bool case_sensitive = false) const;
dynamic_string& remap(int from_char, int to_char); bool contains(const char* p, bool case_sensitive = false) const;
void swap(dynamic_string& other); dynamic_string& trim();
dynamic_string& trim_crlf();
// Returns -1 on failure, or the number of bytes written. dynamic_string& remap(int from_char, int to_char);
int serialize(void* pBuf, uint buf_size, bool little_endian) const;
// Returns -1 on failure, or the number of bytes read. void swap(dynamic_string& other);
int deserialize(const void* pBuf, uint buf_size, bool little_endian);
void translate_lf_to_crlf(); // Returns -1 on failure, or the number of bytes written.
int serialize(void* pBuf, uint buf_size, bool little_endian) const;
static inline char* create_raw_buffer(uint& buf_size_in_chars); // Returns -1 on failure, or the number of bytes read.
static inline void free_raw_buffer(char* p) { crnlib_delete_array(p); } int deserialize(const void* pBuf, uint buf_size, bool little_endian);
dynamic_string& set_from_raw_buf_and_assume_ownership(char* pBuf, uint buf_size_in_chars, uint len_in_chars);
private: void translate_lf_to_crlf();
uint16 m_buf_size;
uint16 m_len; private:
char* m_pStr; uint16 m_buf_size;
uint16 m_len;
char* m_pStr;
#ifdef CRNLIB_BUILD_DEBUG #ifdef CRNLIB_BUILD_DEBUG
void check() const; void check() const;
#else #else
inline void check() const {} inline void check() const { }
#endif #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 : ""; } const char* get_ptr_priv() const { return m_pStr ? m_pStr : ""; }
char* get_ptr_priv() { return (char*)(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) { inline void swap (dynamic_string& a, dynamic_string& b)
a.swap(b); {
} a.swap(b);
}
inline char* dynamic_string::create_raw_buffer(uint& buf_size_in_chars) { } // namespace crnlib
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
+715
View File
@@ -0,0 +1,715 @@
// File: crn_dynamic_wstring.cpp
// See Copyright Notice and license at the end of inc/crnlib.h
#include "crn_core.h"
#include "crn_dynamic_wstring.h"
#include "crn_winhdr.h"
namespace crnlib
{
dynamic_wstring g_empty_dynamic_wstring;
dynamic_wstring::dynamic_wstring(eVarArg dummy, const wchar_t* p, ...) :
m_buf_size(0), m_len(0), m_pStr(NULL)
{
dummy;
CRNLIB_ASSERT(p);
va_list args;
va_start(args, p);
format_args(p, args);
va_end(args);
}
dynamic_wstring::dynamic_wstring(const wchar_t* p) :
m_buf_size(0), m_len(0), m_pStr(NULL)
{
CRNLIB_ASSERT(p);
set(p);
}
dynamic_wstring::dynamic_wstring(const wchar_t* p, uint len) :
m_buf_size(0), m_len(0), m_pStr(NULL)
{
CRNLIB_ASSERT(p);
set_from_buf(p, len);
}
dynamic_wstring::dynamic_wstring(const dynamic_wstring& other) :
m_buf_size(0), m_len(0), m_pStr(NULL)
{
set(other);
}
void dynamic_wstring::clear()
{
check();
if (m_pStr)
{
crnlib_delete_array(m_pStr);
m_pStr = NULL;
m_len = 0;
m_buf_size = 0;
}
}
void dynamic_wstring::empty()
{
truncate(0);
}
void dynamic_wstring::optimize()
{
if (!m_len)
clear();
else
{
uint min_buf_size = math::next_pow2((uint)m_len + 1);
if (m_buf_size > min_buf_size)
{
wchar_t* p = crnlib_new_array<wchar_t>(min_buf_size);
memcpy(p, m_pStr, (m_len + 1) * sizeof(wchar_t));
crnlib_delete_array(m_pStr);
m_pStr = p;
m_buf_size = static_cast<uint16>(min_buf_size);
check();
}
}
}
int dynamic_wstring::compare(const wchar_t* p, bool case_sensitive) const
{
CRNLIB_ASSERT(p);
const int result = (case_sensitive ? wcscmp : _wcsicmp)(get_ptr_priv(), p);
if (result < 0)
return -1;
else if (result > 0)
return 1;
return 0;
}
int dynamic_wstring::compare(const dynamic_wstring& rhs, bool case_sensitive) const
{
return compare(rhs.get_ptr_priv(), case_sensitive);
}
dynamic_wstring& dynamic_wstring::set(const wchar_t* p, uint max_len)
{
CRNLIB_ASSERT(p);
const uint len = math::minimum<uint>(max_len, static_cast<uint>(wcslen(p)));
CRNLIB_ASSERT(len < UINT16_MAX);
if ((!len) || (len >= UINT16_MAX))
clear();
else if ((m_pStr) && (p >= m_pStr) && (p < (m_pStr + m_buf_size)))
{
if (m_pStr != p)
memmove(m_pStr, p, len * sizeof(wchar_t));
m_pStr[len] = L'\0';
m_len = static_cast<uint16>(len);
}
else if (ensure_buf(len, false))
{
m_len = static_cast<uint16>(len);
memcpy(m_pStr, p, (m_len + 1) * sizeof(wchar_t));
}
check();
return *this;
}
dynamic_wstring& dynamic_wstring::set(const dynamic_wstring& other, uint max_len)
{
if (this == &other)
{
if (max_len < m_len)
{
m_pStr[max_len] = L'\0';
m_len = static_cast<uint16>(max_len);
}
}
else
{
const uint len = math::minimum<uint>(max_len, other.m_len);
if (!len)
clear();
else if (ensure_buf(len, false))
{
m_len = static_cast<uint16>(len);
memcpy(m_pStr, other.get_ptr_priv(), m_len * sizeof(wchar_t));
m_pStr[len] = L'\0';
}
}
check();
return *this;
}
bool dynamic_wstring::set_len(uint new_len, wchar_t fill_char)
{
if ((new_len >= UINT16_MAX) || (!fill_char))
return false;
uint cur_len = m_len;
if (ensure_buf(new_len, true))
{
if (new_len > cur_len)
{
for (uint i = 0; i < (new_len - cur_len); i++)
m_pStr[cur_len + i] = fill_char;
}
m_pStr[new_len] = L'\0';
m_len = static_cast<uint16>(new_len);
check();
}
return true;
}
dynamic_wstring& dynamic_wstring::set_from_buf(const void* pBuf, uint buf_size, bool little_endian)
{
CRNLIB_ASSERT(pBuf);
if (buf_size >= UINT16_MAX)
{
clear();
return *this;
}
for (uint i = 0; i < buf_size; i++)
{
if (static_cast<const wchar_t*>(pBuf)[i] == L'\0')
{
CRNLIB_ASSERT(0);
clear();
return *this;
}
}
if (ensure_buf(buf_size, false))
{
utils::copy_words(reinterpret_cast<uint16*>(m_pStr), reinterpret_cast<const uint16*>(pBuf), buf_size, c_crnlib_little_endian_platform != little_endian);
m_pStr[buf_size] = L'\0';
m_len = static_cast<uint16>(buf_size);
check();
}
return *this;
}
dynamic_wstring& dynamic_wstring::set_char(uint index, wchar_t c)
{
CRNLIB_ASSERT(index <= m_len);
if (!c)
truncate(index);
else if (index < m_len)
{
m_pStr[index] = c;
check();
}
else if (index == m_len)
append_char(c);
return *this;
}
dynamic_wstring& dynamic_wstring::append_char(wchar_t c)
{
if (ensure_buf(m_len + 1))
{
m_pStr[m_len] = c;
m_pStr[m_len + 1] = L'\0';
m_len++;
check();
}
return *this;
}
dynamic_wstring& dynamic_wstring::truncate(uint new_len)
{
if (new_len < m_len)
{
m_pStr[new_len] = L'\0';
m_len = static_cast<uint16>(new_len);
check();
}
return *this;
}
dynamic_wstring& dynamic_wstring::tolower()
{
if (m_len)
{
#ifdef _MSC_VER
_wcslwr_s(get_ptr_priv(), m_buf_size);
#else
_wcslwr(get_ptr_priv());
#endif
}
return *this;
}
dynamic_wstring& dynamic_wstring::toupper()
{
if (m_len)
{
#ifdef _MSC_VER
_wcsupr_s(get_ptr_priv(), m_buf_size);
#else
_wcsupr(get_ptr_priv());
#endif
}
return *this;
}
dynamic_wstring& dynamic_wstring::append(const wchar_t* p)
{
CRNLIB_ASSERT(p);
uint len = static_cast<uint>(wcslen(p));
uint new_total_len = m_len + len;
if ((new_total_len) && ensure_buf(new_total_len))
{
memcpy(m_pStr + m_len, p, (len + 1) * sizeof(wchar_t));
m_len = static_cast<uint16>(m_len + len);
check();
}
return *this;
}
dynamic_wstring& dynamic_wstring::append(const dynamic_wstring& other)
{
uint len = other.m_len;
uint new_total_len = m_len + len;
if ((new_total_len) && ensure_buf(new_total_len))
{
memcpy(m_pStr + m_len, other.get_ptr_priv(), (len + 1) * sizeof(wchar_t));
m_len = static_cast<uint16>(m_len + len);
check();
}
return *this;
}
dynamic_wstring operator+ (const wchar_t* p, const dynamic_wstring& a)
{
return dynamic_wstring(p).append(a);
}
dynamic_wstring operator+ (const dynamic_wstring& a, const wchar_t* p)
{
return dynamic_wstring(a).append(p);
}
dynamic_wstring operator+ (const dynamic_wstring& a, const dynamic_wstring& b)
{
return dynamic_wstring(a).append(b);
}
dynamic_wstring& dynamic_wstring::format_args(const wchar_t* p, va_list args)
{
CRNLIB_ASSERT(p);
const uint cBufSize = 4096;
wchar_t buf[cBufSize];
#ifdef _MSC_VER
int l = _vsnwprintf_s(buf, cBufSize, _TRUNCATE, p, args);
#else
int l = _vsnwprintf(buf, cBufSize, p, args);
#endif
if (l <= 0)
clear();
else if (ensure_buf(l, false))
{
memcpy(m_pStr, buf, (l + 1) * sizeof(wchar_t));
m_len = static_cast<uint16>(l);
check();
}
return *this;
}
dynamic_wstring& dynamic_wstring::format(const wchar_t* p, ...)
{
CRNLIB_ASSERT(p);
va_list args;
va_start(args, p);
format_args(p, args);
va_end(args);
return *this;
}
dynamic_wstring& dynamic_wstring::crop(uint start, uint len)
{
if (start >= m_len)
{
clear();
return *this;
}
len = math::minimum<uint>(len, m_len - start);
if (start)
memmove(get_ptr_priv(), get_ptr_priv() + start, len * sizeof(wchar_t));
m_pStr[len] = L'\0';
m_len = static_cast<uint16>(len);
check();
return *this;
}
dynamic_wstring& dynamic_wstring::substring(uint start, uint end)
{
CRNLIB_ASSERT(start <= end);
if (start > end)
return *this;
return crop(start, end - start);
}
dynamic_wstring& dynamic_wstring::left(uint len)
{
return substring(0, len);
}
dynamic_wstring& dynamic_wstring::mid(uint start, uint len)
{
return crop(start, len);
}
dynamic_wstring& dynamic_wstring::right(uint start)
{
return substring(start, get_len());
}
dynamic_wstring& dynamic_wstring::tail(uint num)
{
return substring(math::maximum<int>(static_cast<int>(get_len()) - static_cast<int>(num), 0), get_len());
}
dynamic_wstring& dynamic_wstring::unquote()
{
if (m_len >= 2)
{
if ( ((*this)[0] == L'\"') && ((*this)[m_len - 1] == L'\"') )
{
return mid(1, m_len - 2);
}
}
return *this;
}
int dynamic_wstring::find_left(const wchar_t* p, bool case_sensitive) const
{
CRNLIB_ASSERT(p);
const int p_len = (int)wcslen(p);
for (int i = 0; i <= (m_len - p_len); i++)
if ((case_sensitive ? wcsncmp : _wcsnicmp)(p, &m_pStr[i], p_len) == 0)
return i;
return -1;
}
bool dynamic_wstring::contains(const wchar_t* p, bool case_sensitive) const
{
return find_left(p, case_sensitive) >= 0;
}
uint dynamic_wstring::count_char(wchar_t c) const
{
uint count = 0;
for (uint i = 0; i < m_len; i++)
if (m_pStr[i] == c)
count++;
return count;
}
int dynamic_wstring::find_left(wchar_t c) const
{
for (uint i = 0; i < m_len; i++)
if (m_pStr[i] == c)
return i;
return -1;
}
int dynamic_wstring::find_right(wchar_t c) const
{
for (int i = (int)m_len - 1; i >= 0; i--)
if (m_pStr[i] == c)
return i;
return -1;
}
int dynamic_wstring::find_right(const wchar_t* p, bool case_sensitive) const
{
CRNLIB_ASSERT(p);
const int p_len = (int)wcslen(p);
for (int i = m_len - p_len; i >= 0; i--)
if ((case_sensitive ? wcsncmp : _wcsnicmp)(p, &m_pStr[i], p_len) == 0)
return i;
return -1;
}
dynamic_wstring& dynamic_wstring::trim()
{
int s, e;
for (s = 0; s < (int)m_len; s++)
if (!iswspace(m_pStr[s]))
break;
for (e = m_len - 1; e > s; e--)
if (!iswspace(m_pStr[e]))
break;
return crop(s, e - s + 1);
}
dynamic_wstring& dynamic_wstring::trim_crlf()
{
int s = 0, e;
for (e = m_len - 1; e > s; e--)
if ((m_pStr[e] != 13) && (m_pStr[e] != 10))
break;
return crop(s, e - s + 1);
}
dynamic_wstring& dynamic_wstring::remap(int from_char, int to_char)
{
for (uint i = 0; i < m_len; i++)
if (m_pStr[i] == from_char)
m_pStr[i] = (wchar_t)to_char;
return *this;
}
#ifdef CRNLIB_BUILD_DEBUG
void dynamic_wstring::check() const
{
if (!m_pStr)
{
CRNLIB_ASSERT(!m_buf_size && !m_len);
}
else
{
CRNLIB_ASSERT(m_buf_size);
CRNLIB_ASSERT((m_buf_size == UINT16_MAX) || math::is_power_of_2((uint32)m_buf_size));
CRNLIB_ASSERT(m_len < m_buf_size);
CRNLIB_ASSERT(wcslen(m_pStr) == m_len);
}
}
#endif
bool dynamic_wstring::ensure_buf(uint len, bool preserve_contents)
{
uint buf_size_needed = len + 1;
CRNLIB_ASSERT(buf_size_needed <= UINT16_MAX);
if (buf_size_needed <= UINT16_MAX)
{
if (buf_size_needed > m_buf_size)
expand_buf(buf_size_needed, preserve_contents);
}
return m_buf_size >= buf_size_needed;
}
bool dynamic_wstring::expand_buf(uint new_buf_size, bool preserve_contents)
{
new_buf_size = math::minimum<uint>(UINT16_MAX, math::next_pow2(math::maximum<uint>(m_buf_size, new_buf_size)));
if (new_buf_size != m_buf_size)
{
wchar_t* p = crnlib_new_array<wchar_t>(new_buf_size);
if (preserve_contents)
memcpy(p, get_ptr_priv(), (m_len + 1) * sizeof(wchar_t));
crnlib_delete_array(m_pStr);
m_pStr = p;
m_buf_size = static_cast<uint16>(new_buf_size);
if (preserve_contents)
check();
}
return m_buf_size >= new_buf_size;
}
void dynamic_wstring::swap(dynamic_wstring& other)
{
utils::swap(other.m_buf_size, m_buf_size);
utils::swap(other.m_len, m_len);
utils::swap(other.m_pStr, m_pStr);
}
int dynamic_wstring::serialize(void* pBuf, uint buf_size, bool little_endian) const
{
CRNLIB_ASSERT(pBuf);
uint buf_left = buf_size;
if (m_len > UINT16_MAX)
return -1;
if (!utils::write_val((uint16)m_len, pBuf, buf_left, little_endian))
return -1;
if (buf_left < (m_len * sizeof(wchar_t)))
return -1;
utils::copy_words(reinterpret_cast<uint16*>(pBuf), reinterpret_cast<const uint16*>(get_ptr_priv()), m_len, little_endian != c_crnlib_little_endian_platform);
buf_left -= m_len * sizeof(wchar_t);
return buf_size - buf_left;
}
int dynamic_wstring::deserialize(const void* pBuf, uint buf_size, bool little_endian)
{
CRNLIB_ASSERT(pBuf);
uint buf_left = buf_size;
if (buf_left < sizeof(uint16)) return -1;
uint16 l;
if (!utils::read_obj(l, pBuf, buf_left, little_endian))
return -1;
if (buf_left < (l * sizeof(wchar_t)))
return -1;
set_from_buf(pBuf, l, little_endian);
buf_left -= l * sizeof(wchar_t);
return buf_size - buf_left;
}
dynamic_wstring::dynamic_wstring(const char* p) :
m_buf_size(0), m_len(0), m_pStr(NULL)
{
set(p);
}
dynamic_wstring::dynamic_wstring(const dynamic_string& s) :
m_buf_size(0), m_len(0), m_pStr(NULL)
{
set(s.get_ptr());
}
dynamic_wstring& dynamic_wstring::set(const char* p)
{
CRNLIB_ASSERT(p);
if (!p)
{
clear();
return *this;
}
uint l = static_cast<uint>(strlen(p));
if (!l)
{
clear();
return *this;
}
const uint num_needed = static_cast<uint>(MultiByteToWideChar(CP_ACP, 0, p, l, NULL, 0));
if (!num_needed)
{
clear();
return *this;
}
if (!ensure_buf(num_needed, false))
{
clear();
return *this;
}
const uint num_written = static_cast<uint>(MultiByteToWideChar(CP_ACP, 0, p, l, m_pStr, num_needed));
CRNLIB_ASSERT(num_needed == num_written);
m_pStr[num_written] = L'\0';
m_len = static_cast<uint16>(num_written);
check();
return *this;
}
dynamic_string& dynamic_wstring::as_ansi(dynamic_string& buf)
{
if (!m_len)
{
buf.clear();
return buf;
}
const uint num_needed = WideCharToMultiByte(CP_ACP, 0, m_pStr, m_len, NULL, 0, NULL, NULL);
if (num_needed <= 0)
{
buf.clear();
return buf;
}
if (!buf.ensure_buf(num_needed, false))
{
buf.clear();
return buf;
}
const uint num_written = WideCharToMultiByte(CP_ACP, 0, m_pStr, m_len, buf.get_ptr_raw(), num_needed, NULL, NULL);
CRNLIB_ASSERT(num_written == num_needed);
buf.get_ptr_raw()[num_written] = 0;
buf.m_len = static_cast<uint16>(num_written);
buf.check();
return buf;
}
dynamic_wstring& dynamic_wstring::operator= (const dynamic_string& rhs)
{
return set(rhs.get_ptr());
}
} // namespace crnlib
+159
View File
@@ -0,0 +1,159 @@
// File: crn_dynamic_wstring.h
// See Copyright Notice and license at the end of inc/crnlib.h
#pragma once
namespace crnlib
{
// UCS-2 string class (plane 0 characters only)
class dynamic_wstring
{
public:
inline dynamic_wstring() : m_buf_size(0), m_len(0), m_pStr(NULL) { }
dynamic_wstring(eVarArg dummy, const wchar_t* p, ...);
dynamic_wstring(const wchar_t* p);
dynamic_wstring(const wchar_t* p, uint len);
dynamic_wstring(const dynamic_wstring& other);
// Conversion from UCS-2 to ANSI and vice versa
explicit dynamic_wstring(const char* p);
explicit dynamic_wstring(const dynamic_string& s);
dynamic_wstring& set(const char* p);
dynamic_string& as_ansi(dynamic_string& buf);
inline ~dynamic_wstring() { CRNLIB_ASSUME(sizeof(wchar_t) == sizeof(uint16)); 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, but does not free the buffer.
void empty();
inline uint get_len() const { return m_len; }
inline bool is_empty() const { return !m_len; }
inline const wchar_t* get_ptr() const { return m_pStr ? m_pStr : L""; }
inline const wchar_t* get_ptr_raw() const { return m_pStr; }
inline wchar_t* get_ptr_raw() { return m_pStr; }
inline wchar_t 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 * sizeof(wchar_t)) ^ fast_hash(&m_len, sizeof(m_len)); }
int compare(const wchar_t* p, bool case_sensitive = false) const;
int compare(const dynamic_wstring& rhs, bool case_sensitive = false) const;
inline bool operator== (const dynamic_wstring& rhs) const { return compare(rhs) == 0; }
inline bool operator== (const wchar_t* p) const { return compare(p) == 0; }
inline bool operator!= (const dynamic_wstring& rhs) const { return compare(rhs) != 0; }
inline bool operator!= (const wchar_t* p) const { return compare(p) != 0; }
inline bool operator< (const dynamic_wstring& rhs) const { return compare(rhs) < 0; }
inline bool operator< (const wchar_t* p) const { return compare(p) < 0; }
inline bool operator> (const dynamic_wstring& rhs) const { return compare(rhs) > 0; }
inline bool operator> (const wchar_t* p) const { return compare(p) > 0; }
inline bool operator<= (const dynamic_wstring& rhs) const { return compare(rhs) <= 0; }
inline bool operator<= (const wchar_t* p) const { return compare(p) <= 0; }
inline bool operator>= (const dynamic_wstring& rhs) const { return compare(rhs) >= 0; }
inline bool operator>= (const wchar_t* p) const { return compare(p) >= 0; }
friend inline bool operator== (const wchar_t* p, const dynamic_wstring& rhs) { return rhs.compare(p) == 0; }
dynamic_wstring& set(const wchar_t* p, uint max_len = UINT_MAX);
dynamic_wstring& set(const dynamic_wstring& other, uint max_len = UINT_MAX);
bool set_len(uint new_len, wchar_t fill_char = ' ');
// Set from non-zero terminated buffer.
// little_endian is the endianness of the buffer's data
dynamic_wstring& set_from_buf(const void* pBuf, uint buf_size, bool little_endian = c_crnlib_little_endian_platform);
dynamic_wstring& operator= (const dynamic_wstring& rhs) { return set(rhs); }
dynamic_wstring& operator= (const dynamic_string& rhs);
dynamic_wstring& operator= (const wchar_t* p) { return set(p); }
dynamic_wstring& operator= (const char* p) { return set(p); }
dynamic_wstring& set_char(uint index, wchar_t c);
dynamic_wstring& append_char(wchar_t c);
dynamic_wstring& append_char(int c) { CRNLIB_ASSERT((c >= 0) && (c <= 0xFFFF)); return append_char(static_cast<wchar_t>(c)); }
dynamic_wstring& truncate(uint new_len);
dynamic_wstring& tolower();
dynamic_wstring& toupper();
dynamic_wstring& append(const wchar_t* p);
dynamic_wstring& append(const dynamic_wstring& other);
dynamic_wstring& operator += (const wchar_t* p) { return append(p); }
dynamic_wstring& operator += (const dynamic_wstring& other) { return append(other); }
friend dynamic_wstring operator+ (const wchar_t* p, const dynamic_wstring& a);
friend dynamic_wstring operator+ (const dynamic_wstring& a, const wchar_t* p);
friend dynamic_wstring operator+ (const dynamic_wstring& a, const dynamic_wstring& b);
dynamic_wstring& format_args(const wchar_t* p, va_list args);
dynamic_wstring& format(const wchar_t* p, ...);
dynamic_wstring& crop(uint start, uint len);
dynamic_wstring& substring(uint start, uint end);
dynamic_wstring& left(uint len);
dynamic_wstring& mid(uint start, uint len);
dynamic_wstring& right(uint start);
dynamic_wstring& tail(uint num);
dynamic_wstring& unquote();
uint count_char(wchar_t c) const;
int find_left(const wchar_t* p, bool case_sensitive = false) const;
int find_left(wchar_t c) const;
int find_right(wchar_t c) const;
int find_right(const wchar_t* p, bool case_sensitive = false) const;
bool contains(const wchar_t* p, bool case_sensitive = false) const;
dynamic_wstring& trim();
dynamic_wstring& trim_crlf();
dynamic_wstring& remap(int from_char, int to_char);
void swap(dynamic_wstring& other);
int serialize(void* pBuf, uint buf_size, bool little_endian) const;
int deserialize(const void* pBuf, uint buf_size, bool little_endian);
private:
// These values are in characters, not bytes!
uint16 m_buf_size;
uint16 m_len;
wchar_t* m_pStr;
#ifdef CRNLIB_BUILD_DEBUG
void check() const;
#else
void check() const { }
#endif
bool ensure_buf(uint len, bool preserve_contents = true);
bool expand_buf(uint new_buf_size, bool preserve_contents);
const wchar_t* get_ptr_priv() const { return m_pStr ? m_pStr : L""; }
wchar_t* get_ptr_priv() { return (wchar_t*)(m_pStr ? m_pStr : L""); }
};
typedef crnlib::vector<dynamic_wstring> dynamic_wstring_array;
extern dynamic_wstring g_empty_dynamic_wstring;
CRNLIB_DEFINE_BITWISE_MOVABLE(dynamic_wstring);
inline void swap (dynamic_wstring& a, dynamic_wstring& b)
{
a.swap(b);
}
} // namespace crnlib
-1626
View File
File diff suppressed because it is too large Load Diff
-543
View File
@@ -1,543 +0,0 @@
// File: crn_etc.h
// See Copyright Notice and license at the end of inc/crnlib.h
#pragma once
#include "../inc/crnlib.h"
#include "crn_dxt.h"
namespace crnlib {
enum etc_constants {
cETC1BytesPerBlock = 8U,
cETC1SelectorBits = 2U,
cETC1SelectorValues = 1U << cETC1SelectorBits,
cETC1SelectorMask = cETC1SelectorValues - 1U,
cETC1BlockShift = 2U,
cETC1BlockSize = 1U << cETC1BlockShift,
cETC1LSBSelectorIndicesBitOffset = 0,
cETC1MSBSelectorIndicesBitOffset = 16,
cETC1FlipBitOffset = 32,
cETC1DiffBitOffset = 33,
cETC1IntenModifierNumBits = 3,
cETC1IntenModifierValues = 1 << cETC1IntenModifierNumBits,
cETC1RightIntenModifierTableBitOffset = 34,
cETC1LeftIntenModifierTableBitOffset = 37,
// Base+Delta encoding (5 bit bases, 3 bit delta)
cETC1BaseColorCompNumBits = 5,
cETC1BaseColorCompMax = 1 << cETC1BaseColorCompNumBits,
cETC1DeltaColorCompNumBits = 3,
cETC1DeltaColorComp = 1 << cETC1DeltaColorCompNumBits,
cETC1DeltaColorCompMax = 1 << cETC1DeltaColorCompNumBits,
cETC1BaseColor5RBitOffset = 59,
cETC1BaseColor5GBitOffset = 51,
cETC1BaseColor5BBitOffset = 43,
cETC1DeltaColor3RBitOffset = 56,
cETC1DeltaColor3GBitOffset = 48,
cETC1DeltaColor3BBitOffset = 40,
// Absolute (non-delta) encoding (two 4-bit per component bases)
cETC1AbsColorCompNumBits = 4,
cETC1AbsColorCompMax = 1 << cETC1AbsColorCompNumBits,
cETC1AbsColor4R1BitOffset = 60,
cETC1AbsColor4G1BitOffset = 52,
cETC1AbsColor4B1BitOffset = 44,
cETC1AbsColor4R2BitOffset = 56,
cETC1AbsColor4G2BitOffset = 48,
cETC1AbsColor4B2BitOffset = 40,
cETC1ColorDeltaMin = -4,
cETC1ColorDeltaMax = 3,
// Delta3:
// 0 1 2 3 4 5 6 7
// 000 001 010 011 100 101 110 111
// 0 1 2 3 -4 -3 -2 -1
};
extern const int g_etc1_inten_tables[cETC1IntenModifierValues][cETC1SelectorValues];
extern const uint8 g_etc1_to_selector_index[cETC1SelectorValues];
extern const uint8 g_selector_index_to_etc1[cETC1SelectorValues];
struct etc1_coord2 {
uint8 m_x, m_y;
};
extern const etc1_coord2 g_etc1_pixel_coords[2][2][8]; // [flipped][subblock][subblock_pixel]
struct etc1_block {
// big endian uint64:
// bit ofs: 56 48 40 32 24 16 8 0
// byte ofs: b0, b1, b2, b3, b4, b5, b6, b7
union {
uint64 m_uint64;
uint8 m_bytes[8];
};
uint8 m_low_color[2];
uint8 m_high_color[2];
enum { cNumSelectorBytes = 4 };
uint8 m_selectors[cNumSelectorBytes];
inline void clear() {
utils::zero_this(this);
}
inline uint get_general_bits(uint ofs, uint num) const {
CRNLIB_ASSERT((ofs + num) <= 64U);
CRNLIB_ASSERT(num && (num < 32U));
return (utils::read_be64(&m_uint64) >> ofs) & ((1UL << num) - 1UL);
}
inline void set_general_bits(uint ofs, uint num, uint bits) {
CRNLIB_ASSERT((ofs + num) <= 64U);
CRNLIB_ASSERT(num && (num < 32U));
uint64 x = utils::read_be64(&m_uint64);
uint64 msk = ((1ULL << static_cast<uint64>(num)) - 1ULL) << static_cast<uint64>(ofs);
x &= ~msk;
x |= (static_cast<uint64>(bits) << static_cast<uint64>(ofs));
utils::write_be64(&m_uint64, x);
}
inline uint get_byte_bits(uint ofs, uint num) const {
CRNLIB_ASSERT((ofs + num) <= 64U);
CRNLIB_ASSERT(num && (num <= 8U));
CRNLIB_ASSERT((ofs >> 3) == ((ofs + num - 1) >> 3));
const uint byte_ofs = 7 - (ofs >> 3);
const uint byte_bit_ofs = ofs & 7;
return (m_bytes[byte_ofs] >> byte_bit_ofs) & ((1 << num) - 1);
}
inline void set_byte_bits(uint ofs, uint num, uint bits) {
CRNLIB_ASSERT((ofs + num) <= 64U);
CRNLIB_ASSERT(num && (num < 32U));
CRNLIB_ASSERT((ofs >> 3) == ((ofs + num - 1) >> 3));
CRNLIB_ASSERT(bits < (1U << num));
const uint byte_ofs = 7 - (ofs >> 3);
const uint byte_bit_ofs = ofs & 7;
const uint mask = (1 << num) - 1;
m_bytes[byte_ofs] &= ~(mask << byte_bit_ofs);
m_bytes[byte_ofs] |= (bits << byte_bit_ofs);
}
// false = left/right subblocks
// true = upper/lower subblocks
inline bool get_flip_bit() const {
return (m_bytes[3] & 1) != 0;
}
inline void set_flip_bit(bool flip) {
m_bytes[3] &= ~1;
m_bytes[3] |= static_cast<uint8>(flip);
}
inline bool get_diff_bit() const {
return (m_bytes[3] & 2) != 0;
}
inline void set_diff_bit(bool diff) {
m_bytes[3] &= ~2;
m_bytes[3] |= (static_cast<uint>(diff) << 1);
}
// Returns intensity modifier table (0-7) used by subblock subblock_id.
// subblock_id=0 left/top (CW 1), 1=right/bottom (CW 2)
inline uint get_inten_table(uint subblock_id) const {
CRNLIB_ASSERT(subblock_id < 2);
const uint ofs = subblock_id ? 2 : 5;
return (m_bytes[3] >> ofs) & 7;
}
// Sets intensity modifier table (0-7) used by subblock subblock_id (0 or 1)
inline void set_inten_table(uint subblock_id, uint t) {
CRNLIB_ASSERT(subblock_id < 2);
CRNLIB_ASSERT(t < 8);
const uint ofs = subblock_id ? 2 : 5;
m_bytes[3] &= ~(7 << ofs);
m_bytes[3] |= (t << ofs);
}
// Returned selector value ranges from 0-3 and is a direct index into g_etc1_inten_tables.
inline uint get_selector(uint x, uint y) const {
CRNLIB_ASSERT((x | y) < 4);
const uint bit_index = x * 4 + y;
const uint byte_bit_ofs = bit_index & 7;
const uint8* p = &m_bytes[7 - (bit_index >> 3)];
const uint lsb = (p[0] >> byte_bit_ofs) & 1;
const uint msb = (p[-2] >> byte_bit_ofs) & 1;
const uint val = lsb | (msb << 1);
return g_etc1_to_selector_index[val];
}
// Selector "val" ranges from 0-3 and is a direct index into g_etc1_inten_tables.
inline void set_selector(uint x, uint y, uint val) {
CRNLIB_ASSERT((x | y | val) < 4);
const uint bit_index = x * 4 + y;
uint8* p = &m_bytes[7 - (bit_index >> 3)];
const uint byte_bit_ofs = bit_index & 7;
const uint mask = 1 << byte_bit_ofs;
const uint etc1_val = g_selector_index_to_etc1[val];
const uint lsb = etc1_val & 1;
const uint msb = etc1_val >> 1;
p[0] &= ~mask;
p[0] |= (lsb << byte_bit_ofs);
p[-2] &= ~mask;
p[-2] |= (msb << byte_bit_ofs);
}
inline void set_base4_color(uint idx, uint16 c) {
if (idx) {
set_byte_bits(cETC1AbsColor4R2BitOffset, 4, (c >> 8) & 15);
set_byte_bits(cETC1AbsColor4G2BitOffset, 4, (c >> 4) & 15);
set_byte_bits(cETC1AbsColor4B2BitOffset, 4, c & 15);
} else {
set_byte_bits(cETC1AbsColor4R1BitOffset, 4, (c >> 8) & 15);
set_byte_bits(cETC1AbsColor4G1BitOffset, 4, (c >> 4) & 15);
set_byte_bits(cETC1AbsColor4B1BitOffset, 4, c & 15);
}
}
inline uint16 get_base4_color(uint idx) const {
uint r, g, b;
if (idx) {
r = get_byte_bits(cETC1AbsColor4R2BitOffset, 4);
g = get_byte_bits(cETC1AbsColor4G2BitOffset, 4);
b = get_byte_bits(cETC1AbsColor4B2BitOffset, 4);
} else {
r = get_byte_bits(cETC1AbsColor4R1BitOffset, 4);
g = get_byte_bits(cETC1AbsColor4G1BitOffset, 4);
b = get_byte_bits(cETC1AbsColor4B1BitOffset, 4);
}
return static_cast<uint16>(b | (g << 4U) | (r << 8U));
}
inline void set_base5_color(uint16 c) {
set_byte_bits(cETC1BaseColor5RBitOffset, 5, (c >> 10) & 31);
set_byte_bits(cETC1BaseColor5GBitOffset, 5, (c >> 5) & 31);
set_byte_bits(cETC1BaseColor5BBitOffset, 5, c & 31);
}
inline uint16 get_base5_color() const {
const uint r = get_byte_bits(cETC1BaseColor5RBitOffset, 5);
const uint g = get_byte_bits(cETC1BaseColor5GBitOffset, 5);
const uint b = get_byte_bits(cETC1BaseColor5BBitOffset, 5);
return static_cast<uint16>(b | (g << 5U) | (r << 10U));
}
void set_delta3_color(uint16 c) {
set_byte_bits(cETC1DeltaColor3RBitOffset, 3, (c >> 6) & 7);
set_byte_bits(cETC1DeltaColor3GBitOffset, 3, (c >> 3) & 7);
set_byte_bits(cETC1DeltaColor3BBitOffset, 3, c & 7);
}
inline uint16 get_delta3_color() const {
const uint r = get_byte_bits(cETC1DeltaColor3RBitOffset, 3);
const uint g = get_byte_bits(cETC1DeltaColor3GBitOffset, 3);
const uint b = get_byte_bits(cETC1DeltaColor3BBitOffset, 3);
return static_cast<uint16>(b | (g << 3U) | (r << 6U));
}
// Base color 5
static uint16 pack_color5(const color_quad_u8& color, bool scaled, uint bias = 127U);
static uint16 pack_color5(uint r, uint g, uint b, bool scaled, uint bias = 127U);
static color_quad_u8 unpack_color5(uint16 packed_color5, bool scaled, uint alpha = 255U);
static void unpack_color5(uint& r, uint& g, uint& b, uint16 packed_color, bool scaled);
static bool unpack_color5(color_quad_u8& result, uint16 packed_color5, uint16 packed_delta3, bool scaled, uint alpha = 255U);
static bool unpack_color5(uint& r, uint& g, uint& b, uint16 packed_color5, uint16 packed_delta3, bool scaled, uint alpha = 255U);
// Delta color 3
// Inputs range from -4 to 3 (cETC1ColorDeltaMin to cETC1ColorDeltaMax)
static uint16 pack_delta3(const color_quad_i16& color);
static uint16 pack_delta3(int r, int g, int b);
// Results range from -4 to 3 (cETC1ColorDeltaMin to cETC1ColorDeltaMax)
static color_quad_i16 unpack_delta3(uint16 packed_delta3);
static void unpack_delta3(int& r, int& g, int& b, uint16 packed_delta3);
// Abs color 4
static uint16 pack_color4(const color_quad_u8& color, bool scaled, uint bias = 127U);
static uint16 pack_color4(uint r, uint g, uint b, bool scaled, uint bias = 127U);
static color_quad_u8 unpack_color4(uint16 packed_color4, bool scaled, uint alpha = 255U);
static void unpack_color4(uint& r, uint& g, uint& b, uint16 packed_color4, bool scaled);
// subblock colors
static void get_diff_subblock_colors(color_quad_u8* pDst, uint16 packed_color5, uint table_idx);
static bool get_diff_subblock_colors(color_quad_u8* pDst, uint16 packed_color5, uint16 packed_delta3, uint table_idx);
static void get_abs_subblock_colors(color_quad_u8* pDst, uint16 packed_color4, uint table_idx);
static inline void unscaled_to_scaled_color(color_quad_u8& dst, const color_quad_u8& src, bool color4) {
if (color4) {
dst.r = src.r | (src.r << 4);
dst.g = src.g | (src.g << 4);
dst.b = src.b | (src.b << 4);
} else {
dst.r = (src.r >> 2) | (src.r << 3);
dst.g = (src.g >> 2) | (src.g << 3);
dst.b = (src.b >> 2) | (src.b << 3);
}
dst.a = src.a;
}
};
CRNLIB_DEFINE_BITWISE_COPYABLE(etc1_block);
// Returns false if the block is invalid (it will still be unpacked with clamping).
bool unpack_etc1(const etc1_block& block, color_quad_u8* pDst, bool preserve_alpha = false);
enum crn_etc_quality {
cCRNETCQualityFast,
cCRNETCQualityMedium,
cCRNETCQualitySlow,
cCRNETCQualityTotal,
cCRNETCQualityForceDWORD = 0xFFFFFFFF
};
struct crn_etc1_pack_params {
crn_etc_quality m_quality;
bool m_perceptual;
bool m_dithering;
inline crn_etc1_pack_params() {
clear();
}
void clear() {
m_quality = cCRNETCQualitySlow;
m_perceptual = true;
m_dithering = false;
}
};
struct etc1_solution_coordinates {
inline etc1_solution_coordinates()
: m_unscaled_color(0, 0, 0, 0),
m_inten_table(0),
m_color4(false) {
}
inline etc1_solution_coordinates(uint r, uint g, uint b, uint inten_table, bool color4)
: m_unscaled_color(r, g, b, 255),
m_inten_table(inten_table),
m_color4(color4) {
}
inline etc1_solution_coordinates(const color_quad_u8& c, uint inten_table, bool color4)
: m_unscaled_color(c),
m_inten_table(inten_table),
m_color4(color4) {
}
inline etc1_solution_coordinates(const etc1_solution_coordinates& other) {
*this = other;
}
inline etc1_solution_coordinates& operator=(const etc1_solution_coordinates& rhs) {
m_unscaled_color = rhs.m_unscaled_color;
m_inten_table = rhs.m_inten_table;
m_color4 = rhs.m_color4;
return *this;
}
inline void clear() {
m_unscaled_color.clear();
m_inten_table = 0;
m_color4 = false;
}
inline color_quad_u8 get_scaled_color() const {
int br, bg, bb;
if (m_color4) {
br = m_unscaled_color.r | (m_unscaled_color.r << 4);
bg = m_unscaled_color.g | (m_unscaled_color.g << 4);
bb = m_unscaled_color.b | (m_unscaled_color.b << 4);
} else {
br = (m_unscaled_color.r >> 2) | (m_unscaled_color.r << 3);
bg = (m_unscaled_color.g >> 2) | (m_unscaled_color.g << 3);
bb = (m_unscaled_color.b >> 2) | (m_unscaled_color.b << 3);
}
return color_quad_u8(br, bg, bb);
}
inline void get_block_colors(color_quad_u8* pBlock_colors) {
int br, bg, bb;
if (m_color4) {
br = m_unscaled_color.r | (m_unscaled_color.r << 4);
bg = m_unscaled_color.g | (m_unscaled_color.g << 4);
bb = m_unscaled_color.b | (m_unscaled_color.b << 4);
} else {
br = (m_unscaled_color.r >> 2) | (m_unscaled_color.r << 3);
bg = (m_unscaled_color.g >> 2) | (m_unscaled_color.g << 3);
bb = (m_unscaled_color.b >> 2) | (m_unscaled_color.b << 3);
}
const int* pInten_table = g_etc1_inten_tables[m_inten_table];
pBlock_colors[0].set(br + pInten_table[0], bg + pInten_table[0], bb + pInten_table[0]);
pBlock_colors[1].set(br + pInten_table[1], bg + pInten_table[1], bb + pInten_table[1]);
pBlock_colors[2].set(br + pInten_table[2], bg + pInten_table[2], bb + pInten_table[2]);
pBlock_colors[3].set(br + pInten_table[3], bg + pInten_table[3], bb + pInten_table[3]);
}
color_quad_u8 m_unscaled_color;
uint m_inten_table;
bool m_color4;
};
class etc1_optimizer {
CRNLIB_NO_COPY_OR_ASSIGNMENT_OP(etc1_optimizer);
public:
etc1_optimizer() {
clear();
}
void clear() {
m_pParams = NULL;
m_pResult = NULL;
m_pSorted_luma = NULL;
m_pSorted_luma_indices = NULL;
}
struct params : crn_etc1_pack_params {
params() {
clear();
}
params(const crn_etc1_pack_params& base_params)
: crn_etc1_pack_params(base_params) {
clear_optimizer_params();
}
void clear() {
crn_etc1_pack_params::clear();
clear_optimizer_params();
}
void clear_optimizer_params() {
m_num_src_pixels = 0;
m_pSrc_pixels = 0;
m_use_color4 = false;
static const int s_default_scan_delta[] = {0};
m_pScan_deltas = s_default_scan_delta;
m_scan_delta_size = 1;
m_base_color5.clear();
m_constrain_against_base_color5 = false;
}
uint m_num_src_pixels;
const color_quad_u8* m_pSrc_pixels;
bool m_use_color4;
const int* m_pScan_deltas;
uint m_scan_delta_size;
color_quad_u8 m_base_color5;
bool m_constrain_against_base_color5;
};
struct results {
uint64 m_error;
color_quad_u8 m_block_color_unscaled;
uint m_block_inten_table;
uint m_n;
uint8* m_pSelectors;
bool m_block_color4;
inline results& operator=(const results& rhs) {
m_block_color_unscaled = rhs.m_block_color_unscaled;
m_block_color4 = rhs.m_block_color4;
m_block_inten_table = rhs.m_block_inten_table;
m_error = rhs.m_error;
CRNLIB_ASSERT(m_n == rhs.m_n);
memcpy(m_pSelectors, rhs.m_pSelectors, rhs.m_n);
return *this;
}
};
void init(const params& params, results& result);
bool compute();
private:
struct potential_solution {
potential_solution()
: m_coords(), m_error(cUINT64_MAX), m_valid(false) {
}
etc1_solution_coordinates m_coords;
crnlib::vector<uint8> m_selectors;
uint64 m_error;
bool m_valid;
void clear() {
m_coords.clear();
m_selectors.resize(0);
m_error = cUINT64_MAX;
m_valid = false;
}
bool are_selectors_all_equal() const {
if (m_selectors.empty())
return false;
const uint s = m_selectors[0];
for (uint i = 1; i < m_selectors.size(); i++)
if (m_selectors[i] != s)
return false;
return true;
}
};
const params* m_pParams;
results* m_pResult;
int m_limit;
vec3F m_avg_color;
int m_br, m_bg, m_bb;
crnlib::vector<uint16> m_luma;
crnlib::vector<uint32> m_sorted_luma[2];
const uint32* m_pSorted_luma_indices;
uint32* m_pSorted_luma;
crnlib::vector<uint8> m_selectors;
crnlib::vector<uint8> m_best_selectors;
potential_solution m_best_solution;
potential_solution m_trial_solution;
crnlib::vector<uint8> m_temp_selectors;
bool evaluate_solution(const etc1_solution_coordinates& coords, potential_solution& trial_solution, potential_solution* pBest_solution);
bool evaluate_solution_fast(const etc1_solution_coordinates& coords, potential_solution& trial_solution, potential_solution* pBest_solution);
};
struct pack_etc1_block_context {
etc1_optimizer m_optimizer;
};
void pack_etc1_block_init();
uint64 pack_etc1_block(etc1_block& block, const color_quad_u8* pSrc_pixels, crn_etc1_pack_params& pack_params, pack_etc1_block_context& context);
uint64 pack_etc1s_block(etc1_block& block, const color_quad_u8* pSrc_pixels, crn_etc1_pack_params& pack_params);
} // namespace crnlib
+27
View File
@@ -0,0 +1,27 @@
// File: crn_event.h
// See Copyright Notice and license at the end of inc/crnlib.h
#pragma once
namespace crnlib
{
class event
{
CRNLIB_NO_COPY_OR_ASSIGNMENT_OP(event);
public:
event(bool manual_reset = false, bool initial_state = false, const char* pName = NULL);
~event();
inline void *get_handle(void) const { return m_handle; }
void set(void);
void reset(void);
void pulse(void);
bool wait(uint32 milliseconds = UINT32_MAX);
private:
void *m_handle;
};
} // namespace crnlib
-526
View File
@@ -1,526 +0,0 @@
// File: crn_file_utils.cpp
// See Copyright Notice and license at the end of inc/crnlib.h
#include "crn_core.h"
#include "crn_file_utils.h"
#include "crn_strutils.h"
#if CRNLIB_USE_WIN32_API
#include "crn_winhdr.h"
#endif
#ifdef WIN32
#include <direct.h>
#endif
#ifdef __GNUC__
#include <sys/stat.h>
#include <sys/stat.h>
#include <libgen.h>
#endif
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;
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::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::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::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;
}
if (file_size64 > cUINT32_MAX)
file_size64 = cUINT32_MAX;
file_size = static_cast<uint32>(file_size64);
return true;
}
bool file_utils::is_path_separator(char c) {
#ifdef WIN32
return (c == '/') || (c == '\\');
#else
return (c == '/');
#endif
}
bool file_utils::is_path_or_drive_separator(char c) {
#ifdef WIN32
return (c == '/') || (c == '\\') || (c == ':');
#else
return (c == '/');
#endif
}
bool file_utils::is_drive_separator(char c) {
#ifdef WIN32
return (c == ':');
#else
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);
#ifdef WIN32
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;
#else
// 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;
#else
char dirtmp[1024];
char nametmp[1024];
strcpy_safe(dirtmp, sizeof(dirtmp), p);
strcpy_safe(nametmp, sizeof(nametmp), p);
if (pDrive)
pDrive->clear();
const char* pDirName = dirname(dirtmp);
if (!pDirName)
return false;
if (pDir) {
pDir->set(pDirName);
if ((!pDir->is_empty()) && (pDir->back() != '/'))
pDir->append_char('/');
}
const char* pBaseName = basename(nametmp);
if (!pBaseName)
return false;
if (pFilename) {
pFilename->set(pBaseName);
remove_extension(*pFilename);
}
if (pExt) {
pExt->set(pBaseName);
get_extension(*pExt);
*pExt = "." + *pExt;
}
#endif // #ifdef WIN32
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;
filename += temp_ext;
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;
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;
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, const char* pC) {
combine_path(dst, pA, pB);
combine_path(dst, dst.get_ptr(), pC);
}
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;
#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());
}
#endif
return true;
}
bool file_utils::get_extension(dynamic_string& filename) {
int sep = -1;
#ifdef WIN32
sep = filename.find_right('\\');
#endif
if (sep < 0)
sep = filename.find_right('/');
int dot = filename.find_right('.');
if (dot < sep) {
filename.clear();
return false;
}
filename.right(dot + 1);
return true;
}
bool file_utils::remove_extension(dynamic_string& filename) {
int sep = -1;
#ifdef WIN32
sep = filename.find_right('\\');
#endif
if (sep < 0)
sep = filename.find_right('/');
int dot = filename.find_right('.');
if (dot < sep)
return false;
filename.left(dot);
return true;
}
bool file_utils::create_path(const dynamic_string& fullpath) {
#ifdef WIN32
bool got_unc = false;
#endif
dynamic_string cur_path;
const int l = fullpath.get_len();
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));
if (((sep) && (!back_sep)) || (is_last_char)) {
if ((is_last_char) && (!sep))
cur_path.append_char(c);
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;
#endif
if (cur_path == "/")
valid = false;
if ((valid) && (cur_path.get_len())) {
#ifdef WIN32
_mkdir(cur_path.get_ptr());
#else
mkdir(cur_path.get_ptr(), S_IRWXU | S_IRWXG | S_IRWXO);
#endif
}
}
cur_path.append_char(c);
n++;
}
return true;
}
void file_utils::trim_trailing_seperator(dynamic_string& path) {
if ((path.get_len()) && (is_path_separator(path.back())))
path.truncate(path.get_len() - 1);
}
// 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) && (*pWild != '*')) {
if ((*pWild != *pString) && (*pWild != '?'))
return 0;
pWild++;
pString++;
}
// Either *pString=='\0' or *pWild='*' here.
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 (*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;
#else
pFile = fopen(pPath, "wb");
#endif
if (!pFile)
return false;
bool success = fwrite(pData, 1, data_size, pFile) == data_size;
fclose(pFile);
return success;
}
} // namespace crnlib
-41
View File
@@ -1,41 +0,0 @@
// File: crn_file_utils.h
// 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);
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 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 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 bool write_buf_to_file(const char* pPath, const void* pData, size_t data_size);
}; // struct file_utils
} // namespace crnlib
-253
View File
@@ -1,253 +0,0 @@
// File: crn_win32_find_files.cpp
// See Copyright Notice and license at the end of inc/crnlib.h
#include "crn_core.h"
#include "crn_find_files.h"
#include "crn_file_utils.h"
#include "crn_strutils.h"
#ifdef CRNLIB_USE_WIN32_API
#include "crn_winhdr.h"
#elif defined(__GNUC__)
#include <fnmatch.h>
#include <dirent.h>
#endif
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);
return find_internal(pBasepath, "", pFilespec, flags, 0);
}
bool find_files::find(const char* pSpec, uint flags) {
dynamic_string find_name(pSpec);
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;
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;
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, "*");
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);
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) {
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);
HRESULT hres = GetLastError();
FindClose(handle);
handle = INVALID_HANDLE_VALUE;
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 (!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;
}
}
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* pSpec, uint flags) {
dynamic_string find_name(pSpec);
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;
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;
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(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;
}
#else
#error Unimplemented
#endif
} // namespace crnlib
-56
View File
@@ -1,56 +0,0 @@
// File: crn_win32_find_files.h
// 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) {}
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 operator size_t() const { return static_cast<size_t>(m_fullname); }
};
typedef crnlib::vector<file_desc> file_desc_vec;
inline find_files() {
m_last_error = 0; // S_OK;
}
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* pSpec, uint flags = cFlagAllowFiles);
// 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; }
private:
file_desc_vec m_files;
// A HRESULT under Win32
int64 m_last_error;
bool find_internal(const char* pBasepath, const char* pRelpath, const char* pFilespec, uint flags, int level);
}; // class find_files
} // namespace crnlib
-144
View File
@@ -1,144 +0,0 @@
// File: crn_freeimage_image_utils.h
// See Copyright Notice and license at the end of inc/crnlib.h
// Note: This header file requires FreeImage/FreeImagePlus.
#include "crn_image_utils.h"
#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;
if (!src_image.loadU(pFilename, fi_flag))
return false;
const uint orig_bits_per_pixel = src_image.getBitsPerPixel();
const FREE_IMAGE_COLOR_TYPE orig_color_type = src_image.getColorType();
if (!src_image.convertTo32Bits())
return false;
if (src_image.getBitsPerPixel() != 32)
return false;
uint width = src_image.getWidth();
uint height = src_image.getHeight();
dest.resize(src_image.getWidth(), src_image.getHeight(), src_image.getWidth());
color_quad_u8* pDst = dest.get_ptr();
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;
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);
pSrc += 4;
*pD++ = c;
}
pDst += width;
}
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));
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);
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++) {
const color_quad_u8* pSrc = src.get_scanline(y);
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);
pSrc++;
}
}
if (!dst_image.saveU(pFilename, fi_flag))
return false;
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" #include "crn_core.h"
#undef get16bits #undef get16bits
#if (defined(__GNUC__) && defined(__i386__)) || defined(__WATCOMC__) || defined(_MSC_VER) || defined(__BORLANDC__) || defined(__TURBOC__) #if (defined(__GNUC__) && defined(__i386__)) || defined(__WATCOMC__) \
#define get16bits(d) (*((const uint16*)(d))) || defined(_MSC_VER) || defined (__BORLANDC__) || defined (__TURBOC__)
#define get16bits(d) (*((const uint16 *) (d)))
#endif #endif
#if !defined(get16bits) #if !defined (get16bits)
#define get16bits(d) ((((uint32)(((const uint8*)(d))[1])) << 8) + (uint32)(((const uint8*)(d))[0])) #define get16bits(d) ((((uint32)(((const uint8 *)(d))[1])) << 8)\
+(uint32)(((const uint8 *)(d))[0]) )
#endif #endif
namespace crnlib { namespace crnlib
uint32 fast_hash(const void* p, int len) { {
const char* data = static_cast<const char*>(p); uint32 fast_hash (const void* p, int len)
{
const char * data = static_cast<const char *>(p);
uint32 hash = len, tmp; uint32 hash = len, tmp;
int rem; int rem;
if (len <= 0 || data == NULL) if (len <= 0 || data == NULL) return 0;
return 0;
rem = len & 3; rem = len & 3;
len >>= 2; len >>= 2;
/* Main loop */ /* Main loop */
for (; len > 0; len--) { for (;len > 0; len--) {
hash += get16bits(data); hash += get16bits (data);
tmp = (get16bits(data + 2) << 11) ^ hash; tmp = (get16bits (data+2) << 11) ^ hash;
hash = (hash << 16) ^ tmp; hash = (hash << 16) ^ tmp;
data += 2 * sizeof(uint16); data += 2*sizeof (uint16);
hash += hash >> 11; hash += hash >> 11;
} }
/* Handle end cases */ /* Handle end cases */
switch (rem) { switch (rem) {
case 3: case 3: hash += get16bits (data);
hash += get16bits(data); hash ^= hash << 16;
hash ^= hash << 16; hash ^= data[sizeof (uint16)] << 18;
hash ^= data[sizeof(uint16)] << 18; hash += hash >> 11;
hash += hash >> 11; break;
break; case 2: hash += get16bits (data);
case 2: hash ^= hash << 11;
hash += get16bits(data); hash += hash >> 17;
hash ^= hash << 11; break;
case 1: hash += *data;
hash ^= hash << 10;
hash += hash >> 1;
}
/* Force "avalanching" of final 127 bits */
hash ^= hash << 3;
hash += hash >> 5;
hash ^= hash << 4;
hash += hash >> 17; hash += hash >> 17;
break; hash ^= hash << 25;
case 1: hash += hash >> 6;
hash += *data;
hash ^= hash << 10;
hash += hash >> 1;
}
/* Force "avalanching" of final 127 bits */ return hash;
hash ^= hash << 3; }
hash += hash >> 5;
hash ^= hash << 4;
hash += hash >> 17;
hash ^= hash << 25;
hash += hash >> 6;
return hash;
}
} // namespace crnlib } // namespace crnlib
+26 -23
View File
@@ -2,30 +2,33 @@
// See Copyright Notice and license at the end of inc/crnlib.h // See Copyright Notice and license at the end of inc/crnlib.h
#pragma once #pragma once
namespace crnlib { namespace crnlib
uint32 fast_hash(const void* p, int len); {
uint32 fast_hash (const void* p, int len);
// 4-byte integer hash, full avalanche // 4-byte integer hash, full avalanche
inline uint32 bitmix32c(uint32 a) { inline uint32 bitmix32c(uint32 a)
a = (a + 0x7ed55d16) + (a << 12); {
a = (a ^ 0xc761c23c) ^ (a >> 19); a = (a+0x7ed55d16) + (a<<12);
a = (a + 0x165667b1) + (a << 5); a = (a^0xc761c23c) ^ (a>>19);
a = (a + 0xd3a2646c) ^ (a << 9); a = (a+0x165667b1) + (a<<5);
a = (a + 0xfd7046c5) + (a << 3); a = (a+0xd3a2646c) ^ (a<<9);
a = (a ^ 0xb55a4f09) ^ (a >> 16); a = (a+0xfd7046c5) + (a<<3);
return a; a = (a^0xb55a4f09) ^ (a>>16);
} return a;
}
// 4-byte integer hash, full avalanche, no constants // 4-byte integer hash, full avalanche, no constants
inline uint32 bitmix32(uint32 a) { inline uint32 bitmix32(uint32 a)
a -= (a << 6); {
a ^= (a >> 17); a -= (a<<6);
a -= (a << 9); a ^= (a>>17);
a ^= (a << 4); a -= (a<<9);
a -= (a << 3); a ^= (a<<4);
a ^= (a << 10); a -= (a<<3);
a ^= (a >> 15); a ^= (a<<10);
return a; a ^= (a>>15);
} return a;
}
} // namespace crnlib } // namespace crnlib
+3 -2
View File
@@ -4,7 +4,8 @@
#include "crn_hash_map.h" #include "crn_hash_map.h"
#include "crn_rand.h" #include "crn_rand.h"
namespace crnlib { namespace crnlib
{
#if 0 #if 0
class counted_obj class counted_obj
{ {
@@ -151,4 +152,4 @@ namespace crnlib {
} }
#endif #endif
} // namespace crnlib } // namespace crnlib
+784 -678
View File
File diff suppressed because it is too large Load Diff
+50 -48
View File
@@ -2,61 +2,63 @@
// See Copyright Notice and license at the end of inc/crnlib.h // See Copyright Notice and license at the end of inc/crnlib.h
#pragma once #pragma once
#define CRNLIB_NO_COPY_OR_ASSIGNMENT_OP(c) \ #define CRNLIB_NO_COPY_OR_ASSIGNMENT_OP(c) c(const c&); c& operator= (const c&);
c(const c&); \ #define CRNLIB_NO_HEAP_ALLOC() private: static void* operator new(size_t); static void* operator new[](size_t);
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 crnlib
namespace helpers { {
template <typename T> namespace helpers
struct rel_ops { {
friend bool operator!=(const T& x, const T& y) { return (!(x == y)); } template<typename T> struct rel_ops
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)); }
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> template <typename T>
inline T* construct(T* p) { inline T* construct(T* p)
return new (static_cast<void*>(p)) T; {
} return new (static_cast<void*>(p)) T;
}
template <typename T, typename U> template <typename T, typename U>
inline T* construct(T* p, const U& init) { inline T* construct(T* p, const U& init)
return new (static_cast<void*>(p)) T(init); {
} return new (static_cast<void*>(p)) T(init);
}
template <typename T> template <typename T>
inline void construct_array(T* p, uint n) { void construct_array(T* p, uint n)
T* q = p + n; {
for (; p != q; ++p) T* q = p + n;
new (static_cast<void*>(p)) T; for ( ; p != q; ++p)
} new (static_cast<void*>(p)) T;
}
template <typename T, typename U> template <typename T, typename U>
inline void construct_array(T* p, uint n, const U& init) { void construct_array(T* p, uint n, const U& init)
T* q = p + n; {
for (; p != q; ++p) T* q = p + n;
new (static_cast<void*>(p)) T(init); for ( ; p != q; ++p)
} new (static_cast<void*>(p)) T(init);
}
template <typename T> template <typename T>
inline void destruct(T* p) { inline void destruct(T* p)
(void)p; {
p->~T(); p;
} p->~T();
}
template <typename T> template <typename T> inline void destruct_array(T* p, uint n)
inline void destruct_array(T* p, uint n) { {
T* q = p + n; T* q = p + n;
for (; p != q; ++p) for ( ; p != q; ++p)
p->~T(); p->~T();
} }
} // namespace helpers } // namespace helpers
} // namespace crnlib } // namespace crnlib
+300 -279
View File
@@ -3,364 +3,385 @@
#include "crn_core.h" #include "crn_core.h"
#include "crn_huffman_codes.h" #include "crn_huffman_codes.h"
namespace crnlib { namespace crnlib
struct sym_freq { {
uint m_freq; struct sym_freq
uint16 m_left; {
uint16 m_right; uint m_freq;
uint16 m_left;
uint16 m_right;
inline bool operator<(const sym_freq& other) const { inline bool operator< (const sym_freq& other) const
return m_freq > other.m_freq; {
} return m_freq > other.m_freq;
}; }
};
static inline sym_freq* radix_sort_syms(uint num_syms, sym_freq* syms0, sym_freq* syms1) { static inline sym_freq* radix_sort_syms(uint num_syms, sym_freq* syms0, sym_freq* syms1)
const uint cMaxPasses = 2; {
uint hist[256 * cMaxPasses]; const uint cMaxPasses = 2;
uint hist[256 * cMaxPasses];
memset(hist, 0, sizeof(hist[0]) * 256 * cMaxPasses); memset(hist, 0, sizeof(hist[0]) * 256 * cMaxPasses);
sym_freq* p = syms0; sym_freq* p = syms0;
sym_freq* q = syms0 + (num_syms >> 1) * 2; sym_freq* q = syms0 + (num_syms >> 1) * 2;
for (; p != q; p += 2) { for ( ; p != q; p += 2)
const uint freq0 = p[0].m_freq; {
const uint freq1 = p[1].m_freq; const uint freq0 = p[0].m_freq;
const uint freq1 = p[1].m_freq;
hist[freq0 & 0xFF]++; hist[ freq0 & 0xFF]++;
hist[256 + ((freq0 >> 8) & 0xFF)]++; hist[256 + ((freq0 >> 8) & 0xFF)]++;
hist[freq1 & 0xFF]++; hist[ freq1 & 0xFF]++;
hist[256 + ((freq1 >> 8) & 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;
} }
c0 &= 0xFF; if (num_syms & 1)
c1 &= 0xFF; {
const uint freq = p->m_freq;
if (c0 == c1) { hist[ freq & 0xFF]++;
uint dst_offset0 = offsets[c0]; hist[256 + ((freq >> 8) & 0xFF)]++;
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) { sym_freq* pCur_syms = syms0;
uint c = ((p->m_freq) >> pass_shift) & 0xFF; sym_freq* pNew_syms = syms1;
uint dst_offset = offsets[c]; for (uint pass = 0; pass < cMaxPasses; pass++)
offsets[c] = dst_offset + 1; {
const uint* pHist = &hist[pass << 8];
pNew_syms[dst_offset] = *p; uint offsets[256];
}
sym_freq* t = pCur_syms; uint cur_ofs = 0;
pCur_syms = pNew_syms; for (uint i = 0; i < 256; i += 2)
pNew_syms = t; {
} 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;
}
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;
}
#ifdef CRNLIB_ASSERTS_ENABLED #ifdef CRNLIB_ASSERTS_ENABLED
uint prev_freq = 0; uint prev_freq = 0;
for (uint i = 0; i < num_syms; i++) { for (uint i = 0; i < num_syms; i++)
CRNLIB_ASSERT(!(pCur_syms[i].m_freq < prev_freq)); {
prev_freq = pCur_syms[i].m_freq; CRNLIB_ASSERT(!(pCur_syms[i].m_freq < prev_freq));
} prev_freq = pCur_syms[i].m_freq;
}
#endif #endif
return pCur_syms; return pCur_syms;
} }
struct huffman_work_tables { struct huffman_work_tables
enum { cMaxInternalNodes = cHuffmanMaxSupportedSyms }; {
enum { cMaxInternalNodes = cHuffmanMaxSupportedSyms };
sym_freq syms0[cHuffmanMaxSupportedSyms + 1 + cMaxInternalNodes]; sym_freq syms0[cHuffmanMaxSupportedSyms + 1 + cMaxInternalNodes];
sym_freq syms1[cHuffmanMaxSupportedSyms + 1 + cMaxInternalNodes]; sym_freq syms1[cHuffmanMaxSupportedSyms + 1 + cMaxInternalNodes];
uint16 queue[cMaxInternalNodes]; uint16 queue[cMaxInternalNodes];
}; };
void* create_generate_huffman_codes_tables() { void* create_generate_huffman_codes_tables()
return crnlib_new<huffman_work_tables>(); {
} return crnlib_new<huffman_work_tables>();
}
void free_generate_huffman_codes_tables(void* p) { void free_generate_huffman_codes_tables(void* p)
crnlib_delete(static_cast<huffman_work_tables*>(p)); {
} crnlib_delete(static_cast<huffman_work_tables*>(p));
}
#if USE_CALCULATE_MINIMUM_REDUNDANCY #if USE_CALCULATE_MINIMUM_REDUNDANCY
/* calculate_minimum_redundancy() written by /* calculate_minimum_redundancy() written by
Alistair Moffat, alistair@cs.mu.oz.au, Alistair Moffat, alistair@cs.mu.oz.au,
Jyrki Katajainen, jyrki@diku.dk Jyrki Katajainen, jyrki@diku.dk
November 1996. November 1996.
*/ */
static void calculate_minimum_redundancy(int A[], int n) { static void calculate_minimum_redundancy(int A[], int n) {
int root; /* next root node to be used */ int root; /* next root node to be used */
int leaf; /* next leaf to be used */ int leaf; /* next leaf to be used */
int next; /* next value to be assigned */ int next; /* next value to be assigned */
int avbl; /* number of available nodes */ int avbl; /* number of available nodes */
int used; /* number of internal nodes */ int used; /* number of internal nodes */
int dpth; /* current depth of leaves */ int dpth; /* current depth of leaves */
/* check for pathological cases */ /* check for pathological cases */
if (n == 0) { if (n==0) { return; }
return; if (n==1) { A[0] = 0; return; }
}
if (n == 1) {
A[0] = 0;
return;
}
/* first pass, left to right, setting parent pointers */ /* first pass, left to right, setting parent pointers */
A[0] += A[1]; A[0] += A[1]; root = 0; leaf = 2;
root = 0; for (next=1; next < n-1; next++) {
leaf = 2; /* select first item for a pairing */
for (next = 1; next < n - 1; next++) { if (leaf>=n || A[root]<A[leaf]) {
/* select first item for a pairing */ A[next] = A[root]; A[root++] = next;
if (leaf >= n || A[root] < A[leaf]) { } else
A[next] = A[root]; A[next] = A[leaf++];
A[root++] = next;
} else
A[next] = A[leaf++];
/* add on the second item */ /* add on the second item */
if (leaf >= n || (root < next && A[root] < A[leaf])) { if (leaf>=n || (root<next && A[root]<A[leaf])) {
A[next] += A[root]; A[next] += A[root]; A[root++] = next;
A[root++] = next; } else
} else A[next] += A[leaf++];
A[next] += A[leaf++]; }
}
/* second pass, right to left, setting internal depths */ /* second pass, right to left, setting internal depths */
A[n - 2] = 0; A[n-2] = 0;
for (next = n - 3; next >= 0; next--) for (next=n-3; next>=0; next--)
A[next] = A[A[next]] + 1; A[next] = A[A[next]]+1;
/* third pass, right to left, setting leaf depths */ /* third pass, right to left, setting leaf depths */
avbl = 1; avbl = 1; used = dpth = 0; root = n-2; next = n-1;
used = dpth = 0; while (avbl>0) {
root = n - 2; while (root>=0 && A[root]==dpth) {
next = n - 1; used++; root--;
while (avbl > 0) { }
while (root >= 0 && A[root] == dpth) { while (avbl>used) {
used++; A[next--] = dpth; avbl--;
root--; }
} avbl = 2*used; dpth++; used = 0;
while (avbl > used) { }
A[next--] = dpth; }
avbl--;
}
avbl = 2 * used;
dpth++;
used = 0;
}
}
#endif #endif
bool generate_huffman_codes(void* pContext, uint num_syms, const uint16* pFreq, uint8* pCodesizes, uint& max_code_size, uint& total_freq_ret) { 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; if ((!num_syms) || (num_syms > cHuffmanMaxSupportedSyms))
return false;
huffman_work_tables& state = *static_cast<huffman_work_tables*>(pContext); huffman_work_tables& state = *static_cast<huffman_work_tables*>(pContext);;
;
uint max_freq = 0; uint max_freq = 0;
uint total_freq = 0; uint total_freq = 0;
uint num_used_syms = 0; uint num_used_syms = 0;
for (uint i = 0; i < num_syms; i++) { for (uint i = 0; i < num_syms; i++)
uint freq = pFreq[i]; {
uint freq = pFreq[i];
if (!freq) if (!freq)
pCodesizes[i] = 0; pCodesizes[i] = 0;
else { else
total_freq += freq; {
max_freq = math::maximum(max_freq, freq); total_freq += freq;
max_freq = math::maximum(max_freq, freq);
sym_freq& sf = state.syms0[num_used_syms]; sym_freq& sf = state.syms0[num_used_syms];
sf.m_left = (uint16)i; sf.m_left = (uint16)i;
sf.m_right = cUINT16_MAX; sf.m_right = UINT16_MAX;
sf.m_freq = freq; sf.m_freq = freq;
num_used_syms++; num_used_syms++;
} }
} }
total_freq_ret = total_freq; total_freq_ret = total_freq;
if (num_used_syms == 1) { if (num_used_syms == 1)
pCodesizes[state.syms0[0].m_left] = 1; {
return true; pCodesizes[state.syms0[0].m_left] = 1;
} return true;
}
sym_freq* syms = radix_sort_syms(num_used_syms, state.syms0, state.syms1); sym_freq* syms = radix_sort_syms(num_used_syms, state.syms0, state.syms1);
#if USE_CALCULATE_MINIMUM_REDUNDANCY #if USE_CALCULATE_MINIMUM_REDUNDANCY
int x[cHuffmanMaxSupportedSyms]; int x[cHuffmanMaxSupportedSyms];
for (uint i = 0; i < num_used_syms; i++) for (uint i = 0; i < num_used_syms; i++)
x[i] = state.syms0[i].m_freq; x[i] = state.syms0[i].m_freq;
calculate_minimum_redundancy(x, num_used_syms); calculate_minimum_redundancy(x, num_used_syms);
uint max_len = 0; uint max_len = 0;
for (uint i = 0; i < num_used_syms; i++) { for (uint i = 0; i < num_used_syms; i++)
uint len = x[i]; {
max_len = math::maximum(len, max_len); uint len = x[i];
pCodesizes[state.syms0[i].m_left] = static_cast<uint8>(len); max_len = math::maximum(len, max_len);
} pCodesizes[state.syms0[i].m_left] = static_cast<uint8>(len);
}
return true; return true;
#else #else
// Dummy node // Dummy node
sym_freq& sf = state.syms0[num_used_syms]; sym_freq& sf = state.syms0[num_used_syms];
sf.m_left = cUINT16_MAX; sf.m_left = UINT16_MAX;
sf.m_right = cUINT16_MAX; sf.m_right = UINT16_MAX;
sf.m_freq = UINT_MAX; sf.m_freq = UINT_MAX;
uint next_internal_node = num_used_syms + 1; uint next_internal_node = num_used_syms + 1;
uint queue_front = 0; uint queue_front = 0;
uint queue_end = 0; uint queue_end = 0;
uint next_lowest_sym = 0; uint next_lowest_sym = 0;
uint num_nodes_remaining = num_used_syms; uint num_nodes_remaining = num_used_syms;
do { do
uint left_freq = syms[next_lowest_sym].m_freq; {
uint left_child = next_lowest_sym; 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)) { 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; left_child = state.queue[queue_front];
left_freq = syms[left_child].m_freq;
queue_front++; queue_front++;
} else }
next_lowest_sym++; else
next_lowest_sym++;
uint right_freq = syms[next_lowest_sym].m_freq; uint right_freq = syms[next_lowest_sym].m_freq;
uint right_child = next_lowest_sym; uint right_child = next_lowest_sym;
if ((queue_end > queue_front) && (syms[state.queue[queue_front]].m_freq < right_freq)) { 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; right_child = state.queue[queue_front];
right_freq = syms[right_child].m_freq;
queue_front++; queue_front++;
} else }
next_lowest_sym++; else
next_lowest_sym++;
const uint internal_node_index = next_internal_node; const uint internal_node_index = next_internal_node;
next_internal_node++; next_internal_node++;
CRNLIB_ASSERT(next_internal_node < CRNLIB_ARRAYSIZE(state.syms0)); CRNLIB_ASSERT(next_internal_node < CRNLIB_ARRAYSIZE(state.syms0));
syms[internal_node_index].m_freq = left_freq + right_freq; 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_left = static_cast<uint16>(left_child);
syms[internal_node_index].m_right = static_cast<uint16>(right_child); syms[internal_node_index].m_right = static_cast<uint16>(right_child);
CRNLIB_ASSERT(queue_end < huffman_work_tables::cMaxInternalNodes); CRNLIB_ASSERT(queue_end < huffman_work_tables::cMaxInternalNodes);
state.queue[queue_end] = static_cast<uint16>(internal_node_index); state.queue[queue_end] = static_cast<uint16>(internal_node_index);
queue_end++; queue_end++;
num_nodes_remaining--; num_nodes_remaining--;
} while (num_nodes_remaining > 1); } while (num_nodes_remaining > 1);
CRNLIB_ASSERT(next_lowest_sym == num_used_syms); CRNLIB_ASSERT(next_lowest_sym == num_used_syms);
CRNLIB_ASSERT((queue_end - queue_front) == 1); CRNLIB_ASSERT((queue_end - queue_front) == 1);
uint cur_node_index = state.queue[queue_front]; uint cur_node_index = state.queue[queue_front];
uint32* pStack = (syms == state.syms0) ? (uint32*)state.syms1 : (uint32*)state.syms0; uint32* pStack = (syms == state.syms0) ? (uint32*)state.syms1 : (uint32*)state.syms0;
uint32* pStack_top = pStack; uint32* pStack_top = pStack;
uint max_level = 0; uint max_level = 0;
for (;;) { for ( ; ; )
uint level = cur_node_index >> 16; {
uint node_index = cur_node_index & 0xFFFF; uint level = cur_node_index >> 16;
uint node_index = cur_node_index & 0xFFFF;
uint left_child = syms[node_index].m_left; uint left_child = syms[node_index].m_left;
uint right_child = syms[node_index].m_right; uint right_child = syms[node_index].m_right;
uint next_level = (cur_node_index + 0x10000) & 0xFFFF0000; uint next_level = (cur_node_index + 0x10000) & 0xFFFF0000;
if (left_child < num_used_syms) { if (left_child < num_used_syms)
max_level = math::maximum(max_level, level); {
max_level = math::maximum(max_level, level);
pCodesizes[syms[left_child].m_left] = static_cast<uint8>(level + 1); pCodesizes[syms[left_child].m_left] = static_cast<uint8>(level + 1);
if (right_child < num_used_syms) { if (right_child < num_used_syms)
pCodesizes[syms[right_child].m_left] = static_cast<uint8>(level + 1); {
pCodesizes[syms[right_child].m_left] = static_cast<uint8>(level + 1);
if (pStack == pStack_top) if (pStack == pStack_top) break;
break; cur_node_index = *--pStack;
cur_node_index = *--pStack; }
} else { else
cur_node_index = next_level | right_child; {
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;
}
}
} }
} 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); max_code_size = max_level + 1;
cur_node_index = next_level | left_child;
} else {
*pStack++ = next_level | left_child;
cur_node_index = next_level | right_child;
}
}
}
max_code_size = max_level + 1;
#endif #endif
return true; return true;
} }
} // namespace crnlib
} // namespace crnlib
+7 -6
View File
@@ -2,12 +2,13 @@
// See Copyright Notice and license at the end of inc/crnlib.h // See Copyright Notice and license at the end of inc/crnlib.h
#pragma once #pragma once
namespace crnlib { namespace crnlib
const uint cHuffmanMaxSupportedSyms = 8192; {
const uint cHuffmanMaxSupportedSyms = 8192;
void* create_generate_huffman_codes_tables(); void* create_generate_huffman_codes_tables();
void free_generate_huffman_codes_tables(void* p); 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); bool generate_huffman_codes(void* pContext, uint num_syms, const uint16* pFreq, uint8* pCodesizes, uint& max_code_size, uint& total_freq_ret);
} // namespace crnlib } // namespace crnlib
+580 -603
View File
File diff suppressed because it is too large Load Diff
+1088 -1136
View File
File diff suppressed because it is too large Load Diff
+127 -169
View File
@@ -2,182 +2,140 @@
// See Copyright Notice and license at the end of inc/crnlib.h // See Copyright Notice and license at the end of inc/crnlib.h
#pragma once #pragma once
#include "crn_image.h" #include "crn_image.h"
#include "crn_data_stream_serializer.h"
namespace crnlib { namespace crnlib
enum pixel_format; {
enum pixel_format;
namespace image_utils { namespace image_utils
enum read_flags_t { {
cReadFlagForceSTB = 1, bool load_from_file_stb(const wchar_t* pFilename, image_u8& img);
cReadFlagsAllFlags = 1 enum
}; {
cSaveIgnoreAlpha = 1,
cSaveGrayscale = 2
};
bool read_from_stream_stb(data_stream_serializer& serializer, image_u8& img); const int cSaveLuma = -1;
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. bool save_to_file_stb(const wchar_t* pFilename, const image_u8& img, uint save_flags = 0, int comp_index = cSaveLuma);
// *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 { bool load_from_file(image_u8& dest, const wchar_t* pFilename, int flags = 0);
cWriteFlagIgnoreAlpha = 0x00000001,
cWriteFlagGrayscale = 0x00000002,
cWriteFlagJPEGH1V1 = 0x00010000, bool save_to_grayscale_file(const wchar_t* pFilename, const image_u8& src, int component, int flags = 0);
cWriteFlagJPEGH2V1 = 0x00020000,
cWriteFlagJPEGH2V2 = 0x00040000,
cWriteFlagJPEGTwoPass = 0x00080000,
cWriteFlagJPEGNoChromaDiscrim = 0x00100000,
cWriteFlagJPEGQualityLevelMask = 0xFF000000,
cWriteFlagJPEGQualityLevelShift = 24,
};
const int cLumaComponentIndex = -1; bool save_to_file(const wchar_t* pFilename, const image_u8& src, int flags = 0, bool ignore_alpha = false);
inline uint create_jpeg_write_flags(uint base_flags, uint quality_level) { bool has_alpha(const image_u8& img);
CRNLIB_ASSERT(quality_level <= 100); bool is_normal_map(const image_u8& img, const wchar_t* pFilename = NULL);
return base_flags | ((quality_level << cWriteFlagJPEGQualityLevelShift) & cWriteFlagJPEGQualityLevelMask); 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)
{
}
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 compute_delta(image_u8& dest, image_u8& a, image_u8& b, uint scale = 2);
class error_metrics
{
public:
error_metrics() { utils::zero_this(this); }
void print(const wchar_t* 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);
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;
}
};
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);
enum conversion_type
{
cConversion_Invalid = -1,
cConversion_To_CCxY,
cConversion_From_CCxY,
cConversion_To_xGxR,
cConversion_From_xGxR,
cConversion_To_xGBR,
cConversion_From_xGBR,
cConversion_To_AGBR,
cConversion_From_AGBR,
cConversion_XY_to_XYZ,
cConversion_Y_To_A,
cConversion_A_To_RGBA,
cConversion_Y_To_RGB,
cConversionTotal
};
void convert_image(image_u8& img, conversion_type conv_type);
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);
double compute_std_dev(uint n, const color_quad_u8* pPixels, uint first_channel, uint num_channels);
}
} }
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);
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;
};
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);
class error_metrics {
public:
error_metrics() { utils::zero_this(this); }
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);
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;
}
};
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);
enum conversion_type {
cConversion_Invalid = -1,
cConversion_To_CCxY,
cConversion_From_CCxY,
cConversion_To_xGxR,
cConversion_From_xGxR,
cConversion_To_xGBR,
cConversion_From_xGBR,
cConversion_To_AGBR,
cConversion_From_AGBR,
cConversion_XY_to_XYZ,
cConversion_Y_To_A,
cConversion_A_To_RGBA,
cConversion_Y_To_RGB,
cConversion_To_Y,
cConversionTotal
};
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;
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;
n = dst_pitch * height;
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);
}
return pImage;
}
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);
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);
} // namespace image_utils
} // namespace crnlib
+106 -87
View File
@@ -3,102 +3,121 @@
#pragma once #pragma once
#include "crn_ray.h" #include "crn_ray.h"
namespace crnlib { namespace crnlib
namespace intersection { {
enum result { namespace intersection
cBackfacing = -1, {
cFailure = 0, enum result
cSuccess, {
cParallel, cBackfacing = -1,
cInside, cFailure = 0,
}; cSuccess,
cParallel,
cInside,
};
// Returns cInside, cSuccess, or cFailure. // Returns cInside, cSuccess, or cFailure.
// Algorithm: Graphics Gems 1 // Algorithm: Graphics Gems 1
template <typename vector_type, typename scalar_type, typename ray_type, typename aabb_type> 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) { result ray_aabb(vector_type& coord, scalar_type& t, const ray_type& ray, const aabb_type& box)
enum { {
cNumDim = vector_type::num_elements, enum
cRight = 0, {
cLeft = 1, cNumDim = vector_type::num_elements,
cMiddle = 2 cRight = 0,
}; cLeft = 1,
cMiddle = 2
};
bool inside = true; bool inside = true;
int quadrant[cNumDim]; int quadrant[cNumDim];
scalar_type candidate_plane[cNumDim]; scalar_type candidate_plane[cNumDim];
for (int i = 0; i < cNumDim; i++) { for (int i = 0; i < cNumDim; i++)
if (ray.get_origin()[i] < box[0][i]) { {
quadrant[i] = cLeft; if (ray.get_origin()[i] < box[0][i])
candidate_plane[i] = box[0][i]; {
inside = false; quadrant[i] = cLeft;
} else if (ray.get_origin()[i] > box[1][i]) { candidate_plane[i] = box[0][i];
quadrant[i] = cRight; inside = false;
candidate_plane[i] = box[1][i]; }
inside = false; else if (ray.get_origin()[i] > box[1][i])
} else { {
quadrant[i] = cMiddle; quadrant[i] = cRight;
} candidate_plane[i] = box[1][i];
} inside = false;
}
else
{
quadrant[i] = cMiddle;
}
}
if (inside) { if (inside)
coord = ray.get_origin(); {
t = 0.0f; coord = ray.get_origin();
return cInside; t = 0.0f;
} return cInside;
}
scalar_type max_t[cNumDim]; scalar_type max_t[cNumDim];
for (int i = 0; i < cNumDim; i++) { 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]; if ((quadrant[i] != cMiddle) && (ray.get_direction()[i] != 0.0f))
else max_t[i] = (candidate_plane[i] - ray.get_origin()[i]) / ray.get_direction()[i];
max_t[i] = -1.0f; else
} max_t[i] = -1.0f;
}
int which_plane = 0; int which_plane = 0;
for (int i = 1; i < cNumDim; i++) for (int i = 1; i < cNumDim; i++)
if (max_t[which_plane] < max_t[i]) if (max_t[which_plane] < max_t[i])
which_plane = i; which_plane = i;
if (max_t[which_plane] < 0.0f) if (max_t[which_plane] < 0.0f)
return cFailure; return cFailure;
for (int i = 0; i < cNumDim; 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 (i != which_plane)
{
coord[i] = ray.get_origin()[i] + max_t[which_plane] * ray.get_direction()[i];
if ((coord[i] < box[0][i]) || (coord[i] > box[1][i])) if ( (coord[i] < box[0][i]) || (coord[i] > box[1][i]) )
return cFailure; return cFailure;
} else { }
coord[i] = candidate_plane[i]; else
} {
coord[i] = candidate_plane[i];
}
CRNLIB_ASSERT(coord[i] >= box[0][i] && coord[i] <= box[1][i]); CRNLIB_ASSERT(coord[i] >= box[0][i] && coord[i] <= box[1][i]);
} }
t = max_t[which_plane]; t = max_t[which_plane];
return cSuccess; return cSuccess;
} }
template <typename vector_type, typename scalar_type, typename ray_type, typename aabb_type> 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) { 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; if (!box.contains(ray.get_origin()))
return ray_aabb(coord, t, ray, box); {
} started_within = false;
return ray_aabb(coord, t, ray, box);
started_within = true; }
float diag_dist = box.diagonal_length() * 1.5f; started_within = true;
ray_type outside_ray(ray.eval(diag_dist), -ray.get_direction());
float diag_dist = box.diagonal_length() * 1.5f;
result res(ray_aabb(coord, t, outside_ray, box)); ray_type outside_ray(ray.eval(diag_dist), -ray.get_direction());
if (res != cSuccess)
return res; result res(ray_aabb(coord, t, outside_ray, box));
if (res != cSuccess)
t = math::maximum(0.0f, diag_dist - t); return res;
return cSuccess;
} t = math::maximum(0.0f, diag_dist - t);
} return cSuccess;
}
}
} }
-2943
View File
File diff suppressed because it is too large Load Diff
-349
View File
@@ -1,349 +0,0 @@
// jpgd.h - C++ class for JPEG decompression.
// Public domain, Rich Geldreich <richgel99@gmail.com>
#ifndef JPEG_DECODER_H
#define JPEG_DECODER_H
#include <stdlib.h>
#include <stdio.h>
#include <setjmp.h>
#ifdef _MSC_VER
#define JPGD_NORETURN __declspec(noreturn)
#elif defined(__GNUC__)
#define JPGD_NORETURN __attribute__((noreturn))
#else
#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;
// 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() {}
// 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];
};
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
-1120
View File
File diff suppressed because it is too large Load Diff
-171
View File
@@ -1,171 +0,0 @@
// jpge.h - C++ class for JPEG compression.
// Public domain, Rich Geldreich <richgel99@gmail.com>
// Alex Evans: Added RGBA support, linear memory allocator.
#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;
// 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) {}
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;
// 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;
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 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)); }
};
// 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());
const params& get_params() const { return m_params; }
// 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; }
// 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&);
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;
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
#endif // JPEG_ENCODER
-834
View File
@@ -1,834 +0,0 @@
// File: crn_ktx_texture.cpp
#include "crn_core.h"
#include "crn_ktx_texture.h"
#include "crn_console.h"
// Set #if CRNLIB_KTX_PVRTEX_WORKAROUNDS to 1 to enable various workarounds for oddball KTX files written by PVRTexTool.
#define CRNLIB_KTX_PVRTEX_WORKAROUNDS 1
namespace crnlib {
const uint8 s_ktx_file_id[12] = {0xAB, 0x4B, 0x54, 0x58, 0x20, 0x31, 0x31, 0xBB, 0x0D, 0x0A, 0x1A, 0x0A};
bool is_packed_pixel_ogl_type(uint32 ogl_type) {
switch (ogl_type) {
case KTX_UNSIGNED_BYTE_3_3_2:
case KTX_UNSIGNED_BYTE_2_3_3_REV:
case KTX_UNSIGNED_SHORT_5_6_5:
case KTX_UNSIGNED_SHORT_5_6_5_REV:
case KTX_UNSIGNED_SHORT_4_4_4_4:
case KTX_UNSIGNED_SHORT_4_4_4_4_REV:
case KTX_UNSIGNED_SHORT_5_5_5_1:
case KTX_UNSIGNED_SHORT_1_5_5_5_REV:
case KTX_UNSIGNED_INT_8_8_8_8:
case KTX_UNSIGNED_INT_8_8_8_8_REV:
case KTX_UNSIGNED_INT_10_10_10_2:
case KTX_UNSIGNED_INT_2_10_10_10_REV:
case KTX_UNSIGNED_INT_24_8:
case KTX_UNSIGNED_INT_10F_11F_11F_REV:
case KTX_UNSIGNED_INT_5_9_9_9_REV:
return true;
}
return false;
}
uint get_ogl_type_size(uint32 ogl_type) {
switch (ogl_type) {
case KTX_UNSIGNED_BYTE:
case KTX_BYTE:
return 1;
case KTX_HALF_FLOAT:
case KTX_UNSIGNED_SHORT:
case KTX_SHORT:
return 2;
case KTX_FLOAT:
case KTX_UNSIGNED_INT:
case KTX_INT:
return 4;
case KTX_UNSIGNED_BYTE_3_3_2:
case KTX_UNSIGNED_BYTE_2_3_3_REV:
return 1;
case KTX_UNSIGNED_SHORT_5_6_5:
case KTX_UNSIGNED_SHORT_5_6_5_REV:
case KTX_UNSIGNED_SHORT_4_4_4_4:
case KTX_UNSIGNED_SHORT_4_4_4_4_REV:
case KTX_UNSIGNED_SHORT_5_5_5_1:
case KTX_UNSIGNED_SHORT_1_5_5_5_REV:
return 2;
case KTX_UNSIGNED_INT_8_8_8_8:
case KTX_UNSIGNED_INT_8_8_8_8_REV:
case KTX_UNSIGNED_INT_10_10_10_2:
case KTX_UNSIGNED_INT_2_10_10_10_REV:
case KTX_UNSIGNED_INT_24_8:
case KTX_UNSIGNED_INT_10F_11F_11F_REV:
case KTX_UNSIGNED_INT_5_9_9_9_REV:
return 4;
}
return 0;
}
uint32 get_ogl_base_internal_fmt(uint32 ogl_fmt) {
switch (ogl_fmt) {
case KTX_ETC1_RGB8_OES:
case KTX_COMPRESSED_RGB8_ETC2:
case KTX_RGB_S3TC:
case KTX_RGB4_S3TC:
case KTX_COMPRESSED_RGB_S3TC_DXT1_EXT:
case KTX_COMPRESSED_SRGB_S3TC_DXT1_EXT:
return KTX_RGB;
case KTX_COMPRESSED_RGBA8_ETC2_EAC:
case KTX_COMPRESSED_RGBA_S3TC_DXT1_EXT:
case KTX_COMPRESSED_SRGB_ALPHA_S3TC_DXT1_EXT:
case KTX_RGBA_S3TC:
case KTX_RGBA4_S3TC:
case KTX_COMPRESSED_RGBA_S3TC_DXT3_EXT:
case KTX_COMPRESSED_SRGB_ALPHA_S3TC_DXT3_EXT:
case KTX_COMPRESSED_RGBA_S3TC_DXT5_EXT:
case KTX_COMPRESSED_SRGB_ALPHA_S3TC_DXT5_EXT:
case KTX_RGBA_DXT5_S3TC:
case KTX_RGBA4_DXT5_S3TC:
return KTX_RGBA;
case 1:
case KTX_RED:
case KTX_RED_INTEGER:
case KTX_GREEN:
case KTX_GREEN_INTEGER:
case KTX_BLUE:
case KTX_BLUE_INTEGER:
case KTX_R8:
case KTX_R8UI:
case KTX_LUMINANCE8:
case KTX_ALPHA:
case KTX_LUMINANCE:
case KTX_COMPRESSED_RED_RGTC1_EXT:
case KTX_COMPRESSED_SIGNED_RED_RGTC1_EXT:
case KTX_COMPRESSED_LUMINANCE_LATC1_EXT:
case KTX_COMPRESSED_SIGNED_LUMINANCE_LATC1_EXT:
return KTX_RED;
case 2:
case KTX_RG:
case KTX_RG8:
case KTX_RG_INTEGER:
case KTX_LUMINANCE_ALPHA:
case KTX_COMPRESSED_RED_GREEN_RGTC2_EXT:
case KTX_COMPRESSED_SIGNED_RED_GREEN_RGTC2_EXT:
case KTX_COMPRESSED_LUMINANCE_ALPHA_LATC2_EXT:
case KTX_COMPRESSED_SIGNED_LUMINANCE_ALPHA_LATC2_EXT:
return KTX_RG;
case 3:
case KTX_SRGB:
case KTX_RGB:
case KTX_RGB_INTEGER:
case KTX_BGR:
case KTX_BGR_INTEGER:
case KTX_RGB8:
case KTX_SRGB8:
return KTX_RGB;
case 4:
case KTX_RGBA:
case KTX_BGRA:
case KTX_RGBA_INTEGER:
case KTX_BGRA_INTEGER:
case KTX_SRGB_ALPHA:
case KTX_SRGB8_ALPHA8:
case KTX_RGBA8:
return KTX_RGBA;
}
return 0;
}
bool get_ogl_fmt_desc(uint32 ogl_fmt, uint32 ogl_type, uint& block_dim, uint& bytes_per_block) {
uint ogl_type_size = get_ogl_type_size(ogl_type);
block_dim = 1;
bytes_per_block = 0;
switch (ogl_fmt) {
case KTX_COMPRESSED_RED_RGTC1_EXT:
case KTX_COMPRESSED_SIGNED_RED_RGTC1_EXT:
case KTX_COMPRESSED_LUMINANCE_LATC1_EXT:
case KTX_COMPRESSED_SIGNED_LUMINANCE_LATC1_EXT:
case KTX_ETC1_RGB8_OES:
case KTX_COMPRESSED_RGB8_ETC2:
case KTX_RGB_S3TC:
case KTX_RGB4_S3TC:
case KTX_COMPRESSED_RGB_S3TC_DXT1_EXT:
case KTX_COMPRESSED_RGBA_S3TC_DXT1_EXT:
case KTX_COMPRESSED_SRGB_S3TC_DXT1_EXT:
case KTX_COMPRESSED_SRGB_ALPHA_S3TC_DXT1_EXT: {
block_dim = 4;
bytes_per_block = 8;
break;
}
case KTX_COMPRESSED_RGBA8_ETC2_EAC:
case KTX_COMPRESSED_LUMINANCE_ALPHA_LATC2_EXT:
case KTX_COMPRESSED_SIGNED_LUMINANCE_ALPHA_LATC2_EXT:
case KTX_COMPRESSED_RED_GREEN_RGTC2_EXT:
case KTX_COMPRESSED_SIGNED_RED_GREEN_RGTC2_EXT:
case KTX_RGBA_S3TC:
case KTX_RGBA4_S3TC:
case KTX_COMPRESSED_RGBA_S3TC_DXT3_EXT:
case KTX_COMPRESSED_SRGB_ALPHA_S3TC_DXT3_EXT:
case KTX_COMPRESSED_RGBA_S3TC_DXT5_EXT:
case KTX_COMPRESSED_SRGB_ALPHA_S3TC_DXT5_EXT:
case KTX_RGBA_DXT5_S3TC:
case KTX_RGBA4_DXT5_S3TC: {
block_dim = 4;
bytes_per_block = 16;
break;
}
case 1:
case KTX_ALPHA:
case KTX_RED:
case KTX_GREEN:
case KTX_BLUE:
case KTX_RED_INTEGER:
case KTX_GREEN_INTEGER:
case KTX_BLUE_INTEGER:
case KTX_LUMINANCE: {
bytes_per_block = ogl_type_size;
break;
}
case KTX_R8:
case KTX_R8UI:
case KTX_ALPHA8:
case KTX_LUMINANCE8: {
bytes_per_block = 1;
break;
}
case 2:
case KTX_RG:
case KTX_RG_INTEGER:
case KTX_LUMINANCE_ALPHA: {
bytes_per_block = 2 * ogl_type_size;
break;
}
case KTX_RG8:
case KTX_LUMINANCE8_ALPHA8: {
bytes_per_block = 2;
break;
}
case 3:
case KTX_SRGB:
case KTX_RGB:
case KTX_BGR:
case KTX_RGB_INTEGER:
case KTX_BGR_INTEGER: {
bytes_per_block = is_packed_pixel_ogl_type(ogl_type) ? ogl_type_size : (3 * ogl_type_size);
break;
}
case KTX_RGB8:
case KTX_SRGB8: {
bytes_per_block = 3;
break;
}
case 4:
case KTX_RGBA:
case KTX_BGRA:
case KTX_RGBA_INTEGER:
case KTX_BGRA_INTEGER:
case KTX_SRGB_ALPHA: {
bytes_per_block = is_packed_pixel_ogl_type(ogl_type) ? ogl_type_size : (4 * ogl_type_size);
break;
}
case KTX_SRGB8_ALPHA8:
case KTX_RGBA8: {
bytes_per_block = 4;
break;
}
default:
return false;
}
return true;
}
bool ktx_texture::compute_pixel_info() {
if ((!m_header.m_glType) || (!m_header.m_glFormat)) {
if ((m_header.m_glType) || (m_header.m_glFormat))
return false;
// Must be a compressed format.
if (!get_ogl_fmt_desc(m_header.m_glInternalFormat, m_header.m_glType, m_block_dim, m_bytes_per_block)) {
#if CRNLIB_KTX_PVRTEX_WORKAROUNDS
if ((!m_header.m_glInternalFormat) && (!m_header.m_glType) && (!m_header.m_glTypeSize) && (!m_header.m_glBaseInternalFormat)) {
// PVRTexTool writes bogus headers when outputting ETC1.
console::warning("ktx_texture::compute_pixel_info: Header doesn't specify any format, assuming ETC1 and hoping for the best");
m_header.m_glBaseInternalFormat = KTX_RGB;
m_header.m_glInternalFormat = KTX_ETC1_RGB8_OES;
m_header.m_glTypeSize = 1;
m_block_dim = 4;
m_bytes_per_block = 8;
return true;
}
#endif
return false;
}
if (m_block_dim == 1)
return false;
} else {
// Must be an uncompressed format.
if (!get_ogl_fmt_desc(m_header.m_glFormat, m_header.m_glType, m_block_dim, m_bytes_per_block))
return false;
if (m_block_dim > 1)
return false;
}
return true;
}
bool ktx_texture::read_from_stream(data_stream_serializer& serializer) {
clear();
// Read header
if (serializer.read(&m_header, 1, sizeof(m_header)) != sizeof(ktx_header))
return false;
// Check header
if (memcmp(s_ktx_file_id, m_header.m_identifier, sizeof(m_header.m_identifier)))
return false;
if ((m_header.m_endianness != KTX_OPPOSITE_ENDIAN) && (m_header.m_endianness != KTX_ENDIAN))
return false;
m_opposite_endianness = (m_header.m_endianness == KTX_OPPOSITE_ENDIAN);
if (m_opposite_endianness) {
m_header.endian_swap();
if ((m_header.m_glTypeSize != sizeof(uint8)) && (m_header.m_glTypeSize != sizeof(uint16)) && (m_header.m_glTypeSize != sizeof(uint32)))
return false;
}
if (!check_header())
return false;
if (!compute_pixel_info())
return false;
uint8 pad_bytes[3];
// Read the key value entries
uint num_key_value_bytes_remaining = m_header.m_bytesOfKeyValueData;
while (num_key_value_bytes_remaining) {
if (num_key_value_bytes_remaining < sizeof(uint32))
return false;
uint32 key_value_byte_size;
if (serializer.read(&key_value_byte_size, 1, sizeof(uint32)) != sizeof(uint32))
return false;
num_key_value_bytes_remaining -= sizeof(uint32);
if (m_opposite_endianness)
key_value_byte_size = utils::swap32(key_value_byte_size);
if (key_value_byte_size > num_key_value_bytes_remaining)
return false;
uint8_vec key_value_data;
if (key_value_byte_size) {
key_value_data.resize(key_value_byte_size);
if (serializer.read(&key_value_data[0], 1, key_value_byte_size) != key_value_byte_size)
return false;
}
m_key_values.push_back(key_value_data);
uint padding = 3 - ((key_value_byte_size + 3) % 4);
if (padding) {
if (serializer.read(pad_bytes, 1, padding) != padding)
return false;
}
num_key_value_bytes_remaining -= key_value_byte_size;
if (num_key_value_bytes_remaining < padding)
return false;
num_key_value_bytes_remaining -= padding;
}
// Now read the mip levels
uint total_faces = get_num_mips() * get_array_size() * get_num_faces() * get_depth();
if ((!total_faces) || (total_faces > 65535))
return false;
// See Section 2.8 of KTX file format: No rounding to block sizes should be applied for block compressed textures.
// OK, I'm going to break that rule otherwise KTX can only store a subset of textures that DDS can handle for no good reason.
#if 0
const uint mip0_row_blocks = m_header.m_pixelWidth / m_block_dim;
const uint mip0_col_blocks = CRNLIB_MAX(1, m_header.m_pixelHeight) / m_block_dim;
#else
const uint mip0_row_blocks = (m_header.m_pixelWidth + m_block_dim - 1) / m_block_dim;
const uint mip0_col_blocks = (CRNLIB_MAX(1, m_header.m_pixelHeight) + m_block_dim - 1) / m_block_dim;
#endif
if ((!mip0_row_blocks) || (!mip0_col_blocks))
return false;
bool has_valid_image_size_fields = true;
bool disable_mip_and_cubemap_padding = false;
#if CRNLIB_KTX_PVRTEX_WORKAROUNDS
{
// PVRTexTool has a bogus KTX writer that doesn't write any imageSize fields. Nice.
size_t expected_bytes_remaining = 0;
for (uint mip_level = 0; mip_level < get_num_mips(); mip_level++) {
uint mip_width, mip_height, mip_depth;
get_mip_dim(mip_level, mip_width, mip_height, mip_depth);
const uint mip_row_blocks = (mip_width + m_block_dim - 1) / m_block_dim;
const uint mip_col_blocks = (mip_height + m_block_dim - 1) / m_block_dim;
if ((!mip_row_blocks) || (!mip_col_blocks))
return false;
expected_bytes_remaining += sizeof(uint32);
if ((!m_header.m_numberOfArrayElements) && (get_num_faces() == 6)) {
for (uint face = 0; face < get_num_faces(); face++) {
uint slice_size = mip_row_blocks * mip_col_blocks * m_bytes_per_block;
expected_bytes_remaining += slice_size;
uint num_cube_pad_bytes = 3 - ((slice_size + 3) % 4);
expected_bytes_remaining += num_cube_pad_bytes;
}
} else {
uint total_mip_size = 0;
for (uint array_element = 0; array_element < get_array_size(); array_element++) {
for (uint face = 0; face < get_num_faces(); face++) {
for (uint zslice = 0; zslice < mip_depth; zslice++) {
uint slice_size = mip_row_blocks * mip_col_blocks * m_bytes_per_block;
total_mip_size += slice_size;
}
}
}
expected_bytes_remaining += total_mip_size;
uint num_mip_pad_bytes = 3 - ((total_mip_size + 3) % 4);
expected_bytes_remaining += num_mip_pad_bytes;
}
}
if (serializer.get_stream()->get_remaining() < expected_bytes_remaining) {
has_valid_image_size_fields = false;
disable_mip_and_cubemap_padding = true;
console::warning("ktx_texture::read_from_stream: KTX file size is smaller than expected - trying to read anyway without imageSize fields");
}
}
#endif
for (uint mip_level = 0; mip_level < get_num_mips(); mip_level++) {
uint mip_width, mip_height, mip_depth;
get_mip_dim(mip_level, mip_width, mip_height, mip_depth);
const uint mip_row_blocks = (mip_width + m_block_dim - 1) / m_block_dim;
const uint mip_col_blocks = (mip_height + m_block_dim - 1) / m_block_dim;
if ((!mip_row_blocks) || (!mip_col_blocks))
return false;
uint32 image_size = 0;
if (!has_valid_image_size_fields)
image_size = mip_depth * mip_row_blocks * mip_col_blocks * m_bytes_per_block * get_array_size() * get_num_faces();
else {
if (serializer.read(&image_size, 1, sizeof(image_size)) != sizeof(image_size))
return false;
if (m_opposite_endianness)
image_size = utils::swap32(image_size);
}
if (!image_size)
return false;
uint total_mip_size = 0;
if ((!m_header.m_numberOfArrayElements) && (get_num_faces() == 6)) {
// plain non-array cubemap
for (uint face = 0; face < get_num_faces(); face++) {
CRNLIB_ASSERT(m_image_data.size() == get_image_index(mip_level, 0, face, 0));
m_image_data.push_back(uint8_vec());
uint8_vec& image_data = m_image_data.back();
image_data.resize(image_size);
if (serializer.read(&image_data[0], 1, image_size) != image_size)
return false;
if (m_opposite_endianness)
utils::endian_swap_mem(&image_data[0], image_size, m_header.m_glTypeSize);
uint num_cube_pad_bytes = disable_mip_and_cubemap_padding ? 0 : (3 - ((image_size + 3) % 4));
if (serializer.read(pad_bytes, 1, num_cube_pad_bytes) != num_cube_pad_bytes)
return false;
total_mip_size += image_size + num_cube_pad_bytes;
}
} else {
// 1D, 2D, 3D (normal or array texture), or array cubemap
uint num_image_bytes_remaining = image_size;
for (uint array_element = 0; array_element < get_array_size(); array_element++) {
for (uint face = 0; face < get_num_faces(); face++) {
for (uint zslice = 0; zslice < mip_depth; zslice++) {
CRNLIB_ASSERT(m_image_data.size() == get_image_index(mip_level, array_element, face, zslice));
uint slice_size = mip_row_blocks * mip_col_blocks * m_bytes_per_block;
if ((!slice_size) || (slice_size > num_image_bytes_remaining))
return false;
m_image_data.push_back(uint8_vec());
uint8_vec& image_data = m_image_data.back();
image_data.resize(slice_size);
if (serializer.read(&image_data[0], 1, slice_size) != slice_size)
return false;
if (m_opposite_endianness)
utils::endian_swap_mem(&image_data[0], slice_size, m_header.m_glTypeSize);
num_image_bytes_remaining -= slice_size;
total_mip_size += slice_size;
}
}
}
if (num_image_bytes_remaining)
return false;
}
uint num_mip_pad_bytes = disable_mip_and_cubemap_padding ? 0 : (3 - ((total_mip_size + 3) % 4));
if (serializer.read(pad_bytes, 1, num_mip_pad_bytes) != num_mip_pad_bytes)
return false;
}
return true;
}
bool ktx_texture::write_to_stream(data_stream_serializer& serializer, bool no_keyvalue_data) {
if (!consistency_check()) {
CRNLIB_ASSERT(0);
return false;
}
memcpy(m_header.m_identifier, s_ktx_file_id, sizeof(m_header.m_identifier));
m_header.m_endianness = m_opposite_endianness ? KTX_OPPOSITE_ENDIAN : KTX_ENDIAN;
if (m_block_dim == 1) {
m_header.m_glTypeSize = get_ogl_type_size(m_header.m_glType);
m_header.m_glBaseInternalFormat = m_header.m_glFormat;
} else {
m_header.m_glBaseInternalFormat = get_ogl_base_internal_fmt(m_header.m_glInternalFormat);
}
m_header.m_bytesOfKeyValueData = 0;
if (!no_keyvalue_data) {
for (uint i = 0; i < m_key_values.size(); i++)
m_header.m_bytesOfKeyValueData += sizeof(uint32) + ((m_key_values[i].size() + 3) & ~3);
}
if (m_opposite_endianness)
m_header.endian_swap();
bool success = (serializer.write(&m_header, sizeof(m_header), 1) == 1);
if (m_opposite_endianness)
m_header.endian_swap();
if (!success)
return success;
uint total_key_value_bytes = 0;
const uint8 padding[3] = {0, 0, 0};
if (!no_keyvalue_data) {
for (uint i = 0; i < m_key_values.size(); i++) {
uint32 key_value_size = m_key_values[i].size();
if (m_opposite_endianness)
key_value_size = utils::swap32(key_value_size);
success = (serializer.write(&key_value_size, sizeof(key_value_size), 1) == 1);
total_key_value_bytes += sizeof(key_value_size);
if (m_opposite_endianness)
key_value_size = utils::swap32(key_value_size);
if (!success)
return false;
if (key_value_size) {
if (serializer.write(&m_key_values[i][0], key_value_size, 1) != 1)
return false;
total_key_value_bytes += key_value_size;
uint num_padding = 3 - ((key_value_size + 3) % 4);
if ((num_padding) && (serializer.write(padding, num_padding, 1) != 1))
return false;
total_key_value_bytes += num_padding;
}
}
(void)total_key_value_bytes;
}
CRNLIB_ASSERT(total_key_value_bytes == m_header.m_bytesOfKeyValueData);
for (uint mip_level = 0; mip_level < get_num_mips(); mip_level++) {
uint mip_width, mip_height, mip_depth;
get_mip_dim(mip_level, mip_width, mip_height, mip_depth);
const uint mip_row_blocks = (mip_width + m_block_dim - 1) / m_block_dim;
const uint mip_col_blocks = (mip_height + m_block_dim - 1) / m_block_dim;
if ((!mip_row_blocks) || (!mip_col_blocks))
return false;
uint32 image_size = mip_row_blocks * mip_col_blocks * m_bytes_per_block;
if ((m_header.m_numberOfArrayElements) || (get_num_faces() == 1))
image_size *= (get_array_size() * get_num_faces() * get_depth());
if (!image_size)
return false;
if (m_opposite_endianness)
image_size = utils::swap32(image_size);
success = (serializer.write(&image_size, sizeof(image_size), 1) == 1);
if (m_opposite_endianness)
image_size = utils::swap32(image_size);
if (!success)
return false;
uint total_mip_size = 0;
if ((!m_header.m_numberOfArrayElements) && (get_num_faces() == 6)) {
// plain non-array cubemap
for (uint face = 0; face < get_num_faces(); face++) {
const uint8_vec& image_data = get_image_data(get_image_index(mip_level, 0, face, 0));
if ((!image_data.size()) || (image_data.size() != image_size))
return false;
if (m_opposite_endianness) {
uint8_vec tmp_image_data(image_data);
utils::endian_swap_mem(&tmp_image_data[0], tmp_image_data.size(), m_header.m_glTypeSize);
if (serializer.write(&tmp_image_data[0], tmp_image_data.size(), 1) != 1)
return false;
} else if (serializer.write(&image_data[0], image_data.size(), 1) != 1)
return false;
uint num_cube_pad_bytes = 3 - ((image_data.size() + 3) % 4);
if ((num_cube_pad_bytes) && (serializer.write(padding, num_cube_pad_bytes, 1) != 1))
return false;
total_mip_size += image_size + num_cube_pad_bytes;
}
} else {
// 1D, 2D, 3D (normal or array texture), or array cubemap
for (uint array_element = 0; array_element < get_array_size(); array_element++) {
for (uint face = 0; face < get_num_faces(); face++) {
for (uint zslice = 0; zslice < mip_depth; zslice++) {
const uint8_vec& image_data = get_image_data(get_image_index(mip_level, array_element, face, zslice));
if (!image_data.size())
return false;
if (m_opposite_endianness) {
uint8_vec tmp_image_data(image_data);
utils::endian_swap_mem(&tmp_image_data[0], tmp_image_data.size(), m_header.m_glTypeSize);
if (serializer.write(&tmp_image_data[0], tmp_image_data.size(), 1) != 1)
return false;
} else if (serializer.write(&image_data[0], image_data.size(), 1) != 1)
return false;
total_mip_size += image_data.size();
}
}
}
uint num_mip_pad_bytes = 3 - ((total_mip_size + 3) % 4);
if ((num_mip_pad_bytes) && (serializer.write(padding, num_mip_pad_bytes, 1) != 1))
return false;
total_mip_size += num_mip_pad_bytes;
}
CRNLIB_ASSERT((total_mip_size & 3) == 0);
}
return true;
}
bool ktx_texture::init_2D(uint width, uint height, uint num_mips, uint32 ogl_internal_fmt, uint32 ogl_fmt, uint32 ogl_type) {
clear();
m_header.m_pixelWidth = width;
m_header.m_pixelHeight = height;
m_header.m_numberOfMipmapLevels = num_mips;
m_header.m_glInternalFormat = ogl_internal_fmt;
m_header.m_glFormat = ogl_fmt;
m_header.m_glType = ogl_type;
m_header.m_numberOfFaces = 1;
if (!compute_pixel_info())
return false;
return true;
}
bool ktx_texture::init_2D_array(uint width, uint height, uint num_mips, uint array_size, uint32 ogl_internal_fmt, uint32 ogl_fmt, uint32 ogl_type) {
clear();
m_header.m_pixelWidth = width;
m_header.m_pixelHeight = height;
m_header.m_numberOfMipmapLevels = num_mips;
m_header.m_numberOfArrayElements = array_size;
m_header.m_glInternalFormat = ogl_internal_fmt;
m_header.m_glFormat = ogl_fmt;
m_header.m_glType = ogl_type;
m_header.m_numberOfFaces = 1;
if (!compute_pixel_info())
return false;
return true;
}
bool ktx_texture::init_3D(uint width, uint height, uint depth, uint num_mips, uint32 ogl_internal_fmt, uint32 ogl_fmt, uint32 ogl_type) {
clear();
m_header.m_pixelWidth = width;
m_header.m_pixelHeight = height;
m_header.m_pixelDepth = depth;
m_header.m_numberOfMipmapLevels = num_mips;
m_header.m_glInternalFormat = ogl_internal_fmt;
m_header.m_glFormat = ogl_fmt;
m_header.m_glType = ogl_type;
m_header.m_numberOfFaces = 1;
if (!compute_pixel_info())
return false;
return true;
}
bool ktx_texture::init_cubemap(uint dim, uint num_mips, uint32 ogl_internal_fmt, uint32 ogl_fmt, uint32 ogl_type) {
clear();
m_header.m_pixelWidth = dim;
m_header.m_pixelHeight = dim;
m_header.m_numberOfMipmapLevels = num_mips;
m_header.m_glInternalFormat = ogl_internal_fmt;
m_header.m_glFormat = ogl_fmt;
m_header.m_glType = ogl_type;
m_header.m_numberOfFaces = 6;
if (!compute_pixel_info())
return false;
return true;
}
bool ktx_texture::check_header() const {
if (((get_num_faces() != 1) && (get_num_faces() != 6)) || (!m_header.m_pixelWidth))
return false;
if ((!m_header.m_pixelHeight) && (m_header.m_pixelDepth))
return false;
if ((get_num_faces() == 6) && ((m_header.m_pixelDepth) || (!m_header.m_pixelHeight)))
return false;
if (m_header.m_numberOfMipmapLevels) {
const uint max_mipmap_dimension = 1U << (m_header.m_numberOfMipmapLevels - 1U);
if (max_mipmap_dimension > (CRNLIB_MAX(CRNLIB_MAX(m_header.m_pixelWidth, m_header.m_pixelHeight), m_header.m_pixelDepth)))
return false;
}
return true;
}
bool ktx_texture::consistency_check() const {
if (!check_header())
return false;
uint block_dim = 0, bytes_per_block = 0;
if ((!m_header.m_glType) || (!m_header.m_glFormat)) {
if ((m_header.m_glType) || (m_header.m_glFormat))
return false;
if (!get_ogl_fmt_desc(m_header.m_glInternalFormat, m_header.m_glType, block_dim, bytes_per_block))
return false;
if (block_dim == 1)
return false;
//if ((get_width() % block_dim) || (get_height() % block_dim))
// return false;
} else {
if (!get_ogl_fmt_desc(m_header.m_glFormat, m_header.m_glType, block_dim, bytes_per_block))
return false;
if (block_dim > 1)
return false;
}
if ((m_block_dim != block_dim) || (m_bytes_per_block != bytes_per_block))
return false;
if (m_image_data.size() != get_total_images())
return false;
for (uint mip_level = 0; mip_level < get_num_mips(); mip_level++) {
uint mip_width, mip_height, mip_depth;
get_mip_dim(mip_level, mip_width, mip_height, mip_depth);
const uint mip_row_blocks = (mip_width + m_block_dim - 1) / m_block_dim;
const uint mip_col_blocks = (mip_height + m_block_dim - 1) / m_block_dim;
if ((!mip_row_blocks) || (!mip_col_blocks))
return false;
for (uint array_element = 0; array_element < get_array_size(); array_element++) {
for (uint face = 0; face < get_num_faces(); face++) {
for (uint zslice = 0; zslice < mip_depth; zslice++) {
const uint8_vec& image_data = get_image_data(get_image_index(mip_level, array_element, face, zslice));
uint expected_image_size = mip_row_blocks * mip_col_blocks * m_bytes_per_block;
if (image_data.size() != expected_image_size)
return false;
}
}
}
}
return true;
}
const uint8_vec* ktx_texture::find_key(const char* pKey) const {
const size_t n = strlen(pKey) + 1;
for (uint i = 0; i < m_key_values.size(); i++) {
const uint8_vec& v = m_key_values[i];
if ((v.size() >= n) && (!memcmp(&v[0], pKey, n)))
return &v;
}
return NULL;
}
bool ktx_texture::get_key_value_as_string(const char* pKey, dynamic_string& str) const {
const uint8_vec* p = find_key(pKey);
if (!p) {
str.clear();
return false;
}
const uint ofs = (static_cast<uint>(strlen(pKey)) + 1);
const uint8* pValue = p->get_ptr() + ofs;
const uint n = p->size() - ofs;
uint i;
for (i = 0; i < n; i++)
if (!pValue[i])
break;
str.set_from_buf(pValue, i);
return true;
}
uint ktx_texture::add_key_value(const char* pKey, const void* pVal, uint val_size) {
const uint idx = m_key_values.size();
m_key_values.resize(idx + 1);
uint8_vec& v = m_key_values.back();
v.append(reinterpret_cast<const uint8*>(pKey), static_cast<uint>(strlen(pKey)) + 1);
v.append(static_cast<const uint8*>(pVal), val_size);
return idx;
}
} // namespace crnlib
-291
View File
@@ -1,291 +0,0 @@
// File: crn_ktx_texture.h
#ifndef _KTX_TEXTURE_H_
#define _KTX_TEXTURE_H_
#ifdef _MSC_VER
#pragma once
#endif
#include "crn_data_stream_serializer.h"
#define KTX_ENDIAN 0x04030201
#define KTX_OPPOSITE_ENDIAN 0x01020304
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;
void clear() {
memset(this, 0, sizeof(*this));
}
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;
// Compressed pixel data formats: ETC1, DXT1, DXT3, DXT5
enum {
KTX_ETC1_RGB8_OES = 0x8D64,
KTX_COMPRESSED_RGB8_ETC2 = 0x9274,
KTX_COMPRESSED_RGBA8_ETC2_EAC = 0x9278,
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 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);
class ktx_texture {
public:
ktx_texture() {
clear();
}
ktx_texture(const ktx_texture& other) {
*this = other;
}
ktx_texture& operator=(const ktx_texture& rhs) {
if (this == &rhs)
return *this;
clear();
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;
return *this;
}
void clear() {
m_header.clear();
m_key_values.clear();
m_image_data.clear();
m_block_dim = 0;
m_bytes_per_block = 0;
m_opposite_endianness = false;
}
// 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);
bool check_header() const;
bool consistency_check() const;
// General info
bool is_valid() const { return (m_header.m_pixelWidth > 0) && (m_image_data.size() > 0); }
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; }
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()); }
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; }
uint32 get_block_dim() const { return m_block_dim; }
uint32 get_bytes_per_block() const { return m_bytes_per_block; }
const ktx_header& get_header() const { return m_header; }
// 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; }
const uint8_vec* find_key(const char* pKey) const;
bool get_key_value_as_string(const char* pKey, dynamic_string& str) const;
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); }
// Image data
uint get_num_images() const { return m_image_data.size(); }
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 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_
+106 -101
View File
@@ -4,129 +4,134 @@
#include "crn_lzma_codec.h" #include "crn_lzma_codec.h"
#include "crn_strutils.h" #include "crn_strutils.h"
#include "crn_checksum.h" #include "crn_checksum.h"
#include "lzma_LzmaLib.h" #include "lzma_lzmalib.h"
#include "crn_threading.h"
namespace crnlib { namespace crnlib
lzma_codec::lzma_codec() {
: m_pCompress(LzmaCompress), lzma_codec::lzma_codec() :
m_pUncompress(LzmaUncompress) { m_pCompress(LzmaCompress),
CRNLIB_ASSUME(cLZMAPropsSize == LZMA_PROPS_SIZE); 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) { bool lzma_codec::pack(const void* p, uint n, crnlib::vector<uint8>& buf)
if (n > 1024U * 1024U * 1024U) {
return false; if (n > 1024U*1024U*1024U)
return false;
uint max_comp_size = n + math::maximum<uint>(128, n >> 8); 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)];
utils::zero_object(*pHDR);
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;
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 */
#ifdef WIN32
(g_number_of_processors > 1) ? 2 : 1
#else
1
#endif
);
if (status != SZ_ERROR_OUTPUT_EOF)
break;
max_comp_size += ((n + 1) / 2);
buf.resize(sizeof(header) + max_comp_size); buf.resize(sizeof(header) + max_comp_size);
pHDR = reinterpret_cast<header*>(&buf[0]);
pComp_data = &buf[sizeof(header)];
}
if (status != SZ_OK) { header* pHDR = reinterpret_cast<header*>(&buf[0]);
buf.clear(); uint8* pComp_data = &buf[sizeof(header)];
return false;
}
pHDR->m_comp_size = static_cast<uint>(destLen); utils::zero_object(*pHDR);
buf.resize(CRNLIB_SIZEOF_U32(header) + static_cast<uint32>(destLen)); pHDR->m_uncomp_size = n;
} pHDR->m_adler32 = adler32(p, n);
pHDR->m_sig = header::cSig; if (n)
pHDR->m_checksum = static_cast<uint8>(adler32((uint8*)pHDR + header::cChecksumSkipBytes, sizeof(header) - header::cChecksumSkipBytes)); {
size_t destLen = 0;
size_t outPropsSize = 0;
int status = SZ_ERROR_INPUT_EOF;
return true; for (uint trial = 0; trial < 3; trial++)
} {
destLen = max_comp_size;
outPropsSize = cLZMAPropsSize;
bool lzma_codec::unpack(const void* p, uint n, crnlib::vector<uint8>& buf) { status = (*m_pCompress)(pComp_data, &destLen, reinterpret_cast<const unsigned char*>(p), n,
buf.resize(0); 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 */
(g_number_of_processors > 1) ? 2 : 1
);
if (n < sizeof(header)) if (status != SZ_ERROR_OUTPUT_EOF)
return false; break;
const header& hdr = *static_cast<const header*>(p); max_comp_size += ((n+1)/2);
if (hdr.m_sig != header::cSig) buf.resize(sizeof(header) + max_comp_size);
return false; pHDR = reinterpret_cast<header*>(&buf[0]);
pComp_data = &buf[sizeof(header)];
}
if (static_cast<uint8>(adler32((const uint8*)&hdr + header::cChecksumSkipBytes, sizeof(hdr) - header::cChecksumSkipBytes)) != hdr.m_checksum) if (status != SZ_OK)
return false; {
buf.clear();
return false;
}
if (!hdr.m_uncomp_size) pHDR->m_comp_size = static_cast<uint>(destLen);
return true;
if (!hdr.m_comp_size) buf.resize(CRNLIB_SIZEOF_U32(header) + static_cast<uint32>(destLen));
return false; }
if (hdr.m_uncomp_size > 1024U * 1024U * 1024U) pHDR->m_sig = header::cSig;
return false; pHDR->m_checksum = static_cast<uint8>(adler32((uint8*)pHDR + header::cChecksumSkipBytes, sizeof(header) - header::cChecksumSkipBytes));
if (!buf.try_resize(hdr.m_uncomp_size)) return true;
return false; }
const uint8* pComp_data = static_cast<const uint8*>(p) + sizeof(header); bool lzma_codec::unpack(const void* p, uint n, crnlib::vector<uint8>& buf)
size_t srcLen = n - sizeof(header); {
if (srcLen < hdr.m_comp_size) buf.resize(0);
return false;
size_t destLen = hdr.m_uncomp_size; if (n < sizeof(header))
return false;
int status = (*m_pUncompress)(&buf[0], &destLen, pComp_data, &srcLen, const header& hdr = *static_cast<const header*>(p);
hdr.m_lzma_props, cLZMAPropsSize); if (hdr.m_sig != header::cSig)
return false;
if ((status != SZ_OK) || (destLen != hdr.m_uncomp_size)) { if (static_cast<uint8>(adler32((const uint8*)&hdr + header::cChecksumSkipBytes, sizeof(hdr) - header::cChecksumSkipBytes)) != hdr.m_checksum)
buf.clear(); return false;
return false;
}
if (adler32(&buf[0], buf.size()) != hdr.m_adler32) { if (!hdr.m_uncomp_size)
buf.clear(); return true;
return false;
}
return true; if (!hdr.m_comp_size)
} return false;
} // namespace crnlib if (hdr.m_uncomp_size > 1024U*1024U*1024U)
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;
size_t destLen = hdr.m_uncomp_size;
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 (adler32(&buf[0], buf.size()) != hdr.m_adler32)
{
buf.clear();
return false;
}
return true;
}
} // namespace crnlib
+40 -37
View File
@@ -3,55 +3,58 @@
#pragma once #pragma once
#include "crn_packed_uint.h" #include "crn_packed_uint.h"
namespace crnlib { namespace crnlib
class lzma_codec { {
public: class lzma_codec
lzma_codec(); {
~lzma_codec(); public:
lzma_codec();
~lzma_codec();
// Always available, because we're statically linking in lzmalib now vs. dynamically loading the DLL. // Always available, because we're statically linking in lzmalib now vs. dynamically loading the DLL.
bool is_initialized() const { return true; } const 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: private:
typedef int(CRNLIB_STDCALL* LzmaCompressFuncPtr)(unsigned char* dest, size_t* destLen, const unsigned char* src, size_t srcLen, typedef int (__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 */ unsigned char *outProps, size_t *outPropsSize, /* *outPropsSize must be = 5 */
int level, /* 0 <= level <= 9, default = 5 */ int level, /* 0 <= level <= 9, default = 5 */
unsigned dictSize, /* default = (1 << 24) */ unsigned dictSize, /* default = (1 << 24) */
int lc, /* 0 <= lc <= 8, default = 3 */ int lc, /* 0 <= lc <= 8, default = 3 */
int lp, /* 0 <= lp <= 4, default = 0 */ int lp, /* 0 <= lp <= 4, default = 0 */
int pb, /* 0 <= pb <= 4, default = 2 */ int pb, /* 0 <= pb <= 4, default = 2 */
int fb, /* 5 <= fb <= 273, default = 32 */ int fb, /* 5 <= fb <= 273, default = 32 */
int numThreads /* 1 or 2, default = 2 */ 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, typedef int (__stdcall *LzmaUncompressFuncPtr)(unsigned char *dest, size_t *destLen, const unsigned char *src, size_t *srcLen,
const unsigned char* props, size_t propsSize); const unsigned char *props, size_t propsSize);
LzmaCompressFuncPtr m_pCompress; LzmaCompressFuncPtr m_pCompress;
LzmaUncompressFuncPtr m_pUncompress; LzmaUncompressFuncPtr m_pUncompress;
enum { cLZMAPropsSize = 5 }; enum { cLZMAPropsSize = 5 };
#pragma pack(push) #pragma pack(push)
#pragma pack(1) #pragma pack(1)
struct header { struct header
enum { cSig = 'L' | ('0' << 8), {
cChecksumSkipBytes = 3 }; enum { cSig = 'L' | ('0' << 8), cChecksumSkipBytes = 3 };
packed_uint<2> m_sig; packed_uint<2> m_sig;
uint8 m_checksum; uint8 m_checksum;
uint8 m_lzma_props[cLZMAPropsSize]; uint8 m_lzma_props[cLZMAPropsSize];
packed_uint<4> m_comp_size; packed_uint<4> m_comp_size;
packed_uint<4> m_uncomp_size; packed_uint<4> m_uncomp_size;
packed_uint<4> m_adler32; packed_uint<4> m_adler32;
}; };
#pragma pack(pop) #pragma pack(pop)
};
} // namespace crnlib };
} // namespace crnlib
+60 -51
View File
@@ -2,66 +2,75 @@
// See Copyright Notice and license at the end of inc/crnlib.h // See Copyright Notice and license at the end of inc/crnlib.h
#include "crn_core.h" #include "crn_core.h"
namespace crnlib { namespace crnlib
namespace math { {
uint g_bitmasks[32] = namespace math
{ {
1U << 0U, 1U << 1U, 1U << 2U, 1U << 3U, uint g_bitmasks[32] =
1U << 4U, 1U << 5U, 1U << 6U, 1U << 7U, {
1U << 8U, 1U << 9U, 1U << 10U, 1U << 11U, 1U << 0U, 1U << 1U, 1U << 2U, 1U << 3U,
1U << 12U, 1U << 13U, 1U << 14U, 1U << 15U, 1U << 4U, 1U << 5U, 1U << 6U, 1U << 7U,
1U << 16U, 1U << 17U, 1U << 18U, 1U << 19U, 1U << 8U, 1U << 9U, 1U << 10U, 1U << 11U,
1U << 20U, 1U << 21U, 1U << 22U, 1U << 23U, 1U << 12U, 1U << 13U, 1U << 14U, 1U << 15U,
1U << 24U, 1U << 25U, 1U << 26U, 1U << 27U, 1U << 16U, 1U << 17U, 1U << 18U, 1U << 19U,
1U << 28U, 1U << 29U, 1U << 30U, 1U << 31U}; 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) { double compute_entropy(const uint8* p, uint n)
uint hist[256]; {
utils::zero_object(hist); uint hist[256];
utils::zero_object(hist);
for (uint i = 0; i < n; i++) for (uint i = 0; i < n; i++)
hist[*p++]++; hist[*p++]++;
double entropy = 0.0f; double entropy = 0.0f;
const double invln2 = 1.0f / log(2.0f); const double invln2 = 1.0f/log(2.0f);
for (uint i = 0; i < 256; i++) { for (uint i = 0; i < 256; i++)
if (!hist[i]) {
continue; if (!hist[i])
continue;
double prob = static_cast<double>(hist[i]) / n; double prob = static_cast<double>(hist[i]) / n;
entropy += (-log(prob) * invln2) * hist[i]; entropy += (-log(prob) * invln2) * hist[i];
} }
return entropy; return entropy;
} }
void compute_lower_pow2_dim(int& width, int& height) { void compute_lower_pow2_dim(int& width, int& height)
const int tex_width = width; {
const int tex_height = height; const int tex_width = width;
const int tex_height = height;
width = 1; width = 1;
for (;;) { for ( ; ; )
if ((width * 2) > tex_width) {
break; if ((width * 2) > tex_width)
width *= 2; break;
} width *= 2;
}
height = 1; height = 1;
for (;;) { for ( ; ; )
if ((height * 2) > tex_height) {
break; if ((height * 2) > tex_height)
height *= 2; break;
} height *= 2;
} }
}
void compute_upper_pow2_dim(int& width, int& height) { 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)width))
width = math::next_pow2((uint32)width);
if (!math::is_power_of_2((uint32)height)) if (!math::is_power_of_2((uint32)height))
height = math::next_pow2((uint32)height); height = math::next_pow2((uint32)height);
} }
} // namespace math } // namespace math
} // namespace crnlib } // namespace crnlib
+168 -226
View File
@@ -3,278 +3,220 @@
#pragma once #pragma once
#if defined(_M_IX86) && defined(_MSC_VER) #if defined(_M_IX86) && defined(_MSC_VER)
#include <intrin.h> #include <intrin.h>
#pragma intrinsic(__emulu) #pragma intrinsic(__emulu)
unsigned __int64 __emulu(unsigned int a, unsigned int b); unsigned __int64 __emulu(unsigned int a,unsigned int b );
#endif #endif
namespace crnlib { namespace crnlib
namespace math { {
const float cNearlyInfinite = 1.0e+37f; namespace math
{
const float cNearlyInfinite = 1.0e+37f;
const float cDegToRad = 0.01745329252f; const float cDegToRad = 0.01745329252f;
const float cRadToDeg = 57.29577951f; const float cRadToDeg = 57.29577951f;
extern uint g_bitmasks[32]; extern uint g_bitmasks[32];
template <typename T> template<typename T> inline bool within_closed_range(T a, T b, T c) { return (a >= b) && (a <= c); }
inline bool within_closed_range(T a, T b, T c) {
return (a >= b) && (a <= c);
}
template <typename T> template<typename T> inline bool within_open_range(T a, T b, T c) { return (a >= b) && (a < c); }
inline bool within_open_range(T a, T b, T c) {
return (a >= b) && (a < c);
}
// Yes I know these should probably be pass by ref, not val: // Yes I know these should probably be pass by ref, not val:
// http://www.stepanovpapers.com/notes.pdf // http://www.stepanovpapers.com/notes.pdf
// Just don't use them on non-simple (non built-in) types! // Just don't use them on non-simple (non built-in) types!
template <typename T> template<typename T> inline T minimum(T a, T b) { return (a < b) ? a : b; }
inline T minimum(T a, T b) {
return (a < b) ? a : b;
}
template <typename T> template<typename T> inline T minimum(T a, T b, T c) { return minimum(minimum(a, b), c); }
inline T minimum(T a, T b, T c) {
return minimum(minimum(a, b), c);
}
template <typename T> template<typename T> inline T maximum(T a, T b) { return (a > b) ? a : b; }
inline T maximum(T a, T b) {
return (a > b) ? a : b;
}
template <typename T> template<typename T> inline T maximum(T a, T b, T c) { return maximum(maximum(a, b), c); }
inline T maximum(T a, T b, T c) {
return maximum(maximum(a, b), c);
}
template <typename T, typename U> template<typename T, typename U> inline T lerp(T a, T b, U c) { return a + (b - a) * c; }
inline T lerp(T a, T b, U c) {
return a + (b - a) * c;
}
template <typename T> template<typename T> inline T clamp(T value, T low, T high) { return (value < low) ? low : ((value > high) ? high : value); }
inline T clamp(T value, T low, T high) {
return (value < low) ? low : ((value > high) ? high : value);
}
template <typename T> template<typename T> inline T saturate(T value) { return (value < 0.0f) ? 0.0f : ((value > 1.0f) ? 1.0f : value); }
inline T saturate(T value) {
return (value < 0.0f) ? 0.0f : ((value > 1.0f) ? 1.0f : value);
}
inline int float_to_int(float f) { inline int float_to_int(float f) { return static_cast<int>(f); }
return static_cast<int>(f);
}
inline uint float_to_uint(float f) { inline uint float_to_uint(float f) { return static_cast<uint>(f); }
return static_cast<uint>(f);
}
inline int float_to_int(double f) { inline int float_to_int(double f) { return static_cast<int>(f); }
return static_cast<int>(f);
}
inline uint float_to_uint(double f) { inline uint float_to_uint(double f) { return static_cast<uint>(f); }
return static_cast<uint>(f);
}
inline int float_to_int_round(float f) { inline int float_to_int_round(float f) { return static_cast<int>((f < 0.0f) ? -floor(-f + .5f) : floor(f + .5f)); }
return static_cast<int>((f < 0.0f) ? -floor(-f + .5f) : floor(f + .5f));
}
inline uint float_to_uint_round(float f) { inline uint float_to_uint_round(float f) { return static_cast<uint>((f < 0.0f) ? 0.0f : floor(f + .5f)); }
return static_cast<uint>((f < 0.0f) ? 0.0f : floor(f + .5f));
}
template <typename T> template<typename T> inline int sign(T value) { return (value < 0) ? -1 : ((value > 0) ? 1 : 0); }
inline int sign(T value) {
return (value < 0) ? -1 : ((value > 0) ? 1 : 0);
}
template <typename T> template<typename T> inline T square(T value) { return value * value; }
inline T square(T value) {
return value * value;
}
inline bool is_power_of_2(uint32 x) { inline bool is_power_of_2(uint32 x) { return x && ((x & (x - 1U)) == 0U); }
return x && ((x & (x - 1U)) == 0U); inline bool is_power_of_2(uint64 x) { return x && ((x & (x - 1U)) == 0U); }
}
inline bool is_power_of_2(uint64 x) {
return x && ((x & (x - 1U)) == 0U);
}
template <typename T> template<typename T> inline T align_up_value(T x, uint alignment)
inline T align_up_value(T x, uint alignment) { {
CRNLIB_ASSERT(is_power_of_2(alignment)); CRNLIB_ASSERT(is_power_of_2(alignment));
uint q = static_cast<uint>(x); uint q = static_cast<uint>(x);
q = (q + alignment - 1) & (~(alignment - 1)); q = (q + alignment - 1) & (~(alignment - 1));
return static_cast<T>(q); return static_cast<T>(q);
} }
template <typename T> template<typename T> inline T align_down_value(T x, uint alignment)
inline T align_down_value(T x, uint alignment) { {
CRNLIB_ASSERT(is_power_of_2(alignment)); CRNLIB_ASSERT(is_power_of_2(alignment));
uint q = static_cast<uint>(x); uint q = static_cast<uint>(x);
q = q & (~(alignment - 1)); q = q & (~(alignment - 1));
return static_cast<T>(q); return static_cast<T>(q);
} }
template <typename T> template<typename T> inline T get_align_up_value_delta(T x, uint alignment)
inline T get_align_up_value_delta(T x, uint alignment) { {
return align_up_value(x, alignment) - x; return align_up_value(x, alignment) - x;
} }
// From "Hackers Delight" // From "Hackers Delight"
inline uint32 next_pow2(uint32 val) { inline uint32 next_pow2(uint32 val)
val--; {
val |= val >> 16; val--;
val |= val >> 8; val |= val >> 16;
val |= val >> 4; val |= val >> 8;
val |= val >> 2; val |= val >> 4;
val |= val >> 1; val |= val >> 2;
return val + 1; val |= val >> 1;
} return val + 1;
}
inline uint64 next_pow2(uint64 val) { inline uint64 next_pow2(uint64 val)
val--; {
val |= val >> 32; val--;
val |= val >> 16; val |= val >> 32;
val |= val >> 8; val |= val >> 16;
val |= val >> 4; val |= val >> 8;
val |= val >> 2; val |= val >> 4;
val |= val >> 1; val |= val >> 2;
return val + 1; val |= val >> 1;
} return val + 1;
}
inline uint floor_log2i(uint v) { inline uint floor_log2i(uint v)
uint l = 0; {
while (v > 1U) { uint l = 0;
v >>= 1; while (v > 1U)
l++; {
} v >>= 1;
return l; l++;
} }
return l;
}
inline uint ceil_log2i(uint v) { inline uint ceil_log2i(uint v)
uint l = floor_log2i(v); {
if ((l != cIntBits) && (v > (1U << l))) uint l = floor_log2i(v);
l++; if ((l != cIntBits) && (v > (1U << l)))
return l; l++;
} return l;
}
// Returns the total number of bits needed to encode v. // Returns the total number of bits needed to encode v.
inline uint total_bits(uint v) { inline uint total_bits(uint v)
uint l = 0; {
while (v > 0U) { uint l = 0;
v >>= 1; while (v > 0U)
l++; {
} v >>= 1;
return l; l++;
} }
return l;
}
// Actually counts the number of set bits, but hey // Actually counts the number of set bits, but hey
inline uint bitmask_size(uint mask) { inline uint bitmask_size(uint mask)
uint size = 0; {
while (mask) { uint size = 0;
mask &= (mask - 1U); while (mask)
size++; {
} mask &= (mask - 1U);
return size; size++;
} }
return size;
}
inline uint bitmask_ofs(uint mask) { inline uint bitmask_ofs(uint mask)
if (!mask) {
return 0; if (!mask)
uint ofs = 0; return 0;
while ((mask & 1U) == 0) { uint ofs = 0;
mask >>= 1U; while ((mask & 1U) == 0)
ofs++; {
} mask >>= 1U;
return ofs; ofs++;
} }
return ofs;
}
// See Bit Twiddling Hacks (public domain) // See Bit Twiddling Hacks (public domain)
// http://www-graphics.stanford.edu/~seander/bithacks.html // http://www-graphics.stanford.edu/~seander/bithacks.html
inline uint count_trailing_zero_bits(uint v) { inline uint count_trailing_zero_bits(uint v)
uint c = 32; // c will be the number of zero bits on the right {
uint c = 32; // c will be the number of zero bits on the right
static const unsigned int B[] = {0x55555555, 0x33333333, 0x0F0F0F0F, 0x00FF00FF, 0x0000FFFF}; static const unsigned int B[] = { 0x55555555, 0x33333333, 0x0F0F0F0F, 0x00FF00FF, 0x0000FFFF };
static const unsigned int S[] = {1, 2, 4, 8, 16}; // Our Magic Binary Numbers static const unsigned int S[] = { 1, 2, 4, 8, 16 }; // Our Magic Binary Numbers
for (int i = 4; i >= 0; --i) // unroll for more speed for (int i = 4; i >= 0; --i) // unroll for more speed
{ {
if (v & B[i]) { if (v & B[i])
v <<= S[i]; {
c -= S[i]; v <<= S[i];
} c -= S[i];
} }
}
if (v) { if (v)
c--; {
} c--;
}
return c; return c;
} }
inline uint count_leading_zero_bits(uint v) { inline uint count_leading_zero_bits(uint v)
uint temp; {
uint result = 32U; uint temp;
uint result = 32U;
temp = (v >> 16U); temp = (v >> 16U); if (temp) { result -= 16U; v = temp; }
if (temp) { temp = (v >> 8U); if (temp) { result -= 8U; v = temp; }
result -= 16U; temp = (v >> 4U); if (temp) { result -= 4U; v = temp; }
v = temp; temp = (v >> 2U); if (temp) { result -= 2U; v = temp; }
} temp = (v >> 1U); if (temp) { result -= 1U; 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) if (v & 1U)
result--; result--;
return result; return result;
} }
inline uint64 emulu(uint32 a, uint32 b) { inline uint64 emulu(uint32 a, uint32 b)
{
#if defined(_M_IX86) && defined(_MSC_VER) #if defined(_M_IX86) && defined(_MSC_VER)
return __emulu(a, b); return __emulu(a, b);
#else #else
return static_cast<uint64>(a) * static_cast<uint64>(b); return static_cast<uint64>(a) * static_cast<uint64>(b);
#endif #endif
} }
double compute_entropy(const uint8* p, uint n); double compute_entropy(const uint8* p, uint n);
void compute_lower_pow2_dim(int& width, int& height); void compute_lower_pow2_dim(int& width, int& height);
void compute_upper_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) { } // namespace crnlib
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
+515 -444
View File
File diff suppressed because it is too large Load Diff
+236 -204
View File
@@ -1,257 +1,289 @@
// File: crn_mem.cpp // File: crn_mem.cpp
// See Copyright Notice and license at the end of inc/crnlib.h // See Copyright Notice and license at the end of inc/crnlib.h
#include "crn_core.h" #include "crn_core.h"
#include "crn_spinlock.h"
#include "crn_console.h" #include "crn_console.h"
#include "../inc/crnlib.h" #include "../inc/crnlib.h"
#include <malloc.h> #include <malloc.h>
#if CRNLIB_USE_WIN32_API
#include "crn_winhdr.h" #include "crn_winhdr.h"
#endif
#define CRNLIB_MEM_STATS 0 #define CRNLIB_MEM_STATS 0
#if !CRNLIB_USE_WIN32_API #ifndef CRNLIB_USE_WIN32_API
#define _msize malloc_usable_size #define _msize malloc_usable_size
#endif #endif
namespace crnlib { namespace crnlib
{
#if CRNLIB_MEM_STATS #if CRNLIB_MEM_STATS
#if CRNLIB_64BIT_POINTERS #if CRNLIB_64BIT_POINTERS
typedef LONGLONG mem_stat_t; typedef LONGLONG mem_stat_t;
#define CRNLIB_MEM_COMPARE_EXCHANGE InterlockedCompareExchange64 #define CRNLIB_MEM_COMPARE_EXCHANGE InterlockedCompareExchange64
#else #else
typedef LONG mem_stat_t; typedef LONG mem_stat_t;
#define CRNLIB_MEM_COMPARE_EXCHANGE InterlockedCompareExchange #define CRNLIB_MEM_COMPARE_EXCHANGE InterlockedCompareExchange
#endif #endif
static volatile mem_stat_t g_total_blocks; static volatile mem_stat_t g_total_blocks;
static volatile mem_stat_t g_total_allocated; static volatile mem_stat_t g_total_allocated;
static volatile mem_stat_t g_max_allocated; static volatile mem_stat_t g_max_allocated;
static mem_stat_t update_total_allocated(int block_delta, mem_stat_t byte_delta) { static mem_stat_t update_total_allocated(int block_delta, mem_stat_t byte_delta)
mem_stat_t cur_total_blocks; {
for (;;) { mem_stat_t cur_total_blocks;
cur_total_blocks = (mem_stat_t)g_total_blocks; for ( ; ; )
mem_stat_t new_total_blocks = static_cast<mem_stat_t>(cur_total_blocks + block_delta); {
CRNLIB_ASSERT(new_total_blocks >= 0); cur_total_blocks = (mem_stat_t)g_total_blocks;
if (CRNLIB_MEM_COMPARE_EXCHANGE(&g_total_blocks, new_total_blocks, cur_total_blocks) == cur_total_blocks) mem_stat_t new_total_blocks = static_cast<mem_stat_t>(cur_total_blocks + block_delta);
break; 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*) {
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);
} }
}
if (pActual_size) mem_stat_t cur_total_allocated, new_total_allocated;
*pActual_size = ::_msize(p_final_block); 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
return p_new; static void* crnlib_default_realloc(void* p, size_t size, size_t* pActual_size, bool movable, void* pUser_data)
} {
pUser_data;
static size_t crnlib_default_msize(void* p, void*) { void* p_new;
return p ? _msize(p) : 0;
}
static crn_realloc_func g_pRealloc = crnlib_default_realloc; if (!p)
static crn_msize_func g_pMSize = crnlib_default_msize; {
static void* g_pUser_data; p_new = ::malloc(size);
CRNLIB_ASSERT( (reinterpret_cast<ptr_bits_t>(p_new) & (CRNLIB_MIN_ALLOC_ALIGNMENT - 1)) == 0 );
void crnlib_mem_error(const char* p_msg) { if (pActual_size)
crnlib_assert(p_msg, __FILE__, __LINE__); *pActual_size = p_new ? ::_msize(p_new) : 0;
} }
void* crnlib_malloc(size_t size) { else if (!size)
return crnlib_malloc(size, NULL); {
} ::free(p);
p_new = NULL;
void* crnlib_malloc(size_t size, size_t* pActual_size) { if (pActual_size)
size = (size + sizeof(uint32) - 1U) & ~(sizeof(uint32) - 1U); *pActual_size = 0;
if (!size) }
size = sizeof(uint32); else
{
void* p_final_block = p;
#ifdef WIN32
p_new = ::_expand(p, size);
#else
if (size > CRNLIB_MAX_POSSIBLE_BLOCK_SIZE) { p_new = NULL;
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 #endif
return p_new; 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);
void* crnlib_realloc(void* p, size_t size, size_t* pActual_size, bool movable) { if (p_new)
if ((ptr_bits_t)p & (CRNLIB_MIN_ALLOC_ALIGNMENT - 1)) { {
crnlib_mem_error("crnlib_realloc: bad ptr"); CRNLIB_ASSERT( (reinterpret_cast<ptr_bits_t>(p_new) & (CRNLIB_MIN_ALLOC_ALIGNMENT - 1)) == 0 );
return NULL; p_final_block = p_new;
} }
}
if (size > CRNLIB_MAX_POSSIBLE_BLOCK_SIZE) { if (pActual_size)
crnlib_mem_error("crnlib_malloc: size too big"); *pActual_size = ::_msize(p_final_block);
return NULL; }
}
return p_new;
}
static size_t crnlib_default_msize(void* p, void* pUser_data)
{
pUser_data;
return p ? _msize(p) : 0;
}
static crn_realloc_func g_pRealloc = crnlib_default_realloc;
static crn_msize_func g_pMSize = crnlib_default_msize;
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, 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 #if CRNLIB_MEM_STATS
size_t cur_size = p ? (*g_pMSize)(p, g_pUser_data) : 0; CRNLIB_ASSERT((*g_pMSize)(p_new, g_pUser_data) == actual_size);
CRNLIB_ASSERT(!p || (cur_size >= sizeof(uint32))); update_total_allocated(1, static_cast<mem_stat_t>(actual_size));
#endif #endif
if ((size) && (size < sizeof(uint32)))
size = sizeof(uint32);
size_t actual_size = size; return p_new;
void* p_new = (*g_pRealloc)(p, size, &actual_size, movable, g_pUser_data); }
if (pActual_size) void* crnlib_realloc(void* p, size_t size, size_t* pActual_size, bool movable)
*pActual_size = actual_size; {
if ((ptr_bits_t)p & (CRNLIB_MIN_ALLOC_ALIGNMENT - 1))
{
crnlib_mem_error("crnlib_realloc: bad ptr");
return NULL;
}
CRNLIB_ASSERT((reinterpret_cast<ptr_bits_t>(p_new) & (CRNLIB_MIN_ALLOC_ALIGNMENT - 1)) == 0); if (size > CRNLIB_MAX_POSSIBLE_BLOCK_SIZE)
{
crnlib_mem_error("crnlib_malloc: size too big");
return NULL;
}
#if CRNLIB_MEM_STATS #if CRNLIB_MEM_STATS
CRNLIB_ASSERT(!p_new || ((*g_pMSize)(p_new, g_pUser_data) == actual_size)); size_t cur_size = p ? (*g_pMSize)(p, g_pUser_data) : 0;
CRNLIB_ASSERT(!p || (cur_size >= sizeof(uint32)));
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 #endif
if ((size) && (size < sizeof(uint32)))
size = sizeof(uint32);
return p_new; size_t actual_size = size;
} void* p_new = (*g_pRealloc)(p, size, &actual_size, movable, g_pUser_data);
void* crnlib_calloc(size_t count, size_t size, size_t* pActual_size) { if (pActual_size)
size_t total = count * size; *pActual_size = actual_size;
void* p = crnlib_malloc(total, pActual_size);
if (p)
memset(p, 0, total);
return p;
}
void crnlib_free(void* p) { CRNLIB_ASSERT((reinterpret_cast<ptr_bits_t>(p_new) & (CRNLIB_MIN_ALLOC_ALIGNMENT - 1)) == 0);
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 #if CRNLIB_MEM_STATS
size_t cur_size = (*g_pMSize)(p, g_pUser_data); CRNLIB_ASSERT(!p_new || ((*g_pMSize)(p_new, g_pUser_data) == actual_size));
CRNLIB_ASSERT(cur_size >= sizeof(uint32));
update_total_allocated(-1, -static_cast<mem_stat_t>(cur_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 #endif
(*g_pRealloc)(p, 0, NULL, true, g_pUser_data); return p_new;
} }
size_t crnlib_msize(void* p) { void* crnlib_calloc(size_t count, size_t size, size_t* pActual_size)
if (!p) {
return 0; size_t total = count * size;
void *p = crnlib_malloc(total, pActual_size);
if (p) memset(p, 0, total);
return p;
}
if (reinterpret_cast<ptr_bits_t>(p) & (CRNLIB_MIN_ALLOC_ALIGNMENT - 1)) { void crnlib_free(void* p)
crnlib_mem_error("crnlib_msize: bad ptr"); {
return 0; if (!p)
} return;
return (*g_pMSize)(p, g_pUser_data); if (reinterpret_cast<ptr_bits_t>(p) & (CRNLIB_MIN_ALLOC_ALIGNMENT - 1))
} {
crnlib_mem_error("crnlib_free: bad ptr");
return;
}
void crnlib_print_mem_stats() {
#if CRNLIB_MEM_STATS #if CRNLIB_MEM_STATS
if (console::is_initialized()) { size_t cur_size = (*g_pMSize)(p, g_pUser_data);
console::debug("crnlib_print_mem_stats:"); CRNLIB_ASSERT(cur_size >= sizeof(uint32));
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); update_total_allocated(-1, -static_cast<mem_stat_t>(cur_size));
} 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 #endif
}
} // namespace crnlib (*g_pRealloc)(p, 0, NULL, true, g_pUser_data);
}
void crn_set_memory_callbacks(crn_realloc_func pRealloc, crn_msize_func pMSize, void* pUser_data) { size_t crnlib_msize(void* p)
if ((!pRealloc) || (!pMSize)) { {
crnlib::g_pRealloc = crnlib::crnlib_default_realloc; if (!p)
crnlib::g_pMSize = crnlib::crnlib_default_msize; return 0;
crnlib::g_pUser_data = NULL;
} else { if (reinterpret_cast<ptr_bits_t>(p) & (CRNLIB_MIN_ALLOC_ALIGNMENT - 1))
crnlib::g_pRealloc = pRealloc; {
crnlib::g_pMSize = pMSize; crnlib_mem_error("crnlib_msize: bad ptr");
crnlib::g_pUser_data = pUser_data; return 0;
} }
return (*g_pMSize)(p, g_pUser_data);
}
void crnlib_print_mem_stats()
{
#if CRNLIB_MEM_STATS
if (console::is_initialized())
{
console::debug(L"crnlib_print_mem_stats:");
console::debug(L"Current blocks: %u, allocated: %I64u, max ever allocated: %I64i", g_total_blocks, (int64)g_total_allocated, (int64)g_max_allocated);
}
else
{
printf("crnlib_print_mem_stats:\n");
printf("Current blocks: %u, allocated: %I64u, max ever allocated: %I64i\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;
}
} }
+153 -149
View File
@@ -6,176 +6,180 @@
#define CRNLIB_MIN_ALLOC_ALIGNMENT sizeof(size_t) * 2 #define CRNLIB_MIN_ALLOC_ALIGNMENT sizeof(size_t) * 2
#endif #endif
namespace crnlib { namespace crnlib
{
#if CRNLIB_64BIT_POINTERS #if CRNLIB_64BIT_POINTERS
const uint64 CRNLIB_MAX_POSSIBLE_BLOCK_SIZE = 0x400000000ULL; const uint64 CRNLIB_MAX_POSSIBLE_BLOCK_SIZE = 0x400000000ULL;
#else #else
const uint32 CRNLIB_MAX_POSSIBLE_BLOCK_SIZE = 0x7FFF0000U; const uint32 CRNLIB_MAX_POSSIBLE_BLOCK_SIZE = 0x7FFF0000U;
#endif #endif
void* crnlib_malloc(size_t size); void* crnlib_malloc(size_t size, size_t* pActual_size = NULL);
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_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_calloc(size_t count, size_t size, size_t* pActual_size = NULL); void crnlib_free(void* p);
void crnlib_free(void* p); size_t crnlib_msize(void* p);
size_t crnlib_msize(void* p); void crnlib_print_mem_stats();
void crnlib_print_mem_stats(); void crnlib_mem_error(const char* p_msg);
void crnlib_mem_error(const char* p_msg);
// omfg - there must be a better way // omfg - there must be a better way
template <typename T> template<typename T>
inline T* crnlib_new() { inline T* crnlib_new()
T* p = static_cast<T*>(crnlib_malloc(sizeof(T))); {
if (CRNLIB_IS_SCALAR_TYPE(T)) T* p = static_cast<T*>(crnlib_malloc(sizeof(T)));
return p; if (CRNLIB_IS_SCALAR_TYPE(T))
return helpers::construct(p); return p;
} return helpers::construct(p);
}
template <typename T, typename A> template<typename T, typename A>
inline T* crnlib_new(const A& init0) { inline T* crnlib_new(const A& init0)
T* p = static_cast<T*>(crnlib_malloc(sizeof(T))); {
return new (static_cast<void*>(p)) T(init0); T* p = static_cast<T*>(crnlib_malloc(sizeof(T)));
} return new (static_cast<void*>(p)) T(init0);
}
template <typename T, typename A> template<typename T, typename A>
inline T* crnlib_new(A& init0) { inline T* crnlib_new(A& init0)
T* p = static_cast<T*>(crnlib_malloc(sizeof(T))); {
return new (static_cast<void*>(p)) T(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> template<typename T, typename A, typename B>
inline T* crnlib_new(const A& init0, const B& init1) { 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); 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> template<typename T, typename A, typename B, typename C>
inline T* crnlib_new(const A& init0, const B& init1, const C& init2) { 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); 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> 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) { 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); 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> 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) { 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); 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> 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) { 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); 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> 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) { 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); 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> 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) { 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); 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> 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) { 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); 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> 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) { 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); 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, typename I, typename J, typename K> 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) { 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); 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, typename J, typename K, typename L> 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) { 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); 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> template<typename T>
inline T* crnlib_new_array(uint32 num) { inline T* crnlib_new_array(uint32 num)
if (!num) {
num = 1; if (!num) num = 1;
uint64 total = CRNLIB_MIN_ALLOC_ALIGNMENT + sizeof(T) * num; uint64 total = CRNLIB_MIN_ALLOC_ALIGNMENT + sizeof(T) * num;
if (total > CRNLIB_MAX_POSSIBLE_BLOCK_SIZE) { if (total > CRNLIB_MAX_POSSIBLE_BLOCK_SIZE)
crnlib_mem_error("crnlib_new_array: Array too large!"); {
return NULL; 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)));
crnlib_free(reinterpret_cast<uint8*>(p) - CRNLIB_MIN_ALLOC_ALIGNMENT); T* p = reinterpret_cast<T*>(q + CRNLIB_MIN_ALLOC_ALIGNMENT);
}
}
}
} // namespace crnlib reinterpret_cast<uint32*>(p)[-1] = num;
#define CRNLIB_DEFINE_NEW_DELETE \ reinterpret_cast<uint32*>(p)[-2] = ~num;
void* operator new(size_t size) { \
void* p = crnlib::crnlib_malloc(size); \ if (!CRNLIB_IS_SCALAR_TYPE(T))
if (!p) \ {
crnlib_fail("new: Out of memory!", __FILE__, __LINE__); \ helpers::construct_array(p, num);
return p; \ }
} \ return p;
void* operator new[](size_t size) { \ }
void* p = crnlib::crnlib_malloc(size); \
if (!p) \ template<typename T>
crnlib_fail("new[]: Out of memory!", __FILE__, __LINE__); \ inline void crnlib_delete(T* p)
return p; \ {
} \ if (p)
void operator delete(void* p_block) { \ {
crnlib::crnlib_free(p_block); \ if (!CRNLIB_IS_SCALAR_TYPE(T))
} \ {
void operator delete[](void* p_block) { \ helpers::destruct(p);
crnlib::crnlib_free(p_block); \ }
} 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
-4322
View File
File diff suppressed because it is too large Load Diff
-934
View File
@@ -1,934 +0,0 @@
/* miniz.c v1.14 - public domain deflate/inflate, zlib-subset, ZIP reading/writing/appending, PNG writing
See "unlicense" statement at the end of this file.
Rich Geldreich <richgel99@gmail.com>, last updated May 20, 2012
Implements RFC 1950: http://www.ietf.org/rfc/rfc1950.txt and RFC 1951: http://www.ietf.org/rfc/rfc1951.txt
Most API's defined in miniz.c are optional. For example, to disable the archive related functions just define
MINIZ_NO_ARCHIVE_APIS, or to get rid of all stdio usage define MINIZ_NO_STDIO (see the list below for more macros).
* Change History
5/20/12 v1.14 - MinGW32/64 GCC 4.6.1 compiler fixes: added MZ_FORCEINLINE, #include <time.h> (thanks fermtect).
5/19/12 v1.13 - From jason@cornsyrup.org and kelwert@mtu.edu - Fix mz_crc32() so it doesn't compute the wrong CRC-32's when mz_ulong is 64-bit.
Temporarily/locally slammed in "typedef unsigned long mz_ulong" and re-ran a randomized regression test on ~500k files.
Eliminated a bunch of warnings when compiling with GCC 32-bit/64.
Ran all examples, miniz.c, and tinfl.c through MSVC 2008's /analyze (static analysis) option and fixed all warnings (except for the silly
"Use of the comma-operator in a tested expression.." analysis warning, which I purposely use to work around a MSVC compiler warning).
Created 32-bit and 64-bit Codeblocks projects/workspace. Built and tested Linux executables. The codeblocks workspace is compatible with Linux+Win32/x64.
Added miniz_tester solution/project, which is a useful little app derived from LZHAM's tester app that I use as part of the regression test.
Ran miniz.c and tinfl.c through another series of regression testing on ~500,000 files and archives.
Modified example5.c so it purposely disables a bunch of high-level functionality (MINIZ_NO_STDIO, etc.). (Thanks to corysama for the MINIZ_NO_STDIO bug report.)
Fix ftell() usage in examples so they exit with an error on files which are too large (a limitation of the examples, not miniz itself).
4/12/12 v1.12 - More comments, added low-level example5.c, fixed a couple minor level_and_flags issues in the archive API's.
level_and_flags can now be set to MZ_DEFAULT_COMPRESSION. Thanks to Bruce Dawson <bruced@valvesoftware.com> for the feedback/bug report.
5/28/11 v1.11 - Added statement from unlicense.org
5/27/11 v1.10 - Substantial compressor optimizations:
Level 1 is now ~4x faster than before. The L1 compressor's throughput now varies between 70-110MB/sec. on a
Core i7 (actual throughput varies depending on the type of data, and x64 vs. x86).
Improved baseline L2-L9 compression perf. Also, greatly improved compression perf. issues on some file types.
Refactored the compression code for better readability and maintainability.
Added level 10 compression level (L10 has slightly better ratio than level 9, but could have a potentially large
drop in throughput on some files).
5/15/11 v1.09 - Initial stable release.
* Low-level Deflate/Inflate implementation notes:
Compression: Use the "tdefl" API's. The compressor supports raw, static, and dynamic blocks, lazy or
greedy parsing, match length filtering, RLE-only, and Huffman-only streams. It performs and compresses
approximately as well as zlib.
Decompression: Use the "tinfl" API's. The entire decompressor is implemented as a single function
coroutine: see tinfl_decompress(). It supports decompression into a 32KB (or larger power of 2) wrapping buffer, or into a memory
block large enough to hold the entire file.
The low-level tdefl/tinfl API's do not make any use of dynamic memory allocation.
* zlib-style API notes:
miniz.c implements a fairly large subset of zlib. There's enough functionality present for it to be a drop-in
zlib replacement in many apps:
The z_stream struct, optional memory allocation callbacks
deflateInit/deflateInit2/deflate/deflateReset/deflateEnd/deflateBound
inflateInit/inflateInit2/inflate/inflateEnd
compress, compress2, compressBound, uncompress
CRC-32, Adler-32 - Using modern, minimal code size, CPU cache friendly routines.
Supports raw deflate streams or standard zlib streams with adler-32 checking.
Limitations:
The callback API's are not implemented yet. No support for gzip headers or zlib static dictionaries.
I've tried to closely emulate zlib's various flavors of stream flushing and return status codes, but
there are no guarantees that miniz.c pulls this off perfectly.
* PNG writing: See the tdefl_write_image_to_png_file_in_memory() function, originally written by
Alex Evans. Supports 1-4 bytes/pixel images.
* ZIP archive API notes:
The ZIP archive API's where designed with simplicity and efficiency in mind, with just enough abstraction to
get the job done with minimal fuss. There are simple API's to retrieve file information, read files from
existing archives, create new archives, append new files to existing archives, or clone archive data from
one archive to another. It supports archives located in memory or the heap, on disk (using stdio.h),
or you can specify custom file read/write callbacks.
- Archive reading: Just call this function to read a single file from a disk archive:
void *mz_zip_extract_archive_file_to_heap(const char *pZip_filename, const char *pArchive_name,
size_t *pSize, mz_uint zip_flags);
For more complex cases, use the "mz_zip_reader" functions. Upon opening an archive, the entire central
directory is located and read as-is into memory, and subsequent file access only occurs when reading individual files.
- Archives file scanning: The simple way is to use this function to scan a loaded archive for a specific file:
int mz_zip_reader_locate_file(mz_zip_archive *pZip, const char *pName, const char *pComment, mz_uint flags);
The locate operation can optionally check file comments too, which (as one example) can be used to identify
multiple versions of the same file in an archive. This function uses a simple linear search through the central
directory, so it's not very fast.
Alternately, you can iterate through all the files in an archive (using mz_zip_reader_get_num_files()) and
retrieve detailed info on each file by calling mz_zip_reader_file_stat().
- Archive creation: Use the "mz_zip_writer" functions. The ZIP writer immediately writes compressed file data
to disk and builds an exact image of the central directory in memory. The central directory image is written
all at once at the end of the archive file when the archive is finalized.
The archive writer can optionally align each file's local header and file data to any power of 2 alignment,
which can be useful when the archive will be read from optical media. Also, the writer supports placing
arbitrary data blobs at the very beginning of ZIP archives. Archives written using either feature are still
readable by any ZIP tool.
- Archive appending: The simple way to add a single file to an archive is to call this function:
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);
The archive will be created if it doesn't already exist, otherwise it'll be appended to.
Note the appending is done in-place and is not an atomic operation, so if something goes wrong
during the operation it's possible the archive could be left without a central directory (although the local
file headers and file data will be fine, so the archive will be recoverable).
For more complex archive modification scenarios:
1. The safest way is to use a mz_zip_reader to read the existing archive, cloning only those bits you want to
preserve into a new archive using using the mz_zip_writer_add_from_zip_reader() function (which compiles the
compressed file data as-is). When you're done, delete the old archive and rename the newly written archive, and
you're done. This is safe but requires a bunch of temporary disk space or heap memory.
2. Or, you can convert an mz_zip_reader in-place to an mz_zip_writer using mz_zip_writer_init_from_reader(),
append new files as needed, then finalize the archive which will write an updated central directory to the
original archive. (This is basically what mz_zip_add_mem_to_archive_file_in_place() does.) There's a
possibility that the archive's central directory could be lost with this method if anything goes wrong, though.
- ZIP archive support limitations:
No zip64 or spanning support. Extraction functions can only handle unencrypted, stored or deflated files.
Requires streams capable of seeking.
* This is a header file library, like stb_image.c. To get only a header file, either cut and paste the
below header, or create miniz.h, #define MINIZ_HEADER_FILE_ONLY, and then include miniz.c from it.
* Important: For best perf. be sure to customize the below macros for your target platform:
#define MINIZ_USE_UNALIGNED_LOADS_AND_STORES 1
#define MINIZ_LITTLE_ENDIAN 1
#define MINIZ_HAS_64BIT_REGISTERS 1
*/
#pragma once
#ifndef MINIZ_HEADER_INCLUDED
#define MINIZ_HEADER_INCLUDED
#include <stdlib.h>
#if !defined(MINIZ_NO_TIME) && !defined(MINIZ_NO_ARCHIVE_APIS)
#include <time.h>
#endif
// Defines to completely disable specific portions of miniz.c:
// If all macros here are defined the only functionality remaining will be CRC-32, adler-32, tinfl, and tdefl.
// Define MINIZ_NO_STDIO to disable all usage and any functions which rely on stdio for file I/O.
//#define MINIZ_NO_STDIO
// If MINIZ_NO_TIME is specified then the ZIP archive functions will not be able to get the current time, or
// get/set file times.
//#define MINIZ_NO_TIME
// Define MINIZ_NO_ARCHIVE_APIS to disable all ZIP archive API's.
//#define MINIZ_NO_ARCHIVE_APIS
// Define MINIZ_NO_ARCHIVE_APIS to disable all writing related ZIP archive API's.
//#define MINIZ_NO_ARCHIVE_WRITING_APIS
// Define MINIZ_NO_ZLIB_APIS to remove all ZLIB-style compression/decompression API's.
//#define MINIZ_NO_ZLIB_APIS
// Define MINIZ_NO_ZLIB_COMPATIBLE_NAME to disable zlib names, to prevent conflicts against stock zlib.
//#define MINIZ_NO_ZLIB_COMPATIBLE_NAMES
// Define MINIZ_NO_MALLOC to disable all calls to malloc, free, and realloc.
// Note if MINIZ_NO_MALLOC is defined then the user must always provide custom user alloc/free/realloc
// callbacks to the zlib and archive API's, and a few stand-alone helper API's which don't provide custom user
// functions (such as tdefl_compress_mem_to_heap() and tinfl_decompress_mem_to_heap()) won't work.
//#define MINIZ_NO_MALLOC
#if defined(_M_IX86) || defined(_M_X64) || defined(__i386__) || defined(__i386) || defined(__i486__) || defined(__i486) || defined(i386) || defined(__ia64__) || defined(__x86_64__)
// MINIZ_X86_OR_X64_CPU is only used to help set the below macros.
#define MINIZ_X86_OR_X64_CPU 1
#endif
#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
#if MINIZ_X86_OR_X64_CPU
// Set MINIZ_USE_UNALIGNED_LOADS_AND_STORES to 1 on CPU's that permit efficient integer loads and stores from unaligned addresses.
#define MINIZ_USE_UNALIGNED_LOADS_AND_STORES 1
#endif
#if defined(_M_X64) || defined(_WIN64) || defined(__MINGW64__) || defined(_LP64) || defined(__LP64__) || defined(__ia64__) || defined(__x86_64__)
// Set MINIZ_HAS_64BIT_REGISTERS to 1 if operations on 64-bit integers are reasonably fast (and don't involve compiler generated calls to helper functions).
#define MINIZ_HAS_64BIT_REGISTERS 1
#endif
#ifdef __cplusplus
extern "C" {
#endif
// ------------------- zlib-style API Definitions.
// For more compatibility with zlib, miniz.c uses unsigned long for some parameters/struct members. Beware: mz_ulong can be either 32 or 64-bits!
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);
#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);
#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);
// Compression strategies.
enum { MZ_DEFAULT_STRATEGY = 0,
MZ_FILTERED = 1,
MZ_HUFFMAN_ONLY = 2,
MZ_RLE = 3,
MZ_FIXED = 4 };
// Method
#define MZ_DEFLATED 8
#ifndef MINIZ_NO_ZLIB_APIS
// 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);
#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 };
// 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 };
// 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 };
// Window bits
#define MZ_DEFAULT_WINDOW_BITS 15
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
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
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
} mz_stream;
typedef mz_stream* mz_streamp;
// Returns the version string of miniz.c.
const char* mz_version(void);
// mz_deflateInit() initializes a compressor with default options:
// Parameters:
// pStream must point to an initialized mz_stream struct.
// level must be between [MZ_NO_COMPRESSION, MZ_BEST_COMPRESSION].
// level 1 enables a specially optimized compression function that's been optimized purely for performance, not ratio.
// (This special func. is currently only enabled when MINIZ_USE_UNALIGNED_LOADS_AND_STORES and MINIZ_LITTLE_ENDIAN are defined.)
// Return values:
// MZ_OK on success.
// MZ_STREAM_ERROR if the stream is bogus.
// MZ_PARAM_ERROR if the input parameters are bogus.
// MZ_MEM_ERROR on out of memory.
int mz_deflateInit(mz_streamp pStream, int level);
// mz_deflateInit2() is like mz_deflate(), except with more control:
// Additional parameters:
// method must be MZ_DEFLATED
// window_bits must be MZ_DEFAULT_WINDOW_BITS (to wrap the deflate stream with zlib header/adler-32 footer) or -MZ_DEFAULT_WINDOW_BITS (raw deflate/no header or footer)
// mem_level must be between [1, 9] (it's checked but ignored by miniz.c)
int mz_deflateInit2(mz_streamp pStream, int level, int method, int window_bits, int mem_level, int strategy);
// Quickly resets a compressor without having to reallocate anything. Same as calling mz_deflateEnd() followed by mz_deflateInit()/mz_deflateInit2().
int mz_deflateReset(mz_streamp pStream);
// mz_deflate() compresses the input to output, consuming as much of the input and producing as much output as possible.
// Parameters:
// pStream is the stream to read from and write to. You must initialize/update the next_in, avail_in, next_out, and avail_out members.
// flush may be MZ_NO_FLUSH, MZ_PARTIAL_FLUSH/MZ_SYNC_FLUSH, MZ_FULL_FLUSH, or MZ_FINISH.
// Return values:
// MZ_OK on success (when flushing, or if more input is needed but not available, and/or there's more output to be written but the output buffer is full).
// MZ_STREAM_END if all input has been consumed and all output bytes have been written. Don't call mz_deflate() on the stream anymore.
// MZ_STREAM_ERROR if the stream is bogus.
// MZ_PARAM_ERROR if one of the parameters is invalid.
// MZ_BUF_ERROR if no forward progress is possible because the input and/or output buffers are empty. (Fill up the input buffer or free up some output space and try again.)
int mz_deflate(mz_streamp pStream, int flush);
// mz_deflateEnd() deinitializes a compressor:
// Return values:
// MZ_OK on success.
// MZ_STREAM_ERROR if the stream is bogus.
int mz_deflateEnd(mz_streamp pStream);
// mz_deflateBound() returns a (very) conservative upper bound on the amount of data that could be generated by deflate(), assuming flush is set to only MZ_NO_FLUSH or MZ_FINISH.
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);
// 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);
// Initializes a decompressor.
int mz_inflateInit(mz_streamp pStream);
// mz_inflateInit2() is like mz_inflateInit() with an additional option that controls the window size and whether or not the stream has been wrapped with a zlib header/footer:
// window_bits must be MZ_DEFAULT_WINDOW_BITS (to parse zlib header/footer) or -MZ_DEFAULT_WINDOW_BITS (raw deflate).
int mz_inflateInit2(mz_streamp pStream, int window_bits);
// Decompresses the input stream to the output, consuming only as much of the input as needed, and writing as much to the output as possible.
// Parameters:
// pStream is the stream to read from and write to. You must initialize/update the next_in, avail_in, next_out, and avail_out members.
// flush may be MZ_NO_FLUSH, MZ_SYNC_FLUSH, or MZ_FINISH.
// On the first call, if flush is MZ_FINISH it's assumed the input and output buffers are both sized large enough to decompress the entire stream in a single call (this is slightly faster).
// MZ_FINISH implies that there are no more source bytes available beside what's already in the input buffer, and that the output buffer is large enough to hold the rest of the decompressed data.
// Return values:
// MZ_OK on success. Either more input is needed but not available, and/or there's more output to be written but the output buffer is full.
// MZ_STREAM_END if all needed input has been consumed and all output bytes have been written. For zlib streams, the adler-32 of the decompressed data has also been verified.
// MZ_STREAM_ERROR if the stream is bogus.
// MZ_DATA_ERROR if the deflate stream is invalid.
// MZ_PARAM_ERROR if one of the parameters is invalid.
// MZ_BUF_ERROR if no forward progress is possible because the input buffer is empty but the inflater needs more input to continue, or if the output buffer is not large enough. Call mz_inflate() again
// with more input data, or with more room in the output buffer (except when using single call decompression, described above).
int mz_inflate(mz_streamp pStream, int flush);
// Deinitializes a decompressor.
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);
// Returns a string description of the specified error code, or NULL if the error code is invalid.
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
#endif // MINIZ_NO_ZLIB_APIS
// ------------------- Types and macros
typedef unsigned char mz_uint8;
typedef signed short mz_int16;
typedef unsigned short mz_uint16;
typedef unsigned int mz_uint32;
typedef unsigned int mz_uint;
typedef long long mz_int64;
typedef unsigned long long mz_uint64;
typedef int mz_bool;
#define MZ_FALSE (0)
#define MZ_TRUE (1)
// Works around MSVC's spammy "warning C4127: conditional expression is constant" message.
#ifdef _MSC_VER
#define MZ_MACRO_END while (0, 0)
#else
#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,
MZ_ZIP_MAX_ARCHIVE_FILENAME_SIZE = 260,
MZ_ZIP_MAX_ARCHIVE_FILE_COMMENT_SIZE = 256
};
typedef struct
{
mz_uint32 m_file_index;
mz_uint32 m_central_dir_ofs;
mz_uint16 m_version_made_by;
mz_uint16 m_version_needed;
mz_uint16 m_bit_flag;
mz_uint16 m_method;
#ifndef MINIZ_NO_TIME
time_t m_time;
#endif
mz_uint32 m_crc32;
mz_uint64 m_comp_size;
mz_uint64 m_uncomp_size;
mz_uint16 m_internal_attr;
mz_uint32 m_external_attr;
mz_uint64 m_local_header_ofs;
mz_uint32 m_comment_size;
char m_filename[MZ_ZIP_MAX_ARCHIVE_FILENAME_SIZE];
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);
struct mz_zip_internal_state_tag;
typedef struct mz_zip_internal_state_tag mz_zip_internal_state;
typedef enum {
MZ_ZIP_MODE_INVALID = 0,
MZ_ZIP_MODE_READING = 1,
MZ_ZIP_MODE_WRITING = 2,
MZ_ZIP_MODE_WRITING_HAS_BEEN_FINALIZED = 3
} mz_zip_mode;
typedef struct
{
mz_uint64 m_archive_size;
mz_uint64 m_central_directory_file_ofs;
mz_uint m_total_files;
mz_zip_mode m_zip_mode;
mz_uint m_file_offset_alignment;
mz_alloc_func m_pAlloc;
mz_free_func m_pFree;
mz_realloc_func m_pRealloc;
void* m_pAlloc_opaque;
mz_file_read_func m_pRead;
mz_file_write_func m_pWrite;
void* m_pIO_opaque;
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,
MZ_ZIP_FLAG_DO_NOT_SORT_CENTRAL_DIRECTORY = 0x0800
} mz_zip_flags;
// ZIP archive reading
// 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);
#ifndef MINIZ_NO_STDIO
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);
// 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);
// 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);
// 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);
// 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);
// 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);
// 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);
// 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);
// 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);
#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);
#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);
// 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);
#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);
#endif
// Converts a ZIP archive reader object into a writer object, to allow efficient in-place file appends to occur on an existing archive.
// For archives opened using mz_zip_reader_init_file, pFilename must be the archive's filename so it can be reopened for writing. If the file can't be reopened, mz_zip_reader_end() will be called.
// For archives opened using mz_zip_reader_init_mem, the memory block must be growable using the realloc callback (which defaults to realloc unless you've overridden it).
// 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);
// 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);
#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);
#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);
// 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);
// 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);
// 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);
// 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);
#endif // #ifndef MINIZ_NO_ARCHIVE_WRITING_APIS
#endif // #ifndef MINIZ_NO_ARCHIVE_APIS
// ------------------- Low-level Decompression API Definitions
// Decompression flags used by tinfl_decompress().
// TINFL_FLAG_PARSE_ZLIB_HEADER: If set, the input has a valid zlib header and ends with an adler32 checksum (it's a valid zlib stream). Otherwise, the input is a raw deflate stream.
// 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 {
TINFL_FLAG_PARSE_ZLIB_HEADER = 1,
TINFL_FLAG_HAS_MORE_INPUT = 2,
TINFL_FLAG_USING_NON_WRAPPING_OUTPUT_BUF = 4,
TINFL_FLAG_COMPUTE_ADLER32 = 8
};
// High level decompression functions:
// tinfl_decompress_mem_to_heap() decompresses a block in memory to a heap block allocated via malloc().
// On entry:
// pSrc_buf, src_buf_len: Pointer and size of the Deflate or zlib source data to decompress.
// On return:
// 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);
// 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);
// 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);
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 {
TINFL_STATUS_BAD_PARAM = -3,
TINFL_STATUS_ADLER32_MISMATCH = -2,
TINFL_STATUS_FAILED = -1,
TINFL_STATUS_DONE = 0,
TINFL_STATUS_NEEDS_MORE_INPUT = 1,
TINFL_STATUS_HAS_MORE_OUTPUT = 2
} tinfl_status;
// Initializes the decompressor to its initial state.
#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);
// 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
};
typedef struct
{
mz_uint8 m_code_size[TINFL_MAX_HUFF_SYMBOLS_0];
mz_int16 m_look_up[TINFL_FAST_LOOKUP_SIZE], m_tree[TINFL_MAX_HUFF_SYMBOLS_0 * 2];
} tinfl_huff_table;
#if MINIZ_HAS_64BIT_REGISTERS
#define TINFL_USE_64BIT_BITBUF 1
#endif
#if TINFL_USE_64BIT_BITBUF
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)
#endif
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;
tinfl_huff_table m_tables[TINFL_MAX_HUFF_TABLES];
mz_uint8 m_raw_header[4], m_len_codes[TINFL_MAX_HUFF_SYMBOLS_0 + TINFL_MAX_HUFF_SYMBOLS_1 + 137];
};
// ------------------- Low-level Compression API Definitions
// Set TDEFL_LESS_MEMORY to 1 to use less memory (compression will be slightly slower, and raw/dynamic blocks will be output more frequently).
#define TDEFL_LESS_MEMORY 0
// 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
};
// 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.
// TDEFL_COMPUTE_ADLER32: Always compute the adler-32 of the input data (even when not writing zlib headers).
// TDEFL_GREEDY_PARSING_FLAG: Set to use faster greedy parsing, instead of more efficient lazy parsing.
// TDEFL_NONDETERMINISTIC_PARSING_FLAG: Enable to decrease the compressor's initialization time to the minimum, but the output may vary from run to run given the same input (depending on the contents of memory).
// TDEFL_RLE_MATCHES: Only look for RLE matches (matches with a distance of 1)
// 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,
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
};
// High level compression functions:
// tdefl_compress_mem_to_heap() compresses a block in memory to a heap block allocated via malloc().
// On entry:
// pSrc_buf, src_buf_len: Pointer and size of source block to compress.
// flags: The max match finder probes (default is 128) logically OR'd against the above flags. Higher probes are slower but improve compression.
// On return:
// 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);
// 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);
// 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.
// 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);
// 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);
// 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);
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 };
#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 };
#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 {
TDEFL_STATUS_BAD_PARAM = -2,
TDEFL_STATUS_PUT_BUF_FAILED = -1,
TDEFL_STATUS_OKAY = 0,
TDEFL_STATUS_DONE = 1,
} tdefl_status;
// Must map to MZ_NO_FLUSH, MZ_SYNC_FLUSH, etc. enums
typedef enum {
TDEFL_NO_FLUSH = 0,
TDEFL_SYNC_FLUSH = 2,
TDEFL_FULL_FLUSH = 3,
TDEFL_FINISH = 4
} tdefl_flush;
// tdefl's compression state structure.
typedef struct
{
tdefl_put_buf_func_ptr m_pPut_buf_func;
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;
mz_uint8 *m_pLZ_code_buf, *m_pLZ_flags, *m_pOutput_buf, *m_pOutput_buf_end;
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;
size_t *m_pIn_buf_size, *m_pOut_buf_size;
tdefl_flush m_flush;
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];
mz_uint16 m_huff_codes[TDEFL_MAX_HUFF_TABLES][TDEFL_MAX_HUFF_SYMBOLS];
mz_uint8 m_huff_code_sizes[TDEFL_MAX_HUFF_TABLES][TDEFL_MAX_HUFF_SYMBOLS];
mz_uint8 m_lz_code_buf[TDEFL_LZ_CODE_BUF_SIZE];
mz_uint16 m_next[TDEFL_LZ_DICT_SIZE];
mz_uint16 m_hash[TDEFL_LZ_HASH_SIZE];
mz_uint8 m_output_buf[TDEFL_OUT_BUF_SIZE];
} tdefl_compressor;
// Initializes the compressor.
// There is no corresponding deinit() function because the tdefl API's do not dynamically allocate memory.
// 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);
// 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_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_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
// Create tdefl_compress() flags given zlib-style compression parameters.
// level may range from [0,10] (where 10 is absolute max compression, but may be much slower on some files)
// 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
#ifdef __cplusplus
}
#endif
#endif // MINIZ_HEADER_INCLUDED
File diff suppressed because it is too large Load Diff
-337
View File
@@ -1,337 +0,0 @@
// File: crn_mipmapped_texture.h
// See Copyright Notice and license at the end of inc/crnlib.h
#pragma once
#include "crn_dxt_image.h"
#include "../inc/dds_defs.h"
#include "crn_pixel_format.h"
#include "crn_image.h"
#include "crn_resampler.h"
#include "crn_data_stream_serializer.h"
#include "crn_qdxt1.h"
#include "crn_qdxt5.h"
#include "crn_texture_file_types.h"
#include "crn_image_utils.h"
namespace crnlib {
extern const vec2I g_vertical_cross_image_offsets[6];
enum orientation_flags_t {
cOrientationFlagXFlipped = 1,
cOrientationFlagYFlipped = 2,
cDefaultOrientationFlags = 0
};
enum unpack_flags_t {
cUnpackFlagUncook = 1,
cUnpackFlagUnflip = 2
};
class mip_level {
friend class mipmapped_texture;
public:
mip_level();
~mip_level();
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);
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 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;
inline bool is_packed() const { return m_pDXTImage != NULL; }
inline bool is_valid() const { return (m_pImage != NULL) || (m_pDXTImage != NULL); }
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 pixel_format get_format() const { return m_format; }
inline void set_format(pixel_format fmt) { m_format = fmt; }
bool convert(pixel_format fmt, bool cook, const dxt_image::pack_params& p);
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 unpack_from_dxt(bool uncook = true);
// 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 flip_x();
bool flip_y();
private:
uint m_width;
uint m_height;
pixel_format_helpers::component_flags m_comp_flags;
pixel_format m_format;
image_u8* m_pImage;
dxt_image* m_pDXTImage;
orientation_flags_t m_orient_flags;
void cook_image(image_u8& img) const;
void uncook_image(image_u8& img) const;
};
// A face is an array of mip_level ptr's.
typedef crnlib::vector<mip_level*> mip_ptr_vec;
// And an array of one, six, or N faces make up a texture.
typedef crnlib::vector<mip_ptr_vec> face_vec;
class mipmapped_texture {
public:
// Construction/destruction
mipmapped_texture();
~mipmapped_texture();
mipmapped_texture(const mipmapped_texture& other);
mipmapped_texture& operator=(const mipmapped_texture& rhs);
void clear();
void init(uint width, uint height, uint levels, uint faces, pixel_format fmt, const char* pName, orientation_flags_t orient_flags);
// 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);
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);
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
+40
View File
@@ -0,0 +1,40 @@
// File: crn_mutex.h
// See Copyright Notice and license at the end of inc/crnlib.h
#pragma once
namespace crnlib
{
class mutex
{
mutex(const mutex&);
mutex& operator= (const mutex&);
public:
mutex(unsigned int spin_count = 0);
~mutex();
void lock();
void unlock();
void set_spin_count(unsigned int count);
private:
int m_buf[12];
#ifdef CRNLIB_BUILD_DEBUG
unsigned int m_lock_count;
#endif
};
class scoped_mutex
{
scoped_mutex(const scoped_mutex&);
scoped_mutex& operator= (const scoped_mutex&);
public:
inline scoped_mutex(mutex& m) : m_mutex(m) { m_mutex.lock(); }
inline ~scoped_mutex() { m_mutex.unlock(); }
private:
mutex& m_mutex;
};
} // namespace crnlib
+74 -62
View File
@@ -2,78 +2,90 @@
// See Copyright Notice and license at the end of inc/crnlib.h // See Copyright Notice and license at the end of inc/crnlib.h
#pragma once #pragma once
namespace crnlib { namespace crnlib
template <unsigned int N> {
struct packed_uint { template<unsigned int N>
inline packed_uint() {} 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) { inline packed_uint& operator= (const packed_uint& rhs)
if (this != &rhs) {
memcpy(m_buf, rhs.m_buf, sizeof(m_buf)); if (this != &rhs)
return *this; 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 #ifdef CRNLIB_BUILD_DEBUG
if (N == 1) { if (N == 1)
CRNLIB_ASSERT(val <= 0xFFU); {
} else if (N == 2) { CRNLIB_ASSERT(val <= 0xFFU);
CRNLIB_ASSERT(val <= 0xFFFFU); }
} else if (N == 3) { else if (N == 2)
CRNLIB_ASSERT(val <= 0xFFFFFFU); {
} CRNLIB_ASSERT(val <= 0xFFFFU);
}
else if (N == 3)
{
CRNLIB_ASSERT(val <= 0xFFFFFFU);
}
#endif #endif
val <<= (8U * (4U - N)); val <<= (8U * (4U - N));
for (unsigned int i = 0; i < N; i++) { for (unsigned int i = 0; i < N; i++)
m_buf[i] = static_cast<unsigned char>(val >> 24U); {
val <<= 8U; m_buf[i] = static_cast<unsigned char>(val >> 24U);
} val <<= 8U;
}
return *this; return *this;
} }
inline operator unsigned int() const { inline operator unsigned int() const
switch (N) { {
case 1: switch (N)
return m_buf[0]; {
case 2: case 1: return m_buf[0];
return (m_buf[0] << 8U) | m_buf[1]; case 2: return (m_buf[0] << 8U) | m_buf[1];
case 3: case 3: return (m_buf[0] << 16U) | (m_buf[1] << 8U) | (m_buf[2]);
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]);
default: }
return (m_buf[0] << 24U) | (m_buf[1] << 16U) | (m_buf[2] << 8U) | (m_buf[3]); }
}
}
unsigned char m_buf[N]; unsigned char m_buf[N];
}; };
template <typename T> template<typename T>
class packed_value { class packed_value
public: {
packed_value() {} public:
packed_value(T val) { *this = val; } packed_value() { }
packed_value(T val) { *this = val; }
inline operator T() const { inline operator T() const
T result = 0; {
for (int i = sizeof(T) - 1; i >= 0; i--) T result = 0;
result = static_cast<T>((result << 8) | m_bytes[i]); for (int i = sizeof(T) - 1; i >= 0; i--)
return result; result = static_cast<T>((result << 8) | m_bytes[i]);
} return result;
packed_value& operator=(T val) { }
for (int i = 0; i < sizeof(T); i++) { packed_value& operator= (T val)
m_bytes[i] = static_cast<uint8>(val); {
val >>= 8; for (int i = 0; i < sizeof(T); i++)
} {
return *this; m_bytes[i] = static_cast<uint8>(val);
} val >>= 8;
}
return *this;
}
private:
uint8 m_bytes[sizeof(T)];
};
} // namespace crnlib
private:
uint8 m_bytes[sizeof(T)];
};
} // namespace crnlib
+300 -316
View File
@@ -4,330 +4,314 @@
#include "crn_pixel_format.h" #include "crn_pixel_format.h"
#include "crn_image.h" #include "crn_image.h"
namespace crnlib { namespace crnlib
namespace pixel_format_helpers { {
const pixel_format g_all_pixel_formats[] = namespace pixel_format_helpers
{ {
PIXEL_FMT_DXT1, const pixel_format g_all_pixel_formats[] =
PIXEL_FMT_DXT2, {
PIXEL_FMT_DXT3, PIXEL_FMT_DXT1,
PIXEL_FMT_DXT4, PIXEL_FMT_DXT2,
PIXEL_FMT_DXT5, PIXEL_FMT_DXT3,
PIXEL_FMT_3DC, PIXEL_FMT_DXT4,
PIXEL_FMT_DXN, PIXEL_FMT_DXT5,
PIXEL_FMT_DXT5A, PIXEL_FMT_3DC,
PIXEL_FMT_DXT5_CCxY, PIXEL_FMT_DXN,
PIXEL_FMT_DXT5_xGxR, PIXEL_FMT_DXT5A,
PIXEL_FMT_DXT5_xGBR, PIXEL_FMT_DXT5_CCxY,
PIXEL_FMT_DXT5_AGBR, PIXEL_FMT_DXT5_xGxR,
PIXEL_FMT_DXT1A, PIXEL_FMT_DXT5_xGBR,
PIXEL_FMT_ETC1, PIXEL_FMT_DXT5_AGBR,
PIXEL_FMT_ETC2, PIXEL_FMT_DXT1A,
PIXEL_FMT_ETC2A, PIXEL_FMT_R8G8B8,
PIXEL_FMT_ETC1S, PIXEL_FMT_L8,
PIXEL_FMT_ETC2AS, PIXEL_FMT_A8,
PIXEL_FMT_R8G8B8, PIXEL_FMT_A8L8,
PIXEL_FMT_L8, PIXEL_FMT_A8R8G8B8
PIXEL_FMT_A8, };
PIXEL_FMT_A8L8,
PIXEL_FMT_A8R8G8B8};
uint get_num_formats() { uint get_num_formats()
return sizeof(g_all_pixel_formats) / sizeof(g_all_pixel_formats[0]); {
} return sizeof(g_all_pixel_formats) / sizeof(g_all_pixel_formats[0]);
}
pixel_format get_pixel_format_by_index(uint index) { pixel_format get_pixel_format_by_index(uint index)
CRNLIB_ASSERT(index < get_num_formats()); {
return g_all_pixel_formats[index]; CRNLIB_ASSERT(index < get_num_formats());
} return g_all_pixel_formats[index];
}
const char* get_pixel_format_string(pixel_format fmt) { const wchar_t* get_pixel_format_string(pixel_format fmt)
switch (fmt) { {
case PIXEL_FMT_INVALID: switch (fmt)
return "INVALID"; {
case PIXEL_FMT_DXT1: case PIXEL_FMT_INVALID: return L"INVALID";
return "DXT1"; case PIXEL_FMT_DXT1: return L"DXT1";
case PIXEL_FMT_DXT1A: case PIXEL_FMT_DXT1A: return L"DXT1A";
return "DXT1A"; case PIXEL_FMT_DXT2: return L"DXT2";
case PIXEL_FMT_DXT2: case PIXEL_FMT_DXT3: return L"DXT3";
return "DXT2"; case PIXEL_FMT_DXT4: return L"DXT4";
case PIXEL_FMT_DXT3: case PIXEL_FMT_DXT5: return L"DXT5";
return "DXT3"; case PIXEL_FMT_3DC: return L"3DC";
case PIXEL_FMT_DXT4: case PIXEL_FMT_DXN: return L"DXN";
return "DXT4"; case PIXEL_FMT_DXT5A: return L"DXT5A";
case PIXEL_FMT_DXT5: case PIXEL_FMT_DXT5_CCxY: return L"DXT5_CCxY";
return "DXT5"; case PIXEL_FMT_DXT5_xGxR: return L"DXT5_xGxR";
case PIXEL_FMT_3DC: case PIXEL_FMT_DXT5_xGBR: return L"DXT5_xGBR";
return "3DC"; case PIXEL_FMT_DXT5_AGBR: return L"DXT5_AGBR";
case PIXEL_FMT_DXN: case PIXEL_FMT_R8G8B8: return L"R8G8B8";
return "DXN"; case PIXEL_FMT_A8R8G8B8: return L"A8R8G8B8";
case PIXEL_FMT_DXT5A: case PIXEL_FMT_A8: return L"A8";
return "DXT5A"; case PIXEL_FMT_L8: return L"L8";
case PIXEL_FMT_DXT5_CCxY: case PIXEL_FMT_A8L8: return L"A8L8";
return "DXT5_CCxY"; default: break;
case PIXEL_FMT_DXT5_xGxR: }
return "DXT5_xGxR"; CRNLIB_ASSERT(false);
case PIXEL_FMT_DXT5_xGBR: return L"?";
return "DXT5_xGBR"; }
case PIXEL_FMT_DXT5_AGBR:
return "DXT5_AGBR";
case PIXEL_FMT_ETC1:
return "ETC1";
case PIXEL_FMT_ETC2:
return "ETC2";
case PIXEL_FMT_ETC2A:
return "ETC2A";
case PIXEL_FMT_ETC1S:
return "ETC1S";
case PIXEL_FMT_ETC2AS:
return "ETC2AS";
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) { const char* get_pixel_format_stringa(pixel_format fmt)
switch (fmt) { {
case cCRNFmtDXT1: switch (fmt)
return "DXT1"; {
case cCRNFmtDXT3: case PIXEL_FMT_INVALID: return "INVALID";
return "DXT3"; case PIXEL_FMT_DXT1: return "DXT1";
case cCRNFmtDXT5: case PIXEL_FMT_DXT1A: return "DXT1A";
return "DXT5"; case PIXEL_FMT_DXT2: return "DXT2";
case cCRNFmtDXT5_CCxY: case PIXEL_FMT_DXT3: return "DXT3";
return "DXT5_CCxY"; case PIXEL_FMT_DXT4: return "DXT4";
case cCRNFmtDXT5_xGBR: case PIXEL_FMT_DXT5: return "DXT5";
return "DXT5_xGBR"; case PIXEL_FMT_3DC: return "3DC";
case cCRNFmtDXT5_AGBR: case PIXEL_FMT_DXN: return "DXN";
return "DXT5_AGBR"; case PIXEL_FMT_DXT5A: return "DXT5A";
case cCRNFmtDXT5_xGxR: case PIXEL_FMT_DXT5_CCxY: return "DXT5_CCxY";
return "DXT5_xGxR"; case PIXEL_FMT_DXT5_xGxR: return "DXT5_xGxR";
case cCRNFmtDXN_XY: case PIXEL_FMT_DXT5_xGBR: return "DXT5_xGBR";
return "DXN_XY"; case PIXEL_FMT_DXT5_AGBR: return "DXT5_AGBR";
case cCRNFmtDXN_YX: case PIXEL_FMT_R8G8B8: return "R8G8B8";
return "DXN_YX"; case PIXEL_FMT_A8R8G8B8: return "A8R8G8B8";
case cCRNFmtDXT5A: case PIXEL_FMT_A8: return "A8";
return "DXT5A"; case PIXEL_FMT_L8: return "L8";
case cCRNFmtETC1: case PIXEL_FMT_A8L8: return "A8L8";
return "ETC1"; default: break;
case cCRNFmtETC2: }
return "ETC2"; CRNLIB_ASSERT(false);
case cCRNFmtETC2A: return "?";
return "ETC2A"; }
case cCRNFmtETC1S:
return "ETC1S";
case cCRNFmtETC2AS:
return "ETC2AS";
default:
break;
}
CRNLIB_ASSERT(false);
return "?";
}
component_flags get_component_flags(pixel_format fmt) { const wchar_t* get_crn_format_string(crn_format fmt)
// These flags are for *uncooked* pixels, i.e. after after adding Z to DXN maps, or converting YCC maps to RGB, etc. {
switch (fmt)
{
case cCRNFmtDXT1: return L"DXT1";
case cCRNFmtDXT3: return L"DXT3";
case cCRNFmtDXT5: return L"DXT5";
case cCRNFmtDXT5_CCxY: return L"DXT5_CCxY";
case cCRNFmtDXT5_xGBR: return L"DXT5_xGBR";
case cCRNFmtDXT5_AGBR: return L"DXT5_AGBR";
case cCRNFmtDXT5_xGxR: return L"DXT5_xGxR";
case cCRNFmtDXN_XY: return L"DXN_XY";
case cCRNFmtDXN_YX: return L"DXN_YX";
case cCRNFmtDXT5A: return L"DXT5A";
default: break;
}
CRNLIB_ASSERT(false);
return L"?";
}
uint flags = cCompFlagRValid | cCompFlagGValid | cCompFlagBValid | cCompFlagAValid | cCompFlagGrayscale; const char* get_crn_format_stringa(crn_format fmt)
switch (fmt) { {
case PIXEL_FMT_DXT1: switch (fmt)
case PIXEL_FMT_ETC1: {
case PIXEL_FMT_ETC2: case cCRNFmtDXT1: return "DXT1";
case PIXEL_FMT_ETC1S: { case cCRNFmtDXT3: return "DXT3";
flags = cCompFlagRValid | cCompFlagGValid | cCompFlagBValid; case cCRNFmtDXT5: return "DXT5";
break; case cCRNFmtDXT5_CCxY: return "DXT5_CCxY";
} case cCRNFmtDXT5_xGBR: return "DXT5_xGBR";
case PIXEL_FMT_DXT1A: { case cCRNFmtDXT5_AGBR: return "DXT5_AGBR";
flags = cCompFlagRValid | cCompFlagGValid | cCompFlagBValid | cCompFlagAValid; case cCRNFmtDXT5_xGxR: return "DXT5_xGxR";
break; case cCRNFmtDXN_XY: return "DXN_XY";
} case cCRNFmtDXN_YX: return "DXN_YX";
case PIXEL_FMT_DXT2: case cCRNFmtDXT5A: return "DXT5A";
case PIXEL_FMT_DXT3: { default: break;
flags = cCompFlagRValid | cCompFlagGValid | cCompFlagBValid | cCompFlagAValid; }
break; CRNLIB_ASSERT(false);
} return "?";
case PIXEL_FMT_DXT4: }
case PIXEL_FMT_DXT5:
case PIXEL_FMT_ETC2A:
case PIXEL_FMT_ETC2AS: {
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) { component_flags get_component_flags(pixel_format fmt)
crn_format fmt = cCRNFmtDXT1; {
switch (crn_fmt) { // These flags are for *uncooked* pixels, i.e. after after adding Z to DXN maps, or converting YCC maps to RGB, etc.
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;
case PIXEL_FMT_ETC2:
fmt = cCRNFmtETC2;
break;
case PIXEL_FMT_ETC2A:
fmt = cCRNFmtETC2A;
break;
case PIXEL_FMT_ETC1S:
fmt = cCRNFmtETC1S;
break;
case PIXEL_FMT_ETC2AS:
fmt = cCRNFmtETC2AS;
break;
default: {
CRNLIB_ASSERT(false);
break;
}
}
return fmt;
}
pixel_format convert_crn_format_to_pixel_format(crn_format fmt) { uint flags = cCompFlagRValid | cCompFlagGValid | cCompFlagBValid | cCompFlagAValid | cCompFlagGrayscale;
switch (fmt) { switch (fmt)
case cCRNFmtDXT1: {
return PIXEL_FMT_DXT1; case PIXEL_FMT_DXT1:
case cCRNFmtDXT3: {
return PIXEL_FMT_DXT3; flags = cCompFlagRValid | cCompFlagGValid | cCompFlagBValid;
case cCRNFmtDXT5: break;
return PIXEL_FMT_DXT5; }
case cCRNFmtDXT5_CCxY: case PIXEL_FMT_DXT1A:
return PIXEL_FMT_DXT5_CCxY; {
case cCRNFmtDXT5_xGxR: flags = cCompFlagRValid | cCompFlagGValid | cCompFlagBValid | cCompFlagAValid;
return PIXEL_FMT_DXT5_xGxR; break;
case cCRNFmtDXT5_xGBR: }
return PIXEL_FMT_DXT5_xGBR; case PIXEL_FMT_DXT2:
case cCRNFmtDXT5_AGBR: case PIXEL_FMT_DXT3:
return PIXEL_FMT_DXT5_AGBR; {
case cCRNFmtDXN_XY: flags = cCompFlagRValid | cCompFlagGValid | cCompFlagBValid | cCompFlagAValid;
return PIXEL_FMT_DXN; break;
case cCRNFmtDXN_YX: }
return PIXEL_FMT_3DC; case PIXEL_FMT_DXT4:
case cCRNFmtDXT5A: case PIXEL_FMT_DXT5:
return PIXEL_FMT_DXT5A; {
case cCRNFmtETC1: flags = cCompFlagRValid | cCompFlagGValid | cCompFlagBValid | cCompFlagAValid;
return PIXEL_FMT_ETC1; break;
case cCRNFmtETC2: }
return PIXEL_FMT_ETC2; case PIXEL_FMT_DXT5A:
case cCRNFmtETC2A: {
return PIXEL_FMT_ETC2A; flags = cCompFlagAValid;
case cCRNFmtETC1S: break;
return PIXEL_FMT_ETC1S; }
case cCRNFmtETC2AS: case PIXEL_FMT_DXT5_CCxY:
return PIXEL_FMT_ETC2AS; {
default: { flags = cCompFlagRValid | cCompFlagGValid | cCompFlagBValid | cCompFlagLumaChroma;
CRNLIB_ASSERT(false); break;
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);
}
return PIXEL_FMT_INVALID; 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;
default:
{
CRNLIB_ASSERT(false);
break;
}
}
return fmt;
}
} // namespace pixel_format 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;
default: break;
}
return PIXEL_FMT_INVALID;
}
} // namespace pixel_format
} // namespace crnlib
} // namespace crnlib
+248 -322
View File
@@ -5,348 +5,274 @@
#include "../inc/crnlib.h" #include "../inc/crnlib.h"
#include "../inc/dds_defs.h" #include "../inc/dds_defs.h"
namespace crnlib { namespace crnlib
namespace pixel_format_helpers { {
uint get_num_formats(); namespace pixel_format_helpers
pixel_format get_pixel_format_by_index(uint index); {
uint get_num_formats();
pixel_format get_pixel_format_by_index(uint index);
const char* get_pixel_format_string(pixel_format fmt); const wchar_t* get_pixel_format_string(pixel_format fmt);
const char* get_pixel_format_stringa(pixel_format fmt);
const char* get_crn_format_string(crn_format fmt); const wchar_t* get_crn_format_string(crn_format fmt);
const char* get_crn_format_stringa(crn_format fmt);
inline bool is_grayscale(pixel_format fmt) { inline bool is_grayscale(pixel_format fmt)
switch (fmt) { {
case PIXEL_FMT_L8: switch (fmt)
case PIXEL_FMT_A8L8: {
return true; case PIXEL_FMT_L8:
default: case PIXEL_FMT_A8L8:
break; return true;
} default: break;
return false; }
} return false;
}
inline bool is_dxt1(pixel_format fmt) { inline bool is_dxt1(pixel_format fmt)
return (fmt == PIXEL_FMT_DXT1) || (fmt == PIXEL_FMT_DXT1A); {
} return (fmt == PIXEL_FMT_DXT1) || (fmt == PIXEL_FMT_DXT1A);
}
// has_alpha() should probably be called "has_opacity()" - it indicates if the format encodes opacity inline bool has_alpha(pixel_format fmt)
// because some swizzled DXT5 formats do not encode opacity. {
inline bool has_alpha(pixel_format fmt) { switch (fmt)
switch (fmt) { {
case PIXEL_FMT_DXT1A: case PIXEL_FMT_DXT1A:
case PIXEL_FMT_DXT2: case PIXEL_FMT_DXT2:
case PIXEL_FMT_DXT3: case PIXEL_FMT_DXT3:
case PIXEL_FMT_DXT4: case PIXEL_FMT_DXT4:
case PIXEL_FMT_DXT5: case PIXEL_FMT_DXT5:
case PIXEL_FMT_DXT5A: case PIXEL_FMT_DXT5A:
case PIXEL_FMT_A8R8G8B8: case PIXEL_FMT_A8R8G8B8:
case PIXEL_FMT_A8: case PIXEL_FMT_A8:
case PIXEL_FMT_A8L8: case PIXEL_FMT_A8L8:
case PIXEL_FMT_DXT5_AGBR: return true;
case PIXEL_FMT_ETC2A: default: break;
case PIXEL_FMT_ETC2AS: }
return true; return false;
default: }
break;
}
return false;
}
inline bool is_alpha_only(pixel_format fmt) { inline bool is_alpha_only(pixel_format fmt)
switch (fmt) { {
case PIXEL_FMT_A8: switch (fmt)
case PIXEL_FMT_DXT5A: {
return true; case PIXEL_FMT_A8:
default: case PIXEL_FMT_DXT5A:
break; return true;
} default: break;
return false; }
} return false;
}
inline bool is_normal_map(pixel_format fmt) { inline bool is_normal_map(pixel_format fmt)
switch (fmt) { {
case PIXEL_FMT_3DC: switch (fmt)
case PIXEL_FMT_DXN: {
case PIXEL_FMT_DXT5_xGBR: case PIXEL_FMT_3DC:
case PIXEL_FMT_DXT5_xGxR: case PIXEL_FMT_DXN:
case PIXEL_FMT_DXT5_AGBR: case PIXEL_FMT_DXT5_xGBR:
return true; case PIXEL_FMT_DXT5_xGxR:
default: case PIXEL_FMT_DXT5_AGBR:
break; return true;
} default: break;
return false; }
} return false;
}
inline int is_dxt(pixel_format fmt) { inline int is_dxt(pixel_format fmt)
switch (fmt) { {
case PIXEL_FMT_DXT1: switch (fmt)
case PIXEL_FMT_DXT1A: {
case PIXEL_FMT_DXT2: case PIXEL_FMT_DXT1:
case PIXEL_FMT_DXT3: case PIXEL_FMT_DXT1A:
case PIXEL_FMT_DXT4: case PIXEL_FMT_DXT2:
case PIXEL_FMT_DXT5: case PIXEL_FMT_DXT3:
case PIXEL_FMT_3DC: case PIXEL_FMT_DXT4:
case PIXEL_FMT_DXT5A: case PIXEL_FMT_DXT5:
case PIXEL_FMT_DXN: case PIXEL_FMT_3DC:
case PIXEL_FMT_DXT5_CCxY: case PIXEL_FMT_DXT5A:
case PIXEL_FMT_DXT5_xGxR: case PIXEL_FMT_DXN:
case PIXEL_FMT_DXT5_xGBR: case PIXEL_FMT_DXT5_CCxY:
case PIXEL_FMT_DXT5_AGBR: case PIXEL_FMT_DXT5_xGxR:
case PIXEL_FMT_ETC1: case PIXEL_FMT_DXT5_xGBR:
case PIXEL_FMT_ETC2: case PIXEL_FMT_DXT5_AGBR:
case PIXEL_FMT_ETC2A: return true;
case PIXEL_FMT_ETC1S: default: break;
case PIXEL_FMT_ETC2AS: }
return true; return false;
default: }
break;
}
return false;
}
inline int get_fundamental_format(pixel_format fmt) { inline int get_fundamental_format(pixel_format fmt)
switch (fmt) { {
case PIXEL_FMT_DXT1A: switch (fmt)
return PIXEL_FMT_DXT1; {
case PIXEL_FMT_DXT5_CCxY: case PIXEL_FMT_DXT1A:
case PIXEL_FMT_DXT5_xGxR: return PIXEL_FMT_DXT1;
case PIXEL_FMT_DXT5_xGBR: case PIXEL_FMT_DXT5_CCxY:
case PIXEL_FMT_DXT5_AGBR: case PIXEL_FMT_DXT5_xGxR:
return PIXEL_FMT_DXT5; case PIXEL_FMT_DXT5_xGBR:
default: case PIXEL_FMT_DXT5_AGBR:
break; return PIXEL_FMT_DXT5;
} default: break;
return fmt; }
} return fmt;
}
inline dxt_format get_dxt_format(pixel_format fmt) { inline dxt_format get_dxt_format(pixel_format fmt)
switch (fmt) { {
case PIXEL_FMT_DXT1: switch (fmt)
return cDXT1; {
case PIXEL_FMT_DXT1A: case PIXEL_FMT_DXT1: return cDXT1;
return cDXT1A; case PIXEL_FMT_DXT1A: return cDXT1A;
case PIXEL_FMT_DXT2: case PIXEL_FMT_DXT2: return cDXT3;
return cDXT3; case PIXEL_FMT_DXT3: return cDXT3;
case PIXEL_FMT_DXT3: case PIXEL_FMT_DXT4: return cDXT5;
return cDXT3; case PIXEL_FMT_DXT5: return cDXT5;
case PIXEL_FMT_DXT4: case PIXEL_FMT_3DC: return cDXN_YX;
return cDXT5; case PIXEL_FMT_DXT5A: return cDXT5A;
case PIXEL_FMT_DXT5: case PIXEL_FMT_DXN: return cDXN_XY;
return cDXT5; case PIXEL_FMT_DXT5_CCxY: return cDXT5;
case PIXEL_FMT_3DC: case PIXEL_FMT_DXT5_xGxR: return cDXT5;
return cDXN_YX; case PIXEL_FMT_DXT5_xGBR: return cDXT5;
case PIXEL_FMT_DXT5A: case PIXEL_FMT_DXT5_AGBR: return cDXT5;
return cDXT5A; default: break;
case PIXEL_FMT_DXN: }
return cDXN_XY; return cDXTInvalid;
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;
case PIXEL_FMT_ETC2:
return cETC2;
case PIXEL_FMT_ETC2A:
return cETC2A;
case PIXEL_FMT_ETC1S:
return cETC1S;
case PIXEL_FMT_ETC2AS:
return cETC2AS;
default:
break;
}
return cDXTInvalid;
}
inline pixel_format from_dxt_format(dxt_format dxt_fmt) { inline pixel_format from_dxt_format(dxt_format dxt_fmt)
switch (dxt_fmt) { {
case cDXT1: switch (dxt_fmt)
return PIXEL_FMT_DXT1; {
case cDXT1A: case cDXT1:
return PIXEL_FMT_DXT1A; return PIXEL_FMT_DXT1;
case cDXT3: case cDXT1A:
return PIXEL_FMT_DXT3; return PIXEL_FMT_DXT1A;
case cDXT5: case cDXT3:
return PIXEL_FMT_DXT5; return PIXEL_FMT_DXT3;
case cDXN_XY: case cDXT5:
return PIXEL_FMT_DXN; return PIXEL_FMT_DXT5;
case cDXN_YX: case cDXN_XY:
return PIXEL_FMT_3DC; return PIXEL_FMT_DXN;
case cDXT5A: case cDXN_YX:
return PIXEL_FMT_DXT5A; return PIXEL_FMT_3DC;
case cETC1: case cDXT5A:
return PIXEL_FMT_ETC1; return PIXEL_FMT_DXT5A;
case cETC2: default: break;
return PIXEL_FMT_ETC2; }
case cETC2A: CRNLIB_ASSERT(false);
return PIXEL_FMT_ETC2A; return PIXEL_FMT_INVALID;
case cETC1S: }
return PIXEL_FMT_ETC1S;
case cETC2AS:
return PIXEL_FMT_ETC2AS;
default:
break;
}
CRNLIB_ASSERT(false);
return PIXEL_FMT_INVALID;
}
inline bool is_pixel_format_non_srgb(pixel_format fmt) { inline bool is_pixel_format_non_srgb(pixel_format fmt)
switch (fmt) { {
case PIXEL_FMT_3DC: switch (fmt)
case PIXEL_FMT_DXN: {
case PIXEL_FMT_DXT5A: case PIXEL_FMT_3DC:
case PIXEL_FMT_DXT5_CCxY: case PIXEL_FMT_DXN:
case PIXEL_FMT_DXT5_xGxR: case PIXEL_FMT_DXT5A:
case PIXEL_FMT_DXT5_xGBR: case PIXEL_FMT_DXT5_CCxY:
case PIXEL_FMT_DXT5_AGBR: case PIXEL_FMT_DXT5_xGxR:
return true; case PIXEL_FMT_DXT5_xGBR:
default: case PIXEL_FMT_DXT5_AGBR:
break; return true;
} default: break;
return false; }
} return false;
}
inline bool is_crn_format_non_srgb(crn_format fmt) { inline bool is_crn_format_non_srgb(crn_format fmt)
switch (fmt) { {
case cCRNFmtDXN_XY: switch (fmt)
case cCRNFmtDXN_YX: {
case cCRNFmtDXT5A: case cCRNFmtDXN_XY:
case cCRNFmtDXT5_CCxY: case cCRNFmtDXN_YX:
case cCRNFmtDXT5_xGxR: case cCRNFmtDXT5A:
case cCRNFmtDXT5_xGBR: case cCRNFmtDXT5_CCxY:
case cCRNFmtDXT5_AGBR: case cCRNFmtDXT5_xGxR:
return true; case cCRNFmtDXT5_xGBR:
default: case cCRNFmtDXT5_AGBR:
break; return true;
} default: break;
return false; }
} return false;
}
inline uint get_bpp(pixel_format fmt) { inline uint get_bpp(pixel_format fmt)
switch (fmt) { {
case PIXEL_FMT_DXT1: switch (fmt)
return 4; {
case PIXEL_FMT_DXT1A: case PIXEL_FMT_DXT1: return 4;
return 4; case PIXEL_FMT_DXT1A: return 4;
case PIXEL_FMT_ETC1: case PIXEL_FMT_DXT2: return 8;
return 4; case PIXEL_FMT_DXT3: return 8;
case PIXEL_FMT_ETC2: case PIXEL_FMT_DXT4: return 8;
return 4; case PIXEL_FMT_DXT5: return 8;
case PIXEL_FMT_ETC2A: case PIXEL_FMT_3DC: return 8;
return 8; case PIXEL_FMT_DXT5A: return 4;
case PIXEL_FMT_ETC1S: case PIXEL_FMT_R8G8B8: return 24;
return 4; case PIXEL_FMT_A8R8G8B8: return 32;
case PIXEL_FMT_ETC2AS: case PIXEL_FMT_A8: return 8;
return 8; case PIXEL_FMT_L8: return 8;
case PIXEL_FMT_DXT2: case PIXEL_FMT_A8L8: return 16;
return 8; case PIXEL_FMT_DXN: return 8;
case PIXEL_FMT_DXT3: case PIXEL_FMT_DXT5_CCxY: return 8;
return 8; case PIXEL_FMT_DXT5_xGxR: return 8;
case PIXEL_FMT_DXT4: case PIXEL_FMT_DXT5_xGBR: return 8;
return 8; case PIXEL_FMT_DXT5_AGBR: return 8;
case PIXEL_FMT_DXT5: default: break;
return 8; }
case PIXEL_FMT_3DC: CRNLIB_ASSERT(false);
return 8; return 0;
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) { inline uint get_dxt_bytes_per_block(pixel_format fmt)
switch (fmt) { {
case PIXEL_FMT_DXT1: switch (fmt)
return 8; {
case PIXEL_FMT_DXT1A: case PIXEL_FMT_DXT1: return 8;
return 8; case PIXEL_FMT_DXT1A: return 8;
case PIXEL_FMT_DXT5A: case PIXEL_FMT_DXT5A: return 8;
return 8;
case PIXEL_FMT_ETC1:
return 8;
case PIXEL_FMT_ETC2:
return 8;
case PIXEL_FMT_ETC2A:
return 16;
case PIXEL_FMT_ETC1S:
return 8;
case PIXEL_FMT_ETC2AS:
return 16;
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 { case PIXEL_FMT_DXT2: return 16;
cCompFlagRValid = 1, case PIXEL_FMT_DXT3: return 16;
cCompFlagGValid = 2, case PIXEL_FMT_DXT4: return 16;
cCompFlagBValid = 4, case PIXEL_FMT_DXT5: return 16;
cCompFlagAValid = 8, 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;
}
cCompFlagGrayscale = 16, enum component_flags
cCompFlagNormalMap = 32, {
cCompFlagLumaChroma = 64, cCompFlagRValid = 1,
cCompFlagGValid = 2,
cCompFlagBValid = 4,
cCompFlagAValid = 8,
cDefaultCompFlags = cCompFlagRValid | cCompFlagGValid | cCompFlagBValid | cCompFlagAValid cCompFlagGrayscale = 16,
}; cCompFlagNormalMap = 32,
cCompFlagLumaChroma = 64,
component_flags get_component_flags(pixel_format fmt); cDefaultCompFlags = cCompFlagRValid | cCompFlagGValid | cCompFlagBValid | cCompFlagAValid
};
crn_format convert_pixel_format_to_best_crn_format(pixel_format crn_fmt); component_flags get_component_flags(pixel_format fmt);
pixel_format convert_crn_format_to_pixel_format(crn_format fmt); crn_format convert_pixel_format_to_best_crn_format(pixel_format crn_fmt);
} // namespace pixel_format_helpers pixel_format convert_crn_format_to_pixel_format(crn_format fmt);
} // namespace pixel_format_helpers
} // namespace crnlib
} // namespace crnlib
+9 -71
View File
@@ -1,81 +1,19 @@
// File: crn_platform.cpp // File: crn_platform.cpp
// See Copyright Notice and license at the end of inc/crnlib.h // See Copyright Notice and license at the end of inc/crnlib.h
#include "crn_core.h" #include "crn_core.h"
#if CRNLIB_USE_WIN32_API
#include "crn_winhdr.h"
#endif
#ifndef _MSC_VER
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);
buffer[sizeOfBuffer - 1] = '\0';
if (c < 0)
return 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 c = vsnprintf(buffer, sizeOfBuffer, format, args);
buffer[sizeOfBuffer - 1] = '\0';
if (c < 0)
return 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* strupr(char* p) {
char* q = p;
while (*q) {
char c = *q;
*q++ = toupper(c);
}
return p;
}
#endif // __GNUC__
void crnlib_debug_break(void) {
CRNLIB_BREAKPOINT
}
#if CRNLIB_USE_WIN32_API
#include "crn_winhdr.h" #include "crn_winhdr.h"
bool crnlib_is_debugger_present(void) { bool crnlib_is_debugger_present(void)
return IsDebuggerPresent() != 0; {
return IsDebuggerPresent() != 0;
} }
void crnlib_output_debug_string(const char* p) { void crnlib_debug_break(void)
OutputDebugStringA(p); {
} DebugBreak();
#else
bool crnlib_is_debugger_present(void) {
return false;
} }
void crnlib_output_debug_string(const char* p) { void crnlib_output_debug_string(const char* p)
puts(p); {
OutputDebugStringA(p);
} }
#endif // CRNLIB_USE_WIN32_API
+38 -86
View File
@@ -2,6 +2,44 @@
// See Copyright Notice and license at the end of inc/crnlib.h // See Copyright Notice and license at the end of inc/crnlib.h
#pragma once #pragma once
#ifdef CRNLIB_PLATFORM_PC
const bool c_crnlib_little_endian_platform = true;
#else
const bool c_crnlib_little_endian_platform = false;
#endif
const bool c_crnlib_big_endian_platform = !c_crnlib_little_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()
{
#ifdef CRNLIB_PLATFORM_PC
return true;
#else
return false;
#endif
}
inline bool crnlib_is_x86()
{
#ifdef CRNLIB_PLATFORM_PC_X86
return true;
#else
return false;
#endif
}
inline bool crnlib_is_x64()
{
#ifdef CRNLIB_PLATFORM_PC_X64
return true;
#else
return false;
#endif
}
bool crnlib_is_debugger_present(void); bool crnlib_is_debugger_present(void);
void crnlib_debug_break(void); void crnlib_debug_break(void);
void crnlib_output_debug_string(const char* p); void crnlib_output_debug_string(const char* p);
@@ -9,89 +47,3 @@ void crnlib_output_debug_string(const char* p);
// actually in crnlib_assert.cpp // actually in crnlib_assert.cpp
void crnlib_assert(const char* pExp, const char* pFile, unsigned line); void crnlib_assert(const char* pExp, const char* pFile, unsigned line);
void crnlib_fail(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;
#else
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
#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
#endif
#if CRNLIB_USE_WIN32_API
#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)
#else
#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))
#elif defined(_MSC_VER)
#define CRNLIB_ALIGNED(x) __declspec(align(x))
#define CRNLIB_NOINLINE __declspec(noinline)
#else
#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
#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_pc() {
#ifdef CRNLIB_PLATFORM_PC
return true;
#else
return false;
#endif
}
inline bool crnlib_is_x86() {
#ifdef CRNLIB_PLATFORM_PC_X86
return true;
#else
return false;
#endif
}
inline bool crnlib_is_x64() {
#ifdef CRNLIB_PLATFORM_PC_X64
return true;
#else
return false;
#endif
}

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