4 Commits

129 changed files with 7997 additions and 6255 deletions
+9
View File
@@ -0,0 +1,9 @@
<?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>
+1 -2
View File
@@ -3,7 +3,6 @@
// Ported from the PowerView DOS image viewer, a product I wrote back in 1993. Not currently used in the open source release of crnlib. // Ported from the PowerView DOS image viewer, a product I wrote back in 1993. Not currently used in the open source release of crnlib.
#include "crn_core.h" #include "crn_core.h"
#include "crn_arealist.h" #include "crn_arealist.h"
#include <stdio.h>
#define RECT_DEBUG #define RECT_DEBUG
@@ -20,7 +19,7 @@ namespace crnlib
#ifdef _MSC_VER #ifdef _MSC_VER
_vsnprintf_s(buf, sizeof(buf), pMsg, args); _vsnprintf_s(buf, sizeof(buf), pMsg, args);
#else #else
_vsnprintf(buf, sizeof(buf), pMsg, args); vsnprintf(buf, sizeof(buf), pMsg, args);
#endif #endif
va_end(args); va_end(args);
+8 -16
View File
@@ -1,8 +1,9 @@
// 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"
#include <stdio.h> #endif
static bool g_fail_exceptions; static bool g_fail_exceptions;
static bool g_exit_on_failure = true; static bool g_exit_on_failure = true;
@@ -16,15 +17,11 @@ void crnlib_assert(const char* pExp, const char* pFile, unsigned line)
{ {
char buf[512]; char buf[512];
#if defined(WIN32) && defined(_MSC_VER)
sprintf_s(buf, sizeof(buf), "%s(%u): Assertion failed: \"%s\"\n", pFile, line, pExp); sprintf_s(buf, sizeof(buf), "%s(%u): Assertion failed: \"%s\"\n", pFile, line, pExp);
#else
sprintf(buf, "%s(%u): Assertion failed: \"%s\"\n", pFile, line, pExp);
#endif
crnlib_output_debug_string(buf); crnlib_output_debug_string(buf);
printf(buf); fputs(buf, stderr);
if (crnlib_is_debugger_present()) if (crnlib_is_debugger_present())
crnlib_debug_break(); crnlib_debug_break();
@@ -34,22 +31,21 @@ void crnlib_fail(const char* pExp, const char* pFile, unsigned line)
{ {
char buf[512]; char buf[512];
#if defined(WIN32) && defined(_MSC_VER)
sprintf_s(buf, sizeof(buf), "%s(%u): Failure: \"%s\"\n", pFile, line, pExp); sprintf_s(buf, sizeof(buf), "%s(%u): Failure: \"%s\"\n", pFile, line, pExp);
#else
sprintf(buf, "%s(%u): Failure: \"%s\"\n", pFile, line, pExp);
#endif
crnlib_output_debug_string(buf); crnlib_output_debug_string(buf);
printf(buf); fputs(buf, stderr);
if (crnlib_is_debugger_present()) if (crnlib_is_debugger_present())
crnlib_debug_break(); crnlib_debug_break();
#if CRNLIB_USE_WIN32_API
if (g_fail_exceptions) if (g_fail_exceptions)
RaiseException(CRNLIB_FAIL_EXCEPTION_CODE, 0, 0, NULL); RaiseException(CRNLIB_FAIL_EXCEPTION_CODE, 0, 0, NULL);
else if (g_exit_on_failure) else
#endif
if (g_exit_on_failure)
exit(EXIT_FAILURE); exit(EXIT_FAILURE);
} }
@@ -58,11 +54,7 @@ void trace(const char* pFmt, va_list args)
if (crnlib_is_debugger_present()) if (crnlib_is_debugger_present())
{ {
char buf[512]; char buf[512];
#if defined(WIN32) && defined(_MSC_VER)
vsprintf_s(buf, sizeof(buf), pFmt, args); vsprintf_s(buf, sizeof(buf), pFmt, args);
#else
vsprintf(buf, pFmt, args);
#endif
crnlib_output_debug_string(buf); crnlib_output_debug_string(buf);
} }
+208
View File
@@ -0,0 +1,208 @@
// 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
+16 -21
View File
@@ -2,7 +2,6 @@
// 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
{ {
@@ -13,13 +12,13 @@ namespace crnlib
{ {
} }
cfile_stream(FILE* pFile, const wchar_t* pFilename, uint attribs, bool has_ownership) : 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) data_stream(), m_pFile(NULL), m_size(0), m_ofs(0), m_has_ownership(false)
{ {
open(pFile, pFilename, attribs, has_ownership); open(pFile, pFilename, attribs, has_ownership);
} }
cfile_stream(const wchar_t* pFilename, uint attribs = cDataStreamReadable | cDataStreamSeekable, bool open_existing = false) : cfile_stream(const char* pFilename, uint attribs = cDataStreamReadable | cDataStreamSeekable, bool open_existing = false) :
data_stream(), m_pFile(NULL), m_size(0), m_ofs(0), m_has_ownership(false) data_stream(), m_pFile(NULL), m_size(0), m_ofs(0), m_has_ownership(false)
{ {
open(pFilename, attribs, open_existing); open(pFilename, attribs, open_existing);
@@ -55,7 +54,7 @@ namespace crnlib
return false; return false;
} }
bool open(FILE* pFile, const wchar_t* pFilename, uint attribs, bool has_ownership) bool open(FILE* pFile, const char* pFilename, uint attribs, bool has_ownership)
{ {
CRNLIB_ASSERT(pFile); CRNLIB_ASSERT(pFile);
CRNLIB_ASSERT(pFilename); CRNLIB_ASSERT(pFilename);
@@ -67,17 +66,17 @@ namespace crnlib
m_has_ownership = has_ownership; m_has_ownership = has_ownership;
m_attribs = static_cast<uint16>(attribs); m_attribs = static_cast<uint16>(attribs);
m_ofs = _ftelli64(m_pFile); m_ofs = crn_ftell(m_pFile);
_fseeki64(m_pFile, 0, SEEK_END); crn_fseek(m_pFile, 0, SEEK_END);
m_size = _ftelli64(m_pFile); m_size = crn_ftell(m_pFile);
_fseeki64(m_pFile, m_ofs, SEEK_SET); crn_fseek(m_pFile, m_ofs, SEEK_SET);
m_opened = true; m_opened = true;
return true; return true;
} }
bool open(const wchar_t* pFilename, uint attribs = cDataStreamReadable | cDataStreamSeekable, bool open_existing = false) bool open(const char* pFilename, uint attribs = cDataStreamReadable | cDataStreamSeekable, bool open_existing = false)
{ {
CRNLIB_ASSERT(pFilename); CRNLIB_ASSERT(pFilename);
@@ -85,13 +84,13 @@ namespace crnlib
m_attribs = static_cast<uint16>(attribs); m_attribs = static_cast<uint16>(attribs);
const wchar_t* pMode; const char* pMode;
if ((is_readable()) && (is_writable())) if ((is_readable()) && (is_writable()))
pMode = open_existing ? L"r+b" : L"w+b"; pMode = open_existing ? "r+b" : "w+b";
else if (is_writable()) else if (is_writable())
pMode = open_existing ? L"ab" : L"wb"; pMode = open_existing ? "ab" : "wb";
else if (is_readable()) else if (is_readable())
pMode = L"rb"; pMode = "rb";
else else
{ {
set_error(); set_error();
@@ -99,11 +98,7 @@ namespace crnlib
} }
FILE* pFile = NULL; FILE* pFile = NULL;
#ifdef _MSC_VER crn_fopen(&pFile, pFilename, pMode);
_wfopen_s(&pFile, pFilename, pMode);
#else
pFile = _wfopen(pFilename, pMode);
#endif
m_has_ownership = true; m_has_ownership = true;
if (!pFile) if (!pFile)
@@ -209,7 +204,7 @@ namespace crnlib
if (static_cast<uint64>(new_ofs) != m_ofs) if (static_cast<uint64>(new_ofs) != m_ofs)
{ {
if (_fseeki64(m_pFile, new_ofs, SEEK_SET) != 0) if (crn_fseek(m_pFile, new_ofs, SEEK_SET) != 0)
{ {
set_error(); set_error();
return false; return false;
@@ -221,7 +216,7 @@ namespace crnlib
return true; return true;
} }
static bool read_file_into_array(const wchar_t* pFilename, vector<uint8>& buf) static bool read_file_into_array(const char* pFilename, vector<uint8>& buf)
{ {
cfile_stream in_stream(pFilename); cfile_stream in_stream(pFilename);
if (!in_stream.is_opened()) if (!in_stream.is_opened())
@@ -229,7 +224,7 @@ namespace crnlib
return in_stream.read_array(buf); return in_stream.read_array(buf);
} }
static bool write_array_to_file(const wchar_t* pFilename, const vector<uint8>& buf) static bool write_array_to_file(const char* pFilename, const vector<uint8>& buf)
{ {
cfile_stream out_stream(pFilename, cDataStreamWritable|cDataStreamSeekable); cfile_stream out_stream(pFilename, cDataStreamWritable|cDataStreamSeekable);
if (!out_stream.is_opened()) if (!out_stream.is_opened())
+5 -5
View File
@@ -140,7 +140,7 @@ namespace crnlib
inline uint get_num_training_vecs() const { return m_training_vecs.size(); } inline uint get_num_training_vecs() const { return m_training_vecs.size(); }
const VectorType& get_training_vec(uint index) const { return m_training_vecs[index].first; } const VectorType& get_training_vec(uint index) const { return m_training_vecs[index].first; }
const uint get_training_vec_weight(uint index) const { return m_training_vecs[index].second; } uint get_training_vec_weight(uint index) const { return m_training_vecs[index].second; }
typedef crnlib::vector< std::pair<VectorType, uint> > training_vec_array; typedef crnlib::vector< std::pair<VectorType, uint> > training_vec_array;
@@ -170,7 +170,7 @@ namespace crnlib
return m_codebook; return m_codebook;
} }
const uint find_best_codebook_entry(const VectorType& v) const uint find_best_codebook_entry(const VectorType& v) const
{ {
uint cur_node_index = 0; uint cur_node_index = 0;
@@ -218,7 +218,7 @@ namespace crnlib
} }
} }
const uint find_best_codebook_entry_fs(const VectorType& v) const uint find_best_codebook_entry_fs(const VectorType& v) const
{ {
float best_dist = math::cNearlyInfinite; float best_dist = math::cNearlyInfinite;
uint best_index = 0; uint best_index = 0;
@@ -362,7 +362,7 @@ namespace crnlib
void compute_split_estimate(VectorType& left_child_res, VectorType& right_child_res, const vq_node& parent_node) void compute_split_estimate(VectorType& left_child_res, VectorType& right_child_res, const vq_node& parent_node)
{ {
VectorType furthest; VectorType furthest(0);
double furthest_dist = -1.0f; double furthest_dist = -1.0f;
for (uint i = 0; i < parent_node.m_vectors.size(); i++) for (uint i = 0; i < parent_node.m_vectors.size(); i++)
@@ -377,7 +377,7 @@ namespace crnlib
} }
} }
VectorType opposite; VectorType opposite(0);
double opposite_dist = -1.0f; double opposite_dist = -1.0f;
for (uint i = 0; i < parent_node.m_vectors.size(); i++) for (uint i = 0; i < parent_node.m_vectors.size(); i++)
+14 -14
View File
@@ -11,8 +11,8 @@ namespace crnlib
{ {
cSigned = false, cSigned = false,
cFloat = false, cFloat = false,
cMin = UINT8_MIN, cMin = cUINT8_MIN,
cMax = UINT8_MAX cMax = cUINT8_MAX
}; };
}; };
@@ -22,8 +22,8 @@ namespace crnlib
{ {
cSigned = true, cSigned = true,
cFloat = false, cFloat = false,
cMin = INT16_MIN, cMin = cINT16_MIN,
cMax = INT16_MAX cMax = cINT16_MAX
}; };
}; };
@@ -33,8 +33,8 @@ namespace crnlib
{ {
cSigned = false, cSigned = false,
cFloat = false, cFloat = false,
cMin = UINT16_MIN, cMin = cUINT16_MIN,
cMax = UINT16_MAX cMax = cUINT16_MAX
}; };
}; };
@@ -44,8 +44,8 @@ namespace crnlib
{ {
cSigned = true, cSigned = true,
cFloat = false, cFloat = false,
cMin = INT32_MIN, cMin = cINT32_MIN,
cMax = INT32_MAX cMax = cINT32_MAX
}; };
}; };
@@ -55,8 +55,8 @@ namespace crnlib
{ {
cSigned = false, cSigned = false,
cFloat = false, cFloat = false,
cMin = UINT32_MIN, cMin = cUINT32_MIN,
cMax = UINT32_MAX cMax = cUINT32_MAX
}; };
}; };
@@ -66,8 +66,8 @@ namespace crnlib
{ {
cSigned = false, cSigned = false,
cFloat = true, cFloat = true,
cMin = INT32_MIN, cMin = cINT32_MIN,
cMax = INT32_MAX cMax = cINT32_MAX
}; };
}; };
@@ -77,8 +77,8 @@ namespace crnlib
{ {
cSigned = false, cSigned = false,
cFloat = true, cFloat = true,
cMin = INT32_MIN, cMin = cINT32_MIN,
cMax = INT32_MAX cMax = cINT32_MAX
}; };
}; };
@@ -1,29 +1,31 @@
// File: crn_win32_console.cpp // File: crn_colorized_console.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_win32_console.h" #include "crn_colorized_console.h"
#ifdef CRNLIB_USE_WIN32_API
#include "crn_winhdr.h" #include "crn_winhdr.h"
#endif
namespace crnlib namespace crnlib
{ {
void win32_console::init() void colorized_console::init()
{ {
console::init(); console::init();
console::add_console_output_func(console_output_func, NULL); console::add_console_output_func(console_output_func, NULL);
} }
void win32_console::deinit() void colorized_console::deinit()
{ {
console::remove_console_output_func(console_output_func); console::remove_console_output_func(console_output_func);
console::deinit(); console::deinit();
} }
void win32_console::tick() void colorized_console::tick()
{ {
} }
#ifdef CRNLIB_PLATFORM_PC #ifdef CRNLIB_USE_WIN32_API
bool win32_console::console_output_func(eConsoleMessageType type, const wchar_t* pMsg, void* pData) bool colorized_console::console_output_func(eConsoleMessageType type, const char* pMsg, void* pData)
{ {
pData; pData;
@@ -50,26 +52,26 @@ namespace crnlib
switch (type) switch (type)
{ {
case cDebugConsoleMessage: case cDebugConsoleMessage:
wprintf(L"Debug: %s", pMsg); printf("Debug: %s", pMsg);
break; break;
case cWarningConsoleMessage: case cWarningConsoleMessage:
wprintf(L"Warning: %s", pMsg); printf("Warning: %s", pMsg);
break; break;
case cErrorConsoleMessage: case cErrorConsoleMessage:
wprintf(L"Error: %s", pMsg); printf("Error: %s", pMsg);
break; break;
default: default:
wprintf(L"%s", pMsg); printf("%s", pMsg);
break; break;
} }
} }
else else
{ {
wprintf(L"%s", pMsg); printf("%s", pMsg);
} }
if (console::get_crlf()) if (console::get_crlf())
wprintf(L"\n"); printf("\n");
if (INVALID_HANDLE_VALUE != cons) if (INVALID_HANDLE_VALUE != cons)
SetConsoleTextAttribute(cons, FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE); SetConsoleTextAttribute(cons, FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE);
@@ -77,8 +79,9 @@ namespace crnlib
return true; return true;
} }
#else #else
bool win32_console::console_output_func(eConsoleMessageType type, const wchar_t* pMsg, void* pData) bool colorized_console::console_output_func(eConsoleMessageType type, const char* pMsg, void* pData)
{ {
pData;
if (console::get_output_disabled()) if (console::get_output_disabled())
return true; return true;
@@ -87,26 +90,26 @@ namespace crnlib
switch (type) switch (type)
{ {
case cDebugConsoleMessage: case cDebugConsoleMessage:
wprintf(L"Debug: %s", pMsg); printf("Debug: %s", pMsg);
break; break;
case cWarningConsoleMessage: case cWarningConsoleMessage:
wprintf(L"Warning: %s", pMsg); printf("Warning: %s", pMsg);
break; break;
case cErrorConsoleMessage: case cErrorConsoleMessage:
wprintf(L"Error: %s", pMsg); printf("Error: %s", pMsg);
break; break;
default: default:
wprintf(L"%s", pMsg); printf("%s", pMsg);
break; break;
} }
} }
else else
{ {
wprintf(L"%s", pMsg); printf("%s", pMsg);
} }
if (console::get_crlf()) if (console::get_crlf())
wprintf(L"\n"); printf("\n");
return true; return true;
} }
@@ -1,21 +1,19 @@
// File: crn_win32_console.h // File: crn_colorized_console.h
// 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_console.h" #include "crn_console.h"
#include "crn_event.h"
namespace crnlib namespace crnlib
{ {
class win32_console class colorized_console
{ {
public: public:
static void init(); static void init();
static void deinit(); static void deinit();
static void tick(); static void tick();
private:
static bool console_output_func(eConsoleMessageType type, const wchar_t* pMsg, void* pData);
private:
static bool console_output_func(eConsoleMessageType type, const char* pMsg, void* pData);
}; };
} // namespace crnlib } // namespace crnlib
+157 -124
View File
@@ -5,41 +5,67 @@
#include "crn_console.h" #include "crn_console.h"
#include "crn_cfile_stream.h" #include "crn_cfile_stream.h"
#ifdef WIN32
#define CRNLIB_CMD_LINE_ALLOW_SLASH_PARAMS 1
#endif
#if CRNLIB_USE_WIN32_API
#include "crn_winhdr.h"
#endif
namespace crnlib namespace crnlib
{ {
void get_command_line(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() command_line_params::command_line_params()
{ {
} }
void command_line_params::clear() void command_line_params::clear()
{ {
m_params.clear(); m_params.clear();
m_param_map.clear(); m_param_map.clear();
} }
bool command_line_params::split_params(const wchar_t* p, dynamic_wstring_array& params) bool command_line_params::split_params(const char* p, dynamic_string_array& params)
{ {
bool within_param = false; bool within_param = false;
bool within_quote = false; bool within_quote = false;
uint ofs = 0; uint ofs = 0;
dynamic_wstring str; dynamic_string str;
while (p[ofs]) while (p[ofs])
{ {
const wchar_t c = p[ofs]; const char c = p[ofs];
if (within_param) if (within_param)
{ {
if (within_quote) if (within_quote)
{ {
if (c == L'"') if (c == '"')
within_quote = false; within_quote = false;
str.append_char(c); str.append_char(c);
} }
else if ((c == L' ') || (c == L'\t')) else if ((c == ' ') || (c == '\t'))
{ {
if (!str.is_empty()) if (!str.is_empty())
{ {
@@ -50,141 +76,144 @@ namespace crnlib
} }
else else
{ {
if (c == L'"') if (c == '"')
within_quote = true; within_quote = true;
str.append_char(c); str.append_char(c);
} }
} }
else if ((c != L' ') && (c != L'\t')) else if ((c != ' ') && (c != '\t'))
{ {
within_param = true; within_param = true;
if (c == L'"') if (c == '"')
within_quote = true; within_quote = true;
str.append_char(c); str.append_char(c);
} }
ofs++; ofs++;
} }
if (within_quote) if (within_quote)
{ {
console::error(L"Unmatched quote in command line \"%s\"", p); console::error("Unmatched quote in command line \"%s\"", p);
return false; return false;
} }
if (!str.is_empty()) if (!str.is_empty())
params.push_back(str); params.push_back(str);
return true; return true;
} }
bool command_line_params::load_string_file(const wchar_t* pFilename, dynamic_wstring_array& strings) bool command_line_params::load_string_file(const char* pFilename, dynamic_string_array& strings)
{ {
cfile_stream in_stream; cfile_stream in_stream;
if (!in_stream.open(pFilename, cDataStreamReadable | cDataStreamSeekable)) if (!in_stream.open(pFilename, cDataStreamReadable | cDataStreamSeekable))
{ {
console::error(L"Unable to open file \"%s\" for reading!", pFilename); console::error("Unable to open file \"%s\" for reading!", pFilename);
return false; return false;
} }
dynamic_string ansi_str; dynamic_string ansi_str;
for ( ; ; ) for ( ; ; )
{ {
if (!in_stream.read_line(ansi_str)) if (!in_stream.read_line(ansi_str))
break; break;
ansi_str.trim(); ansi_str.trim();
if (ansi_str.is_empty()) if (ansi_str.is_empty())
continue; continue;
strings.push_back(dynamic_wstring(ansi_str.get_ptr())); strings.push_back(dynamic_string(ansi_str.get_ptr()));
} }
return true; return true;
} }
bool command_line_params::parse(const dynamic_wstring_array& params, uint n, const param_desc* pParam_desc) bool command_line_params::parse(const dynamic_string_array& params, uint n, const param_desc* pParam_desc)
{ {
CRNLIB_ASSERT(n && pParam_desc); CRNLIB_ASSERT(n && pParam_desc);
m_params = params; m_params = params;
uint arg_index = 0; uint arg_index = 0;
while (arg_index < params.size()) while (arg_index < params.size())
{ {
const uint cur_arg_index = arg_index; const uint cur_arg_index = arg_index;
const dynamic_wstring& src_param = params[arg_index++]; const dynamic_string& src_param = params[arg_index++];
if (src_param.is_empty()) if (src_param.is_empty())
continue; continue;
#if CRNLIB_CMD_LINE_ALLOW_SLASH_PARAMS
if ((src_param[0] == L'/') || (src_param[0] == L'-')) if ((src_param[0] == '/') || (src_param[0] == '-'))
#else
if (src_param[0] == '-')
#endif
{ {
if (src_param.get_len() < 2) if (src_param.get_len() < 2)
{ {
console::error(L"Invalid command line parameter: \"%s\"", src_param.get_ptr()); console::error("Invalid command line parameter: \"%s\"", src_param.get_ptr());
return false; return false;
} }
dynamic_wstring key_str(src_param); dynamic_string key_str(src_param);
key_str.right(1); key_str.right(1);
int modifier = 0; int modifier = 0;
wchar_t c = key_str[key_str.get_len() - 1]; char c = key_str[key_str.get_len() - 1];
if (c == L'+') if (c == '+')
modifier = 1; modifier = 1;
else if (c == L'-') else if (c == '-')
modifier = -1; modifier = -1;
if (modifier) if (modifier)
key_str.left(key_str.get_len() - 1); key_str.left(key_str.get_len() - 1);
uint param_index; uint param_index;
for (param_index = 0; param_index < n; param_index++) for (param_index = 0; param_index < n; param_index++)
if (key_str == pParam_desc[param_index].m_pName) if (key_str == pParam_desc[param_index].m_pName)
break; break;
if (param_index == n) if (param_index == n)
{ {
console::error(L"Unrecognized command line parameter: \"%s\"", src_param.get_ptr()); console::error("Unrecognized command line parameter: \"%s\"", src_param.get_ptr());
return false; return false;
} }
const param_desc& desc = pParam_desc[param_index]; const param_desc& desc = pParam_desc[param_index];
const uint cMaxValues = 16; const uint cMaxValues = 16;
dynamic_wstring val_str[cMaxValues]; dynamic_string val_str[cMaxValues];
uint num_val_strs = 0; uint num_val_strs = 0;
if (desc.m_num_values) if (desc.m_num_values)
{ {
CRNLIB_ASSERT(desc.m_num_values <= cMaxValues); CRNLIB_ASSERT(desc.m_num_values <= cMaxValues);
if ((arg_index + desc.m_num_values) > params.size()) if ((arg_index + desc.m_num_values) > params.size())
{ {
console::error(L"Expected %u value(s) after command line parameter: \"%s\"", desc.m_num_values, src_param.get_ptr()); console::error("Expected %u value(s) after command line parameter: \"%s\"", desc.m_num_values, src_param.get_ptr());
return false; return false;
} }
for (uint v = 0; v < desc.m_num_values; v++) for (uint v = 0; v < desc.m_num_values; v++)
val_str[num_val_strs++] = params[arg_index++]; val_str[num_val_strs++] = params[arg_index++];
} }
dynamic_wstring_array strings; dynamic_string_array strings;
if ((desc.m_support_listing_file) && (val_str[0].get_len() >= 2) && (val_str[0][0] == L'@')) if ((desc.m_support_listing_file) && (val_str[0].get_len() >= 2) && (val_str[0][0] == '@'))
{ {
dynamic_wstring filename(val_str[0]); dynamic_string filename(val_str[0]);
filename.right(1); filename.right(1);
filename.unquote(); filename.unquote();
if (!load_string_file(filename.get_ptr(), strings)) if (!load_string_file(filename.get_ptr(), strings))
{ {
console::error(L"Failed loading listing file \"%s\"!", filename.get_ptr()); console::error("Failed loading listing file \"%s\"!", filename.get_ptr());
return false; return false;
} }
} }
@@ -196,7 +225,7 @@ namespace crnlib
strings.push_back(val_str[v]); strings.push_back(val_str[v]);
} }
} }
param_value pv; param_value pv;
pv.m_values.swap(strings); pv.m_values.swap(strings);
pv.m_index = cur_arg_index; pv.m_index = cur_arg_index;
@@ -209,18 +238,18 @@ namespace crnlib
pv.m_values.push_back(src_param); pv.m_values.push_back(src_param);
pv.m_values.back().unquote(); pv.m_values.back().unquote();
pv.m_index = cur_arg_index; pv.m_index = cur_arg_index;
m_param_map.insert(std::make_pair(g_empty_dynamic_wstring, pv)); m_param_map.insert(std::make_pair(g_empty_dynamic_string, pv));
} }
} }
return true; return true;
} }
bool command_line_params::parse(const wchar_t* pCmd_line, uint n, const param_desc* pParam_desc, bool skip_first_param) bool command_line_params::parse(const char* pCmd_line, uint n, const param_desc* pParam_desc, bool skip_first_param)
{ {
CRNLIB_ASSERT(n && pParam_desc); CRNLIB_ASSERT(n && pParam_desc);
dynamic_wstring_array p; dynamic_string_array p;
if (!split_params(pCmd_line, p)) if (!split_params(pCmd_line, p))
return 0; return 0;
@@ -232,110 +261,114 @@ namespace crnlib
return parse(p, n, pParam_desc); return parse(p, n, pParam_desc);
} }
bool command_line_params::is_param(uint index) const bool command_line_params::is_param(uint index) const
{ {
CRNLIB_ASSERT(index < m_params.size()); CRNLIB_ASSERT(index < m_params.size());
if (index >= m_params.size()) if (index >= m_params.size())
return false; return false;
const dynamic_wstring& w = m_params[index]; const dynamic_string& w = m_params[index];
if (w.is_empty()) if (w.is_empty())
return false; return false;
return (w.get_len() >= 2) && ((w[0] == L'-') || (w[0] == L'/')); #if CRNLIB_CMD_LINE_ALLOW_SLASH_PARAMS
return (w.get_len() >= 2) && ((w[0] == '-') || (w[0] == '/'));
#else
return (w.get_len() >= 2) && (w[0] == '-');
#endif
} }
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 uint command_line_params::find(uint num_keys, const char** ppKeys, crnlib::vector<param_map_const_iterator>* pIterators, crnlib::vector<uint>* pUnmatched_indices) const
{ {
CRNLIB_ASSERT(ppKeys); CRNLIB_ASSERT(ppKeys);
if (pUnmatched_indices) if (pUnmatched_indices)
{ {
pUnmatched_indices->resize(m_params.size()); pUnmatched_indices->resize(m_params.size());
for (uint i = 0; i < m_params.size(); i++) for (uint i = 0; i < m_params.size(); i++)
(*pUnmatched_indices)[i] = i; (*pUnmatched_indices)[i] = i;
} }
uint n = 0; uint n = 0;
for (uint i = 0; i < num_keys; i++) for (uint i = 0; i < num_keys; i++)
{ {
const wchar_t* pKey = ppKeys[i]; const char* pKey = ppKeys[i];
param_map_const_iterator begin, end; param_map_const_iterator begin, end;
find(pKey, begin, end); find(pKey, begin, end);
while (begin != end) while (begin != end)
{ {
if (pIterators) if (pIterators)
pIterators->push_back(begin); pIterators->push_back(begin);
if (pUnmatched_indices) if (pUnmatched_indices)
{ {
int k = pUnmatched_indices->find(begin->second.m_index); int k = pUnmatched_indices->find(begin->second.m_index);
if (k >= 0) if (k >= 0)
pUnmatched_indices->erase_unordered(k); pUnmatched_indices->erase_unordered(k);
} }
n++; n++;
begin++; begin++;
} }
} }
return n; return n;
} }
void command_line_params::find(const wchar_t* pKey, param_map_const_iterator& begin, param_map_const_iterator& end) const void command_line_params::find(const char* pKey, param_map_const_iterator& begin, param_map_const_iterator& end) const
{ {
dynamic_wstring key(pKey); dynamic_string key(pKey);
begin = m_param_map.lower_bound(key); begin = m_param_map.lower_bound(key);
end = m_param_map.upper_bound(key); end = m_param_map.upper_bound(key);
} }
uint command_line_params::get_count(const wchar_t* pKey) const uint command_line_params::get_count(const char* pKey) const
{ {
param_map_const_iterator begin, end; param_map_const_iterator begin, end;
find(pKey, begin, end); find(pKey, begin, end);
uint n = 0; uint n = 0;
while (begin != end) while (begin != end)
{ {
n++; n++;
begin++; begin++;
} }
return n; return n;
} }
command_line_params::param_map_const_iterator command_line_params::get_param(const wchar_t* pKey, uint index) const command_line_params::param_map_const_iterator command_line_params::get_param(const char* pKey, uint index) const
{ {
param_map_const_iterator begin, end; param_map_const_iterator begin, end;
find(pKey, begin, end); find(pKey, begin, end);
if (begin == end) if (begin == end)
return m_param_map.end(); return m_param_map.end();
uint n = 0; uint n = 0;
while ((begin != end) && (n != index)) while ((begin != end) && (n != index))
{ {
n++; n++;
begin++; begin++;
} }
if (begin == end) if (begin == end)
return m_param_map.end(); return m_param_map.end();
return begin; return begin;
} }
bool command_line_params::has_value(const wchar_t* pKey, uint index) const bool command_line_params::has_value(const char* pKey, uint index) const
{ {
return get_num_values(pKey, index) != 0; return get_num_values(pKey, index) != 0;
} }
uint command_line_params::get_num_values(const wchar_t* pKey, uint index) const uint command_line_params::get_num_values(const char* pKey, uint index) const
{ {
param_map_const_iterator it = get_param(pKey, index); param_map_const_iterator it = get_param(pKey, index);
@@ -344,76 +377,76 @@ namespace crnlib
return it->second.m_values.size(); return it->second.m_values.size();
} }
bool command_line_params::get_value_as_bool(const wchar_t* pKey, uint index, bool def) const bool command_line_params::get_value_as_bool(const char* pKey, uint index, bool def) const
{ {
param_map_const_iterator it = get_param(pKey, index); param_map_const_iterator it = get_param(pKey, index);
if (it == end()) if (it == end())
return def; return def;
if (it->second.m_modifier) if (it->second.m_modifier)
return it->second.m_modifier > 0; return it->second.m_modifier > 0;
else else
return true; 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 int command_line_params::get_value_as_int(const char* pKey, uint index, int def, int l, int h, uint value_index) const
{ {
param_map_const_iterator it = get_param(pKey, index); param_map_const_iterator it = get_param(pKey, index);
if ((it == end()) || (value_index >= it->second.m_values.size())) if ((it == end()) || (value_index >= it->second.m_values.size()))
return def; return def;
int val; int val;
const wchar_t* p = it->second.m_values[value_index].get_ptr(); const char* p = it->second.m_values[value_index].get_ptr();
if (!string_to_int(p, val)) if (!string_to_int(p, val))
{ {
crnlib::console::warning(L"Invalid value specified for parameter \"%s\", using default value of %i", pKey, def); crnlib::console::warning("Invalid value specified for parameter \"%s\", using default value of %i", pKey, def);
return def; return def;
} }
if (val < l) if (val < l)
{ {
crnlib::console::warning(L"Value %i for parameter \"%s\" is out of range, clamping to %i", val, pKey, l); crnlib::console::warning("Value %i for parameter \"%s\" is out of range, clamping to %i", val, pKey, l);
val = l; val = l;
} }
else if (val > h) else if (val > h)
{ {
crnlib::console::warning(L"Value %i for parameter \"%s\" is out of range, clamping to %i", val, pKey, h); crnlib::console::warning("Value %i for parameter \"%s\" is out of range, clamping to %i", val, pKey, h);
val = h; val = h;
} }
return val; 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 float command_line_params::get_value_as_float(const char* pKey, uint index, float def, float l, float h, uint value_index) const
{ {
param_map_const_iterator it = get_param(pKey, index); param_map_const_iterator it = get_param(pKey, index);
if ((it == end()) || (value_index >= it->second.m_values.size())) if ((it == end()) || (value_index >= it->second.m_values.size()))
return def; return def;
float val; float val;
const wchar_t* p = it->second.m_values[value_index].get_ptr(); const char* p = it->second.m_values[value_index].get_ptr();
if (!string_to_float(p, val)) if (!string_to_float(p, val))
{ {
crnlib::console::warning(L"Invalid value specified for float parameter \"%s\", using default value of %f", pKey, def); crnlib::console::warning("Invalid value specified for float parameter \"%s\", using default value of %f", pKey, def);
return def; return def;
} }
if (val < l) if (val < l)
{ {
crnlib::console::warning(L"Value %f for parameter \"%s\" is out of range, clamping to %f", val, pKey, l); crnlib::console::warning("Value %f for parameter \"%s\" is out of range, clamping to %f", val, pKey, l);
val = l; val = l;
} }
else if (val > h) else if (val > h)
{ {
crnlib::console::warning(L"Value %f for parameter \"%s\" is out of range, clamping to %f", val, pKey, h); crnlib::console::warning("Value %f for parameter \"%s\" is out of range, clamping to %f", val, pKey, h);
val = h; val = h;
} }
return val; return val;
} }
bool command_line_params::get_value_as_string(const wchar_t* pKey, uint index, dynamic_wstring& value, uint value_index) const bool command_line_params::get_value_as_string(const char* pKey, uint index, dynamic_string& value, uint value_index) const
{ {
param_map_const_iterator it = get_param(pKey, index); param_map_const_iterator it = get_param(pKey, index);
if ((it == end()) || (value_index >= it->second.m_values.size())) if ((it == end()) || (value_index >= it->second.m_values.size()))
@@ -425,13 +458,13 @@ namespace crnlib
value = it->second.m_values[value_index]; value = it->second.m_values[value_index];
return true; return true;
} }
const dynamic_wstring& command_line_params::get_value_as_string_or_empty(const wchar_t* pKey, uint index, uint value_index) const const dynamic_string& command_line_params::get_value_as_string_or_empty(const char* pKey, uint index, uint value_index) const
{ {
param_map_const_iterator it = get_param(pKey, index); param_map_const_iterator it = get_param(pKey, index);
if ((it == end()) || (value_index >= it->second.m_values.size())) if ((it == end()) || (value_index >= it->second.m_values.size()))
return g_empty_dynamic_wstring; return g_empty_dynamic_string;
return it->second.m_values[value_index]; return it->second.m_values[value_index];
} }
+49 -47
View File
@@ -6,77 +6,79 @@
namespace crnlib namespace crnlib
{ {
void get_command_line(dynamic_string& cmd_line, int argc, char *argv[]);
class command_line_params class command_line_params
{ {
public: public:
struct param_value struct param_value
{ {
param_value() : m_index(0), m_modifier(0) { } inline param_value() : m_index(0), m_modifier(0) { }
dynamic_wstring_array m_values; dynamic_string_array m_values;
uint m_index; uint m_index;
int8 m_modifier; int8 m_modifier;
}; };
typedef std::multimap<dynamic_wstring, param_value> param_map; typedef std::multimap<dynamic_string, param_value> param_map;
typedef param_map::const_iterator param_map_const_iterator; typedef param_map::const_iterator param_map_const_iterator;
typedef param_map::iterator param_map_iterator; typedef param_map::iterator param_map_iterator;
command_line_params(); 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 struct param_desc
{ {
const wchar_t* m_pName; const char* m_pName;
uint m_num_values; uint m_num_values;
bool m_support_listing_file; bool m_support_listing_file;
}; };
bool parse(const dynamic_wstring_array& params, uint n, const param_desc* pParam_desc); bool parse(const dynamic_string_array& params, uint n, const param_desc* pParam_desc);
bool parse(const wchar_t* pCmd_line, uint n, const param_desc* pParam_desc, bool skip_first_param = true); bool parse(const char* pCmd_line, uint n, const param_desc* pParam_desc, bool skip_first_param = true);
const dynamic_wstring_array& get_array() const { return m_params; } const dynamic_string_array& get_array() const { return m_params; }
bool is_param(uint index) const; bool is_param(uint index) const;
const param_map& get_map() const { return m_param_map; } const param_map& get_map() const { return m_param_map; }
uint get_num_params() const { return static_cast<uint>(m_param_map.size()); } uint get_num_params() const { return static_cast<uint>(m_param_map.size()); }
param_map_const_iterator begin() const { return m_param_map.begin(); } param_map_const_iterator begin() const { return m_param_map.begin(); }
param_map_const_iterator end() const { return m_param_map.end(); } param_map_const_iterator end() const { return m_param_map.end(); }
uint find(uint num_keys, const wchar_t** ppKeys, crnlib::vector<param_map_const_iterator>* pIterators, crnlib::vector<uint>* pUnmatched_indices) const; uint find(uint num_keys, const char** ppKeys, crnlib::vector<param_map_const_iterator>* pIterators, crnlib::vector<uint>* pUnmatched_indices) const;
void find(const 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. // 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; param_map_const_iterator get_param(const char* pKey, uint index) const;
bool has_key(const wchar_t* pKey) const { return get_param(pKey, 0) != end(); } bool has_key(const char* pKey) const { return get_param(pKey, 0) != end(); }
bool has_value(const wchar_t* pKey, uint index) const; bool has_value(const char* pKey, uint index) const;
uint get_num_values(const wchar_t* pKey, uint index) const; uint get_num_values(const char* pKey, uint index) const;
bool get_value_as_bool(const wchar_t* pKey, uint index = 0, bool def = false) const; bool get_value_as_bool(const char* pKey, uint index = 0, bool def = false) const;
int get_value_as_int(const wchar_t* pKey, uint index, int def, int l = INT_MIN, int h = INT_MAX, uint value_index = 0) const; int get_value_as_int(const char* pKey, uint index, int def, int l = INT_MIN, int h = INT_MAX, uint value_index = 0) const;
float get_value_as_float(const wchar_t* pKey, uint index, float def = 0.0f, float l = -math::cNearlyInfinite, float h = math::cNearlyInfinite, uint value_index = 0) const; float get_value_as_float(const char* pKey, uint index, float def = 0.0f, float l = -math::cNearlyInfinite, float h = math::cNearlyInfinite, uint value_index = 0) const;
bool get_value_as_string(const wchar_t* pKey, uint index, dynamic_wstring& value, uint value_index = 0) const; bool get_value_as_string(const char* pKey, uint index, dynamic_string& value, uint value_index = 0) const;
const dynamic_wstring& get_value_as_string_or_empty(const wchar_t* pKey, uint index = 0, uint value_index = 0) const; const dynamic_string& get_value_as_string_or_empty(const char* pKey, uint index = 0, uint value_index = 0) const;
private: private:
dynamic_wstring_array m_params; dynamic_string_array m_params;
param_map m_param_map; 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
+475 -475
View File
File diff suppressed because it is too large Load Diff
+52 -52
View File
@@ -18,30 +18,30 @@ namespace crnlib
class crn_comp : public itexture_comp class crn_comp : public itexture_comp
{ {
CRNLIB_NO_COPY_OR_ASSIGNMENT_OP(crn_comp); CRNLIB_NO_COPY_OR_ASSIGNMENT_OP(crn_comp);
public: public:
crn_comp(); crn_comp();
virtual ~crn_comp(); virtual ~crn_comp();
virtual const wchar_t *get_ext() const { return L"CRN"; } virtual const char *get_ext() const { return "CRN"; }
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; }
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];
struct struct level_tag
{ {
uint m_width, m_height; uint m_width, m_height;
uint m_chunk_width, m_chunk_height; uint m_chunk_width, m_chunk_height;
@@ -50,130 +50,130 @@ namespace crnlib
uint m_first_chunk; uint m_first_chunk;
uint m_group_first_chunk; uint m_group_first_chunk;
} m_levels[cCRNMaxLevels]; } m_levels[cCRNMaxLevels];
struct mip_group struct mip_group
{ {
mip_group() : m_first_chunk(0), m_num_chunks(0) { } mip_group() : m_first_chunk(0), m_num_chunks(0) { }
uint m_first_chunk; uint m_first_chunk;
uint m_num_chunks; uint m_num_chunks;
}; };
crnlib::vector<mip_group> m_mip_groups; crnlib::vector<mip_group> m_mip_groups;
enum comp enum comp
{ {
cColor, cColor,
cAlpha0, cAlpha0,
cAlpha1, cAlpha1,
cNumComps cNumComps
}; };
bool m_has_comp[cNumComps]; bool m_has_comp[cNumComps];
struct chunk_detail struct chunk_detail
{ {
chunk_detail() { utils::zero_object(*this); } chunk_detail() { utils::zero_object(*this); }
uint m_first_endpoint_index; uint m_first_endpoint_index;
uint m_first_selector_index; uint m_first_selector_index;
}; };
typedef crnlib::vector<chunk_detail> chunk_detail_vec; typedef crnlib::vector<chunk_detail> chunk_detail_vec;
chunk_detail_vec m_chunk_details; chunk_detail_vec m_chunk_details;
crnlib::vector<uint> m_endpoint_indices[cNumComps]; crnlib::vector<uint> m_endpoint_indices[cNumComps];
crnlib::vector<uint> m_selector_indices[cNumComps]; crnlib::vector<uint> m_selector_indices[cNumComps];
uint m_total_chunks; uint m_total_chunks;
dxt_hc::pixel_chunk_vec m_chunks; dxt_hc::pixel_chunk_vec m_chunks;
crnd::crn_header m_crn_header; crnd::crn_header m_crn_header;
crnlib::vector<uint8> m_comp_data; crnlib::vector<uint8> m_comp_data;
dxt_hc m_hvq; dxt_hc m_hvq;
symbol_histogram m_chunk_encoding_hist; symbol_histogram m_chunk_encoding_hist;
static_huffman_data_model m_chunk_encoding_dm; static_huffman_data_model m_chunk_encoding_dm;
symbol_histogram m_endpoint_index_hist[2]; symbol_histogram m_endpoint_index_hist[2];
static_huffman_data_model m_endpoint_index_dm[2]; // color, alpha static_huffman_data_model m_endpoint_index_dm[2]; // color, alpha
symbol_histogram m_selector_index_hist[2]; symbol_histogram m_selector_index_hist[2];
static_huffman_data_model m_selector_index_dm[2]; // color, alpha static_huffman_data_model m_selector_index_dm[2]; // color, alpha
crnlib::vector<uint8> m_packed_chunks[cCRNMaxLevels]; crnlib::vector<uint8> m_packed_chunks[cCRNMaxLevels];
crnlib::vector<uint8> m_packed_data_models; crnlib::vector<uint8> m_packed_data_models;
crnlib::vector<uint8> m_packed_color_endpoints; crnlib::vector<uint8> m_packed_color_endpoints;
crnlib::vector<uint8> m_packed_color_selectors; crnlib::vector<uint8> m_packed_color_selectors;
crnlib::vector<uint8> m_packed_alpha_endpoints; crnlib::vector<uint8> m_packed_alpha_endpoints;
crnlib::vector<uint8> m_packed_alpha_selectors; crnlib::vector<uint8> m_packed_alpha_selectors;
void clear(); void clear();
void append_chunks(const image_u8& img, uint num_chunks_x, uint num_chunks_y, dxt_hc::pixel_chunk_vec& chunks, float weight); void append_chunks(const image_u8& img, uint num_chunks_x, uint num_chunks_y, dxt_hc::pixel_chunk_vec& chunks, float weight);
static float color_endpoint_similarity_func(uint index_a, uint index_b, void* pContext); static float 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); 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_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); 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_color_endpoints(crnlib::vector<uint8>& data, const crnlib::vector<uint>& remapping, const crnlib::vector<uint>& endpoint_indices, uint trial_index);
bool pack_alpha_endpoints(crnlib::vector<uint8>& data, const crnlib::vector<uint>& remapping, const crnlib::vector<uint>& endpoint_indices, uint trial_index); bool pack_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 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); 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); void sort_selector_codebook(crnlib::vector<uint>& remapping, const crnlib::vector<dxt_hc::selectors>& selectors, const uint8* pTo_linear);
bool pack_selectors( bool pack_selectors(
crnlib::vector<uint8>& packed_data, crnlib::vector<uint8>& packed_data,
const crnlib::vector<uint>& selector_indices, const crnlib::vector<uint>& selector_indices,
const crnlib::vector<dxt_hc::selectors>& selectors, const crnlib::vector<dxt_hc::selectors>& selectors,
const crnlib::vector<uint>& remapping, const crnlib::vector<uint>& remapping,
uint max_selector_value, uint max_selector_value,
const uint8* pTo_linear, const uint8* pTo_linear,
uint trial_index); uint trial_index);
bool alias_images(); bool alias_images();
void create_chunks(); void create_chunks();
bool quantize_chunks(); bool quantize_chunks();
void create_chunk_indices(); void create_chunk_indices();
bool pack_chunks( bool pack_chunks(
uint first_chunk, uint num_chunks, uint first_chunk, uint num_chunks,
bool clear_histograms, bool clear_histograms,
symbol_codec* pCodec, symbol_codec* pCodec,
const crnlib::vector<uint>* pColor_endpoint_remap, const crnlib::vector<uint>* pColor_endpoint_remap,
const crnlib::vector<uint>* pColor_selector_remap, const crnlib::vector<uint>* pColor_selector_remap,
const crnlib::vector<uint>* pAlpha_endpoint_remap, const crnlib::vector<uint>* pAlpha_endpoint_remap,
const crnlib::vector<uint>* pAlpha_selector_remap); const crnlib::vector<uint>* pAlpha_selector_remap);
bool pack_chunks_simulation( bool pack_chunks_simulation(
uint first_chunk, uint num_chunks, uint first_chunk, uint num_chunks,
uint& total_bits, uint& total_bits,
const crnlib::vector<uint>* pColor_endpoint_remap, const crnlib::vector<uint>* pColor_endpoint_remap,
const crnlib::vector<uint>* pColor_selector_remap, const crnlib::vector<uint>* pColor_selector_remap,
const crnlib::vector<uint>* pAlpha_endpoint_remap, const crnlib::vector<uint>* pAlpha_endpoint_remap,
const crnlib::vector<uint>* pAlpha_selector_remap); const crnlib::vector<uint>* pAlpha_selector_remap);
void optimize_color_endpoint_codebook_task(uint64 data, void* pData_ptr); void optimize_color_endpoint_codebook_task(uint64 data, void* pData_ptr);
bool optimize_color_endpoint_codebook(crnlib::vector<uint>& remapping); bool optimize_color_endpoint_codebook(crnlib::vector<uint>& remapping);
void optimize_color_selector_codebook_task(uint64 data, void* pData_ptr); void optimize_color_selector_codebook_task(uint64 data, void* pData_ptr);
bool optimize_color_selector_codebook(crnlib::vector<uint>& remapping); bool optimize_color_selector_codebook(crnlib::vector<uint>& remapping);
void optimize_alpha_endpoint_codebook_task(uint64 data, void* pData_ptr); void optimize_alpha_endpoint_codebook_task(uint64 data, void* pData_ptr);
bool optimize_alpha_endpoint_codebook(crnlib::vector<uint>& remapping); bool optimize_alpha_endpoint_codebook(crnlib::vector<uint>& remapping);
void optimize_alpha_selector_codebook_task(uint64 data, void* pData_ptr); void optimize_alpha_selector_codebook_task(uint64 data, void* pData_ptr);
bool optimize_alpha_selector_codebook(crnlib::vector<uint>& remapping); bool optimize_alpha_selector_codebook(crnlib::vector<uint>& remapping);
bool create_comp_data(); bool create_comp_data();
bool pack_data_models(); bool pack_data_models();
bool update_progress(uint phase_index, uint subphase_index, uint subphase_total); bool update_progress(uint phase_index, uint subphase_index, uint subphase_total);
bool compress_internal(); bool compress_internal();
static void append_vec(crnlib::vector<uint8>& a, const void* p, uint size); static void append_vec(crnlib::vector<uint8>& a, const void* p, uint size);
static void append_vec(crnlib::vector<uint8>& a, const crnlib::vector<uint8>& b); static void append_vec(crnlib::vector<uint8>& a, const crnlib::vector<uint8>& b);
}; };
-431
View File
@@ -1,431 +0,0 @@
// 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
@@ -1,91 +0,0 @@
// 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
+22 -35
View File
@@ -3,6 +3,7 @@
#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
{ {
@@ -48,7 +49,7 @@ namespace crnlib
m_crlf = true; m_crlf = true;
} }
void console::vprintf(eConsoleMessageType type, const wchar_t* p, va_list args) void console::vprintf(eConsoleMessageType type, const char* p, va_list args)
{ {
init(); init();
@@ -56,12 +57,8 @@ namespace crnlib
m_num_messages[type]++; m_num_messages[type]++;
wchar_t buf[cConsoleBufSize]; char buf[cConsoleBufSize];
#ifdef _MSC_VER vsprintf_s(buf, cConsoleBufSize, p, args);
vswprintf_s(buf, cConsoleBufSize, p, args);
#else
vswprintf(buf, p, args);
#endif
bool handled = false; bool handled = false;
@@ -72,48 +69,38 @@ namespace crnlib
handled = true; handled = true;
} }
const wchar_t* pPrefix = NULL; const char* pPrefix = NULL;
if (m_prefixes) if (m_prefixes)
{ {
switch (type) switch (type)
{ {
case cDebugConsoleMessage: pPrefix = L"Debug: "; break; case cDebugConsoleMessage: pPrefix = "Debug: "; break;
case cWarningConsoleMessage: pPrefix = L"Warning: "; break; case cWarningConsoleMessage: pPrefix = "Warning: "; break;
case cErrorConsoleMessage: pPrefix = L"Error: "; break; case cErrorConsoleMessage: pPrefix = "Error: "; break;
default: break; default: break;
} }
} }
if ((!m_output_disabled) && (!handled)) if ((!m_output_disabled) && (!handled))
{ {
#ifdef _XBOX
if (pPrefix) if (pPrefix)
OutputDebugStringW(pPrefix); ::printf("%s", pPrefix);
OutputDebugStringW(buf); ::printf(m_crlf ? "%s\n" : "%s", buf);
if (m_crlf)
OutputDebugStringW(L"\n");
#else
if (pPrefix)
::wprintf(pPrefix);
::wprintf(m_crlf ? L"%s\n" : L"%s", buf);
#endif
} }
if ((type != cProgressConsoleMessage) && (m_pLog_stream)) if ((type != cProgressConsoleMessage) && (m_pLog_stream))
{ {
// Yes this is bad. // Yes this is bad.
dynamic_wstring utf16_buf(buf); dynamic_string tmp_buf(buf);
dynamic_string ansi_buf; tmp_buf.translate_lf_to_crlf();
utf16_buf.as_ansi(ansi_buf);
ansi_buf.translate_lf_to_crlf();
m_pLog_stream->printf(m_crlf ? "%s\r\n" : "%s", ansi_buf.get_ptr()); m_pLog_stream->printf(m_crlf ? "%s\r\n" : "%s", tmp_buf.get_ptr());
m_pLog_stream->flush(); m_pLog_stream->flush();
} }
} }
void console::printf(eConsoleMessageType type, const wchar_t* p, ...) void console::printf(eConsoleMessageType type, const char* p, ...)
{ {
va_list args; va_list args;
va_start(args, p); va_start(args, p);
@@ -121,7 +108,7 @@ namespace crnlib
va_end(args); va_end(args);
} }
void console::printf(const wchar_t* p, ...) void console::printf(const char* p, ...)
{ {
va_list args; va_list args;
va_start(args, p); va_start(args, p);
@@ -172,7 +159,7 @@ namespace crnlib
} }
} }
void console::progress(const wchar_t* p, ...) void console::progress(const char* p, ...)
{ {
va_list args; va_list args;
va_start(args, p); va_start(args, p);
@@ -180,7 +167,7 @@ namespace crnlib
va_end(args); va_end(args);
} }
void console::info(const wchar_t* p, ...) void console::info(const char* p, ...)
{ {
va_list args; va_list args;
va_start(args, p); va_start(args, p);
@@ -188,7 +175,7 @@ namespace crnlib
va_end(args); va_end(args);
} }
void console::message(const wchar_t* p, ...) void console::message(const char* p, ...)
{ {
va_list args; va_list args;
va_start(args, p); va_start(args, p);
@@ -196,7 +183,7 @@ namespace crnlib
va_end(args); va_end(args);
} }
void console::cons(const wchar_t* p, ...) void console::cons(const char* p, ...)
{ {
va_list args; va_list args;
va_start(args, p); va_start(args, p);
@@ -204,7 +191,7 @@ namespace crnlib
va_end(args); va_end(args);
} }
void console::debug(const wchar_t* p, ...) void console::debug(const char* p, ...)
{ {
va_list args; va_list args;
va_start(args, p); va_start(args, p);
@@ -212,7 +199,7 @@ namespace crnlib
va_end(args); va_end(args);
} }
void console::warning(const wchar_t* p, ...) void console::warning(const char* p, ...)
{ {
va_list args; va_list args;
va_start(args, p); va_start(args, p);
@@ -220,7 +207,7 @@ namespace crnlib
va_end(args); va_end(args);
} }
void console::error(const wchar_t* p, ...) void console::error(const char* p, ...)
{ {
va_list args; va_list args;
va_start(args, p); va_start(args, p);
+65 -34
View File
@@ -3,92 +3,123 @@
#pragma once #pragma once
#include "crn_dynamic_string.h" #include "crn_dynamic_string.h"
#ifdef WIN32
#include <tchar.h>
#include <conio.h>
#endif
namespace crnlib namespace crnlib
{ {
class dynamic_string; class dynamic_string;
class data_stream; class data_stream;
class mutex; class mutex;
enum eConsoleMessageType enum eConsoleMessageType
{ {
cDebugConsoleMessage, // debugging messages cDebugConsoleMessage, // debugging messages
cProgressConsoleMessage, // progress messages cProgressConsoleMessage, // progress messages
cInfoConsoleMessage, // ordinary messages cInfoConsoleMessage, // ordinary messages
cConsoleConsoleMessage, // user console output cConsoleConsoleMessage, // user console output
cMessageConsoleMessage, // high importance messages cMessageConsoleMessage, // high importance messages
cWarningConsoleMessage, // warnings cWarningConsoleMessage, // warnings
cErrorConsoleMessage, // errors cErrorConsoleMessage, // errors
cCMTTotal cCMTTotal
}; };
typedef bool (*console_output_func)(eConsoleMessageType type, const wchar_t* pMsg, void* pData); typedef bool (*console_output_func)(eConsoleMessageType type, const char* pMsg, void* pData);
class console class console
{ {
public: public:
static void init(); static void init();
static void deinit(); 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 wchar_t* p, ...); static void printf(const char* p, ...);
static void vprintf(eConsoleMessageType type, const wchar_t* p, va_list args); static void vprintf(eConsoleMessageType type, const char* p, va_list args);
static void printf(eConsoleMessageType type, const wchar_t* p, ...); static void printf(eConsoleMessageType type, const char* p, ...);
static void cons(const wchar_t* p, ...); static void cons(const char* p, ...);
static void debug(const wchar_t* p, ...); static void debug(const char* p, ...);
static void progress(const wchar_t* p, ...); static void progress(const char* p, ...);
static void info(const wchar_t* p, ...); static void info(const char* p, ...);
static void message(const wchar_t* p, ...); static void message(const char* p, ...);
static void warning(const wchar_t* p, ...); static void warning(const char* p, ...);
static void error(const wchar_t* p, ...); static void error(const char* 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 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];
}; };
#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 } // namespace crnlib
+10 -3
View File
@@ -1,7 +1,14 @@
// 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"
#include "crn_winhdr.h"
char *g_copyright_str = "Copyright (c) 2010-2012 Rich Geldreich and Tenacious Software LLC"; #if CRNLIB_USE_WIN32_API
char *g_sig_str = "C8cfRlaorj0wLtnMSxrBJxTC85rho2L9hUZKHcBL"; #include "crn_winhdr.h"
#endif
namespace crnlib
{
const char *g_copyright_str = "Copyright (c) 2010-2012 Rich Geldreich and Tenacious Software LLC";
const char *g_sig_str = "C8cfRlaorj0wLtnMSxrBJxTC85rho2L9hUZKHcBL";
} // namespace crnlib
+104 -29
View File
@@ -6,38 +6,34 @@
#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) #if defined(WIN32) && !defined(CRNLIB_ANSI_CPLUSPLUS)
// MSVC or MinGW, x86 or x64, Win32 API's for threading and Win32 Interlocked API's or GCC built-ins for atomic ops.
#if 0
#ifdef NDEBUG #ifdef NDEBUG
// Ensure checked iterators are disabled. // Ensure checked iterators are disabled.
#define _SECURE_SCL 0 #define _SECURE_SCL 0
#define _HAS_ITERATOR_DEBUGGING 0 #define _HAS_ITERATOR_DEBUGGING 0
#endif #endif
#ifndef _DLL #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. // 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 (up to 5%) speed boost. // Otherwise, we disable exceptions for a small speed boost.
#define _HAS_EXCEPTIONS 0 #define _HAS_EXCEPTIONS 0
#endif #endif
#endif
//#define _CRT_SECURE_NO_WARNINGS
#define NOMINMAX #define NOMINMAX
#define CRNLIB_PLATFORM_PC 1
#ifdef _WIN64
#define CRNLIB_PLATFORM_PC_X64 1
#else
#define CRNLIB_PLATFORM_PC_X86 1
#endif
#define CRNLIB_USE_WIN32_API 1 #define CRNLIB_USE_WIN32_API 1
#ifdef _WIN64 #if defined(__MINGW32__) || defined(__MINGW64__)
#define CRNLIB_USE_GCC_ATOMIC_BUILTINS 1
#else
#define CRNLIB_USE_WIN32_ATOMIC_FUNCTIONS 1
#endif
#define CRNLIB_PLATFORM_PC 1
#if defined(_WIN64) || defined(__MINGW64__) || defined(_LP64) || defined(__LP64__)
#define CRNLIB_PLATFORM_PC_X64 1 #define CRNLIB_PLATFORM_PC_X64 1
#define CRNLIB_64BIT_POINTERS 1 #define CRNLIB_64BIT_POINTERS 1
#define CRNLIB_CPU_HAS_64BIT_REGISTERS 1 #define CRNLIB_CPU_HAS_64BIT_REGISTERS 1
@@ -48,15 +44,99 @@
#define CRNLIB_CPU_HAS_64BIT_REGISTERS 0 #define CRNLIB_CPU_HAS_64BIT_REGISTERS 0
#define CRNLIB_LITTLE_ENDIAN_CPU 1 #define CRNLIB_LITTLE_ENDIAN_CPU 1
#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 #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
@@ -78,16 +158,15 @@
#ifndef NDEBUG #ifndef NDEBUG
#define NDEBUG #define NDEBUG
#endif #endif
#ifdef DEBUG
#error DEBUG cannot be defined in CRNLIB_BUILD_RELEASE
#endif
#endif #endif
#include "crn_platform.h"
#if defined(WIN32)
#include "crn_mutex.h"
#endif
#include "crn_assert.h"
#include "crn_types.h" #include "crn_types.h"
#include "crn_assert.h"
#include "crn_platform.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"
@@ -95,9 +174,5 @@
#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_win32_timer.h" #include "crn_timer.h"
#include "crn_win32_threading.h"
#include "crn_dynamic_string.h" #include "crn_dynamic_string.h"
#include "crn_dynamic_wstring.h"
+3 -29
View File
@@ -2,7 +2,6 @@
// 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
{ {
@@ -12,7 +11,7 @@ namespace crnlib
{ {
} }
data_stream::data_stream(const wchar_t* pName, uint attribs) : data_stream::data_stream(const char* 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_error(false), m_got_cr(false) m_opened(false), m_error(false), m_got_cr(false)
@@ -85,28 +84,11 @@ namespace crnlib
va_list args; va_list args;
va_start(args, p); va_start(args, p);
char buf[4096]; dynamic_string buf;
#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); buf.format_args(p, args);
va_end(args); va_end(args);
return write(buf.get_ptr(), buf.get_len() * sizeof(wchar_t)) == buf.get_len() * sizeof(wchar_t); return write(buf.get_ptr(), buf.get_len() * sizeof(char)) == buf.get_len() * sizeof(char);
} }
bool data_stream::write_line(const dynamic_string& str) bool data_stream::write_line(const dynamic_string& str)
@@ -117,14 +99,6 @@ namespace crnlib
return true; return true;
} }
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);
return true;
}
bool data_stream::read_array(vector<uint8>& buf) bool data_stream::read_array(vector<uint8>& buf)
{ {
if (buf.size() < get_remaining()) if (buf.size() < get_remaining())
+31 -33
View File
@@ -10,82 +10,80 @@ namespace crnlib
cDataStreamWritable = 2, cDataStreamWritable = 2,
cDataStreamSeekable = 4 cDataStreamSeekable = 4
}; };
const int64 DATA_STREAM_SIZE_UNKNOWN = INT64_MAX; const int64 DATA_STREAM_SIZE_UNKNOWN = cINT64_MAX;
const int64 DATA_STREAM_SIZE_INFINITE = UINT64_MAX; const int64 DATA_STREAM_SIZE_INFINITE = cUINT64_MAX;
class data_stream class data_stream
{ {
data_stream(const data_stream&); data_stream(const data_stream&);
data_stream& operator= (const data_stream&); data_stream& operator= (const data_stream&);
public: public:
data_stream(); data_stream();
data_stream(const wchar_t* pName, uint attribs); data_stream(const char* pName, uint attribs);
virtual ~data_stream() { } virtual ~data_stream() { }
virtual data_stream *get_parent() { return NULL; } virtual data_stream *get_parent() { return NULL; }
virtual bool close() { m_opened = false; m_error = false; m_got_cr = false; return true; } virtual bool close() { m_opened = false; m_error = false; m_got_cr = false; return true; }
typedef uint16 attribs_t; 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_wstring& get_name() const { return m_name; } inline const dynamic_string& get_name() const { return m_name; }
inline void set_name(const wchar_t* pName) { m_name.set(pName); } inline void set_name(const char* 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() { uint8 c; if (read(&c, 1) != 1) return -1; return c; } inline int read_byte() { uint8 c; if (read(&c, 1) != 1) return -1; return c; }
inline bool write_byte(uint8 c) { return write(&c, 1) == 1; } inline 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 printf(const wchar_t* p, ...);
bool write_line(const dynamic_string& str); bool write_line(const dynamic_string& str);
bool write_line(const dynamic_wstring& str);
bool write_bom() { uint16 bom = 0xFEFF; 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_wstring m_name; dynamic_string 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
+4 -4
View File
@@ -15,7 +15,7 @@ namespace crnlib
dds_comp(); dds_comp();
virtual ~dds_comp(); virtual ~dds_comp();
virtual const wchar_t *get_ext() const { return L"DDS"; } virtual const char *get_ext() const { return "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);
@@ -23,7 +23,7 @@ namespace crnlib
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:
dds_texture m_src_tex; dds_texture m_src_tex;
dds_texture m_packed_tex; dds_texture m_packed_tex;
@@ -31,7 +31,7 @@ namespace crnlib
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;
@@ -39,7 +39,7 @@ namespace crnlib
qdxt1_params m_q1_params; qdxt1_params m_q1_params;
qdxt5_params m_q5_params; qdxt5_params m_q5_params;
dds_texture::qdxt_state *m_pQDXT_state; dds_texture::qdxt_state *m_pQDXT_state;
void clear(); void clear();
bool create_dds_tex(dds_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);
+74 -74
View File
@@ -216,7 +216,7 @@ namespace crnlib
if (m_pImage->is_grayscale()) if (m_pImage->is_grayscale())
m_format = m_pImage->has_alpha() ? PIXEL_FMT_A8L8 : PIXEL_FMT_L8; m_format = m_pImage->has_alpha() ? PIXEL_FMT_A8L8 : PIXEL_FMT_L8;
else else
m_format = m_pImage->has_alpha() ? PIXEL_FMT_A8R8G8B8 : PIXEL_FMT_R8G8B8; m_format = m_pImage->has_alpha() ? PIXEL_FMT_A8R8G8B8 : PIXEL_FMT_R8G8B8;
return true; return true;
@@ -380,7 +380,7 @@ namespace crnlib
return *this; return *this;
} }
bool dds_texture::write_dds(const wchar_t* pFilename) const bool dds_texture::write_dds(const char* pFilename) const
{ {
cfile_stream out_stream(pFilename, cDataStreamWritable | cDataStreamSeekable); cfile_stream out_stream(pFilename, cDataStreamWritable | cDataStreamSeekable);
if (!out_stream.is_opened()) if (!out_stream.is_opened())
@@ -390,7 +390,7 @@ namespace crnlib
return write_dds(out_serializer); return write_dds(out_serializer);
} }
bool dds_texture::read_dds(const wchar_t* pFilename) bool dds_texture::read_dds(const char* pFilename)
{ {
cfile_stream in_stream(pFilename); cfile_stream in_stream(pFilename);
if (!in_stream.is_opened()) if (!in_stream.is_opened())
@@ -417,7 +417,7 @@ namespace crnlib
clear(); clear();
set_last_error(L"Not a DDS file"); set_last_error("Not a DDS file");
uint8 hdr[4]; uint8 hdr[4];
if (!serializer.read(hdr, sizeof(hdr))) if (!serializer.read(hdr, sizeof(hdr)))
@@ -460,7 +460,7 @@ namespace crnlib
const uint all_faces_mask = DDSCAPS2_CUBEMAP_POSITIVEX|DDSCAPS2_CUBEMAP_NEGATIVEX|DDSCAPS2_CUBEMAP_POSITIVEY|DDSCAPS2_CUBEMAP_NEGATIVEY|DDSCAPS2_CUBEMAP_POSITIVEZ|DDSCAPS2_CUBEMAP_NEGATIVEZ; const uint all_faces_mask = DDSCAPS2_CUBEMAP_POSITIVEX|DDSCAPS2_CUBEMAP_NEGATIVEX|DDSCAPS2_CUBEMAP_POSITIVEY|DDSCAPS2_CUBEMAP_NEGATIVEY|DDSCAPS2_CUBEMAP_POSITIVEZ|DDSCAPS2_CUBEMAP_NEGATIVEZ;
if ((desc.ddsCaps.dwCaps2 & all_faces_mask) != all_faces_mask) if ((desc.ddsCaps.dwCaps2 & all_faces_mask) != all_faces_mask)
{ {
set_last_error(L"Incomplete cubemaps unsupported"); set_last_error("Incomplete cubemaps unsupported");
return false; return false;
} }
@@ -468,7 +468,7 @@ namespace crnlib
} }
else if (desc.ddsCaps.dwCaps2 & DDSCAPS2_VOLUME) else if (desc.ddsCaps.dwCaps2 & DDSCAPS2_VOLUME)
{ {
set_last_error(L"Volume textures unsupported"); set_last_error("Volume textures unsupported");
return false; return false;
} }
} }
@@ -479,7 +479,7 @@ namespace crnlib
// nvdxt just hangs // nvdxt just hangs
// dxtex.exe just makes all-white textures // dxtex.exe just makes all-white textures
// So screw it. // So screw it.
set_last_error(L"Palettized textures unsupported"); set_last_error("Palettized textures unsupported");
return false; return false;
} }
@@ -555,7 +555,7 @@ namespace crnlib
} }
default: default:
{ {
dynamic_wstring err_msg(cVarArg, L"Unsupported DDS FOURCC format: 0x%08X", desc.ddpfPixelFormat.dwFourCC); dynamic_string err_msg(cVarArg, "Unsupported DDS FOURCC format: 0x%08X", desc.ddpfPixelFormat.dwFourCC);
set_last_error(err_msg.get_ptr()); set_last_error(err_msg.get_ptr());
return false; return false;
} }
@@ -563,7 +563,7 @@ namespace crnlib
} }
else if ((desc.ddpfPixelFormat.dwRGBBitCount < 8) || (desc.ddpfPixelFormat.dwRGBBitCount > 32) || (desc.ddpfPixelFormat.dwRGBBitCount & 7)) else if ((desc.ddpfPixelFormat.dwRGBBitCount < 8) || (desc.ddpfPixelFormat.dwRGBBitCount > 32) || (desc.ddpfPixelFormat.dwRGBBitCount & 7))
{ {
set_last_error(L"Unsupported bit count"); set_last_error("Unsupported bit count");
return false; return false;
} }
else if (desc.ddpfPixelFormat.dwFlags & DDPF_RGB) else if (desc.ddpfPixelFormat.dwFlags & DDPF_RGB)
@@ -597,7 +597,7 @@ namespace crnlib
} }
else else
{ {
set_last_error(L"Unsupported format"); set_last_error("Unsupported format");
return false; return false;
} }
@@ -609,7 +609,7 @@ namespace crnlib
//bits_per_pixel = ((m_format == PIXEL_FMT_DXT1) || (m_format == PIXEL_FMT_DXT5A)) ? 4 : 8; //bits_per_pixel = ((m_format == PIXEL_FMT_DXT1) || (m_format == PIXEL_FMT_DXT5A)) ? 4 : 8;
bits_per_pixel = pixel_format_helpers::get_bpp(m_format); bits_per_pixel = pixel_format_helpers::get_bpp(m_format);
set_last_error(L"Load failed"); set_last_error("Load failed");
uint default_pitch; uint default_pitch;
if (desc.ddpfPixelFormat.dwFlags & DDPF_FOURCC) if (desc.ddpfPixelFormat.dwFlags & DDPF_FOURCC)
@@ -620,19 +620,19 @@ namespace crnlib
uint pitch = desc.lPitch; uint pitch = desc.lPitch;
if (!pitch) if (!pitch)
pitch = default_pitch; pitch = default_pitch;
#if 0 #if 0
else if (pitch & 3) else if (pitch & 3)
{ {
// MS's DDS docs say the pitch must be DWORD aligned - but this isn't always the case. // MS's DDS docs say the pitch must be DWORD aligned - but this isn't always the case.
// ATI Compressonator writes images with non-DWORD aligned pitches, and the DDSWithoutD3DX sample from MS doesn't compute the proper DWORD aligned pitch when reading DDS // ATI Compressonator writes images with non-DWORD aligned pitches, and the DDSWithoutD3DX sample from MS doesn't compute the proper DWORD aligned pitch when reading DDS
// files, so the docs must be wrong/outdated. // files, so the docs must be wrong/outdated.
console::warning(L"DDS file's pitch is not divisible by 4 - trying to load anyway."); console::warning("DDS file's pitch is not divisible by 4 - trying to load anyway.");
} }
#endif #endif
// Check for obviously wacky source pitches (probably a corrupted/invalid file). // Check for obviously wacky source pitches (probably a corrupted/invalid file).
else if (pitch > default_pitch * 8) else if (pitch > default_pitch * 8)
{ {
set_last_error(L"Invalid pitch"); set_last_error("Invalid pitch");
return false; return false;
} }
@@ -869,11 +869,11 @@ namespace crnlib
{ {
if (!m_width) if (!m_width)
{ {
set_last_error(L"Nothing to write"); set_last_error("Nothing to write");
return false; return false;
} }
set_last_error(L"Write_dds() failed"); set_last_error("Write_dds() failed");
if (!serializer.write("DDS ", sizeof(uint32))) if (!serializer.write("DDS ", sizeof(uint32)))
return false; return false;
@@ -1017,7 +1017,7 @@ namespace crnlib
desc.lPitch = (desc.dwWidth * bits_per_pixel) >> 3; desc.lPitch = (desc.dwWidth * bits_per_pixel) >> 3;
desc.dwFlags |= DDSD_LINEARSIZE; desc.dwFlags |= DDSD_LINEARSIZE;
} }
if (!c_crnlib_little_endian_platform) if (!c_crnlib_little_endian_platform)
utils::endian_switch_dwords(reinterpret_cast<uint32*>(&desc), sizeof(desc) / sizeof(uint32)); utils::endian_switch_dwords(reinterpret_cast<uint32*>(&desc), sizeof(desc) / sizeof(uint32));
@@ -1257,7 +1257,7 @@ namespace crnlib
CRNLIB_ASSERT(check()); CRNLIB_ASSERT(check());
} }
void dds_texture::init(uint width, uint height, uint levels, uint faces, pixel_format fmt, const wchar_t* pName) void dds_texture::init(uint width, uint height, uint levels, uint faces, pixel_format fmt, const char* pName)
{ {
clear(); clear();
@@ -2029,7 +2029,7 @@ namespace crnlib
{ {
dxt1_blocks.resize(state.m_pixel_blocks.size()); dxt1_blocks.resize(state.m_pixel_blocks.size());
float pow_mul = 1.0f; float pow_mul = 1.0f;
if (state.m_fmt == PIXEL_FMT_DXT5_CCxY) if (state.m_fmt == PIXEL_FMT_DXT5_CCxY)
{ {
// use a "deeper" codebook size curves when compressing chroma into DXT1, because it's not as important // use a "deeper" codebook size curves when compressing chroma into DXT1, because it's not as important
@@ -2099,7 +2099,7 @@ namespace crnlib
return true; return true;
} }
bool dds_texture::load_from_file(const wchar_t* pFilename, texture_file_types::format file_format) bool dds_texture::load_from_file(const char* pFilename, texture_file_types::format file_format)
{ {
clear(); clear();
@@ -2108,11 +2108,11 @@ namespace crnlib
if (file_format == texture_file_types::cFormatInvalid) if (file_format == texture_file_types::cFormatInvalid)
{ {
set_last_error(L"Unrecognized image format extension"); set_last_error("Unrecognized image format extension");
return false; return false;
} }
set_last_error(L"Image file load failed"); set_last_error("Image file load failed");
bool success = false; bool success = false;
switch (file_format) switch (file_format)
@@ -2143,7 +2143,7 @@ namespace crnlib
return success; return success;
} }
bool dds_texture::load_regular(const wchar_t* pFilename, texture_file_types::format file_format) bool dds_texture::load_regular(const char* pFilename, texture_file_types::format file_format)
{ {
file_format; file_format;
@@ -2153,7 +2153,7 @@ namespace crnlib
{ {
crnlib_delete(pImg); crnlib_delete(pImg);
set_last_error(L"Failed loading image file"); set_last_error("Failed loading image file");
return false; return false;
} }
@@ -2166,12 +2166,12 @@ namespace crnlib
return true; return true;
} }
bool dds_texture::load_dds(const wchar_t* pFilename) bool dds_texture::load_dds(const char* pFilename)
{ {
cfile_stream in_stream; cfile_stream in_stream;
if (!in_stream.open(pFilename)) if (!in_stream.open(pFilename))
{ {
set_last_error(L"Failed opening file"); set_last_error("Failed opening file");
return false; return false;
} }
@@ -2188,11 +2188,11 @@ namespace crnlib
return true; return true;
} }
bool dds_texture::load_crn_from_memory(const wchar_t* pFilename, const void *pData, uint data_size) bool dds_texture::load_crn_from_memory(const char* pFilename, const void *pData, uint data_size)
{ {
clear(); clear();
set_last_error(L"Image file load failed"); set_last_error("Image file load failed");
if ((!pData) || (data_size < 1)) return false; if ((!pData) || (data_size < 1)) return false;
@@ -2200,14 +2200,14 @@ namespace crnlib
tex_info.m_struct_size = sizeof(crnd::crn_texture_info); tex_info.m_struct_size = sizeof(crnd::crn_texture_info);
if (!crnd_get_texture_info(pData, data_size, &tex_info)) if (!crnd_get_texture_info(pData, data_size, &tex_info))
{ {
set_last_error(L"crnd_get_texture_info() failed"); set_last_error("crnd_get_texture_info() failed");
return false; return false;
} }
const pixel_format dds_fmt = (pixel_format)crnd::crnd_crn_format_to_fourcc(tex_info.m_format); const pixel_format dds_fmt = (pixel_format)crnd::crnd_crn_format_to_fourcc(tex_info.m_format);
if (dds_fmt == PIXEL_FMT_INVALID) if (dds_fmt == PIXEL_FMT_INVALID)
{ {
set_last_error(L"Unsupported DXT format"); set_last_error("Unsupported DXT format");
return false; return false;
} }
@@ -2229,7 +2229,7 @@ namespace crnlib
// Create temp buffer big enough to hold the largest mip level, and all faces if it's a cubemap. // Create temp buffer big enough to hold the largest mip level, and all faces if it's a cubemap.
dxt_data.resize(tex_info.m_bytes_per_block * tex_num_blocks_x * tex_num_blocks_y * tex_info.m_faces); dxt_data.resize(tex_info.m_bytes_per_block * tex_num_blocks_x * tex_num_blocks_y * tex_info.m_faces);
set_last_error(L"CRN unpack failed"); set_last_error("CRN unpack failed");
timer t; timer t;
double total_time = 0.0f; double total_time = 0.0f;
@@ -2305,7 +2305,7 @@ namespace crnlib
#if 0 #if 0
if (total_pixels) if (total_pixels)
{ {
console::info(L"load_crn: Total pixels: %u, ms: %3.3fms, megapixels/sec: %3.3f", console::info("load_crn: Total pixels: %u, ms: %3.3fms, megapixels/sec: %3.3f",
total_pixels, total_time * 1000.0f, total_pixels / total_time); total_pixels, total_time * 1000.0f, total_pixels / total_time);
} }
#endif #endif
@@ -2321,19 +2321,19 @@ namespace crnlib
return true; return true;
} }
bool dds_texture::load_crn(const wchar_t* pFilename) bool dds_texture::load_crn(const char* pFilename)
{ {
cfile_stream in_stream; cfile_stream in_stream;
if (!in_stream.open(pFilename)) if (!in_stream.open(pFilename))
{ {
set_last_error(L"Failed opening CRN file"); set_last_error("Failed opening CRN file");
return false; return false;
} }
crnlib::vector<uint8> crn_data; crnlib::vector<uint8> crn_data;
if (!in_stream.read_array(crn_data)) if (!in_stream.read_array(crn_data))
{ {
set_last_error(L"Failed reading CRN file"); set_last_error("Failed reading CRN file");
return false; return false;
} }
@@ -2343,7 +2343,7 @@ namespace crnlib
} }
bool dds_texture::write_to_file( bool dds_texture::write_to_file(
const wchar_t* pFilename, const char* pFilename,
texture_file_types::format file_format, texture_file_types::format file_format,
crn_comp_params* pCRN_comp_params, crn_comp_params* pCRN_comp_params,
uint32 *pActual_quality_level, float *pActual_bitrate) uint32 *pActual_quality_level, float *pActual_bitrate)
@@ -2353,7 +2353,7 @@ namespace crnlib
if (!is_valid()) if (!is_valid())
{ {
set_last_error(L"Unable to save empty texture"); set_last_error("Unable to save empty texture");
return false; return false;
} }
@@ -2386,26 +2386,26 @@ namespace crnlib
return success; return success;
} }
bool dds_texture::save_regular(const wchar_t* pFilename) bool dds_texture::save_regular(const char* pFilename)
{ {
image_u8 tmp; image_u8 tmp;
image_u8* pLevel_image = get_level_image(0, 0, tmp); image_u8* pLevel_image = get_level_image(0, 0, tmp);
if (!image_utils::save_to_file(pFilename, *pLevel_image, 0)) if (!image_utils::save_to_file(pFilename, *pLevel_image, 0))
{ {
set_last_error(L"File write failed"); set_last_error("File write failed");
return false; return false;
} }
return true; return true;
} }
bool dds_texture::save_dds(const wchar_t* pFilename) bool dds_texture::save_dds(const char* pFilename)
{ {
cfile_stream out_stream; cfile_stream out_stream;
if (!out_stream.open(pFilename, cDataStreamWritable | cDataStreamSeekable)) if (!out_stream.open(pFilename, cDataStreamWritable | cDataStreamSeekable))
{ {
set_last_error(L"Unable to open file"); set_last_error("Unable to open file");
return false; return false;
} }
@@ -2413,7 +2413,7 @@ namespace crnlib
if (!write_dds(serializer)) if (!write_dds(serializer))
{ {
set_last_error(L"File write failed"); set_last_error("File write failed");
return false; return false;
} }
@@ -2422,34 +2422,34 @@ namespace crnlib
void dds_texture::print_crn_comp_params(const crn_comp_params& p) void dds_texture::print_crn_comp_params(const crn_comp_params& p)
{ {
console::debug(L"CRN compression params:"); console::debug("CRN compression params:");
console::debug(L" File Type: %s", crn_get_file_type_ext(p.m_file_type)); console::debug(" File Type: %s", crn_get_file_type_ext(p.m_file_type));
console::debug(L" Quality level: %u", p.m_quality_level); console::debug(" Quality level: %u", p.m_quality_level);
console::debug(L" Target Bitrate: %f", p.m_target_bitrate); console::debug(" Target Bitrate: %f", p.m_target_bitrate);
console::debug(L" Faces: %u", p.m_faces); console::debug(" Faces: %u", p.m_faces);
console::debug(L" Width: %u", p.m_width); console::debug(" Width: %u", p.m_width);
console::debug(L" Height: %u", p.m_height); console::debug(" Height: %u", p.m_height);
console::debug(L" Levels: %u", p.m_levels); console::debug(" Levels: %u", p.m_levels);
console::debug(L" Pixel Format: %s", crn_get_format_string(p.m_format)); console::debug(" Pixel Format: %s", crn_get_format_string(p.m_format));
console::debug(L"Use manual CRN palette sizes: %u", p.get_flag(cCRNCompFlagManualPaletteSizes)); console::debug("Use manual CRN palette sizes: %u", p.get_flag(cCRNCompFlagManualPaletteSizes));
console::debug(L"Color endpoints: %u", p.m_crn_color_endpoint_palette_size); console::debug("Color endpoints: %u", p.m_crn_color_endpoint_palette_size);
console::debug(L"Color selectors: %u", p.m_crn_color_selector_palette_size); console::debug("Color selectors: %u", p.m_crn_color_selector_palette_size);
console::debug(L"Alpha endpoints: %u", p.m_crn_alpha_endpoint_palette_size); console::debug("Alpha endpoints: %u", p.m_crn_alpha_endpoint_palette_size);
console::debug(L"Alpha selectors: %u", p.m_crn_alpha_selector_palette_size); console::debug("Alpha selectors: %u", p.m_crn_alpha_selector_palette_size);
console::debug(L"Flags:"); console::debug("Flags:");
console::debug(L" Perceptual: %u", p.get_flag(cCRNCompFlagPerceptual)); console::debug(" Perceptual: %u", p.get_flag(cCRNCompFlagPerceptual));
console::debug(L" Hierarchical: %u", p.get_flag(cCRNCompFlagHierarchical)); console::debug(" Hierarchical: %u", p.get_flag(cCRNCompFlagHierarchical));
console::debug(L" UseBothBlockTypes: %u", p.get_flag(cCRNCompFlagUseBothBlockTypes)); console::debug(" UseBothBlockTypes: %u", p.get_flag(cCRNCompFlagUseBothBlockTypes));
console::debug(L" UseTransparentIndicesForBlack: %u", p.get_flag(cCRNCompFlagUseTransparentIndicesForBlack)); console::debug(" UseTransparentIndicesForBlack: %u", p.get_flag(cCRNCompFlagUseTransparentIndicesForBlack));
console::debug(L" DisableEndpointCaching: %u", p.get_flag(cCRNCompFlagDisableEndpointCaching)); console::debug(" DisableEndpointCaching: %u", p.get_flag(cCRNCompFlagDisableEndpointCaching));
console::debug(L"GrayscaleSampling: %u", p.get_flag(cCRNCompFlagGrayscaleSampling)); console::debug("GrayscaleSampling: %u", p.get_flag(cCRNCompFlagGrayscaleSampling));
console::debug(L" UseDXT1ATransparency: %u", p.get_flag(cCRNCompFlagDXT1AForTransparency)); console::debug(" UseDXT1ATransparency: %u", p.get_flag(cCRNCompFlagDXT1AForTransparency));
console::debug(L"AdaptiveTileColorPSNRDerating: %2.2fdB", p.m_crn_adaptive_tile_color_psnr_derating); console::debug("AdaptiveTileColorPSNRDerating: %2.2fdB", p.m_crn_adaptive_tile_color_psnr_derating);
console::debug(L"AdaptiveTileAlphaPSNRDerating: %2.2fdB", p.m_crn_adaptive_tile_alpha_psnr_derating); console::debug("AdaptiveTileAlphaPSNRDerating: %2.2fdB", p.m_crn_adaptive_tile_alpha_psnr_derating);
console::debug(L"NumHelperThreads: %u", p.m_num_helper_threads); console::debug("NumHelperThreads: %u", p.m_num_helper_threads);
} }
bool dds_texture::save_comp_texture(const wchar_t* pFilename, const crn_comp_params &orig_comp_params, uint32 *pActual_quality_level, float *pActual_bitrate) bool dds_texture::save_comp_texture(const char* pFilename, const crn_comp_params &orig_comp_params, uint32 *pActual_quality_level, float *pActual_bitrate)
{ {
crn_comp_params comp_params(orig_comp_params); crn_comp_params comp_params(orig_comp_params);
@@ -2458,7 +2458,7 @@ namespace crnlib
if (math::maximum(get_height(), get_width()) > cCRNMaxLevelResolution) if (math::maximum(get_height(), get_width()) > cCRNMaxLevelResolution)
{ {
set_last_error(L"Texture resolution is too big!"); set_last_error("Texture resolution is too big!");
return false; return false;
} }
@@ -2487,32 +2487,32 @@ namespace crnlib
crnlib::vector<uint8> comp_data; crnlib::vector<uint8> comp_data;
if (!create_compressed_texture(comp_params, comp_data, pActual_quality_level, pActual_bitrate)) if (!create_compressed_texture(comp_params, comp_data, pActual_quality_level, pActual_bitrate))
{ {
set_last_error(L"CRN compression failed"); set_last_error("CRN compression failed");
return false; return false;
} }
double total_time = t.get_elapsed_secs(); double total_time = t.get_elapsed_secs();
if (comp_params.get_flag(cCRNCompFlagDebugging)) if (comp_params.get_flag(cCRNCompFlagDebugging))
{ {
console::debug(L"\nTotal compression time: %3.3fs", total_time); console::debug("\nTotal compression time: %3.3fs", total_time);
} }
cfile_stream out_stream; cfile_stream out_stream;
if (!out_stream.open(pFilename, cDataStreamWritable | cDataStreamSeekable)) if (!out_stream.open(pFilename, cDataStreamWritable | cDataStreamSeekable))
{ {
set_last_error(L"Failed opening file"); set_last_error("Failed opening file");
return false; return false;
} }
if (out_stream.write(comp_data.get_ptr(), comp_data.size()) != comp_data.size()) if (out_stream.write(comp_data.get_ptr(), comp_data.size()) != comp_data.size())
{ {
set_last_error(L"Failed writing to file"); set_last_error("Failed writing to file");
return false; return false;
} }
if (!out_stream.close()) if (!out_stream.close())
{ {
set_last_error(L"Failed writing to file"); set_last_error("Failed writing to file");
return false; return false;
} }
+78 -78
View File
@@ -15,7 +15,7 @@
namespace crnlib namespace crnlib
{ {
extern const vec2I g_vertical_cross_image_offsets[6]; extern const vec2I g_vertical_cross_image_offsets[6];
class mip_level class mip_level
{ {
friend class dds_texture; friend class dds_texture;
@@ -23,29 +23,29 @@ namespace crnlib
public: public:
mip_level(); mip_level();
~mip_level(); ~mip_level();
mip_level(const mip_level& other); mip_level(const mip_level& other);
mip_level& operator= (const mip_level& rhs); mip_level& operator= (const mip_level& rhs);
// Assumes ownership. // Assumes ownership.
void assign(image_u8* p, pixel_format fmt = PIXEL_FMT_INVALID); void assign(image_u8* p, pixel_format fmt = PIXEL_FMT_INVALID);
void assign(dxt_image* p, pixel_format fmt = PIXEL_FMT_INVALID); void assign(dxt_image* p, pixel_format fmt = PIXEL_FMT_INVALID);
void clear(); void clear();
inline uint get_width() const { return m_width; } inline uint get_width() const { return m_width; }
inline uint get_height() const { return m_height; } inline uint get_height() const { return m_height; }
inline uint get_total_pixels() const { return m_width * m_height; } inline uint get_total_pixels() const { return m_width * m_height; }
inline image_u8* get_image() const { return m_pImage; } inline image_u8* get_image() const { return m_pImage; }
inline dxt_image* get_dxt_image() const { return m_pDXTImage; } inline dxt_image* get_dxt_image() const { return m_pDXTImage; }
image_u8* get_unpacked_image(image_u8& tmp, bool uncook) const; image_u8* get_unpacked_image(image_u8& tmp, bool uncook) const;
inline bool is_packed() const { return m_pDXTImage != NULL; } inline bool is_packed() const { return m_pDXTImage != NULL; }
inline bool is_valid() const { return (m_pImage != NULL) || (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 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 void set_comp_flags(pixel_format_helpers::component_flags comp_flags) { m_comp_flags = comp_flags; }
@@ -53,35 +53,35 @@ namespace crnlib
inline void set_format(pixel_format fmt) { m_format = fmt; } inline void set_format(pixel_format fmt) { m_format = fmt; }
bool convert(pixel_format fmt, bool cook, const dxt_image::pack_params& p); 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(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 pack_to_dxt(pixel_format fmt, bool cook, const dxt_image::pack_params& p);
bool unpack_from_dxt(bool uncook = true); bool unpack_from_dxt(bool uncook = true);
bool set_alpha_to_luma(); bool set_alpha_to_luma();
bool convert(image_utils::conversion_type conv_type); bool convert(image_utils::conversion_type conv_type);
private: private:
uint m_width; uint m_width;
uint m_height; uint m_height;
pixel_format_helpers::component_flags m_comp_flags; pixel_format_helpers::component_flags m_comp_flags;
pixel_format m_format; pixel_format m_format;
image_u8* m_pImage; image_u8* m_pImage;
dxt_image* m_pDXTImage; dxt_image* m_pDXTImage;
void cook_image(image_u8& img) const; void cook_image(image_u8& img) const;
void uncook_image(image_u8& img) const; void uncook_image(image_u8& img) const;
}; };
// A face is an array of mip_level ptr's. // A face is an array of mip_level ptr's.
typedef crnlib::vector<mip_level*> mip_ptr_vec; typedef crnlib::vector<mip_level*> mip_ptr_vec;
// And an array of one, six, or N faces make up a texture. // And an array of one, six, or N faces make up a texture.
typedef crnlib::vector<mip_ptr_vec> face_vec; typedef crnlib::vector<mip_ptr_vec> face_vec;
class dds_texture class dds_texture
{ {
public: public:
@@ -93,8 +93,8 @@ namespace crnlib
dds_texture& operator= (const dds_texture& rhs); dds_texture& operator= (const dds_texture& rhs);
void clear(); void clear();
void init(uint width, uint height, uint levels, uint faces, pixel_format fmt, const wchar_t* pName); void init(uint width, uint height, uint levels, uint faces, pixel_format fmt, const char* pName);
// Assumes ownership. // Assumes ownership.
void assign(face_vec& faces); void assign(face_vec& faces);
@@ -109,10 +109,10 @@ namespace crnlib
inline bool is_valid() const { return m_faces.size() > 0; } inline bool is_valid() const { return m_faces.size() > 0; }
const dynamic_wstring& get_name() const { return m_name; } const dynamic_string& get_name() const { return m_name; }
void set_name(const dynamic_wstring& name) { m_name = name; } void set_name(const dynamic_string& name) { m_name = name; }
const dynamic_wstring& get_source_filename() const { return get_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; } 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_width() const { return m_width; }
@@ -133,34 +133,34 @@ namespace crnlib
inline const mip_level* get_level(uint face, uint mip) const { return m_faces[face][mip]; } 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]; } inline mip_level* get_level(uint face, uint mip) { return m_faces[face][mip]; }
bool has_alpha() const; bool has_alpha() const;
bool is_normal_map() const; bool is_normal_map() const;
bool is_vertical_cross() const; bool is_vertical_cross() const;
bool is_packed() const; bool is_packed() const;
texture_type determine_texture_type() const; texture_type determine_texture_type() const;
const dynamic_wstring& get_last_error() const { return m_last_error; } const dynamic_string& get_last_error() const { return m_last_error; }
void clear_last_error() { m_last_error.clear(); } void clear_last_error() { m_last_error.clear(); }
// Loading/saving // Loading/saving
bool read_dds(const wchar_t* pFilename); bool read_dds(const char* pFilename);
bool read_dds(data_stream_serializer& serializer); bool read_dds(data_stream_serializer& serializer);
bool write_dds(const wchar_t* pFilename) const; bool write_dds(const char* pFilename) const;
bool write_dds(data_stream_serializer& serializer) const; bool write_dds(data_stream_serializer& serializer) const;
bool load_crn_from_memory(const wchar_t* pFilename, const void *pData, uint data_size); bool load_crn_from_memory(const char* 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. // 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 load_from_file(const char* pFilename, texture_file_types::format file_format);
bool write_to_file( bool write_to_file(
const wchar_t* pFilename, const char* pFilename,
texture_file_types::format file_format, texture_file_types::format file_format,
crn_comp_params* pCRN_comp_params, crn_comp_params* pCRN_comp_params,
uint32 *pActual_quality_level, float *pActual_bitrate); uint32 *pActual_quality_level, float *pActual_bitrate);
// Conversion // Conversion
bool convert(pixel_format fmt, bool cook, const dxt_image::pack_params& p); 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, const dxt_image::pack_params& p);
@@ -168,16 +168,16 @@ namespace crnlib
bool convert(image_utils::conversion_type conv_type); bool convert(image_utils::conversion_type conv_type);
bool unpack_from_dxt(bool uncook = true); bool unpack_from_dxt(bool uncook = true);
bool set_alpha_to_luma(); bool set_alpha_to_luma();
void discard_mipmaps(); void discard_mipmaps();
void discard_mips(); void discard_mips();
struct resample_params struct resample_params
{ {
resample_params() : resample_params() :
m_pFilter("kaiser"), m_pFilter("kaiser"),
m_wrapping(false), m_wrapping(false),
m_srgb(false), m_srgb(false),
@@ -186,8 +186,8 @@ namespace crnlib
m_gamma(1.75f), // or 2.2f m_gamma(1.75f), // or 2.2f
m_multithreaded(true) m_multithreaded(true)
{ {
} }
const char* m_pFilter; const char* m_pFilter;
bool m_wrapping; bool m_wrapping;
bool m_srgb; bool m_srgb;
@@ -196,45 +196,45 @@ namespace crnlib
float m_gamma; float m_gamma;
bool m_multithreaded; bool m_multithreaded;
}; };
bool resize(uint new_width, uint new_height, const resample_params& params); bool resize(uint new_width, uint new_height, const resample_params& params);
struct generate_mipmap_params : public resample_params struct generate_mipmap_params : public resample_params
{ {
generate_mipmap_params() : generate_mipmap_params() :
resample_params(), resample_params(),
m_min_mip_size(1), m_min_mip_size(1),
m_max_mips(0) m_max_mips(0)
{ {
} }
uint m_min_mip_size; uint m_min_mip_size;
uint m_max_mips; // actually the max # of total levels uint m_max_mips; // actually the max # of total levels
}; };
bool generate_mipmaps(const generate_mipmap_params& params, bool force); bool generate_mipmaps(const generate_mipmap_params& params, bool force);
bool crop(uint x, uint y, uint width, uint height); bool crop(uint x, uint y, uint width, uint height);
bool vertical_cross_to_cubemap(); bool vertical_cross_to_cubemap();
// Low-level clustered DXT (QDXT) compression // Low-level clustered DXT (QDXT) compression
struct qdxt_state struct qdxt_state
{ {
qdxt_state(task_pool& tp) : m_fmt(PIXEL_FMT_INVALID), m_qdxt1(tp), m_qdxt5a(tp), m_qdxt5b(tp) qdxt_state(task_pool& tp) : m_fmt(PIXEL_FMT_INVALID), m_qdxt1(tp), m_qdxt5a(tp), m_qdxt5b(tp)
{ {
} }
pixel_format m_fmt; pixel_format m_fmt;
qdxt1 m_qdxt1; qdxt1 m_qdxt1;
qdxt5 m_qdxt5a; qdxt5 m_qdxt5a;
qdxt5 m_qdxt5b; qdxt5 m_qdxt5b;
crnlib::vector<dxt_pixel_block> m_pixel_blocks; crnlib::vector<dxt_pixel_block> m_pixel_blocks;
qdxt1_params m_qdxt1_params; qdxt1_params m_qdxt1_params;
qdxt5_params m_qdxt5_params[2]; qdxt5_params m_qdxt5_params[2];
bool m_has_blocks[3]; bool m_has_blocks[3];
void clear() void clear()
{ {
m_fmt = PIXEL_FMT_INVALID; m_fmt = PIXEL_FMT_INVALID;
@@ -250,43 +250,43 @@ namespace crnlib
}; };
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_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); 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); void swap(dds_texture& img);
bool check() const; bool check() const;
private: private:
dynamic_wstring m_name; dynamic_string m_name;
uint m_width; uint m_width;
uint m_height; uint m_height;
pixel_format_helpers::component_flags m_comp_flags; pixel_format_helpers::component_flags m_comp_flags;
pixel_format m_format; pixel_format m_format;
face_vec m_faces; face_vec m_faces;
texture_file_types::format m_source_file_type; texture_file_types::format m_source_file_type;
mutable dynamic_wstring m_last_error; mutable dynamic_string m_last_error;
inline void clear_last_error() const { m_last_error.clear(); } inline void clear_last_error() const { m_last_error.clear(); }
inline void set_last_error(const wchar_t* p) const { m_last_error = p; } inline void set_last_error(const char* p) const { m_last_error = p; }
void free_all_mips(); void free_all_mips();
bool read_dds_internal(data_stream_serializer& serializer); bool read_dds_internal(data_stream_serializer& serializer);
bool load_regular(const wchar_t* pFilename, texture_file_types::format file_format); bool load_regular(const char* pFilename, texture_file_types::format file_format);
bool load_dds(const wchar_t* pFilename); bool load_dds(const char* pFilename);
bool load_crn(const wchar_t* pFilename); bool load_crn(const char* pFilename);
void print_crn_comp_params(const crn_comp_params& p); void print_crn_comp_params(const crn_comp_params& p);
bool save_regular(const wchar_t* pFilename); bool save_regular(const char* pFilename);
bool save_dds(const wchar_t* pFilename); bool save_dds(const char* pFilename);
bool save_comp_texture(const wchar_t* pFilename, const crn_comp_params &comp_params, uint32 *pActual_quality_level, float *pActual_bitrate); bool save_comp_texture(const char* pFilename, const crn_comp_params &comp_params, uint32 *pActual_quality_level, float *pActual_bitrate);
}; };
inline void swap(dds_texture& a, dds_texture& b) inline void swap(dds_texture& a, dds_texture& b)
{ {
a.swap(b); a.swap(b);
} }
} // namespace crnlib } // namespace crnlib
+19 -16
View File
@@ -11,43 +11,46 @@ namespace crnlib
{ {
const uint8 g_dxt5_from_linear[cDXT5SelectorValues] = { 0U, 2U, 3U, 4U, 5U, 6U, 7U, 1U }; 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_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 wchar_t* get_dxt_format_string(dxt_format fmt) const char* get_dxt_format_string(dxt_format fmt)
{ {
switch (fmt) switch (fmt)
{ {
case cDXT1: return L"DXT1"; case cDXT1: return "DXT1";
case cDXT1A: return L"DXT1A"; case cDXT1A: return "DXT1A";
case cDXT3: return L"DXT3"; case cDXT3: return "DXT3";
case cDXT5: return L"DXT5"; case cDXT5: return "DXT5";
case cDXT5A: return L"DXT5A"; case cDXT5A: return "DXT5A";
case cDXN_XY: return L"DXN_XY"; case cDXN_XY: return "DXN_XY";
case cDXN_YX: return L"DXN_YX"; case cDXN_YX: return "DXN_YX";
default: break; default: break;
} }
CRNLIB_ASSERT(false); CRNLIB_ASSERT(false);
return L"?"; return "?";
} }
const wchar_t* get_dxt_compressor_name(crn_dxt_compressor_type c) const char* get_dxt_compressor_name(crn_dxt_compressor_type c)
{ {
switch (c) switch (c)
{ {
case cCRNDXTCompressorCRN: return L"CRN"; case cCRNDXTCompressorCRN: return "CRN";
case cCRNDXTCompressorCRNF: return L"CRNF"; case cCRNDXTCompressorCRNF: return "CRNF";
case cCRNDXTCompressorRYG: return L"RYG"; case cCRNDXTCompressorRYG: return "RYG";
#if CRNLIB_SUPPORT_ATI_COMPRESS
case cCRNDXTCompressorATI: return "ATI";
#endif
default: break; default: break;
} }
CRNLIB_ASSERT(false); CRNLIB_ASSERT(false);
return L"?"; return "?";
} }
uint get_dxt_format_bits_per_pixel(dxt_format fmt) uint get_dxt_format_bits_per_pixel(dxt_format fmt)
+58 -58
View File
@@ -1,6 +1,6 @@
// File: crn_dxt.h // File: crn_dxt.h
// 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/crnlib.h" #include "../inc/crnlib.h"
#include "crn_color.h" #include "crn_color.h"
#include "crn_vec.h" #include "crn_vec.h"
@@ -25,7 +25,7 @@ namespace crnlib
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
}; };
@@ -33,28 +33,28 @@ namespace crnlib
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
}; };
const float cDXT1MaxLinearValue = 3.0f; const float cDXT1MaxLinearValue = 3.0f;
const float cDXT1InvMaxLinearValue = 1.0f/3.0f; const float cDXT1InvMaxLinearValue = 1.0f/3.0f;
const float cDXT5MaxLinearValue = 7.0f; const float cDXT5MaxLinearValue = 7.0f;
const float cDXT5InvMaxLinearValue = 1.0f/7.0f; const float cDXT5InvMaxLinearValue = 1.0f/7.0f;
// Converts DXT1 raw color selector index to a linear value. // Converts DXT1 raw color selector index to a linear value.
extern const uint8 g_dxt1_to_linear[cDXT1SelectorValues]; extern const uint8 g_dxt1_to_linear[cDXT1SelectorValues];
// Converts DXT5 raw alpha selector index to a linear value. // Converts DXT5 raw alpha selector index to a linear value.
extern const uint8 g_dxt5_to_linear[cDXT5SelectorValues]; extern const uint8 g_dxt5_to_linear[cDXT5SelectorValues];
@@ -63,33 +63,33 @@ namespace crnlib
// Converts DXT5 linear alpha selector index to a raw value (inverse of g_dxt5_to_linear). // Converts DXT5 linear alpha selector index to a raw value (inverse of g_dxt5_to_linear).
extern const uint8 g_dxt5_from_linear[cDXT5SelectorValues]; extern const uint8 g_dxt5_from_linear[cDXT5SelectorValues];
extern const uint8 g_dxt5_alpha6_to_linear[cDXT5SelectorValues]; extern const uint8 g_dxt5_alpha6_to_linear[cDXT5SelectorValues];
extern const uint8 g_six_alpha_invert_table[cDXT5SelectorValues]; extern const uint8 g_six_alpha_invert_table[cDXT5SelectorValues];
extern const uint8 g_eight_alpha_invert_table[cDXT5SelectorValues]; extern const uint8 g_eight_alpha_invert_table[cDXT5SelectorValues];
const wchar_t* get_dxt_format_string(dxt_format fmt); const char* get_dxt_format_string(dxt_format fmt);
uint get_dxt_format_bits_per_pixel(dxt_format fmt); uint get_dxt_format_bits_per_pixel(dxt_format fmt);
bool get_dxt_format_has_alpha(dxt_format fmt); bool get_dxt_format_has_alpha(dxt_format fmt);
const wchar_t* get_dxt_quality_string(crn_dxt_quality q); 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 struct dxt1_block
{ {
uint8 m_low_color[2]; uint8 m_low_color[2];
uint8 m_high_color[2]; uint8 m_high_color[2];
enum { cNumSelectorBytes = 4 }; enum { cNumSelectorBytes = 4 };
uint8 m_selectors[cNumSelectorBytes]; uint8 m_selectors[cNumSelectorBytes];
inline void clear() inline void clear()
{ {
utils::zero_this(this); utils::zero_this(this);
} }
// These methods assume the in-memory rep is in LE byte order. // These methods assume the in-memory rep is in LE byte order.
inline uint get_low_color() const inline uint get_low_color() const
{ {
@@ -100,73 +100,73 @@ namespace crnlib
{ {
return m_high_color[0] | (m_high_color[1] << 8U); return m_high_color[0] | (m_high_color[1] << 8U);
} }
inline void set_low_color(uint16 c) inline void set_low_color(uint16 c)
{ {
m_low_color[0] = static_cast<uint8>(c & 0xFF); m_low_color[0] = static_cast<uint8>(c & 0xFF);
m_low_color[1] = static_cast<uint8>((c >> 8) & 0xFF); m_low_color[1] = static_cast<uint8>((c >> 8) & 0xFF);
} }
inline void set_high_color(uint16 c) inline void set_high_color(uint16 c)
{ {
m_high_color[0] = static_cast<uint8>(c & 0xFF); m_high_color[0] = static_cast<uint8>(c & 0xFF);
m_high_color[1] = static_cast<uint8>((c >> 8) & 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_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_alpha_block() const { return get_low_color() <= get_high_color(); }
inline bool is_non_alpha_block() const { return !is_alpha_block(); } inline bool is_non_alpha_block() const { return !is_alpha_block(); }
inline uint get_selector(uint x, uint y) const inline uint get_selector(uint x, uint y) const
{ {
CRNLIB_ASSERT((x < 4U) && (y < 4U)); CRNLIB_ASSERT((x < 4U) && (y < 4U));
return (m_selectors[y] >> (x * cDXT1SelectorBits)) & cDXT1SelectorMask; return (m_selectors[y] >> (x * cDXT1SelectorBits)) & cDXT1SelectorMask;
} }
inline void set_selector(uint x, uint y, uint val) inline void set_selector(uint x, uint y, uint val)
{ {
CRNLIB_ASSERT((x < 4U) && (y < 4U) && (val < 4U)); CRNLIB_ASSERT((x < 4U) && (y < 4U) && (val < 4U));
m_selectors[y] &= (~(cDXT1SelectorMask << (x * cDXT1SelectorBits))); m_selectors[y] &= (~(cDXT1SelectorMask << (x * cDXT1SelectorBits)));
m_selectors[y] |= (val << (x * cDXT1SelectorBits)); m_selectors[y] |= (val << (x * cDXT1SelectorBits));
} }
static uint16 pack_color(const color_quad_u8& color, bool scaled, uint bias = 127U); static uint16 pack_color(const color_quad_u8& color, bool scaled, uint bias = 127U);
static uint16 pack_color(uint r, uint g, uint b, bool scaled, uint bias = 127U); static uint16 pack_color(uint r, uint g, uint b, bool scaled, uint bias = 127U);
static color_quad_u8 unpack_color(uint16 packed_color, bool scaled, uint alpha = 255U); static 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 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(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_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(color_quad_u8* pDst, uint16 color0, uint16 color1);
static uint get_block_colors4_round(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. // 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(color_quad_u8* pDst, uint16 color0, uint16 color1);
static uint get_block_colors_round(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 color_quad_u8 unpack_endpoint(uint32 endpoints, uint index, bool scaled, uint alpha = 255U);
static uint pack_endpoints(uint lo, uint hi); 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); static void get_block_colors_NV5x(color_quad_u8* pDst, uint16 packed_col0, uint16 packed_col1, bool color4);
}; };
CRNLIB_DEFINE_BITWISE_COPYABLE(dxt1_block); CRNLIB_DEFINE_BITWISE_COPYABLE(dxt1_block);
struct dxt3_block struct dxt3_block
{ {
enum { cNumAlphaBytes = 8 }; enum { cNumAlphaBytes = 8 };
uint8 m_alpha[cNumAlphaBytes]; uint8 m_alpha[cNumAlphaBytes];
void set_alpha(uint x, uint y, uint value, bool scaled); void set_alpha(uint x, uint y, uint value, bool scaled);
uint get_alpha(uint x, uint y, bool scaled) const; uint get_alpha(uint x, uint y, bool scaled) const;
}; };
CRNLIB_DEFINE_BITWISE_COPYABLE(dxt3_block); CRNLIB_DEFINE_BITWISE_COPYABLE(dxt3_block);
struct dxt5_block struct dxt5_block
{ {
uint8 m_endpoints[2]; uint8 m_endpoints[2];
@@ -189,23 +189,23 @@ namespace crnlib
return m_endpoints[1]; return m_endpoints[1];
} }
inline void set_low_alpha(uint i) inline void set_low_alpha(uint i)
{ {
CRNLIB_ASSERT(i <= UINT8_MAX); CRNLIB_ASSERT(i <= cUINT8_MAX);
m_endpoints[0] = static_cast<uint8>(i); m_endpoints[0] = static_cast<uint8>(i);
} }
inline void set_high_alpha(uint i) inline void set_high_alpha(uint i)
{ {
CRNLIB_ASSERT(i <= UINT8_MAX); CRNLIB_ASSERT(i <= cUINT8_MAX);
m_endpoints[1] = static_cast<uint8>(i); m_endpoints[1] = static_cast<uint8>(i);
} }
inline bool is_alpha6_block() const { return get_low_alpha() <= get_high_alpha(); } 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_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); } 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 inline uint get_selector(uint x, uint y) const
{ {
CRNLIB_ASSERT((x < 4U) && (y < 4U)); CRNLIB_ASSERT((x < 4U) && (y < 4U));
@@ -244,7 +244,7 @@ namespace crnlib
if (byte_index < (cNumSelectorBytes - 1)) if (byte_index < (cNumSelectorBytes - 1))
m_selectors[byte_index + 1] = static_cast<uint8>(v >> 8); m_selectors[byte_index + 1] = static_cast<uint8>(v >> 8);
} }
enum { cMaxSelectorValues = 8 }; enum { cMaxSelectorValues = 8 };
// Results written to alpha channel. // Results written to alpha channel.
@@ -260,19 +260,19 @@ namespace crnlib
static uint unpack_endpoint(uint packed, uint index); static uint unpack_endpoint(uint packed, uint index);
static uint pack_endpoints(uint lo, uint hi); static uint pack_endpoints(uint lo, uint hi);
}; };
CRNLIB_DEFINE_BITWISE_COPYABLE(dxt5_block); CRNLIB_DEFINE_BITWISE_COPYABLE(dxt5_block);
struct dxt_pixel_block struct dxt_pixel_block
{ {
color_quad_u8 m_pixels[cDXTBlockSize][cDXTBlockSize]; // [y][x] color_quad_u8 m_pixels[cDXTBlockSize][cDXTBlockSize]; // [y][x]
inline void clear() inline void clear()
{ {
utils::zero_object(*this); utils::zero_object(*this);
} }
}; };
CRNLIB_DEFINE_BITWISE_COPYABLE(dxt_pixel_block); CRNLIB_DEFINE_BITWISE_COPYABLE(dxt_pixel_block);
} // namespace crnlib } // namespace crnlib
+270 -270
View File
File diff suppressed because it is too large Load Diff
+2 -2
View File
@@ -258,7 +258,7 @@ namespace crnlib
struct potential_solution struct potential_solution
{ {
potential_solution() : m_coords(), m_error(UINT64_MAX), m_alpha_block(false), m_valid(false) potential_solution() : m_coords(), m_error(cUINT64_MAX), m_alpha_block(false), m_valid(false)
{ {
} }
@@ -272,7 +272,7 @@ namespace crnlib
{ {
m_coords.clear(); m_coords.clear();
m_selectors.resize(0); m_selectors.resize(0);
m_error = UINT64_MAX; m_error = cUINT64_MAX;
m_alpha_block = false; m_alpha_block = false;
m_valid = false; m_valid = false;
} }
+1 -1
View File
@@ -62,7 +62,7 @@ namespace crnlib
m_trial_selectors.resize(m_unique_values.size()); m_trial_selectors.resize(m_unique_values.size());
m_best_selectors.resize(m_unique_values.size()); m_best_selectors.resize(m_unique_values.size());
r.m_error = UINT64_MAX; r.m_error = cUINT64_MAX;
for (uint i = 0; i < m_unique_values.size() - 1; i++) for (uint i = 0; i < m_unique_values.size() - 1; i++)
{ {
+1 -1
View File
@@ -20,7 +20,7 @@ namespace crnlib
m_pParams = &p; m_pParams = &p;
m_pResults = &r; m_pResults = &r;
r.m_error = UINT64_MAX; r.m_error = cUINT64_MAX;
r.m_low_color = 0; r.m_low_color = 0;
r.m_high_color = 0; r.m_high_color = 0;
+1 -1
View File
@@ -19,7 +19,7 @@ namespace crnlib
m_num_pixels(0), m_num_pixels(0),
m_pSelectors(NULL), m_pSelectors(NULL),
m_alpha_comp_index(0), m_alpha_comp_index(0),
m_error_to_beat(UINT64_MAX), m_error_to_beat(cUINT64_MAX),
m_dxt1_selectors(true), m_dxt1_selectors(true),
m_perceptual(true), m_perceptual(true),
m_highest_quality(true) m_highest_quality(true)
+2 -2
View File
@@ -507,7 +507,7 @@ namespace crnlib
static void refine_endpoints2(uint n, const color_quad_u8* pBlock, uint& low16, uint& high16, uint8* pSelectors, float axis[3]) static void refine_endpoints2(uint n, const color_quad_u8* pBlock, uint& low16, uint& high16, uint8* pSelectors, float axis[3])
{ {
uint64 orig_error = determine_error(n, pBlock, low16, high16, UINT64_MAX); uint64 orig_error = determine_error(n, pBlock, low16, high16, cUINT64_MAX);
if (!orig_error) if (!orig_error)
return; return;
@@ -623,7 +623,7 @@ namespace crnlib
{ {
improved = true; improved = true;
uint64 cur_error = determine_error(n, pBlock, low16, high16, UINT64_MAX); uint64 cur_error = determine_error(n, pBlock, low16, high16, cUINT64_MAX);
if (!cur_error) if (!cur_error)
return; return;
} }
+40 -40
View File
@@ -33,7 +33,7 @@ namespace crnlib
m_has_color_blocks(false), m_has_color_blocks(false),
m_has_alpha0_blocks(false), m_has_alpha0_blocks(false),
m_has_alpha1_blocks(false), m_has_alpha1_blocks(false),
m_main_thread_id(get_current_thread_id()), m_main_thread_id(crn_get_current_thread_id()),
m_canceled(false), m_canceled(false),
m_pTask_pool(NULL), m_pTask_pool(NULL),
m_prev_phase_index(-1), m_prev_phase_index(-1),
@@ -104,7 +104,7 @@ namespace crnlib
bool dxt_hc::compress(const params& p, uint num_chunks, const pixel_chunk* pChunks, task_pool& task_pool) bool dxt_hc::compress(const params& p, uint num_chunks, const pixel_chunk* pChunks, task_pool& task_pool)
{ {
m_pTask_pool = &task_pool; m_pTask_pool = &task_pool;
m_main_thread_id = get_current_thread_id(); m_main_thread_id = crn_get_current_thread_id();
bool result = compress_internal(p, num_chunks, pChunks); bool result = compress_internal(p, num_chunks, pChunks);
@@ -335,7 +335,7 @@ namespace crnlib
if (m_canceled) if (m_canceled)
return; return;
if ((get_current_thread_id() == m_main_thread_id) && ((chunk_index & 511) == 0)) if ((crn_get_current_thread_id() == m_main_thread_id) && ((chunk_index & 511) == 0))
{ {
if (!update_progress(0, chunk_index, m_num_chunks)) if (!update_progress(0, chunk_index, m_num_chunks))
return; return;
@@ -550,9 +550,9 @@ namespace crnlib
} }
} }
interlocked_increment32(&m_encoding_hist[best_encoding]); atomic_increment32(&m_encoding_hist[best_encoding]);
interlocked_exchange_add32(&m_total_tiles, g_chunk_encodings[best_encoding].m_num_tiles); atomic_exchange_add32(&m_total_tiles, g_chunk_encodings[best_encoding].m_num_tiles);
for (uint q = 0; q < cNumCompressedChunkVecs; q++) for (uint q = 0; q < cNumCompressedChunkVecs; q++)
{ {
@@ -664,15 +664,15 @@ namespace crnlib
#if CRNLIB_ENABLE_DEBUG_MESSAGES #if CRNLIB_ENABLE_DEBUG_MESSAGES
if (m_params.m_debugging) if (m_params.m_debugging)
{ {
console::info(L"Total Pixels: %u, Chunks: %u, Blocks: %u, Adapted Tiles: %u", m_num_chunks * cChunkPixelWidth * cChunkPixelHeight, m_num_chunks, m_num_chunks * cChunkBlockWidth * cChunkBlockHeight, m_total_tiles); console::info("Total Pixels: %u, Chunks: %u, Blocks: %u, Adapted Tiles: %u", m_num_chunks * cChunkPixelWidth * cChunkPixelHeight, m_num_chunks, m_num_chunks * cChunkBlockWidth * cChunkBlockHeight, m_total_tiles);
console::info(L"Chunk encoding type symbol_histogram: "); console::info("Chunk encoding type symbol_histogram: ");
for (uint e = 0; e < cNumChunkEncodings; e++) for (uint e = 0; e < cNumChunkEncodings; e++)
console::info(L"%u ", m_encoding_hist[e]); console::info("%u ", m_encoding_hist[e]);
console::info(L"Blocks per chunk encoding type: "); console::info("Blocks per chunk encoding type: ");
for (uint e = 0; e < cNumChunkEncodings; e++) for (uint e = 0; e < cNumChunkEncodings; e++)
console::info(L"%u ", m_encoding_hist[e] * cChunkBlockWidth * cChunkBlockHeight); console::info("%u ", m_encoding_hist[e] * cChunkBlockWidth * cChunkBlockHeight);
} }
#endif #endif
@@ -689,7 +689,7 @@ namespace crnlib
if (m_canceled) if (m_canceled)
return; return;
if ((get_current_thread_id() == m_main_thread_id) && ((chunk_index & 63) == 0)) if ((crn_get_current_thread_id() == m_main_thread_id) && ((chunk_index & 63) == 0))
{ {
if (!update_progress(2, chunk_index, m_num_chunks)) if (!update_progress(2, chunk_index, m_num_chunks))
return; return;
@@ -719,7 +719,7 @@ namespace crnlib
#if CRNLIB_ENABLE_DEBUG_MESSAGES #if CRNLIB_ENABLE_DEBUG_MESSAGES
if (m_params.m_debugging) if (m_params.m_debugging)
console::info(L"Generating color training vectors"); console::info("Generating color training vectors");
#endif #endif
const float r_scale = .5f; const float r_scale = .5f;
@@ -804,7 +804,7 @@ namespace crnlib
#if CRNLIB_ENABLE_DEBUG_MESSAGES #if CRNLIB_ENABLE_DEBUG_MESSAGES
if (m_params.m_debugging) if (m_params.m_debugging)
console::info(L"Begin color cluster analysis"); console::info("Begin color cluster analysis");
timer t; timer t;
t.start(); t.start();
#endif #endif
@@ -816,7 +816,7 @@ namespace crnlib
if (m_params.m_debugging) if (m_params.m_debugging)
{ {
double total_time = t.get_elapsed_secs(); double total_time = t.get_elapsed_secs();
console::info(L"Codebook gen time: %3.3fs, Total color clusters: %u", total_time, vq.get_codebook_size()); console::info("Codebook gen time: %3.3fs, Total color clusters: %u", total_time, vq.get_codebook_size());
} }
#endif #endif
@@ -824,7 +824,7 @@ namespace crnlib
#if CRNLIB_ENABLE_DEBUG_MESSAGES #if CRNLIB_ENABLE_DEBUG_MESSAGES
if (m_params.m_debugging) if (m_params.m_debugging)
console::info(L"Begin color cluster assignment"); console::info("Begin color cluster assignment");
#endif #endif
assign_color_endpoint_clusters_state state(vq, training_vecs); assign_color_endpoint_clusters_state state(vq, training_vecs);
@@ -850,7 +850,7 @@ namespace crnlib
#if CRNLIB_ENABLE_DEBUG_MESSAGES #if CRNLIB_ENABLE_DEBUG_MESSAGES
if (m_params.m_debugging) if (m_params.m_debugging)
console::info(L"Completed color cluster assignment"); console::info("Completed color cluster assignment");
#endif #endif
return true; return true;
@@ -868,7 +868,7 @@ namespace crnlib
if (m_canceled) if (m_canceled)
return; return;
if ((get_current_thread_id() == m_main_thread_id) && ((chunk_index & 63) == 0)) if ((crn_get_current_thread_id() == m_main_thread_id) && ((chunk_index & 63) == 0))
{ {
if (!update_progress(7, m_num_chunks * a + chunk_index, m_num_chunks * m_num_alpha_blocks)) if (!update_progress(7, m_num_chunks * a + chunk_index, m_num_chunks * m_num_alpha_blocks))
return; return;
@@ -899,7 +899,7 @@ namespace crnlib
#if CRNLIB_ENABLE_DEBUG_MESSAGES #if CRNLIB_ENABLE_DEBUG_MESSAGES
if (m_params.m_debugging) if (m_params.m_debugging)
console::info(L"Generating alpha training vectors"); console::info("Generating alpha training vectors");
#endif #endif
determine_alpha_endpoint_clusters_state state; determine_alpha_endpoint_clusters_state state;
@@ -966,7 +966,7 @@ namespace crnlib
#if CRNLIB_ENABLE_DEBUG_MESSAGES #if CRNLIB_ENABLE_DEBUG_MESSAGES
if (m_params.m_debugging) if (m_params.m_debugging)
console::info(L"Begin alpha cluster analysis"); console::info("Begin alpha cluster analysis");
timer t; timer t;
t.start(); t.start();
#endif #endif
@@ -978,7 +978,7 @@ namespace crnlib
if (m_params.m_debugging) if (m_params.m_debugging)
{ {
double total_time = t.get_elapsed_secs(); double total_time = t.get_elapsed_secs();
console::info(L"Codebook gen time: %3.3fs, Total alpha clusters: %u", total_time, state.m_vq.get_codebook_size()); console::info("Codebook gen time: %3.3fs, Total alpha clusters: %u", total_time, state.m_vq.get_codebook_size());
} }
#endif #endif
@@ -986,7 +986,7 @@ namespace crnlib
#if CRNLIB_ENABLE_DEBUG_MESSAGES #if CRNLIB_ENABLE_DEBUG_MESSAGES
if (m_params.m_debugging) if (m_params.m_debugging)
console::info(L"Begin alpha cluster assignment"); console::info("Begin alpha cluster assignment");
#endif #endif
for (uint i = 0; i <= m_pTask_pool->get_num_threads(); i++) for (uint i = 0; i <= m_pTask_pool->get_num_threads(); i++)
@@ -1013,7 +1013,7 @@ namespace crnlib
#if CRNLIB_ENABLE_DEBUG_MESSAGES #if CRNLIB_ENABLE_DEBUG_MESSAGES
if (m_params.m_debugging) if (m_params.m_debugging)
console::info(L"Completed alpha cluster assignment"); console::info("Completed alpha cluster assignment");
#endif #endif
return true; return true;
@@ -1040,7 +1040,7 @@ namespace crnlib
if (m_canceled) if (m_canceled)
return; return;
if ((get_current_thread_id() == m_main_thread_id) && ((cluster_index & 63) == 0)) if ((crn_get_current_thread_id() == m_main_thread_id) && ((cluster_index & 63) == 0))
{ {
if (!update_progress(3, cluster_index, m_color_clusters.size())) if (!update_progress(3, cluster_index, m_color_clusters.size()))
return; return;
@@ -1151,7 +1151,7 @@ namespace crnlib
if (m_params.m_debugging) if (m_params.m_debugging)
{ {
if (total_empty_clusters) if (total_empty_clusters)
console::warning(L"Total empty color clusters: %u", total_empty_clusters); console::warning("Total empty color clusters: %u", total_empty_clusters);
} }
#endif #endif
} }
@@ -1163,7 +1163,7 @@ namespace crnlib
#if CRNLIB_ENABLE_DEBUG_MESSAGES #if CRNLIB_ENABLE_DEBUG_MESSAGES
if (m_params.m_debugging) if (m_params.m_debugging)
console::info(L"Computing optimal color cluster endpoints"); console::info("Computing optimal color cluster endpoints");
#endif #endif
for (uint i = 0; i <= m_pTask_pool->get_num_threads(); i++) for (uint i = 0; i <= m_pTask_pool->get_num_threads(); i++)
@@ -1192,7 +1192,7 @@ namespace crnlib
if (m_canceled) if (m_canceled)
return; return;
if ((get_current_thread_id() == m_main_thread_id) && ((cluster_index & 63) == 0)) if ((crn_get_current_thread_id() == m_main_thread_id) && ((cluster_index & 63) == 0))
{ {
if (!update_progress(8, cluster_index, m_alpha_clusters.size())) if (!update_progress(8, cluster_index, m_alpha_clusters.size()))
return; return;
@@ -1311,7 +1311,7 @@ namespace crnlib
if (m_params.m_debugging) if (m_params.m_debugging)
{ {
if (total_empty_clusters) if (total_empty_clusters)
console::warning(L"Total empty alpha clusters: %u", total_empty_clusters); console::warning("Total empty alpha clusters: %u", total_empty_clusters);
} }
#endif #endif
} }
@@ -1323,7 +1323,7 @@ namespace crnlib
#if CRNLIB_ENABLE_DEBUG_MESSAGES #if CRNLIB_ENABLE_DEBUG_MESSAGES
if (m_params.m_debugging) if (m_params.m_debugging)
console::info(L"Computing optimal alpha cluster endpoints"); console::info("Computing optimal alpha cluster endpoints");
#endif #endif
for (uint i = 0; i <= m_pTask_pool->get_num_threads(); i++) for (uint i = 0; i <= m_pTask_pool->get_num_threads(); i++)
@@ -1461,7 +1461,7 @@ namespace crnlib
if (m_canceled) if (m_canceled)
return; return;
if ((get_current_thread_id() == m_main_thread_id) && ((chunk_index & 127) == 0)) if ((crn_get_current_thread_id() == m_main_thread_id) && ((chunk_index & 127) == 0))
{ {
if (!update_progress(12 + comp_chunk_index, chunk_index, m_num_chunks)) if (!update_progress(12 + comp_chunk_index, chunk_index, m_num_chunks))
return; return;
@@ -1632,7 +1632,7 @@ namespace crnlib
{ {
#if CRNLIB_ENABLE_DEBUG_MESSAGES #if CRNLIB_ENABLE_DEBUG_MESSAGES
if (m_params.m_debugging) if (m_params.m_debugging)
console::info(L"Computing selector training vectors"); console::info("Computing selector training vectors");
#endif #endif
const uint cColorDistToWeight = 2000; const uint cColorDistToWeight = 2000;
@@ -1775,7 +1775,7 @@ namespace crnlib
if (m_params.m_debugging) if (m_params.m_debugging)
{ {
double total_time = t.get_elapsed_secs(); double total_time = t.get_elapsed_secs();
console::info(L"Codebook gen time: %3.3fs, Selector codebook size: %u", total_time, selector_vq.get_codebook_size()); console::info("Codebook gen time: %3.3fs, Selector codebook size: %u", total_time, selector_vq.get_codebook_size());
} }
#endif #endif
@@ -1827,7 +1827,7 @@ namespace crnlib
#if CRNLIB_ENABLE_DEBUG_MESSAGES #if CRNLIB_ENABLE_DEBUG_MESSAGES
if (m_params.m_debugging) if (m_params.m_debugging)
console::info(L"Refining quantized color selectors"); console::info("Refining quantized color selectors");
#endif #endif
uint total_refined_selectors = 0; uint total_refined_selectors = 0;
@@ -1917,7 +1917,7 @@ namespace crnlib
#if CRNLIB_ENABLE_DEBUG_MESSAGES #if CRNLIB_ENABLE_DEBUG_MESSAGES
if (m_params.m_debugging) if (m_params.m_debugging)
console::info(L"Total refined pixels: %u, selectors: %u out of %u", total_refined_pixels, total_refined_selectors, total_selectors); console::info("Total refined pixels: %u, selectors: %u out of %u", total_refined_pixels, total_refined_selectors, total_selectors);
#endif #endif
return true; return true;
@@ -1930,7 +1930,7 @@ namespace crnlib
#if CRNLIB_ENABLE_DEBUG_MESSAGES #if CRNLIB_ENABLE_DEBUG_MESSAGES
if (m_params.m_debugging) if (m_params.m_debugging)
console::info(L"Refining quantized alpha selectors"); console::info("Refining quantized alpha selectors");
#endif #endif
uint total_refined_selectors = 0; uint total_refined_selectors = 0;
@@ -2021,7 +2021,7 @@ namespace crnlib
#if CRNLIB_ENABLE_DEBUG_MESSAGES #if CRNLIB_ENABLE_DEBUG_MESSAGES
if (m_params.m_debugging) if (m_params.m_debugging)
console::info(L"Total refined pixels: %u, selectors: %u out of %u", total_refined_pixels, total_refined_selectors, total_selectors); console::info("Total refined pixels: %u, selectors: %u out of %u", total_refined_pixels, total_refined_selectors, total_selectors);
#endif #endif
return true; return true;
@@ -2037,7 +2037,7 @@ namespace crnlib
#if CRNLIB_ENABLE_DEBUG_MESSAGES #if CRNLIB_ENABLE_DEBUG_MESSAGES
if (m_params.m_debugging) if (m_params.m_debugging)
console::info(L"Refining quantized color endpoints"); console::info("Refining quantized color endpoints");
#endif #endif
for (uint cluster_index = 0; cluster_index < m_color_clusters.size(); cluster_index++) for (uint cluster_index = 0; cluster_index < m_color_clusters.size(); cluster_index++)
@@ -2138,7 +2138,7 @@ namespace crnlib
#if CRNLIB_ENABLE_DEBUG_MESSAGES #if CRNLIB_ENABLE_DEBUG_MESSAGES
if (m_params.m_debugging) if (m_params.m_debugging)
console::info(L"Total refined pixels: %u, endpoints: %u out of %u", total_refined_pixels, total_refined_tiles, m_color_clusters.size()); console::info("Total refined pixels: %u, endpoints: %u out of %u", total_refined_pixels, total_refined_tiles, m_color_clusters.size());
#endif #endif
return true; return true;
@@ -2153,7 +2153,7 @@ namespace crnlib
uint total_refined_pixels = 0; uint total_refined_pixels = 0;
#if CRNLIB_ENABLE_DEBUG_MESSAGES #if CRNLIB_ENABLE_DEBUG_MESSAGES
if (m_params.m_debugging) if (m_params.m_debugging)
console::info(L"Refining quantized alpha endpoints"); console::info("Refining quantized alpha endpoints");
#endif #endif
for (uint cluster_index = 0; cluster_index < m_alpha_clusters.size(); cluster_index++) for (uint cluster_index = 0; cluster_index < m_alpha_clusters.size(); cluster_index++)
@@ -2257,7 +2257,7 @@ namespace crnlib
#if CRNLIB_ENABLE_DEBUG_MESSAGES #if CRNLIB_ENABLE_DEBUG_MESSAGES
if (m_params.m_debugging) if (m_params.m_debugging)
console::info(L"Total refined pixels: %u, endpoints: %u out of %u", total_refined_pixels, total_refined_tiles, m_alpha_clusters.size()); console::info("Total refined pixels: %u, endpoints: %u out of %u", total_refined_pixels, total_refined_tiles, m_alpha_clusters.size());
#endif #endif
return true; return true;
@@ -2515,7 +2515,7 @@ namespace crnlib
bool dxt_hc::update_progress(uint phase_index, uint subphase_index, uint subphase_total) bool dxt_hc::update_progress(uint phase_index, uint subphase_index, uint subphase_total)
{ {
CRNLIB_ASSERT(get_current_thread_id() == m_main_thread_id); CRNLIB_ASSERT(crn_get_current_thread_id() == m_main_thread_id);
if (!m_params.m_pProgress_func) if (!m_params.m_pProgress_func)
return true; return true;
+6 -7
View File
@@ -9,8 +9,7 @@
#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_task_pool.h" #include "crn_threading.h"
#include "crn_spinlock.h"
#define CRN_NO_FUNCTION_DEFINITIONS #define CRN_NO_FUNCTION_DEFINITIONS
#include "../inc/crnlib.h" #include "../inc/crnlib.h"
@@ -163,8 +162,8 @@ namespace crnlib
uint8 m_selectors[cBlockPixelHeight][cBlockPixelWidth]; uint8 m_selectors[cBlockPixelHeight][cBlockPixelWidth];
uint8 get_by_index(uint i) const { CRNLIB_ASSERT(i < (cBlockPixelWidth * cBlockPixelHeight)); return *(&m_selectors[0][0] + i); } uint8 get_by_index(uint i) const { CRNLIB_ASSERT(i < (cBlockPixelWidth * cBlockPixelHeight)); const uint8* p = (const uint8*)m_selectors; return *(p + i); }
void set_by_index(uint i, uint v) { CRNLIB_ASSERT(i < (cBlockPixelWidth * cBlockPixelHeight)); *(&m_selectors[0][0] + i) = static_cast<uint8>(v); } void set_by_index(uint i, uint v) { CRNLIB_ASSERT(i < (cBlockPixelWidth * cBlockPixelHeight)); uint8* p = (uint8*)m_selectors; *(p + i) = static_cast<uint8>(v); }
}; };
typedef crnlib::vector<selectors> selectors_vec; typedef crnlib::vector<selectors> selectors_vec;
@@ -272,9 +271,9 @@ namespace crnlib
}; };
compressed_chunk_vec m_compressed_chunks[cNumCompressedChunkVecs]; compressed_chunk_vec m_compressed_chunks[cNumCompressedChunkVecs];
int32 m_encoding_hist[cNumChunkEncodings]; volatile atomic32_t m_encoding_hist[cNumChunkEncodings];
int32 m_total_tiles; atomic32_t m_total_tiles;
void compress_dxt1_block( void compress_dxt1_block(
dxt1_endpoint_optimizer::results& results, dxt1_endpoint_optimizer::results& results,
@@ -350,7 +349,7 @@ namespace crnlib
pixel_chunk_vec m_dbg_chunk_pixels_final; pixel_chunk_vec m_dbg_chunk_pixels_final;
uint32 m_main_thread_id; crn_thread_id_t m_main_thread_id;
bool m_canceled; bool m_canceled;
task_pool* m_pTask_pool; task_pool* m_pTask_pool;
+9 -9
View File
@@ -7,8 +7,8 @@
#endif #endif
#include "crn_ryg_dxt.hpp" #include "crn_ryg_dxt.hpp"
#include "crn_dxt_fast.h" #include "crn_dxt_fast.h"
#include "crn_task_pool.h"
#include "crn_console.h" #include "crn_console.h"
#include "crn_threading.h"
#if CRNLIB_SUPPORT_ATI_COMPRESS #if CRNLIB_SUPPORT_ATI_COMPRESS
#ifdef _DLL #ifdef _DLL
@@ -216,8 +216,8 @@ namespace crnlib
dxt_format m_fmt; dxt_format m_fmt;
const image_u8* m_pImg; const image_u8* m_pImg;
const dxt_image::pack_params* m_pParams; const dxt_image::pack_params* m_pParams;
uint32 m_main_thread; crn_thread_id_t m_main_thread;
int32 m_canceled; atomic32_t m_canceled;
}; };
void dxt_image::init_task(uint64 data, void* pData_ptr) void dxt_image::init_task(uint64 data, void* pData_ptr)
@@ -227,7 +227,7 @@ namespace crnlib
const image_u8& img = *pInit_params->m_pImg; const image_u8& img = *pInit_params->m_pImg;
const pack_params& p = *pInit_params->m_pParams; const pack_params& p = *pInit_params->m_pParams;
const bool is_main_thread = (get_current_thread_id() == pInit_params->m_main_thread); const bool is_main_thread = (crn_get_current_thread_id() == pInit_params->m_main_thread);
uint block_index = 0; uint block_index = 0;
@@ -252,7 +252,7 @@ namespace crnlib
prev_progress_percentage = progress_percentage; prev_progress_percentage = progress_percentage;
if (!(p.m_pProgress_callback)(progress_percentage, p.m_pProgress_callback_user_data_ptr)) if (!(p.m_pProgress_callback)(progress_percentage, p.m_pProgress_callback_user_data_ptr))
{ {
interlocked_exchange32(&pInit_params->m_canceled, CRNLIB_TRUE); atomic_exchange32(&pInit_params->m_canceled, CRNLIB_TRUE);
return; return;
} }
} }
@@ -351,7 +351,7 @@ namespace crnlib
if (fmt == cDXT1A) if (fmt == cDXT1A)
{ {
options.bDXT1UseAlpha = TRUE; options.bDXT1UseAlpha = true;
options.nAlphaThreshold = (ATI_TC_BYTE)p.m_dxt1a_alpha_threshold; options.nAlphaThreshold = (ATI_TC_BYTE)p.m_dxt1a_alpha_threshold;
} }
options.bDisableMultiThreading = (p.m_num_helper_threads == 0); options.bDisableMultiThreading = (p.m_num_helper_threads == 0);
@@ -370,7 +370,7 @@ namespace crnlib
if (p.m_perceptual) if (p.m_perceptual)
{ {
options.bUseChannelWeighting = TRUE; options.bUseChannelWeighting = true;
options.fWeightingRed = .212671f; options.fWeightingRed = .212671f;
options.fWeightingGreen = .715160f; options.fWeightingGreen = .715160f;
options.fWeightingBlue = .072169f; options.fWeightingBlue = .072169f;
@@ -405,7 +405,7 @@ namespace crnlib
init_params.m_fmt = fmt; init_params.m_fmt = fmt;
init_params.m_pImg = &img; init_params.m_pImg = &img;
init_params.m_pParams = &p; init_params.m_pParams = &p;
init_params.m_main_thread = get_current_thread_id(); init_params.m_main_thread = crn_get_current_thread_id();
init_params.m_canceled = false; init_params.m_canceled = false;
for (uint i = 0; i <= p.m_num_helper_threads; i++) for (uint i = 0; i <= p.m_num_helper_threads; i++)
@@ -1135,7 +1135,7 @@ namespace crnlib
int dxt_image::get_block_endpoints(uint block_x, uint block_y, uint element_index, color_quad_u8& low_endpoint, color_quad_u8& high_endpoint, bool scaled) const int dxt_image::get_block_endpoints(uint block_x, uint block_y, uint element_index, color_quad_u8& low_endpoint, color_quad_u8& high_endpoint, bool scaled) const
{ {
uint l, h; uint l = 0, h = 0;
get_block_endpoints(block_x, block_y, element_index, l, h); get_block_endpoints(block_x, block_y, element_index, l, h);
switch (m_element_type[element_index]) switch (m_element_type[element_index])
+2 -2
View File
@@ -61,8 +61,8 @@ namespace crnlib
uint get_le_word(uint index) const { CRNLIB_ASSERT(index < 4); return m_bytes[index*2] | (m_bytes[index * 2 + 1] << 8); } uint get_le_word(uint index) const { CRNLIB_ASSERT(index < 4); return m_bytes[index*2] | (m_bytes[index * 2 + 1] << 8); }
uint get_be_word(uint index) const { CRNLIB_ASSERT(index < 4); return m_bytes[index*2 + 1] | (m_bytes[index * 2] << 8); } uint get_be_word(uint index) const { CRNLIB_ASSERT(index < 4); return m_bytes[index*2 + 1] | (m_bytes[index * 2] << 8); }
void set_le_word(uint index, uint val) { CRNLIB_ASSERT((index < 4) && (val <= UINT16_MAX)); m_bytes[index*2] = static_cast<uint8>(val & 0xFF); m_bytes[index * 2 + 1] = static_cast<uint8>((val >> 8) & 0xFF); } void set_le_word(uint index, uint val) { CRNLIB_ASSERT((index < 4) && (val <= cUINT16_MAX)); m_bytes[index*2] = static_cast<uint8>(val & 0xFF); m_bytes[index * 2 + 1] = static_cast<uint8>((val >> 8) & 0xFF); }
void set_be_word(uint index, uint val) { CRNLIB_ASSERT((index < 4) && (val <= UINT16_MAX)); m_bytes[index*2+1] = static_cast<uint8>(val & 0xFF); m_bytes[index * 2] = 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() void clear()
{ {
+53 -53
View File
@@ -8,32 +8,32 @@ namespace crnlib
class dynamic_stream : public data_stream class dynamic_stream : public data_stream
{ {
public: public:
dynamic_stream(uint initial_size, const wchar_t* pName = L"dynamic_stream", uint attribs = cDataStreamSeekable | cDataStreamWritable | cDataStreamReadable) : dynamic_stream(uint initial_size, const char* pName = "dynamic_stream", uint attribs = cDataStreamSeekable | cDataStreamWritable | cDataStreamReadable) :
data_stream(pName, attribs), data_stream(pName, attribs),
m_ofs(0) m_ofs(0)
{ {
open(initial_size, pName, attribs); open(initial_size, pName, attribs);
} }
dynamic_stream(const void* pBuf, uint size, const wchar_t* pName = L"dynamic_stream", uint attribs = cDataStreamSeekable | cDataStreamWritable | cDataStreamReadable) : dynamic_stream(const void* pBuf, uint size, const char* pName = "dynamic_stream", uint attribs = cDataStreamSeekable | cDataStreamWritable | cDataStreamReadable) :
data_stream(pName, attribs), data_stream(pName, attribs),
m_ofs(0) m_ofs(0)
{ {
open(pBuf, size, pName, attribs); open(pBuf, size, pName, attribs);
} }
dynamic_stream() : dynamic_stream() :
data_stream(), data_stream(),
m_ofs(0) m_ofs(0)
{ {
open(); open();
} }
virtual ~dynamic_stream() virtual ~dynamic_stream()
{ {
} }
bool open(uint initial_size = 0, const wchar_t* pName = L"dynamic_stream", uint attribs = cDataStreamSeekable | cDataStreamWritable | cDataStreamReadable) bool open(uint initial_size = 0, const char* pName = "dynamic_stream", uint attribs = cDataStreamSeekable | cDataStreamWritable | cDataStreamReadable)
{ {
close(); close();
@@ -41,24 +41,24 @@ namespace crnlib
m_buf.clear(); m_buf.clear();
m_buf.resize(initial_size); m_buf.resize(initial_size);
m_ofs = 0; m_ofs = 0;
m_name.set(pName ? pName : L"dynamic_stream"); m_name.set(pName ? pName : "dynamic_stream");
m_attribs = static_cast<attribs_t>(attribs); m_attribs = static_cast<attribs_t>(attribs);
return true; return true;
} }
bool reopen(const wchar_t* pName, uint attribs) bool reopen(const char* pName, uint attribs)
{ {
if (!m_opened) if (!m_opened)
{ {
return open(0, pName, attribs); return open(0, pName, attribs);
} }
m_name.set(pName ? pName : L"dynamic_stream"); m_name.set(pName ? pName : "dynamic_stream");
m_attribs = static_cast<attribs_t>(attribs); m_attribs = static_cast<attribs_t>(attribs);
return true; return true;
} }
bool open(const void* pBuf, uint size, const wchar_t* pName = L"dynamic_stream", uint attribs = cDataStreamSeekable | cDataStreamWritable | cDataStreamReadable) bool open(const void* pBuf, uint size, const char* pName = "dynamic_stream", uint attribs = cDataStreamSeekable | cDataStreamWritable | cDataStreamReadable)
{ {
if (!m_opened) if (!m_opened)
{ {
@@ -70,14 +70,14 @@ namespace crnlib
memcpy(&m_buf[0], pBuf, size); memcpy(&m_buf[0], pBuf, size);
} }
m_ofs = 0; m_ofs = 0;
m_name.set(pName ? pName : L"dynamic_stream"); m_name.set(pName ? pName : "dynamic_stream");
m_attribs = static_cast<attribs_t>(attribs); m_attribs = static_cast<attribs_t>(attribs);
return true; return true;
} }
return false; return false;
} }
virtual bool close() virtual bool close()
{ {
if (m_opened) if (m_opened)
@@ -87,10 +87,10 @@ namespace crnlib
m_ofs = 0; m_ofs = 0;
return true; return true;
} }
return false; return false;
} }
const crnlib::vector<uint8>& get_buf() const { return m_buf; } const crnlib::vector<uint8>& get_buf() const { return m_buf; }
crnlib::vector<uint8>& get_buf() { return m_buf; } crnlib::vector<uint8>& get_buf() { return m_buf; }
@@ -101,102 +101,102 @@ namespace crnlib
m_buf.reserve(size); m_buf.reserve(size);
} }
} }
virtual const void* get_ptr() const { return m_buf.empty() ? NULL : &m_buf[0]; } virtual const void* get_ptr() const { return m_buf.empty() ? NULL : &m_buf[0]; }
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_buf.size()); CRNLIB_ASSERT(m_ofs <= m_buf.size());
uint bytes_left = m_buf.size() - m_ofs; uint bytes_left = m_buf.size() - m_ofs;
len = math::minimum<uint>(len, bytes_left); len = math::minimum<uint>(len, bytes_left);
if (len) if (len)
memcpy(pBuf, &m_buf[m_ofs], len); memcpy(pBuf, &m_buf[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_buf.size()); CRNLIB_ASSERT(m_ofs <= m_buf.size());
uint new_ofs = m_ofs + len; uint new_ofs = m_ofs + len;
if (new_ofs > m_buf.size()) if (new_ofs > m_buf.size())
m_buf.resize(new_ofs); m_buf.resize(new_ofs);
memcpy(&m_buf[m_ofs], pBuf, len); memcpy(&m_buf[m_ofs], pBuf, len);
m_ofs = new_ofs; m_ofs = new_ofs;
return len; return len;
} }
virtual bool flush() virtual bool flush()
{ {
if (!m_opened) if (!m_opened)
return false; return false;
return true; return true;
} }
virtual uint64 get_size() virtual uint64 get_size()
{ {
if (!m_opened) if (!m_opened)
return 0; return 0;
return m_buf.size(); return m_buf.size();
} }
virtual uint64 get_remaining() virtual uint64 get_remaining()
{ {
if (!m_opened) if (!m_opened)
return 0; return 0;
CRNLIB_ASSERT(m_ofs <= m_buf.size()); CRNLIB_ASSERT(m_ofs <= m_buf.size());
return m_buf.size() - m_ofs; return m_buf.size() - m_ofs;
} }
virtual uint64 get_ofs() virtual uint64 get_ofs()
{ {
if (!m_opened) if (!m_opened)
return 0; 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())) if ((!m_opened) || (!is_seekable()))
return false; 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_buf.size()) else if (new_ofs > m_buf.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:
crnlib::vector<uint8> m_buf; crnlib::vector<uint8> m_buf;
uint m_ofs; uint m_ofs;
+38 -65
View File
@@ -1,10 +1,7 @@
// File: crn_dynamic_string.cpp // File: crn_dynamic_string.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_dynamic_string.h" #include "crn_strutils.h"
#include "crn_dynamic_wstring.h"
#include "crn_winhdr.h"
#include <stdio.h>
namespace crnlib namespace crnlib
{ {
@@ -43,51 +40,6 @@ namespace crnlib
set(other); set(other);
} }
dynamic_string::dynamic_string(const wchar_t* pStr) :
m_buf_size(0), m_len(0), m_pStr(NULL)
{
set(pStr);
}
dynamic_string& dynamic_string::set(const wchar_t *pStr)
{
uint len = static_cast<uint>(wcslen(pStr));
if (!len)
{
clear();
return *this;
}
const uint num_needed = WideCharToMultiByte(CP_ACP, 0, pStr, len, NULL, 0, NULL, NULL);
if (num_needed <= 0)
{
clear();
return *this;
}
if (!ensure_buf(num_needed, false))
{
clear();
return *this;
}
const uint num_written = WideCharToMultiByte(CP_ACP, 0, pStr, len, get_ptr_raw(), num_needed, NULL, NULL);
CRNLIB_ASSERT(num_written == num_needed);
get_ptr_raw()[num_written] = 0;
m_len = static_cast<uint16>(num_written);
check();
return *this;
}
dynamic_wstring& dynamic_string::as_utf16(dynamic_wstring &buf)
{
buf.set(get_ptr());
return buf;
}
void dynamic_string::clear() void dynamic_string::clear()
{ {
check(); check();
@@ -133,7 +85,7 @@ namespace crnlib
{ {
CRNLIB_ASSERT(p); CRNLIB_ASSERT(p);
const int result = (case_sensitive ? strcmp : _stricmp)(get_ptr_priv(), p); const int result = (case_sensitive ? strcmp : crn_stricmp)(get_ptr_priv(), p);
if (result < 0) if (result < 0)
return -1; return -1;
@@ -153,9 +105,9 @@ namespace crnlib
CRNLIB_ASSERT(p); CRNLIB_ASSERT(p);
const uint len = math::minimum<uint>(max_len, static_cast<uint>(strlen(p))); const uint len = math::minimum<uint>(max_len, static_cast<uint>(strlen(p)));
CRNLIB_ASSERT(len < UINT16_MAX); CRNLIB_ASSERT(len < cUINT16_MAX);
if ((!len) || (len >= UINT16_MAX)) if ((!len) || (len >= cUINT16_MAX))
clear(); clear();
else if ((m_pStr) && (p >= m_pStr) && (p < (m_pStr + m_buf_size))) else if ((m_pStr) && (p >= m_pStr) && (p < (m_pStr + m_buf_size)))
{ {
@@ -206,8 +158,11 @@ namespace crnlib
bool dynamic_string::set_len(uint new_len, char fill_char) bool dynamic_string::set_len(uint new_len, char fill_char)
{ {
if ((new_len >= UINT16_MAX) || (!fill_char)) if ((new_len >= cUINT16_MAX) || (!fill_char))
{
CRNLIB_ASSERT(0);
return false; return false;
}
uint cur_len = m_len; uint cur_len = m_len;
@@ -226,22 +181,41 @@ namespace crnlib
return true; return true;
} }
dynamic_string& dynamic_string::set_from_raw_buf_and_assume_ownership(char *pBuf, uint buf_size_in_chars, uint len_in_chars)
{
CRNLIB_ASSERT(buf_size_in_chars <= cUINT16_MAX);
CRNLIB_ASSERT(math::is_power_of_2(buf_size_in_chars) || (buf_size_in_chars == cUINT16_MAX));
CRNLIB_ASSERT((len_in_chars + 1) <= buf_size_in_chars);
clear();
m_pStr = pBuf;
m_buf_size = static_cast<uint16>(buf_size_in_chars);
m_len = static_cast<uint16>(len_in_chars);
check();
return *this;
}
dynamic_string& dynamic_string::set_from_buf(const void* pBuf, uint buf_size) dynamic_string& dynamic_string::set_from_buf(const void* pBuf, uint buf_size)
{ {
CRNLIB_ASSERT(pBuf); CRNLIB_ASSERT(pBuf);
if (buf_size >= UINT16_MAX) if (buf_size >= cUINT16_MAX)
{ {
clear(); clear();
return *this; return *this;
} }
#ifdef CRNLIB_BUILD_DEBUG
if ((buf_size) && (memchr(pBuf, 0, buf_size) != NULL)) if ((buf_size) && (memchr(pBuf, 0, buf_size) != NULL))
{ {
CRNLIB_ASSERT(0); CRNLIB_ASSERT(0);
clear(); clear();
return *this; return *this;
} }
#endif
if (ensure_buf(buf_size, false)) if (ensure_buf(buf_size, false))
{ {
@@ -569,9 +543,12 @@ namespace crnlib
else else
{ {
CRNLIB_ASSERT(m_buf_size); CRNLIB_ASSERT(m_buf_size);
CRNLIB_ASSERT((m_buf_size == UINT16_MAX) || math::is_power_of_2((uint32)m_buf_size)); CRNLIB_ASSERT((m_buf_size == cUINT16_MAX) || math::is_power_of_2((uint32)m_buf_size));
CRNLIB_ASSERT(m_len < m_buf_size); CRNLIB_ASSERT(m_len < m_buf_size);
CRNLIB_ASSERT(!m_pStr[m_len]);
#if CRNLIB_SLOW_STRING_LEN_CHECKS
CRNLIB_ASSERT(strlen(m_pStr) == m_len); CRNLIB_ASSERT(strlen(m_pStr) == m_len);
#endif
} }
} }
#endif #endif
@@ -580,9 +557,9 @@ namespace crnlib
{ {
uint buf_size_needed = len + 1; uint buf_size_needed = len + 1;
CRNLIB_ASSERT(buf_size_needed <= UINT16_MAX); CRNLIB_ASSERT(buf_size_needed <= cUINT16_MAX);
if (buf_size_needed <= UINT16_MAX) if (buf_size_needed <= cUINT16_MAX)
{ {
if (buf_size_needed > m_buf_size) if (buf_size_needed > m_buf_size)
expand_buf(buf_size_needed, preserve_contents); expand_buf(buf_size_needed, preserve_contents);
@@ -593,7 +570,7 @@ namespace crnlib
bool dynamic_string::expand_buf(uint new_buf_size, bool preserve_contents) bool dynamic_string::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))); new_buf_size = math::minimum<uint>(cUINT16_MAX, math::next_pow2(math::maximum<uint>(m_buf_size, new_buf_size)));
if (new_buf_size != m_buf_size) if (new_buf_size != m_buf_size)
{ {
@@ -625,8 +602,9 @@ namespace crnlib
{ {
uint buf_left = buf_size; uint buf_left = buf_size;
if (m_len > UINT16_MAX) //if (m_len > cUINT16_MAX)
return -1; // return -1;
CRNLIB_ASSUME(sizeof(m_len) == sizeof(uint16));
if (!utils::write_val((uint16)m_len, pBuf, buf_left, little_endian)) if (!utils::write_val((uint16)m_len, pBuf, buf_left, little_endian))
return -1; return -1;
@@ -687,9 +665,4 @@ namespace crnlib
swap(tmp); swap(tmp);
} }
dynamic_string& dynamic_string::operator= (const dynamic_wstring& rhs)
{
return set(rhs.get_ptr());
}
} // namespace crnlib } // namespace crnlib
+19 -9
View File
@@ -4,12 +4,9 @@
namespace crnlib namespace crnlib
{ {
class dynamic_wstring; enum { cMaxDynamicStringLen = cUINT16_MAX - 1 };
class dynamic_string class dynamic_string
{ {
friend class dynamic_wstring;
public: public:
inline dynamic_string() : m_buf_size(0), m_len(0), m_pStr(NULL) { } inline dynamic_string() : m_buf_size(0), m_len(0), m_pStr(NULL) { }
dynamic_string(eVarArg dummy, const char* p, ...); dynamic_string(eVarArg dummy, const char* p, ...);
@@ -19,25 +16,26 @@ namespace crnlib
inline ~dynamic_string() { if (m_pStr) crnlib_delete_array(m_pStr); } inline ~dynamic_string() { if (m_pStr) crnlib_delete_array(m_pStr); }
explicit dynamic_string(const wchar_t* pStr);
dynamic_string& set(const wchar_t *pStr);
dynamic_wstring& as_utf16(dynamic_wstring &buf);
// Truncates the string to 0 chars and frees the buffer. // Truncates the string to 0 chars and frees the buffer.
void clear(); void clear();
void optimize(); void optimize();
// Truncates the string to 0 chars, but does not free the buffer. // Truncates the string to 0 chars, but does not free the buffer.
void empty(); void empty();
inline const char *assume_ownership() { const char *p = m_pStr; m_pStr = NULL; m_len = 0; m_buf_size = 0; return p; }
inline uint get_len() const { return m_len; } inline uint get_len() const { return m_len; }
inline bool is_empty() const { return !m_len; } inline bool is_empty() const { return !m_len; }
inline const char* get_ptr() const { return m_pStr ? m_pStr : ""; } inline const char* get_ptr() const { return m_pStr ? m_pStr : ""; }
inline const char* c_str() const { return get_ptr(); }
inline const char* get_ptr_raw() const { return m_pStr; } inline const char* get_ptr_raw() const { return m_pStr; }
inline char* get_ptr_raw() { return m_pStr; } inline char* get_ptr_raw() { return m_pStr; }
inline char front() const { return m_len ? m_pStr[0] : '\0'; }
inline char back() const { return m_len ? m_pStr[m_len - 1] : '\0'; }
inline char operator[] (uint i) const { CRNLIB_ASSERT(i <= m_len); return get_ptr()[i]; } inline char operator[] (uint i) const { CRNLIB_ASSERT(i <= m_len); return get_ptr()[i]; }
inline operator size_t() const { return fast_hash(get_ptr(), m_len) ^ fast_hash(&m_len, sizeof(m_len)); } inline operator size_t() const { return fast_hash(get_ptr(), m_len) ^ fast_hash(&m_len, sizeof(m_len)); }
@@ -74,7 +72,6 @@ namespace crnlib
dynamic_string& set_from_buf(const void* pBuf, uint buf_size); dynamic_string& set_from_buf(const void* pBuf, uint buf_size);
dynamic_string& operator= (const dynamic_string& rhs) { return set(rhs); } dynamic_string& operator= (const dynamic_string& rhs) { return set(rhs); }
dynamic_string& operator= (const dynamic_wstring& rhs);
dynamic_string& operator= (const char* p) { return set(p); } dynamic_string& operator= (const char* p) { return set(p); }
dynamic_string& set_char(uint index, char c); dynamic_string& set_char(uint index, char c);
@@ -130,6 +127,9 @@ namespace crnlib
void translate_lf_to_crlf(); void translate_lf_to_crlf();
static inline char *create_raw_buffer(uint& buf_size_in_chars);
static inline void free_raw_buffer(char *p) { crnlib_delete_array(p); }
dynamic_string& set_from_raw_buf_and_assume_ownership(char *pBuf, uint buf_size_in_chars, uint len_in_chars);
private: private:
uint16 m_buf_size; uint16 m_buf_size;
uint16 m_len; uint16 m_len;
@@ -160,4 +160,14 @@ namespace crnlib
a.swap(b); a.swap(b);
} }
inline char *dynamic_string::create_raw_buffer(uint& buf_size_in_chars)
{
if (buf_size_in_chars > cUINT16_MAX)
{
CRNLIB_ASSERT(0);
return NULL;
}
buf_size_in_chars = math::minimum<uint>(cUINT16_MAX, math::next_pow2(buf_size_in_chars));
return crnlib_new_array<char>(buf_size_in_chars);
}
} // namespace crnlib } // namespace crnlib
-715
View File
@@ -1,715 +0,0 @@
// 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
@@ -1,159 +0,0 @@
// 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
-27
View File
@@ -1,27 +0,0 @@
// 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
+557
View File
@@ -0,0 +1,557 @@
// 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)
{
bool got_unc = false; got_unc;
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;
}
} // namespace crnlib
+48
View File
@@ -0,0 +1,48 @@
// 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);
}; // struct file_utils
} // namespace crnlib
+287
View File
@@ -0,0 +1,287 @@
// 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
@@ -1,7 +1,6 @@
// File: crn_win32_find_files.h // File: crn_win32_find_files.h
// 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_winhdr.h"
namespace crnlib namespace crnlib
{ {
@@ -11,22 +10,25 @@ namespace crnlib
struct file_desc struct file_desc
{ {
inline file_desc() : m_is_dir(false) { } inline file_desc() : m_is_dir(false) { }
dynamic_wstring m_fullname; dynamic_string m_fullname;
dynamic_wstring m_base; dynamic_string m_base;
dynamic_wstring m_rel; dynamic_string m_rel;
dynamic_wstring m_name; dynamic_string m_name;
bool m_is_dir; bool m_is_dir;
inline bool operator== (const file_desc& other) const { return m_fullname == other.m_fullname; } inline bool operator== (const file_desc& other) const { return m_fullname == other.m_fullname; }
inline bool operator< (const file_desc& other) const { return m_fullname < other.m_fullname; } inline bool operator< (const file_desc& other) const { return m_fullname < other.m_fullname; }
inline operator size_t() const { return static_cast<size_t>(m_fullname); } inline operator size_t() const { return static_cast<size_t>(m_fullname); }
}; };
typedef crnlib::vector<file_desc> file_desc_vec; typedef crnlib::vector<file_desc> file_desc_vec;
find_files() : m_last_error(S_OK) { } inline find_files()
{
m_last_error = 0; // S_OK;
}
enum flags enum flags
{ {
@@ -36,19 +38,22 @@ namespace crnlib
cFlagAllowHidden = 8 cFlagAllowHidden = 8
}; };
bool find(const wchar_t* pBasepath, const wchar_t* pFilespec, uint flags = cFlagAllowFiles); bool find(const char* pBasepath, const char* pFilespec, uint flags = cFlagAllowFiles);
bool find(const wchar_t* pSpec, uint flags = cFlagAllowFiles); bool find(const char* pSpec, uint flags = cFlagAllowFiles);
inline HRESULT get_last_error() const { return m_last_error; } // An HRESULT under Win32. FIXME: Abstract this better?
inline int64 get_last_error() const { return m_last_error; }
const file_desc_vec& get_files() const { return m_files; } const file_desc_vec& get_files() const { return m_files; }
private: private:
file_desc_vec m_files; file_desc_vec m_files;
HRESULT m_last_error;
bool find_internal(const wchar_t* pBasepath, const wchar_t* pRelpath, const wchar_t* pFilespec, uint flags); // 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 }; // class find_files
+158
View File
@@ -0,0 +1,158 @@
// 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
+2 -2
View File
@@ -30,7 +30,7 @@ namespace crnlib
} }
template <typename T> template <typename T>
void construct_array(T* p, uint n) inline void construct_array(T* p, uint n)
{ {
T* q = p + n; T* q = p + n;
for ( ; p != q; ++p) for ( ; p != q; ++p)
@@ -38,7 +38,7 @@ namespace crnlib
} }
template <typename T, typename U> template <typename T, typename U>
void construct_array(T* p, uint n, const U& init) inline void construct_array(T* p, uint n, const U& init)
{ {
T* q = p + n; T* q = p + n;
for ( ; p != q; ++p) for ( ; p != q; ++p)
+3 -3
View File
@@ -228,7 +228,7 @@ namespace crnlib
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 = UINT16_MAX; sf.m_right = cUINT16_MAX;
sf.m_freq = freq; sf.m_freq = freq;
num_used_syms++; num_used_syms++;
} }
@@ -263,8 +263,8 @@ namespace crnlib
#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 = UINT16_MAX; sf.m_left = cUINT16_MAX;
sf.m_right = UINT16_MAX; sf.m_right = cUINT16_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;
+39 -35
View File
@@ -6,6 +6,8 @@
#include "crn_resampler.h" #include "crn_resampler.h"
#include "crn_threaded_resampler.h" #include "crn_threaded_resampler.h"
#include "crn_strutils.h" #include "crn_strutils.h"
#include "crn_file_utils.h"
#include "crn_threading.h"
#define STBI_HEADER_FILE_ONLY #define STBI_HEADER_FILE_ONLY
#include "crn_stb_image.cpp" #include "crn_stb_image.cpp"
@@ -18,10 +20,10 @@ namespace crnlib
namespace image_utils namespace image_utils
{ {
bool load_from_file_stb(const wchar_t* pFilename, image_u8& img) bool load_from_file_stb(const char* pFilename, image_u8& img)
{ {
int x = 0, y = 0, n = 0; int x = 0, y = 0, n = 0;
unsigned char* pData = stbi_load_w(pFilename, &x, &y, &n, 4); unsigned char* pData = stbi_load(pFilename, &x, &y, &n, 4);
if (!pData) if (!pData)
return false; return false;
@@ -66,20 +68,20 @@ namespace crnlib
return true; return true;
} }
bool save_to_file_stb(const wchar_t* pFilename, const image_u8& img, uint save_flags, int comp_index) bool save_to_file_stb(const char* pFilename, const image_u8& img, uint save_flags, int comp_index)
{ {
if (!img.get_width()) if (!img.get_width())
return false; return false;
bool bSaveBMP = false; bool bSaveBMP = false;
dynamic_wstring ext(pFilename); dynamic_string ext(pFilename);
if (get_extension(ext)) if (file_utils::get_extension(ext))
{ {
if (ext == L"bmp") if (ext == "bmp")
bSaveBMP = true; bSaveBMP = true;
else if (ext != L"tga") else if (ext != "tga")
{ {
console::error(L"crnlib::image_utils::save_to_file_stb: Can only write .BMP or .TGA files!\n"); console::error("crnlib::image_utils::save_to_file_stb: Can only write .BMP or .TGA files!\n");
return false; return false;
} }
} }
@@ -114,7 +116,7 @@ namespace crnlib
} }
} }
return (bSaveBMP ? stbi_write_bmp_w : stbi_write_tga_w)(pFilename, img.get_width(), img.get_height(), 1, &temp[0]) == CRNLIB_TRUE; return (bSaveBMP ? stbi_write_bmp : stbi_write_tga)(pFilename, img.get_width(), img.get_height(), 1, &temp[0]) == CRNLIB_TRUE;
} }
else if ((!img.is_component_valid(3)) || (save_flags & cSaveIgnoreAlpha)) else if ((!img.is_component_valid(3)) || (save_flags & cSaveIgnoreAlpha))
{ {
@@ -138,27 +140,27 @@ namespace crnlib
} }
} }
return (bSaveBMP ? stbi_write_bmp_w : stbi_write_tga_w)(pFilename, img.get_width(), img.get_height(), 3, &temp[0]) == CRNLIB_TRUE; return (bSaveBMP ? stbi_write_bmp : stbi_write_tga)(pFilename, img.get_width(), img.get_height(), 3, &temp[0]) == CRNLIB_TRUE;
} }
else else
{ {
return (bSaveBMP ? stbi_write_bmp_w : stbi_write_tga_w)(pFilename, img.get_width(), img.get_height(), 4, img.get_ptr()) == CRNLIB_TRUE; return (bSaveBMP ? stbi_write_bmp : stbi_write_tga)(pFilename, img.get_width(), img.get_height(), 4, img.get_ptr()) == CRNLIB_TRUE;
} }
} }
bool load_from_file(image_u8& dest, const wchar_t* pFilename, int flags) bool load_from_file(image_u8& dest, const char* pFilename, int flags)
{ {
flags; flags;
return image_utils::load_from_file_stb(pFilename, dest); return image_utils::load_from_file_stb(pFilename, dest);
} }
bool save_to_grayscale_file(const wchar_t* pFilename, const image_u8& src, int component, int flags) bool save_to_grayscale_file(const char* pFilename, const image_u8& src, int component, int flags)
{ {
flags; flags;
return image_utils::save_to_file_stb(pFilename, src, image_utils::cSaveGrayscale, component); return image_utils::save_to_file_stb(pFilename, src, image_utils::cSaveGrayscale, component);
} }
bool save_to_file(const wchar_t* pFilename, const image_u8& src, int flags, bool ignore_alpha) bool save_to_file(const char* pFilename, const image_u8& src, int flags, bool ignore_alpha)
{ {
if (src.is_grayscale()) if (src.is_grayscale())
return save_to_grayscale_file(pFilename, src, cSaveLuma, flags); return save_to_grayscale_file(pFilename, src, cSaveLuma, flags);
@@ -220,7 +222,7 @@ namespace crnlib
} }
} }
bool is_normal_map(const image_u8& img, const wchar_t* pFilename) bool is_normal_map(const image_u8& img, const char* pFilename)
{ {
float score = 0.0f; float score = 0.0f;
@@ -259,13 +261,13 @@ namespace crnlib
if (pFilename) if (pFilename)
{ {
dynamic_wstring str(pFilename); dynamic_string str(pFilename);
str.tolower(); str.tolower();
if (str.contains(L"normal") || str.contains(L"local") || str.contains(L"nmap")) if (str.contains("normal") || str.contains("local") || str.contains("nmap"))
score += 1.0f; score += 1.0f;
if (str.contains(L"diffuse") || str.contains(L"spec") || str.contains(L"gloss")) if (str.contains("diffuse") || str.contains("spec") || str.contains("gloss"))
score -= 1.0f; score -= 1.0f;
} }
@@ -712,32 +714,34 @@ namespace crnlib
if (!total_blocks) if (!total_blocks)
return 0.0f; return 0.0f;
//save_to_file_stb(L"ssim.tga", yimg, cSaveGrayscale); //save_to_file_stb("ssim.tga", yimg, cSaveGrayscale);
return total_ssim / total_blocks; return total_ssim / total_blocks;
} }
void print_ssim(const image_u8& src_img, const image_u8& dst_img) void print_ssim(const image_u8& src_img, const image_u8& dst_img)
{ {
double y_ssim = compute_ssim(src_img, dst_img, -1); src_img;
console::printf(L"Luma MSSIM: %f, Scaled: %f", y_ssim, (y_ssim - .8f) / .2f); dst_img;
//double y_ssim = compute_ssim(src_img, dst_img, -1);
//console::printf("Luma MSSIM: %f, Scaled: %f", y_ssim, (y_ssim - .8f) / .2f);
//double r_ssim = compute_ssim(src_img, dst_img, 0); //double r_ssim = compute_ssim(src_img, dst_img, 0);
//console::printf(L" R MSSIM: %f", r_ssim); //console::printf(" R MSSIM: %f", r_ssim);
//double g_ssim = compute_ssim(src_img, dst_img, 1); //double g_ssim = compute_ssim(src_img, dst_img, 1);
//console::printf(L" G MSSIM: %f", g_ssim); //console::printf(" G MSSIM: %f", g_ssim);
//double b_ssim = compute_ssim(src_img, dst_img, 2); //double b_ssim = compute_ssim(src_img, dst_img, 2);
//console::printf(L" B MSSIM: %f", b_ssim); //console::printf(" B MSSIM: %f", b_ssim);
} }
void error_metrics::print(const wchar_t* pName) const void error_metrics::print(const char* pName) const
{ {
if (mPeakSNR >= cInfinitePSNR) if (mPeakSNR >= cInfinitePSNR)
console::printf(L"%s Error: Max: %3u, Mean: %3.3f, RMS: %3.3f, PSNR: Infinite", pName, mMax, mMean, mRootMeanSquared); console::printf("%s Error: Max: %3u, Mean: %3.3f, MSE: %3.3f, RMS: %3.3f, PSNR: Infinite", pName, mMax, mMean, mMeanSquared, mRootMeanSquared);
else else
console::printf(L"%s Error: Max: %3u, Mean: %3.3f, RMS: %3.3f, PSNR: %3.3f", pName, mMax, mMean, mRootMeanSquared, mPeakSNR); console::printf("%s Error: Max: %3u, Mean: %3.3f, MSE: %3.3f, RMS: %3.3f, PSNR: %3.3f", pName, mMax, mMean, mMeanSquared, mRootMeanSquared, mPeakSNR);
} }
bool error_metrics::compute(const image_u8& a, const image_u8& b, uint first_channel, uint num_channels, bool average_component_error) bool error_metrics::compute(const image_u8& a, const image_u8& b, uint first_channel, uint num_channels, bool average_component_error)
@@ -808,35 +812,35 @@ namespace crnlib
void print_image_metrics(const image_u8& src_img, const image_u8& dst_img) void print_image_metrics(const image_u8& src_img, const image_u8& dst_img)
{ {
if ( (!src_img.get_width()) || (!dst_img.get_height()) || (src_img.get_width() != dst_img.get_width()) || (src_img.get_height() != dst_img.get_height()) ) if ( (!src_img.get_width()) || (!dst_img.get_height()) || (src_img.get_width() != dst_img.get_width()) || (src_img.get_height() != dst_img.get_height()) )
console::printf(L"print_image_metrics: Image resolutions don't match exactly (%ux%u) vs. (%ux%u)", src_img.get_width(), src_img.get_height(), dst_img.get_width(), dst_img.get_height()); console::printf("print_image_metrics: Image resolutions don't match exactly (%ux%u) vs. (%ux%u)", src_img.get_width(), src_img.get_height(), dst_img.get_width(), dst_img.get_height());
image_utils::error_metrics error_metrics; image_utils::error_metrics error_metrics;
if (src_img.has_rgb() || dst_img.has_rgb()) if (src_img.has_rgb() || dst_img.has_rgb())
{ {
error_metrics.compute(src_img, dst_img, 0, 3, false); error_metrics.compute(src_img, dst_img, 0, 3, false);
error_metrics.print(L"RGB Total "); error_metrics.print("RGB Total ");
error_metrics.compute(src_img, dst_img, 0, 3, true); error_metrics.compute(src_img, dst_img, 0, 3, true);
error_metrics.print(L"RGB Average"); error_metrics.print("RGB Average");
error_metrics.compute(src_img, dst_img, 0, 0); error_metrics.compute(src_img, dst_img, 0, 0);
error_metrics.print(L"Luma "); error_metrics.print("Luma ");
error_metrics.compute(src_img, dst_img, 0, 1); error_metrics.compute(src_img, dst_img, 0, 1);
error_metrics.print(L"Red "); error_metrics.print("Red ");
error_metrics.compute(src_img, dst_img, 1, 1); error_metrics.compute(src_img, dst_img, 1, 1);
error_metrics.print(L"Green "); error_metrics.print("Green ");
error_metrics.compute(src_img, dst_img, 2, 1); error_metrics.compute(src_img, dst_img, 2, 1);
error_metrics.print(L"Blue "); error_metrics.print("Blue ");
} }
if (src_img.has_alpha() || dst_img.has_alpha()) if (src_img.has_alpha() || dst_img.has_alpha())
{ {
error_metrics.compute(src_img, dst_img, 3, 1); error_metrics.compute(src_img, dst_img, 3, 1);
error_metrics.print(L"Alpha "); error_metrics.print("Alpha ");
} }
} }
+35 -35
View File
@@ -6,12 +6,12 @@
namespace crnlib namespace crnlib
{ {
enum pixel_format; enum pixel_format;
namespace image_utils namespace image_utils
{ {
bool load_from_file_stb(const wchar_t* pFilename, image_u8& img); bool load_from_file_stb(const char* pFilename, image_u8& img);
enum enum
{ {
cSaveIgnoreAlpha = 1, cSaveIgnoreAlpha = 1,
cSaveGrayscale = 2 cSaveGrayscale = 2
@@ -19,18 +19,18 @@ namespace crnlib
const int cSaveLuma = -1; const int cSaveLuma = -1;
bool save_to_file_stb(const wchar_t* pFilename, const image_u8& img, uint save_flags = 0, int comp_index = cSaveLuma); bool save_to_file_stb(const char* pFilename, const image_u8& img, uint save_flags = 0, int comp_index = cSaveLuma);
bool load_from_file(image_u8& dest, const wchar_t* pFilename, int flags = 0);
bool save_to_grayscale_file(const wchar_t* pFilename, const image_u8& src, int component, int flags = 0); bool load_from_file(image_u8& dest, const char* pFilename, int flags = 0);
bool save_to_grayscale_file(const char* pFilename, const image_u8& src, int component, int flags = 0);
bool save_to_file(const char* pFilename, const image_u8& src, int flags = 0, bool ignore_alpha = false);
bool save_to_file(const wchar_t* pFilename, const image_u8& src, int flags = 0, bool ignore_alpha = false);
bool has_alpha(const image_u8& img); bool has_alpha(const image_u8& img);
bool is_normal_map(const image_u8& img, const wchar_t* pFilename = NULL); bool is_normal_map(const image_u8& img, const char* pFilename = NULL);
void renorm_normal_map(image_u8& img); void renorm_normal_map(image_u8& img);
struct resample_params struct resample_params
{ {
resample_params() : resample_params() :
@@ -46,7 +46,7 @@ namespace crnlib
m_multithreaded(true) m_multithreaded(true)
{ {
} }
uint m_dst_width; uint m_dst_width;
uint m_dst_height; uint m_dst_height;
const char* m_pFilter; const char* m_pFilter;
@@ -58,40 +58,40 @@ namespace crnlib
float m_source_gamma; float m_source_gamma;
bool m_multithreaded; bool m_multithreaded;
}; };
bool resample_single_thread(const image_u8& src, image_u8& dst, const resample_params& params); bool resample_single_thread(const image_u8& src, image_u8& dst, const resample_params& params);
bool resample_multithreaded(const image_u8& src, image_u8& dst, const resample_params& params); bool resample_multithreaded(const image_u8& src, image_u8& dst, const resample_params& params);
bool resample(const image_u8& src, image_u8& dst, const resample_params& params); bool resample(const image_u8& src, image_u8& dst, const resample_params& params);
bool compute_delta(image_u8& dest, image_u8& a, image_u8& b, uint scale = 2); bool compute_delta(image_u8& dest, image_u8& a, image_u8& b, uint scale = 2);
class error_metrics class error_metrics
{ {
public: public:
error_metrics() { utils::zero_this(this); } error_metrics() { utils::zero_this(this); }
void print(const wchar_t* pName) const; void print(const char* pName) const;
// If num_channels==0, luma error is computed. // If num_channels==0, luma error is computed.
// If pHist != NULL, it must point to a 256 entry array. // 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); bool compute(const image_u8& a, const image_u8& b, uint first_channel, uint num_channels, bool average_component_error = true);
uint mMax; uint mMax;
double mMean; double mMean;
double mMeanSquared; double mMeanSquared;
double mRootMeanSquared; double mRootMeanSquared;
double mPeakSNR; double mPeakSNR;
inline bool operator== (const error_metrics& other) const inline bool operator== (const error_metrics& other) const
{ {
return mPeakSNR == other.mPeakSNR; return mPeakSNR == other.mPeakSNR;
} }
inline bool operator< (const error_metrics& other) const inline bool operator< (const error_metrics& other) const
{ {
return mPeakSNR < other.mPeakSNR; return mPeakSNR < other.mPeakSNR;
} }
inline bool operator> (const error_metrics& other) const inline bool operator> (const error_metrics& other) const
{ {
return mPeakSNR > other.mPeakSNR; return mPeakSNR > other.mPeakSNR;
@@ -99,43 +99,43 @@ namespace crnlib
}; };
void print_image_metrics(const image_u8& src_img, const image_u8& dst_img); void print_image_metrics(const image_u8& src_img, const image_u8& dst_img);
double compute_block_ssim(uint n, const uint8* pX, const uint8* pY); double compute_block_ssim(uint n, const uint8* pX, const uint8* pY);
double compute_ssim(const image_u8& a, const image_u8& b, int channel_index); 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); void print_ssim(const image_u8& src_img, const image_u8& dst_img);
enum conversion_type enum conversion_type
{ {
cConversion_Invalid = -1, cConversion_Invalid = -1,
cConversion_To_CCxY, cConversion_To_CCxY,
cConversion_From_CCxY, cConversion_From_CCxY,
cConversion_To_xGxR, cConversion_To_xGxR,
cConversion_From_xGxR, cConversion_From_xGxR,
cConversion_To_xGBR, cConversion_To_xGBR,
cConversion_From_xGBR, cConversion_From_xGBR,
cConversion_To_AGBR, cConversion_To_AGBR,
cConversion_From_AGBR, cConversion_From_AGBR,
cConversion_XY_to_XYZ, cConversion_XY_to_XYZ,
cConversion_Y_To_A, cConversion_Y_To_A,
cConversion_A_To_RGBA, cConversion_A_To_RGBA,
cConversion_Y_To_RGB, cConversion_Y_To_RGB,
cConversionTotal cConversionTotal
}; };
void convert_image(image_u8& img, conversion_type conv_type); 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_conversion_type(bool cooking, pixel_format fmt);
image_utils::conversion_type get_image_conversion_type_from_crn_format(crn_format fmt); image_utils::conversion_type get_image_conversion_type_from_crn_format(crn_format fmt);
double compute_std_dev(uint n, const color_quad_u8* pPixels, uint first_channel, uint num_channels); double compute_std_dev(uint n, const color_quad_u8* pPixels, uint first_channel, uint num_channels);
} }
} }
+39 -34
View File
@@ -4,17 +4,18 @@
#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() : lzma_codec::lzma_codec() :
m_pCompress(LzmaCompress), m_pCompress(LzmaCompress),
m_pUncompress(LzmaUncompress) m_pUncompress(LzmaUncompress)
{ {
CRNLIB_ASSUME(cLZMAPropsSize == LZMA_PROPS_SIZE); CRNLIB_ASSUME(cLZMAPropsSize == LZMA_PROPS_SIZE);
} }
lzma_codec::~lzma_codec() lzma_codec::~lzma_codec()
{ {
} }
@@ -23,29 +24,29 @@ namespace crnlib
{ {
if (n > 1024U*1024U*1024U) if (n > 1024U*1024U*1024U)
return false; 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); buf.resize(sizeof(header) + max_comp_size);
header* pHDR = reinterpret_cast<header*>(&buf[0]); header* pHDR = reinterpret_cast<header*>(&buf[0]);
uint8* pComp_data = &buf[sizeof(header)]; uint8* pComp_data = &buf[sizeof(header)];
utils::zero_object(*pHDR); utils::zero_object(*pHDR);
pHDR->m_uncomp_size = n; pHDR->m_uncomp_size = n;
pHDR->m_adler32 = adler32(p, n); pHDR->m_adler32 = adler32(p, n);
if (n) if (n)
{ {
size_t destLen = 0; size_t destLen = 0;
size_t outPropsSize = 0; size_t outPropsSize = 0;
int status = SZ_ERROR_INPUT_EOF; int status = SZ_ERROR_INPUT_EOF;
for (uint trial = 0; trial < 3; trial++) for (uint trial = 0; trial < 3; trial++)
{ {
destLen = max_comp_size; destLen = max_comp_size;
outPropsSize = cLZMAPropsSize; outPropsSize = cLZMAPropsSize;
status = (*m_pCompress)(pComp_data, &destLen, reinterpret_cast<const unsigned char*>(p), n, status = (*m_pCompress)(pComp_data, &destLen, reinterpret_cast<const unsigned char*>(p), n,
pHDR->m_lzma_props, &outPropsSize, pHDR->m_lzma_props, &outPropsSize,
-1, /* 0 <= level <= 9, default = 5 */ -1, /* 0 <= level <= 9, default = 5 */
@@ -54,83 +55,87 @@ namespace crnlib
-1, /* 0 <= lp <= 4, default = 0 */ -1, /* 0 <= lp <= 4, default = 0 */
-1, /* 0 <= pb <= 4, default = 2 */ -1, /* 0 <= pb <= 4, default = 2 */
-1, /* 5 <= fb <= 273, default = 32 */ -1, /* 5 <= fb <= 273, default = 32 */
#ifdef WIN32
(g_number_of_processors > 1) ? 2 : 1 (g_number_of_processors > 1) ? 2 : 1
#else
1
#endif
); );
if (status != SZ_ERROR_OUTPUT_EOF) if (status != SZ_ERROR_OUTPUT_EOF)
break; break;
max_comp_size += ((n+1)/2); 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]); pHDR = reinterpret_cast<header*>(&buf[0]);
pComp_data = &buf[sizeof(header)]; pComp_data = &buf[sizeof(header)];
} }
if (status != SZ_OK) if (status != SZ_OK)
{ {
buf.clear(); buf.clear();
return false; return false;
} }
pHDR->m_comp_size = static_cast<uint>(destLen); pHDR->m_comp_size = static_cast<uint>(destLen);
buf.resize(CRNLIB_SIZEOF_U32(header) + static_cast<uint32>(destLen)); buf.resize(CRNLIB_SIZEOF_U32(header) + static_cast<uint32>(destLen));
} }
pHDR->m_sig = header::cSig; pHDR->m_sig = header::cSig;
pHDR->m_checksum = static_cast<uint8>(adler32((uint8*)pHDR + header::cChecksumSkipBytes, sizeof(header) - header::cChecksumSkipBytes)); pHDR->m_checksum = static_cast<uint8>(adler32((uint8*)pHDR + header::cChecksumSkipBytes, sizeof(header) - header::cChecksumSkipBytes));
return true; return true;
} }
bool lzma_codec::unpack(const void* p, uint n, crnlib::vector<uint8>& buf) bool lzma_codec::unpack(const void* p, uint n, crnlib::vector<uint8>& buf)
{ {
buf.resize(0); buf.resize(0);
if (n < sizeof(header)) if (n < sizeof(header))
return false; return false;
const header& hdr = *static_cast<const header*>(p); const header& hdr = *static_cast<const header*>(p);
if (hdr.m_sig != header::cSig) if (hdr.m_sig != header::cSig)
return false; return false;
if (static_cast<uint8>(adler32((const uint8*)&hdr + header::cChecksumSkipBytes, sizeof(hdr) - header::cChecksumSkipBytes)) != hdr.m_checksum) if (static_cast<uint8>(adler32((const uint8*)&hdr + header::cChecksumSkipBytes, sizeof(hdr) - header::cChecksumSkipBytes)) != hdr.m_checksum)
return false; return false;
if (!hdr.m_uncomp_size) if (!hdr.m_uncomp_size)
return true; return true;
if (!hdr.m_comp_size) if (!hdr.m_comp_size)
return false; return false;
if (hdr.m_uncomp_size > 1024U*1024U*1024U) if (hdr.m_uncomp_size > 1024U*1024U*1024U)
return false; return false;
if (!buf.try_resize(hdr.m_uncomp_size)) if (!buf.try_resize(hdr.m_uncomp_size))
return false; return false;
const uint8* pComp_data = static_cast<const uint8*>(p) + sizeof(header); const uint8* pComp_data = static_cast<const uint8*>(p) + sizeof(header);
size_t srcLen = n - sizeof(header); size_t srcLen = n - sizeof(header);
if (srcLen < hdr.m_comp_size) if (srcLen < hdr.m_comp_size)
return false; return false;
size_t destLen = hdr.m_uncomp_size; size_t destLen = hdr.m_uncomp_size;
int status = (*m_pUncompress)(&buf[0], &destLen, pComp_data, &srcLen, int status = (*m_pUncompress)(&buf[0], &destLen, pComp_data, &srcLen,
hdr.m_lzma_props, cLZMAPropsSize); hdr.m_lzma_props, cLZMAPropsSize);
if ((status != SZ_OK) || (destLen != hdr.m_uncomp_size)) if ((status != SZ_OK) || (destLen != hdr.m_uncomp_size))
{ {
buf.clear(); buf.clear();
return false; return false;
} }
if (adler32(&buf[0], buf.size()) != hdr.m_adler32) if (adler32(&buf[0], buf.size()) != hdr.m_adler32)
{ {
buf.clear(); buf.clear();
return false; return false;
} }
return true; return true;
} }
+3 -3
View File
@@ -12,14 +12,14 @@ namespace crnlib
~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.
const bool is_initialized() const { return true; } 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 (__stdcall *LzmaCompressFuncPtr)(unsigned char *dest, size_t *destLen, const unsigned char *src, size_t srcLen, typedef int (CRNLIB_STDCALL *LzmaCompressFuncPtr)(unsigned char *dest, size_t *destLen, const unsigned char *src, size_t srcLen,
unsigned char *outProps, size_t *outPropsSize, /* *outPropsSize must be = 5 */ 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) */
@@ -30,7 +30,7 @@ namespace crnlib
int numThreads /* 1 or 2, default = 2 */ int numThreads /* 1 or 2, default = 2 */
); );
typedef int (__stdcall *LzmaUncompressFuncPtr)(unsigned char *dest, size_t *destLen, const unsigned char *src, size_t *srcLen, typedef int (CRNLIB_STDCALL *LzmaUncompressFuncPtr)(unsigned char *dest, size_t *destLen, const unsigned char *src, size_t *srcLen,
const unsigned char *props, size_t propsSize); const unsigned char *props, size_t propsSize);
LzmaCompressFuncPtr m_pCompress; LzmaCompressFuncPtr m_pCompress;
+8
View File
@@ -216,6 +216,14 @@ namespace crnlib
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)
{
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 } // namespace crnlib
+92 -11
View File
@@ -1,15 +1,16 @@
// 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
#ifndef CRNLIB_USE_WIN32_API #if !CRNLIB_USE_WIN32_API
#define _msize malloc_usable_size #define _msize malloc_usable_size
#endif #endif
@@ -59,7 +60,7 @@ namespace crnlib
return new_total_allocated; return new_total_allocated;
} }
#endif // CRNLIB_MEM_STATS #endif // CRNLIB_MEM_STATS
static void* crnlib_default_realloc(void* p, size_t size, size_t* pActual_size, bool movable, void* pUser_data) static void* crnlib_default_realloc(void* p, size_t size, size_t* pActual_size, bool movable, void* pUser_data)
{ {
pUser_data; pUser_data;
@@ -88,7 +89,6 @@ namespace crnlib
#ifdef WIN32 #ifdef WIN32
p_new = ::_expand(p, size); p_new = ::_expand(p, size);
#else #else
p_new = NULL; p_new = NULL;
#endif #endif
@@ -121,15 +121,96 @@ namespace crnlib
return p ? _msize(p) : 0; return p ? _msize(p) : 0;
} }
#if 0
static __declspec(thread) void *g_pBuf;
static __declspec(thread) size_t g_buf_size;
static __declspec(thread) size_t g_buf_ofs;
static size_t crnlib_nofree_msize(void* p, void* pUser_data)
{
pUser_data;
return p ? ((const size_t*)p)[-1] : 0;
}
static void* crnlib_nofree_realloc(void* p, size_t size, size_t* pActual_size, bool movable, void* pUser_data)
{
pUser_data;
void* p_new;
if (!p)
{
size = math::align_up_value(size, CRNLIB_MIN_ALLOC_ALIGNMENT);
size_t actual_size = sizeof(size_t)*2 + size;
size_t num_remaining = g_buf_size - g_buf_ofs;
if (num_remaining < actual_size)
{
g_buf_size = CRNLIB_MAX(actual_size, 32*1024*1024);
g_buf_ofs = 0;
g_pBuf = malloc(g_buf_size);
if (!g_pBuf)
return NULL;
}
p_new = (uint8*)g_pBuf + g_buf_ofs;
((size_t*)p_new)[1] = size;
p_new = (size_t*)p_new + 2;
g_buf_ofs += actual_size;
if (pActual_size)
*pActual_size = size;
CRNLIB_ASSERT(crnlib_nofree_msize(p_new, NULL) == size);
}
else if (!size)
{
if (pActual_size)
*pActual_size = 0;
p_new = NULL;
}
else
{
size_t cur_size = crnlib_nofree_msize(p, NULL);
p_new = p;
if (!movable)
return NULL;
if (size > cur_size)
{
p_new = crnlib_nofree_realloc(NULL, size, NULL, true, NULL);
if (!p_new)
return NULL;
memcpy(p_new, p, cur_size);
cur_size = size;
}
if (pActual_size)
*pActual_size = cur_size;
}
return p_new;
}
static crn_realloc_func g_pRealloc = crnlib_nofree_realloc;
static crn_msize_func g_pMSize = crnlib_nofree_msize;
#else
static crn_realloc_func g_pRealloc = crnlib_default_realloc; static crn_realloc_func g_pRealloc = crnlib_default_realloc;
static crn_msize_func g_pMSize = crnlib_default_msize; static crn_msize_func g_pMSize = crnlib_default_msize;
#endif
static void* g_pUser_data; static void* g_pUser_data;
void crnlib_mem_error(const char* p_msg) void crnlib_mem_error(const char* p_msg)
{ {
crnlib_assert(p_msg, __FILE__, __LINE__); crnlib_assert(p_msg, __FILE__, __LINE__);
} }
void* crnlib_malloc(size_t size)
{
return crnlib_malloc(size, NULL);
}
void* crnlib_malloc(size_t size, size_t* pActual_size) void* crnlib_malloc(size_t size, size_t* pActual_size)
{ {
size = (size + sizeof(uint32) - 1U) & ~(sizeof(uint32) - 1U); size = (size + sizeof(uint32) - 1U) & ~(sizeof(uint32) - 1U);
@@ -182,7 +263,7 @@ namespace crnlib
size_t cur_size = p ? (*g_pMSize)(p, g_pUser_data) : 0; size_t cur_size = p ? (*g_pMSize)(p, g_pUser_data) : 0;
CRNLIB_ASSERT(!p || (cur_size >= sizeof(uint32))); CRNLIB_ASSERT(!p || (cur_size >= sizeof(uint32)));
#endif #endif
if ((size) && (size < sizeof(uint32))) if ((size) && (size < sizeof(uint32)))
size = sizeof(uint32); size = sizeof(uint32);
size_t actual_size = size; size_t actual_size = size;
@@ -253,19 +334,19 @@ namespace crnlib
return (*g_pMSize)(p, g_pUser_data); return (*g_pMSize)(p, g_pUser_data);
} }
void crnlib_print_mem_stats() void crnlib_print_mem_stats()
{ {
#if CRNLIB_MEM_STATS #if CRNLIB_MEM_STATS
if (console::is_initialized()) if (console::is_initialized())
{ {
console::debug(L"crnlib_print_mem_stats:"); console::debug("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); console::debug("Current blocks: %u, allocated: " CRNLIB_INT64_FORMAT_SPECIFIER ", max ever allocated: " CRNLIB_INT64_FORMAT_SPECIFIER, g_total_blocks, (int64)g_total_allocated, (int64)g_max_allocated);
} }
else else
{ {
printf("crnlib_print_mem_stats:\n"); 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); 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
} }
+25 -1
View File
@@ -14,7 +14,8 @@ namespace crnlib
const uint32 CRNLIB_MAX_POSSIBLE_BLOCK_SIZE = 0x7FFF0000U; const uint32 CRNLIB_MAX_POSSIBLE_BLOCK_SIZE = 0x7FFF0000U;
#endif #endif
void* crnlib_malloc(size_t size, size_t* pActual_size = NULL); void* crnlib_malloc(size_t size);
void* crnlib_malloc(size_t size, size_t* pActual_size);
void* crnlib_realloc(void* p, size_t size, size_t* pActual_size = NULL, bool movable = true); void* crnlib_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);
@@ -183,3 +184,26 @@ namespace crnlib
} }
} // namespace crnlib } // namespace crnlib
#define CRNLIB_DEFINE_NEW_DELETE \
void* operator new (size_t size) \
{ \
void* p = crnlib::crnlib_malloc(size); \
if (!p) \
crnlib_fail("new: Out of memory!", __FILE__, __LINE__); \
return p; \
} \
void* operator new[] (size_t size) \
{ \
void* p = crnlib::crnlib_malloc(size); \
if (!p) \
crnlib_fail("new[]: Out of memory!", __FILE__, __LINE__); \
return p; \
} \
void operator delete (void* p_block) \
{ \
crnlib::crnlib_free(p_block); \
} \
void operator delete[] (void* p_block) \
{ \
crnlib::crnlib_free(p_block); \
}
-40
View File
@@ -1,40 +0,0 @@
// 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
+2 -51
View File
@@ -41,36 +41,7 @@ namespace crnlib
return g_all_pixel_formats[index]; return g_all_pixel_formats[index];
} }
const wchar_t* get_pixel_format_string(pixel_format fmt) const char* get_pixel_format_string(pixel_format fmt)
{
switch (fmt)
{
case PIXEL_FMT_INVALID: return L"INVALID";
case PIXEL_FMT_DXT1: return L"DXT1";
case PIXEL_FMT_DXT1A: return L"DXT1A";
case PIXEL_FMT_DXT2: return L"DXT2";
case PIXEL_FMT_DXT3: return L"DXT3";
case PIXEL_FMT_DXT4: return L"DXT4";
case PIXEL_FMT_DXT5: return L"DXT5";
case PIXEL_FMT_3DC: return L"3DC";
case PIXEL_FMT_DXN: return L"DXN";
case PIXEL_FMT_DXT5A: return L"DXT5A";
case PIXEL_FMT_DXT5_CCxY: return L"DXT5_CCxY";
case PIXEL_FMT_DXT5_xGxR: return L"DXT5_xGxR";
case PIXEL_FMT_DXT5_xGBR: return L"DXT5_xGBR";
case PIXEL_FMT_DXT5_AGBR: return L"DXT5_AGBR";
case PIXEL_FMT_R8G8B8: return L"R8G8B8";
case PIXEL_FMT_A8R8G8B8: return L"A8R8G8B8";
case PIXEL_FMT_A8: return L"A8";
case PIXEL_FMT_L8: return L"L8";
case PIXEL_FMT_A8L8: return L"A8L8";
default: break;
}
CRNLIB_ASSERT(false);
return L"?";
}
const char* get_pixel_format_stringa(pixel_format fmt)
{ {
switch (fmt) switch (fmt)
{ {
@@ -99,27 +70,7 @@ namespace crnlib
return "?"; return "?";
} }
const wchar_t* get_crn_format_string(crn_format fmt) const char* get_crn_format_string(crn_format fmt)
{
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"?";
}
const char* get_crn_format_stringa(crn_format fmt)
{ {
switch (fmt) switch (fmt)
{ {
+2 -4
View File
@@ -12,11 +12,9 @@ namespace crnlib
uint get_num_formats(); uint get_num_formats();
pixel_format get_pixel_format_by_index(uint index); pixel_format get_pixel_format_by_index(uint index);
const wchar_t* get_pixel_format_string(pixel_format fmt); const char* get_pixel_format_string(pixel_format fmt);
const char* get_pixel_format_stringa(pixel_format fmt);
const wchar_t* get_crn_format_string(crn_format fmt); const char* 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)
{ {
+78 -5
View File
@@ -1,6 +1,73 @@
// 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)
@@ -8,12 +75,18 @@ bool crnlib_is_debugger_present(void)
return IsDebuggerPresent() != 0; return IsDebuggerPresent() != 0;
} }
void crnlib_debug_break(void)
{
DebugBreak();
}
void crnlib_output_debug_string(const char* p) void crnlib_output_debug_string(const char* p)
{ {
OutputDebugStringA(p); OutputDebugStringA(p);
} }
#else
bool crnlib_is_debugger_present(void)
{
return false;
}
void crnlib_output_debug_string(const char* p)
{
puts(p);
}
#endif // CRNLIB_USE_WIN32_API
+82 -38
View File
@@ -2,44 +2,6 @@
// 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);
@@ -47,3 +9,85 @@ 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)))
#elif defined(_MSC_VER)
#define CRNLIB_ALIGNED(x) __declspec(align(x))
#else
#define CRNLIB_ALIGNED(x)
#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
}
+2 -2
View File
@@ -156,7 +156,7 @@ namespace crnlib
uint c = pCodesizes[i]; uint c = pCodesizes[i];
if (c) if (c)
{ {
CRNLIB_ASSERT(next_code[c] <= UINT16_MAX); CRNLIB_ASSERT(next_code[c] <= cUINT16_MAX);
pCodes[i] = static_cast<uint16>(next_code[c]++); pCodes[i] = static_cast<uint16>(next_code[c]++);
CRNLIB_ASSERT(math::total_bits(pCodes[i]) <= pCodesizes[i]); CRNLIB_ASSERT(math::total_bits(pCodes[i]) <= pCodesizes[i]);
@@ -300,7 +300,7 @@ namespace crnlib
CRNLIB_ASSERT(t < (1U << table_bits)); CRNLIB_ASSERT(t < (1U << table_bits));
CRNLIB_ASSERT(pTables->m_lookup[t] == UINT32_MAX); CRNLIB_ASSERT(pTables->m_lookup[t] == cUINT32_MAX);
pTables->m_lookup[t] = sym_index | (codesize << 16U); pTables->m_lookup[t] = sym_index | (codesize << 16U);
} }
+14 -13
View File
@@ -61,7 +61,7 @@ namespace crnlib
CRNLIB_ASSERT(n && pBlocks); CRNLIB_ASSERT(n && pBlocks);
m_main_thread_id = get_current_thread_id(); m_main_thread_id = crn_get_current_thread_id();
m_num_blocks = n; m_num_blocks = n;
m_pBlocks = pBlocks; m_pBlocks = pBlocks;
@@ -99,6 +99,11 @@ namespace crnlib
if (debugging) if (debugging)
debug_img.resize(num_chunks_x * cChunkPixelWidth, num_chunks_y * cChunkPixelHeight); debug_img.resize(num_chunks_x * cChunkPixelWidth, num_chunks_y * cChunkPixelHeight);
float adaptive_tile_color_psnr_derating = 1.5f; // was 2.4f
if ((level) && (adaptive_tile_color_psnr_derating > .25f))
{
adaptive_tile_color_psnr_derating = math::maximum(.25f, adaptive_tile_color_psnr_derating / powf(3.1f, static_cast<float>(level))); // was 3.0f
}
for (uint chunk_y = 0; chunk_y < num_chunks_y; chunk_y++) for (uint chunk_y = 0; chunk_y < num_chunks_y; chunk_y++)
{ {
for (uint chunk_x = 0; chunk_x < num_chunks_x; chunk_x++) for (uint chunk_x = 0; chunk_x < num_chunks_x; chunk_x++)
@@ -197,13 +202,8 @@ namespace crnlib
if (mean_squared) if (mean_squared)
peak_snr = math::clamp<double>(log10(255.0f / root_mean_squared) * 20.0f, 0.0f, 500.0f); peak_snr = math::clamp<double>(log10(255.0f / root_mean_squared) * 20.0f, 0.0f, 500.0f);
float adaptive_tile_color_psnr_derating = 2.4f;
//if (level) //if (level)
// adaptive_tile_color_psnr_derating = math::lerp(adaptive_tile_color_psnr_derating * .5f, .3f, math::maximum((level - 1) / float(m_params.m_num_mips - 2), 1.0f)); // adaptive_tile_color_psnr_derating = math::lerp(adaptive_tile_color_psnr_derating * .5f, .3f, math::maximum((level - 1) / float(m_params.m_num_mips - 2), 1.0f));
if ((level) && (adaptive_tile_color_psnr_derating > .25f))
{
adaptive_tile_color_psnr_derating = math::maximum(.25f, adaptive_tile_color_psnr_derating / powf(3.0f, static_cast<float>(level)));
}
float color_derating = math::lerp( 0.0f, adaptive_tile_color_psnr_derating, (g_chunk_encodings[e].m_num_tiles - 1) / 3.0f ); float color_derating = math::lerp( 0.0f, adaptive_tile_color_psnr_derating, (g_chunk_encodings[e].m_num_tiles - 1) / 3.0f );
peak_snr = peak_snr - color_derating; peak_snr = peak_snr - color_derating;
@@ -306,7 +306,7 @@ namespace crnlib
#if GENERATE_DEBUG_IMAGES #if GENERATE_DEBUG_IMAGES
if (debugging) if (debugging)
image_utils::save_to_file_stb(dynamic_wstring(cVarArg, L"debug_%u.tga", level).get_ptr(), debug_img, image_utils::cSaveIgnoreAlpha); image_utils::save_to_file_stb(dynamic_string(cVarArg, "debug_%u.tga", level).get_ptr(), debug_img, image_utils::cSaveIgnoreAlpha);
#endif #endif
} // level } // level
@@ -440,7 +440,7 @@ namespace crnlib
if ((cluster_index & cluster_index_progress_mask) == 0) if ((cluster_index & cluster_index_progress_mask) == 0)
{ {
if (get_current_thread_id() == m_main_thread_id) if (crn_get_current_thread_id() == m_main_thread_id)
{ {
if (!update_progress(cluster_index, m_endpoint_cluster_indices.size() - 1)) if (!update_progress(cluster_index, m_endpoint_cluster_indices.size() - 1))
return; return;
@@ -547,7 +547,8 @@ namespace crnlib
{ {
const uint block_index = indices[block_iter]; const uint block_index = indices[block_iter];
const color_quad_u8* pSrc_pixels = &m_pBlocks[block_index].m_pixels[0][0]; //const color_quad_u8* pSrc_pixels = &m_pBlocks[block_index].m_pixels[0][0];
const color_quad_u8* pSrc_pixels = (const color_quad_u8*)m_pBlocks[block_index].m_pixels;
for (uint i = 0; i < cDXTBlockSize * cDXTBlockSize; i++) for (uint i = 0; i < cDXTBlockSize * cDXTBlockSize; i++)
{ {
@@ -646,7 +647,7 @@ namespace crnlib
if ((cluster_index & 255) == 0) if ((cluster_index & 255) == 0)
{ {
if (get_current_thread_id() == m_main_thread_id) if (crn_get_current_thread_id() == m_main_thread_id)
{ {
if (!update_progress(cluster_index, task_params.m_selector_cluster_indices.size() - 1)) if (!update_progress(cluster_index, task_params.m_selector_cluster_indices.size() - 1))
return; return;
@@ -681,7 +682,7 @@ namespace crnlib
if (m_params.m_dxt1a_alpha_threshold > 0) if (m_params.m_dxt1a_alpha_threshold > 0)
{ {
const color_quad_u8* pSrc_pixels = &m_pBlocks[block_index].m_pixels[0][0]; const color_quad_u8* pSrc_pixels = (const color_quad_u8*)m_pBlocks[block_index].m_pixels;
for (uint i = 0; i < cDXTBlockSize * cDXTBlockSize; i++) for (uint i = 0; i < cDXTBlockSize * cDXTBlockSize; i++)
{ {
@@ -809,7 +810,7 @@ namespace crnlib
{ {
CRNLIB_ASSERT(m_num_blocks); CRNLIB_ASSERT(m_num_blocks);
m_main_thread_id = get_current_thread_id(); m_main_thread_id = crn_get_current_thread_id();
m_canceled = false; m_canceled = false;
m_pDst_elements = pDst_elements; m_pDst_elements = pDst_elements;
@@ -824,7 +825,7 @@ namespace crnlib
const float quality = m_params.m_quality_level / (float)qdxt1_params::cMaxQuality; const float quality = m_params.m_quality_level / (float)qdxt1_params::cMaxQuality;
const float endpoint_quality = powf(quality, 1.8f * quality_power_mul); const float endpoint_quality = powf(quality, 1.8f * quality_power_mul);
const float selector_quality = powf(quality, 1.65f * quality_power_mul); const float selector_quality = powf(quality, 1.65f * quality_power_mul);
//const uint max_endpoint_clusters = math::clamp<uint>(static_cast<uint>(m_endpoint_clusterizer.get_codebook_size() * endpoint_quality), 128U, m_endpoint_clusterizer.get_codebook_size()); //const uint max_endpoint_clusters = math::clamp<uint>(static_cast<uint>(m_endpoint_clusterizer.get_codebook_size() * endpoint_quality), 128U, m_endpoint_clusterizer.get_codebook_size());
//const uint max_selector_clusters = math::clamp<uint>(static_cast<uint>(m_max_selector_clusters * selector_quality), 150U, m_max_selector_clusters); //const uint max_selector_clusters = math::clamp<uint>(static_cast<uint>(m_max_selector_clusters * selector_quality), 150U, m_max_selector_clusters);
const uint max_endpoint_clusters = math::clamp<uint>(static_cast<uint>(m_endpoint_clusterizer.get_codebook_size() * endpoint_quality), 96U, m_endpoint_clusterizer.get_codebook_size()); const uint max_endpoint_clusters = math::clamp<uint>(static_cast<uint>(m_endpoint_clusterizer.get_codebook_size() * endpoint_quality), 96U, m_endpoint_clusterizer.get_codebook_size());
+40 -42
View File
@@ -2,8 +2,6 @@
// 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_dxt.h" #include "crn_dxt.h"
#include "crn_task_pool.h"
#include "crn_spinlock.h"
#include "crn_hash_map.h" #include "crn_hash_map.h"
#include "crn_clusterizer.h" #include "crn_clusterizer.h"
#include "crn_hash.h" #include "crn_hash.h"
@@ -17,8 +15,8 @@ namespace crnlib
qdxt1_params() qdxt1_params()
{ {
clear(); clear();
} }
void clear() void clear()
{ {
m_quality_level = cMaxQuality; m_quality_level = cMaxQuality;
@@ -44,27 +42,27 @@ namespace crnlib
m_quality_level = quality_level; m_quality_level = quality_level;
m_dxt1a_alpha_threshold = pp.m_dxt1a_alpha_threshold; m_dxt1a_alpha_threshold = pp.m_dxt1a_alpha_threshold;
} }
enum { cMaxQuality = cCRNMaxQualityLevel }; enum { cMaxQuality = cCRNMaxQualityLevel };
uint m_quality_level; uint m_quality_level;
uint m_dxt1a_alpha_threshold; uint m_dxt1a_alpha_threshold;
crn_dxt_quality m_dxt_quality; crn_dxt_quality m_dxt_quality;
bool m_perceptual; bool m_perceptual;
bool m_use_alpha_blocks; bool m_use_alpha_blocks;
bool m_hierarchical; bool m_hierarchical;
struct mip_desc struct mip_desc
{ {
uint m_first_block; uint m_first_block;
uint m_block_width; uint m_block_width;
uint m_block_height; uint m_block_height;
}; };
uint m_num_mips; uint m_num_mips;
enum { cMaxMips = 128 }; enum { cMaxMips = 128 };
mip_desc m_mip_desc[cMaxMips]; mip_desc m_mip_desc[cMaxMips];
typedef bool (*progress_callback_func)(uint percentage_completed, void* pProgress_data); typedef bool (*progress_callback_func)(uint percentage_completed, void* pProgress_data);
progress_callback_func m_pProgress_func; progress_callback_func m_pProgress_func;
void* m_pProgress_data; void* m_pProgress_data;
@@ -75,67 +73,67 @@ namespace crnlib
class qdxt1 class qdxt1
{ {
CRNLIB_NO_COPY_OR_ASSIGNMENT_OP(qdxt1); CRNLIB_NO_COPY_OR_ASSIGNMENT_OP(qdxt1);
public: public:
qdxt1(task_pool& task_pool); qdxt1(task_pool& task_pool);
~qdxt1(); ~qdxt1();
void clear(); void clear();
bool init(uint n, const dxt_pixel_block* pBlocks, const qdxt1_params& params); bool init(uint n, const dxt_pixel_block* pBlocks, const qdxt1_params& params);
uint get_num_blocks() const { return m_num_blocks; } uint get_num_blocks() const { return m_num_blocks; }
const dxt_pixel_block* get_blocks() const { return m_pBlocks; } const dxt_pixel_block* get_blocks() const { return m_pBlocks; }
bool pack(dxt1_block* pDst_elements, uint elements_per_block, const qdxt1_params& params, float quality_power_mul); bool pack(dxt1_block* pDst_elements, uint elements_per_block, const qdxt1_params& params, float quality_power_mul);
private: private:
task_pool* m_pTask_pool; task_pool* m_pTask_pool;
uint32 m_main_thread_id; crn_thread_id_t m_main_thread_id;
bool m_canceled; bool m_canceled;
uint m_progress_start; uint m_progress_start;
uint m_progress_range; uint m_progress_range;
uint m_num_blocks; uint m_num_blocks;
const dxt_pixel_block* m_pBlocks; const dxt_pixel_block* m_pBlocks;
dxt1_block* m_pDst_elements; dxt1_block* m_pDst_elements;
uint m_elements_per_block; uint m_elements_per_block;
qdxt1_params m_params; qdxt1_params m_params;
uint m_max_selector_clusters; uint m_max_selector_clusters;
int m_prev_percentage_complete; int m_prev_percentage_complete;
typedef vec<6, float> vec6F; typedef vec<6, float> vec6F;
typedef clusterizer<vec6F> vec6F_clusterizer; typedef clusterizer<vec6F> vec6F_clusterizer;
vec6F_clusterizer m_endpoint_clusterizer; vec6F_clusterizer m_endpoint_clusterizer;
crnlib::vector< crnlib::vector<uint> > m_endpoint_cluster_indices; crnlib::vector< crnlib::vector<uint> > m_endpoint_cluster_indices;
typedef vec<16, float> vec16F; typedef vec<16, float> vec16F;
typedef threaded_clusterizer<vec16F> vec16F_clusterizer; typedef threaded_clusterizer<vec16F> vec16F_clusterizer;
typedef vec16F_clusterizer::weighted_vec weighted_selector_vec; typedef vec16F_clusterizer::weighted_vec weighted_selector_vec;
typedef vec16F_clusterizer::weighted_vec_array weighted_selector_vec_array; typedef vec16F_clusterizer::weighted_vec_array weighted_selector_vec_array;
vec16F_clusterizer m_selector_clusterizer; vec16F_clusterizer m_selector_clusterizer;
crnlib::vector< crnlib::vector<uint> > m_cached_selector_cluster_indices[qdxt1_params::cMaxQuality + 1]; crnlib::vector< crnlib::vector<uint> > m_cached_selector_cluster_indices[qdxt1_params::cMaxQuality + 1];
struct cluster_id struct cluster_id
{ {
cluster_id() : m_hash(0) cluster_id() : m_hash(0)
{ {
} }
cluster_id(const crnlib::vector<uint>& indices) cluster_id(const crnlib::vector<uint>& indices)
{ {
set(indices); set(indices);
} }
void set(const crnlib::vector<uint>& indices) void set(const crnlib::vector<uint>& indices)
{ {
m_cells.resize(indices.size()); m_cells.resize(indices.size());
@@ -145,29 +143,29 @@ namespace crnlib
std::sort(m_cells.begin(), m_cells.end()); std::sort(m_cells.begin(), m_cells.end());
m_hash = fast_hash(&m_cells[0], sizeof(m_cells[0]) * m_cells.size()); m_hash = fast_hash(&m_cells[0], sizeof(m_cells[0]) * m_cells.size());
} }
bool operator< (const cluster_id& rhs) const bool operator< (const cluster_id& rhs) const
{ {
return m_cells < rhs.m_cells; return m_cells < rhs.m_cells;
} }
bool operator== (const cluster_id& rhs) const bool operator== (const cluster_id& rhs) const
{ {
if (m_hash != rhs.m_hash) if (m_hash != rhs.m_hash)
return false; return false;
return m_cells == rhs.m_cells; return m_cells == rhs.m_cells;
} }
crnlib::vector<uint32> m_cells; crnlib::vector<uint32> m_cells;
size_t m_hash; size_t m_hash;
operator size_t() const { return m_hash; } operator size_t() const { return m_hash; }
}; };
typedef crnlib::hash_map<cluster_id, uint> cluster_hash; typedef crnlib::hash_map<cluster_id, uint> cluster_hash;
cluster_hash m_cluster_hash; cluster_hash m_cluster_hash;
spinlock m_cluster_hash_lock; spinlock m_cluster_hash_lock;
@@ -178,10 +176,10 @@ namespace crnlib
void pack_endpoints_task(uint64 data, void* pData_ptr); void pack_endpoints_task(uint64 data, void* pData_ptr);
void optimize_selectors_task(uint64 data, void* pData_ptr); void optimize_selectors_task(uint64 data, void* pData_ptr);
bool create_selector_clusters(uint max_selector_clusters, crnlib::vector< crnlib::vector<uint> >& selector_cluster_indices); bool create_selector_clusters(uint max_selector_clusters, crnlib::vector< crnlib::vector<uint> >& selector_cluster_indices);
inline dxt1_block& get_block(uint index) const { return m_pDst_elements[index * m_elements_per_block]; } inline dxt1_block& get_block(uint index) const { return m_pDst_elements[index * m_elements_per_block]; }
}; };
CRNLIB_DEFINE_BITWISE_MOVABLE(qdxt1::cluster_id); CRNLIB_DEFINE_BITWISE_MOVABLE(qdxt1::cluster_id);
} // namespace crnlib } // namespace crnlib
+7 -6
View File
@@ -62,7 +62,7 @@ namespace crnlib
CRNLIB_ASSERT(n && pBlocks); CRNLIB_ASSERT(n && pBlocks);
m_main_thread_id = get_current_thread_id(); m_main_thread_id = crn_get_current_thread_id();
m_num_blocks = n; m_num_blocks = n;
m_pBlocks = pBlocks; m_pBlocks = pBlocks;
@@ -286,7 +286,7 @@ namespace crnlib
#if QDXT5_DEBUGGING #if QDXT5_DEBUGGING
if (debugging) if (debugging)
image_utils::save_to_file_stb(dynamic_wstring(cVarArg, L"debug_%u.tga", level).get_ptr(), debug_img, image_utils::cSaveIgnoreAlpha); image_utils::save_to_file_stb(dynamic_wstring(cVarArg, "debug_%u.tga", level).get_ptr(), debug_img, image_utils::cSaveIgnoreAlpha);
#endif #endif
} // level } // level
@@ -419,7 +419,7 @@ namespace crnlib
if ((cluster_index & cluster_index_progress_mask) == 0) if ((cluster_index & cluster_index_progress_mask) == 0)
{ {
if (get_current_thread_id() == m_main_thread_id) if (crn_get_current_thread_id() == m_main_thread_id)
{ {
if (!update_progress(cluster_index, m_endpoint_cluster_indices.size() - 1)) if (!update_progress(cluster_index, m_endpoint_cluster_indices.size() - 1))
return; return;
@@ -444,7 +444,8 @@ namespace crnlib
{ {
const uint block_index = cluster_indices[block_iter]; const uint block_index = cluster_indices[block_iter];
const color_quad_u8* pSrc_pixels = &m_pBlocks[block_index].m_pixels[0][0]; //const color_quad_u8* pSrc_pixels = &m_pBlocks[block_index].m_pixels[0][0];
const color_quad_u8* pSrc_pixels = (const color_quad_u8*)m_pBlocks[block_index].m_pixels;
for (uint i = 0; i < cDXTBlockSize * cDXTBlockSize; i++) for (uint i = 0; i < cDXTBlockSize * cDXTBlockSize; i++)
{ {
@@ -521,7 +522,7 @@ namespace crnlib
if ((cluster_index & 255) == 0) if ((cluster_index & 255) == 0)
{ {
if (get_current_thread_id() == m_main_thread_id) if (crn_get_current_thread_id() == m_main_thread_id)
{ {
if (!update_progress(cluster_index, task_params.m_selector_cluster_indices.size() - 1)) if (!update_progress(cluster_index, task_params.m_selector_cluster_indices.size() - 1))
return; return;
@@ -735,7 +736,7 @@ namespace crnlib
{ {
CRNLIB_ASSERT(m_num_blocks); CRNLIB_ASSERT(m_num_blocks);
m_main_thread_id = get_current_thread_id(); m_main_thread_id = crn_get_current_thread_id();
m_canceled = false; m_canceled = false;
m_pDst_elements = pDst_elements; m_pDst_elements = pDst_elements;
+13 -15
View File
@@ -1,8 +1,6 @@
// File: crn_qdxt5.h // File: crn_qdxt5.h
// 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_task_pool.h"
#include "crn_spinlock.h"
#include "crn_hash_map.h" #include "crn_hash_map.h"
#include "crn_clusterizer.h" #include "crn_clusterizer.h"
#include "crn_hash.h" #include "crn_hash.h"
@@ -17,23 +15,23 @@ namespace crnlib
qdxt5_params() qdxt5_params()
{ {
clear(); clear();
} }
void clear() void clear()
{ {
m_quality_level = cMaxQuality; m_quality_level = cMaxQuality;
m_dxt_quality = cCRNDXTQualityUber; m_dxt_quality = cCRNDXTQualityUber;
m_pProgress_func = NULL; m_pProgress_func = NULL;
m_pProgress_data = NULL; m_pProgress_data = NULL;
m_num_mips = 0; m_num_mips = 0;
m_hierarchical = true; m_hierarchical = true;
utils::zero_object(m_mip_desc); utils::zero_object(m_mip_desc);
m_comp_index = 3; m_comp_index = 3;
m_progress_start = 0; m_progress_start = 0;
m_progress_range = 100; m_progress_range = 100;
m_use_both_block_types = true; m_use_both_block_types = true;
} }
@@ -50,7 +48,7 @@ namespace crnlib
uint m_quality_level; uint m_quality_level;
crn_dxt_quality m_dxt_quality; crn_dxt_quality m_dxt_quality;
bool m_hierarchical; bool m_hierarchical;
struct mip_desc struct mip_desc
{ {
uint m_first_block; uint m_first_block;
@@ -67,20 +65,20 @@ namespace crnlib
void* m_pProgress_data; void* m_pProgress_data;
uint m_progress_start; uint m_progress_start;
uint m_progress_range; uint m_progress_range;
uint m_comp_index; uint m_comp_index;
bool m_use_both_block_types; bool m_use_both_block_types;
}; };
class qdxt5 class qdxt5
{ {
CRNLIB_NO_COPY_OR_ASSIGNMENT_OP(qdxt5); CRNLIB_NO_COPY_OR_ASSIGNMENT_OP(qdxt5);
public: public:
qdxt5(task_pool& task_pool); qdxt5(task_pool& task_pool);
~qdxt5(); ~qdxt5();
void clear(); void clear();
bool init(uint n, const dxt_pixel_block* pBlocks, const qdxt5_params& params); bool init(uint n, const dxt_pixel_block* pBlocks, const qdxt5_params& params);
@@ -92,7 +90,7 @@ namespace crnlib
private: private:
task_pool* m_pTask_pool; task_pool* m_pTask_pool;
uint32 m_main_thread_id; crn_thread_id_t m_main_thread_id;
bool m_canceled; bool m_canceled;
uint m_progress_start; uint m_progress_start;
@@ -146,7 +144,7 @@ namespace crnlib
std::sort(m_cells.begin(), m_cells.end()); std::sort(m_cells.begin(), m_cells.end());
m_hash = fast_hash(&m_cells[0], sizeof(m_cells[0]) * m_cells.size()); m_hash = fast_hash(&m_cells[0], sizeof(m_cells[0]) * m_cells.size());
} }
bool operator< (const cluster_id& rhs) const bool operator< (const cluster_id& rhs) const
@@ -156,7 +154,7 @@ namespace crnlib
bool operator== (const cluster_id& rhs) const bool operator== (const cluster_id& rhs) const
{ {
if (m_hash != rhs.m_hash) if (m_hash != rhs.m_hash)
return false; return false;
return m_cells == rhs.m_cells; return m_cells == rhs.m_cells;
+14
View File
@@ -174,6 +174,13 @@ namespace crnlib
return m_kiss99.next() ^ (m_ranctx.next() + m_well512.next()); return m_kiss99.next() ^ (m_ranctx.next() + m_well512.next());
} }
uint64 random::urand64()
{
uint64 result = urand32();
result <<= 32ULL;
result |= urand32();
return result;
}
uint32 random::fast_urand32() uint32 random::fast_urand32()
{ {
return m_well512.next(); return m_well512.next();
@@ -317,6 +324,13 @@ namespace crnlib
return SHR3 ^ CONG; return SHR3 ^ CONG;
} }
uint64 fast_random::urand64()
{
uint64 result = urand32();
result <<= 32ULL;
result |= urand32();
return result;
}
int fast_random::irand(int l, int h) int fast_random::irand(int l, int h)
{ {
CRNLIB_ASSERT(l < h); CRNLIB_ASSERT(l < h);
+2
View File
@@ -63,6 +63,7 @@ namespace crnlib
void seed(uint32 i1, uint32 i2, uint32 i3); void seed(uint32 i1, uint32 i2, uint32 i3);
uint32 urand32(); uint32 urand32();
uint64 urand64();
// "Fast" variant uses no multiplies. // "Fast" variant uses no multiplies.
uint32 fast_urand32(); uint32 fast_urand32();
@@ -99,6 +100,7 @@ namespace crnlib
void seed(uint32 i); void seed(uint32 i);
uint32 urand32(); uint32 urand32();
uint64 urand64();
int irand(int l, int h); int irand(int l, int h);
-25
View File
@@ -1,25 +0,0 @@
// File: crn_semaphore.h
// See Copyright Notice and license at the end of inc/crnlib.h
#pragma once
namespace crnlib
{
class semaphore
{
CRNLIB_NO_COPY_OR_ASSIGNMENT_OP(semaphore);
public:
semaphore(int32 initialCount = 0, int32 maximumCount = 1, const char* pName = NULL);
~semaphore();
inline void *get_handle(void) const { return m_handle; }
void release(int32 releaseCount = 1, int32 *pPreviousCount = NULL);
bool wait(uint32 milliseconds = UINT32_MAX);
private:
void *m_handle;
};
} // namespace crnlib
-38
View File
@@ -1,38 +0,0 @@
// File: crn_spinlock.h
// See Copyright Notice and license at the end of inc/crnlib.h
#pragma once
namespace crnlib
{
// Simple non-recursive spinlock.
class spinlock
{
public:
inline spinlock() : m_flag(0) { }
void lock(uint32 max_spins = 4096, bool yielding = true, bool memoryBarrier = true);
inline void lock_no_barrier(uint32 max_spins = 4096, bool yielding = true) { lock(max_spins, yielding, false); }
void unlock();
inline void unlock_no_barrier() { m_flag = CRNLIB_FALSE; }
private:
volatile int32 m_flag;
};
class scoped_spinlock
{
scoped_spinlock(const scoped_spinlock&);
scoped_spinlock& operator= (const scoped_spinlock&);
public:
inline scoped_spinlock(spinlock& lock) : m_lock(lock) { m_lock.lock(); }
inline ~scoped_spinlock() { m_lock.unlock(); }
private:
spinlock& m_lock;
};
} // namespace crnlib
+43 -16
View File
@@ -193,17 +193,23 @@ typedef unsigned char stbi_uc;
// (you must include the appropriate extension in the filename). // (you must include the appropriate extension in the filename).
// returns TRUE on success, FALSE if couldn't open file, error writing file // returns TRUE on success, FALSE if couldn't open file, error writing file
extern int stbi_write_bmp (char const *filename, int x, int y, int comp, const void *data); extern int stbi_write_bmp (char const *filename, int x, int y, int comp, const void *data);
#ifdef _MSC_VER
extern int stbi_write_bmp_w (wchar_t const *filename, int x, int y, int comp, const void *data); extern int stbi_write_bmp_w (wchar_t const *filename, int x, int y, int comp, const void *data);
#endif
extern int stbi_write_tga (char const *filename, int x, int y, int comp, const void *data); extern int stbi_write_tga (char const *filename, int x, int y, int comp, const void *data);
#ifdef _MSC_VER
extern int stbi_write_tga_w (wchar_t const *filename, int x, int y, int comp, const void *data); extern int stbi_write_tga_w (wchar_t const *filename, int x, int y, int comp, const void *data);
#endif #endif
#endif
// PRIMARY API - works on images of any type // PRIMARY API - works on images of any type
// load image by filename, open file, or memory buffer // load image by filename, open file, or memory buffer
#ifndef STBI_NO_STDIO #ifndef STBI_NO_STDIO
extern stbi_uc *stbi_load (char const *filename, int *x, int *y, int *comp, int req_comp); extern stbi_uc *stbi_load (char const *filename, int *x, int *y, int *comp, int req_comp);
#ifdef _MSC_VER
extern stbi_uc *stbi_load_w (wchar_t const *filename, int *x, int *y, int *comp, int req_comp); extern stbi_uc *stbi_load_w (wchar_t const *filename, int *x, int *y, int *comp, int req_comp);
#endif
extern stbi_uc *stbi_load_from_file (FILE *f, int *x, int *y, int *comp, int req_comp); extern stbi_uc *stbi_load_from_file (FILE *f, int *x, int *y, int *comp, int req_comp);
extern int stbi_info_from_file (FILE *f, int *x, int *y, int *comp); extern int stbi_info_from_file (FILE *f, int *x, int *y, int *comp);
#endif #endif
@@ -227,7 +233,7 @@ extern void stbi_ldr_to_hdr_scale(float scale);
// get a VERY brief reason for failure // get a VERY brief reason for failure
// NOT THREADSAFE // NOT THREADSAFE
extern char *stbi_failure_reason (void); extern const char *stbi_failure_reason (void);
// free the loaded image -- this is just stb_free() // free the loaded image -- this is just stb_free()
extern void stbi_image_free (void *retval_from_stbi_load); extern void stbi_image_free (void *retval_from_stbi_load);
@@ -418,14 +424,14 @@ typedef unsigned char validate_uint32[sizeof(uint32)==4];
// //
// this is not threadsafe // this is not threadsafe
static char *failure_reason; static const char *failure_reason;
char *stbi_failure_reason(void) const char *stbi_failure_reason(void)
{ {
return failure_reason; return failure_reason;
} }
static int e(char *str) static int e(const char *str)
{ {
failure_reason = str; failure_reason = str;
return 0; return 0;
@@ -485,6 +491,7 @@ unsigned char *stbi_load(char const *filename, int *x, int *y, int *comp, int re
return result; return result;
} }
#ifdef _MSC_VER
unsigned char *stbi_load_w(wchar_t const *filename, int *x, int *y, int *comp, int req_comp) unsigned char *stbi_load_w(wchar_t const *filename, int *x, int *y, int *comp, int req_comp)
{ {
FILE *f = _wfopen(filename, L"rb"); FILE *f = _wfopen(filename, L"rb");
@@ -494,6 +501,7 @@ unsigned char *stbi_load_w(wchar_t const *filename, int *x, int *y, int *comp, i
fclose(f); fclose(f);
return result; return result;
} }
#endif
unsigned char *stbi_load_from_file(FILE *f, int *x, int *y, int *comp, int req_comp) unsigned char *stbi_load_from_file(FILE *f, int *x, int *y, int *comp, int req_comp)
{ {
@@ -748,7 +756,7 @@ static void getn(stbi *s, stbi_uc *buffer, int n)
{ {
#ifndef STBI_NO_STDIO #ifndef STBI_NO_STDIO
if (s->img_file) { if (s->img_file) {
fread(buffer, 1, n, s->img_file); size_t nr = fread(buffer, 1, n, s->img_file); nr;
return; return;
} }
#endif #endif
@@ -1615,11 +1623,13 @@ typedef uint8 *(*resample_row_func)(uint8 *out, uint8 *in0, uint8 *in1,
static uint8 *resample_row_1(uint8 *out, uint8 *in_near, uint8 *in_far, int w, int hs) static uint8 *resample_row_1(uint8 *out, uint8 *in_near, uint8 *in_far, int w, int hs)
{ {
out, in_far, w, hs;
return in_near; return in_near;
} }
static uint8* resample_row_v_2(uint8 *out, uint8 *in_near, uint8 *in_far, int w, int hs) static uint8* resample_row_v_2(uint8 *out, uint8 *in_near, uint8 *in_far, int w, int hs)
{ {
hs;
// need to generate two samples vertically for every one in input // need to generate two samples vertically for every one in input
int i; int i;
for (i=0; i < w; ++i) for (i=0; i < w; ++i)
@@ -1629,6 +1639,7 @@ static uint8* resample_row_v_2(uint8 *out, uint8 *in_near, uint8 *in_far, int w,
static uint8* resample_row_h_2(uint8 *out, uint8 *in_near, uint8 *in_far, int w, int hs) static uint8* resample_row_h_2(uint8 *out, uint8 *in_near, uint8 *in_far, int w, int hs)
{ {
hs, in_far;
// need to generate two samples horizontally for every one in input // need to generate two samples horizontally for every one in input
int i; int i;
uint8 *input = in_near; uint8 *input = in_near;
@@ -1654,6 +1665,7 @@ static uint8* resample_row_h_2(uint8 *out, uint8 *in_near, uint8 *in_far, int w
static uint8 *resample_row_hv_2(uint8 *out, uint8 *in_near, uint8 *in_far, int w, int hs) static uint8 *resample_row_hv_2(uint8 *out, uint8 *in_near, uint8 *in_far, int w, int hs)
{ {
hs;
// need to generate 2x2 samples for every one in input // need to generate 2x2 samples for every one in input
int i,t0,t1; int i,t0,t1;
if (w == 1) { if (w == 1) {
@@ -1675,6 +1687,7 @@ static uint8 *resample_row_hv_2(uint8 *out, uint8 *in_near, uint8 *in_far, int w
static uint8 *resample_row_generic(uint8 *out, uint8 *in_near, uint8 *in_far, int w, int hs) static uint8 *resample_row_generic(uint8 *out, uint8 *in_near, uint8 *in_far, int w, int hs)
{ {
in_far;
// resample with nearest-neighbor // resample with nearest-neighbor
int i,j; int i,j;
for (i=0; i < w; ++i) for (i=0; i < w; ++i)
@@ -2395,10 +2408,14 @@ static int create_png_image_raw(png *a, uint8 *raw, uint32 raw_len, int out_n, u
a->out = (uint8 *) stb_malloc(x * y * out_n); a->out = (uint8 *) stb_malloc(x * y * out_n);
if (!a->out) return e("outofmem", "Out of memory"); if (!a->out) return e("outofmem", "Out of memory");
if (!stbi_png_partial) { if (!stbi_png_partial) {
if (s->img_x == x && s->img_y == y) if ((s->img_x == x) && (s->img_y == y))
{
if (raw_len != (img_n * x + 1) * y) return e("not enough pixels","Corrupt PNG"); if (raw_len != (img_n * x + 1) * y) return e("not enough pixels","Corrupt PNG");
}
else // interlaced: else // interlaced:
{
if (raw_len < (img_n * x + 1) * y) return e("not enough pixels","Corrupt PNG"); if (raw_len < (img_n * x + 1) * y) return e("not enough pixels","Corrupt PNG");
}
} }
for (j=0; j < y; ++j) { for (j=0; j < y; ++j) {
uint8 *cur = a->out + stride*j; uint8 *cur = a->out + stride*j;
@@ -2528,6 +2545,7 @@ static int compute_transparency(png *z, uint8 tc[3], int out_n)
static int expand_palette(png *a, uint8 *palette, int len, int pal_img_n) static int expand_palette(png *a, uint8 *palette, int len, int pal_img_n)
{ {
len;
uint32 i, pixel_count = a->s.img_x * a->s.img_y; uint32 i, pixel_count = a->s.img_x * a->s.img_y;
uint8 *p, *temp_out, *orig = a->out; uint8 *p, *temp_out, *orig = a->out;
@@ -3164,7 +3182,7 @@ static stbi_uc *tga_load(stbi *s, int *x, int *y, int *comp, int req_comp)
unsigned char *tga_palette = NULL; unsigned char *tga_palette = NULL;
int i, j; int i, j;
unsigned char raw_data[4]; unsigned char raw_data[4];
unsigned char trans_data[4]; unsigned char trans_data[4] = { 0, 0, 0, 0 };
int RLE_count = 0; int RLE_count = 0;
int RLE_repeating = 0; int RLE_repeating = 0;
int read_next_pixel = 1; int read_next_pixel = 1;
@@ -3402,6 +3420,7 @@ int stbi_psd_test_file(FILE *f)
{ {
stbi s; stbi s;
int r,n = ftell(f); int r,n = ftell(f);
memset(&s, 0, sizeof(s));
start_file(&s, f); start_file(&s, f);
r = psd_test(&s); r = psd_test(&s);
fseek(f,n,SEEK_SET); fseek(f,n,SEEK_SET);
@@ -3608,7 +3627,7 @@ stbi_uc *stbi_psd_load_from_memory (stbi_uc const *buffer, int len, int *x, int
#ifndef STBI_NO_HDR #ifndef STBI_NO_HDR
static int hdr_test(stbi *s) static int hdr_test(stbi *s)
{ {
char *signature = "#?RADIANCE\n"; const char *signature = "#?RADIANCE\n";
int i; int i;
for (i=0; signature[i]; ++i) for (i=0; signature[i]; ++i)
if (get8(s) != signature[i]) if (get8(s) != signature[i])
@@ -3628,6 +3647,7 @@ int stbi_hdr_test_file(FILE *f)
{ {
stbi s; stbi s;
int r,n = ftell(f); int r,n = ftell(f);
memset(&s, 0, sizeof(s));
start_file(&s, f); start_file(&s, f);
r = hdr_test(&s); r = hdr_test(&s);
fseek(f,n,SEEK_SET); fseek(f,n,SEEK_SET);
@@ -3639,7 +3659,8 @@ int stbi_hdr_test_file(FILE *f)
static char *hdr_gettoken(stbi *z, char *buffer) static char *hdr_gettoken(stbi *z, char *buffer)
{ {
int len=0; int len=0;
char *s = buffer, c = '\0'; //char *s = buffer;
char c = '\0';
c = get8(z); c = get8(z);
@@ -3859,18 +3880,18 @@ static void write_pixels(FILE *f, int rgb_dir, int vdir, int x, int y, int comp,
fwrite(&d[comp-1], 1, 1, f); fwrite(&d[comp-1], 1, 1, f);
switch (comp) { switch (comp) {
case 1: case 1:
case 2: writef(f, "111", d[0],d[0],d[0]); case 2: writef(f, (char*)"111", d[0],d[0],d[0]);
break; break;
case 4: case 4:
if (!write_alpha) { if (!write_alpha) {
for (k=0; k < 3; ++k) for (k=0; k < 3; ++k)
px[k] = bg[k] + ((d[k] - bg[k]) * d[3])/255; px[k] = bg[k] + ((d[k] - bg[k]) * d[3])/255;
writef(f, "111", px[1-rgb_dir],px[1],px[1+rgb_dir]); writef(f, (char*)"111", px[1-rgb_dir],px[1],px[1+rgb_dir]);
break; break;
} }
/* FALLTHROUGH */ /* FALLTHROUGH */
case 3: case 3:
writef(f, "111", d[1-rgb_dir],d[1],d[1+rgb_dir]); writef(f, (char*)"111", d[1-rgb_dir],d[1],d[1+rgb_dir]);
break; break;
} }
if (write_alpha > 0) if (write_alpha > 0)
@@ -3894,6 +3915,7 @@ static int outfile(char const *filename, int rgb_dir, int vdir, int x, int y, in
return f != NULL; return f != NULL;
} }
#ifdef _MSC_VER
static int outfile_w(wchar_t const *filename, int rgb_dir, int vdir, int x, int y, int comp, const void *data, int alpha, int pad, char *fmt, ...) static int outfile_w(wchar_t const *filename, int rgb_dir, int vdir, int x, int y, int comp, const void *data, int alpha, int pad, char *fmt, ...)
{ {
FILE *f = _wfopen(filename, L"wb"); FILE *f = _wfopen(filename, L"wb");
@@ -3907,38 +3929,43 @@ static int outfile_w(wchar_t const *filename, int rgb_dir, int vdir, int x, int
} }
return f != NULL; return f != NULL;
} }
#endif
int stbi_write_bmp(char const *filename, int x, int y, int comp, const void *data) int stbi_write_bmp(char const *filename, int x, int y, int comp, const void *data)
{ {
int pad = (-x*3) & 3; int pad = (-x*3) & 3;
return outfile(filename,-1,-1,x,y,comp,data,0,pad, return outfile(filename,-1,-1,x,y,comp,data,0,pad,
"11 4 22 4" "4 44 22 444444", (char*)"11 4 22 4" "4 44 22 444444",
'B', 'M', 14+40+(x*3+pad)*y, 0,0, 14+40, // file header 'B', 'M', 14+40+(x*3+pad)*y, 0,0, 14+40, // file header
40, x,y, 1,24, 0,0,0,0,0,0); // bitmap header 40, x,y, 1,24, 0,0,0,0,0,0); // bitmap header
} }
#ifdef _MSC_VER
int stbi_write_bmp_w(wchar_t const *filename, int x, int y, int comp, const void *data) int stbi_write_bmp_w(wchar_t const *filename, int x, int y, int comp, const void *data)
{ {
int pad = (-x*3) & 3; int pad = (-x*3) & 3;
return outfile_w(filename,-1,-1,x,y,comp,data,0,pad, return outfile_w(filename,-1,-1,x,y,comp,data,0,pad,
"11 4 22 4" "4 44 22 444444", (char*)"11 4 22 4" "4 44 22 444444",
'B', 'M', 14+40+(x*3+pad)*y, 0,0, 14+40, // file header 'B', 'M', 14+40+(x*3+pad)*y, 0,0, 14+40, // file header
40, x,y, 1,24, 0,0,0,0,0,0); // bitmap header 40, x,y, 1,24, 0,0,0,0,0,0); // bitmap header
} }
#endif
int stbi_write_tga(char const *filename, int x, int y, int comp, const void *data) int stbi_write_tga(char const *filename, int x, int y, int comp, const void *data)
{ {
int has_alpha = !(comp & 1); int has_alpha = !(comp & 1);
return outfile(filename, -1,-1, x, y, comp, data, has_alpha, 0, return outfile(filename, -1,-1, x, y, comp, data, has_alpha, 0,
"111 221 2222 11", 0,0,2, 0,0,0, 0,0,x,y, 24+8*has_alpha, 8*has_alpha); (char*)"111 221 2222 11", 0,0,2, 0,0,0, 0,0,x,y, 24+8*has_alpha, 8*has_alpha);
} }
#ifdef _MSC_VER
int stbi_write_tga_w(wchar_t const *filename, int x, int y, int comp, const void *data) int stbi_write_tga_w(wchar_t const *filename, int x, int y, int comp, const void *data)
{ {
int has_alpha = !(comp & 1); int has_alpha = !(comp & 1);
return outfile_w(filename, -1,-1, x, y, comp, data, has_alpha, 0, return outfile_w(filename, -1,-1, x, y, comp, data, has_alpha, 0,
"111 221 2222 11", 0,0,2, 0,0,0, 0,0,x,y, 24+8*has_alpha, 8*has_alpha); (char*)"111 221 2222 11", 0,0,2, 0,0,0, 0,0,x,y, 24+8*has_alpha, 8*has_alpha);
} }
#endif
// any other image formats that do interleaved rgb data? // any other image formats that do interleaved rgb data?
// PNG: requires adler32,crc32 -- significant amount of code // PNG: requires adler32,crc32 -- significant amount of code
+64 -711
View File
@@ -2,10 +2,27 @@
// 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_strutils.h" #include "crn_strutils.h"
#include <direct.h>
namespace crnlib namespace crnlib
{ {
char* crn_strdup(const char* pStr)
{
if (!pStr)
pStr = "";
size_t l = strlen(pStr) + 1;
char *p = (char *)crnlib_malloc(l);
if (p)
memcpy(p, pStr, l);
return p;
}
int crn_stricmp(const char *p, const char *q)
{
return _stricmp(p, q);
}
char* strcpy_safe(char* pDst, uint dst_len, const char* pSrc) char* strcpy_safe(char* pDst, uint dst_len, const char* pSrc)
{ {
CRNLIB_ASSERT(pDst && pSrc && dst_len); CRNLIB_ASSERT(pDst && pSrc && dst_len);
@@ -164,76 +181,6 @@ namespace crnlib
return true; return true;
} }
bool string_to_int(const wchar_t*& pBuf, int& value)
{
value = 0;
CRNLIB_ASSERT(pBuf);
const wchar_t* p = pBuf;
while (*p && isspace(*p))
p++;
uint result = 0;
bool negative = false;
if (!iswdigit(*p))
{
if (p[0] == '-')
{
negative = true;
p++;
}
else
return false;
}
while (*p && iswdigit(*p))
{
if (result & 0xE0000000U)
return false;
const uint result8 = result << 3U;
const uint result2 = result << 1U;
if (result2 > (0xFFFFFFFFU - result8))
return false;
result = result8 + result2;
uint c = p[0] - L'0';
if (c > (0xFFFFFFFFU - result))
return false;
result += c;
p++;
}
if (negative)
{
if (result > 0x80000000U)
{
value = 0;
return false;
}
value = -static_cast<int>(result);
}
else
{
if (result > 0x7FFFFFFFU)
{
value = 0;
return false;
}
value = static_cast<int>(result);
}
pBuf = p;
return true;
}
bool string_to_int64(const char*& pBuf, int64& value) bool string_to_int64(const char*& pBuf, int64& value)
{ {
value = 0; value = 0;
@@ -348,50 +295,6 @@ namespace crnlib
return true; return true;
} }
bool string_to_uint(const wchar_t*& pBuf, uint& value)
{
value = 0;
CRNLIB_ASSERT(pBuf);
const wchar_t* p = pBuf;
while (*p && iswspace(*p))
p++;
uint result = 0;
if (!iswdigit(*p))
return false;
while (*p && iswdigit(*p))
{
if (result & 0xE0000000U)
return false;
const uint result8 = result << 3U;
const uint result2 = result << 1U;
if (result2 > (0xFFFFFFFFU - result8))
return false;
result = result8 + result2;
uint c = p[0] - L'0';
if (c > (0xFFFFFFFFU - result))
return false;
result += c;
p++;
}
value = result;
pBuf = p;
return true;
}
bool string_to_uint64(const char*& pBuf, uint64& value) bool string_to_uint64(const char*& pBuf, uint64& value)
{ {
value = 0; value = 0;
@@ -467,77 +370,66 @@ namespace crnlib
return false; return false;
} }
bool string_to_bool(const wchar_t* p, bool& value)
{
CRNLIB_ASSERT(p);
value = false;
if (_wcsicmp(p, L"false") == 0)
return true;
if (_wcsicmp(p, L"true") == 0)
{
value = true;
return true;
}
const wchar_t* q = p;
uint v;
if (string_to_uint(q, v))
{
if (!v)
return true;
else if (v == 1)
{
value = true;
return true;
}
}
return false;
}
bool string_to_float(const char*& p, float& value, uint round_digit) bool string_to_float(const char*& p, float& value, uint round_digit)
{
double d;
if (!string_to_double(p, d, round_digit))
{
value = 0;
return false;
}
value = static_cast<float>(d);
return true;
}
bool string_to_double(const char*& p, double& value, uint round_digit)
{
return string_to_double(p, p + 128, value, round_digit);
}
// I wrote this approx. 20 years ago in C/assembly using a limited FP emulator package, so it's a bit crude.
bool string_to_double(const char*& p, const char *pEnd, double& value, uint round_digit)
{ {
CRNLIB_ASSERT(p); CRNLIB_ASSERT(p);
value = 0; value = 0;
enum { AF_BLANK = 1, AF_SIGN = 2, AF_DPOINT = 3, AF_BADCHAR = 4, AF_OVRFLOW = 5, AF_EXPONENT = 6, AF_NODIGITS = 7 }; enum { AF_BLANK = 1, AF_SIGN = 2, AF_DPOINT = 3, AF_BADCHAR = 4, AF_OVRFLOW = 5, AF_EXPONENT = 6, AF_NODIGITS = 7 };
int status = 0;
const char* buf = p; const char* buf = p;
int status = 0; int got_sign_flag = 0, got_dp_flag = 0, got_num_flag = 0;
int got_e_flag = 0, got_e_sign_flag = 0, e_sign = 0;
uint whole_count = 0, frac_count = 0;
if (round_digit > 10) double whole = 0, frac = 0, scale = 1, exponent = 1;
round_digit = 10;
int got_sign_flag = 0; if (p >= pEnd)
int got_dp_flag = 0; {
int got_num_flag = 0; status = AF_NODIGITS;
goto af_exit;
int got_e_flag = 0; }
int got_e_sign_flag = 0;
int e_sign = 0;
uint whole_count = 0;
uint frac_count = 0;
float whole = 0;
float frac = 0;
float scale = 1;
float exponent = 1;
while (*buf) while (*buf)
{ {
if (!isspace(*buf)) if (!isspace(*buf))
break; break;
if (++buf >= pEnd)
buf++; {
status = AF_NODIGITS;
goto af_exit;
}
} }
p = buf;
while (*buf) while (*buf)
{ {
p = buf;
if (buf >= pEnd)
break;
int i = *buf++; int i = *buf++;
switch (i) switch (i)
@@ -616,7 +508,7 @@ namespace crnlib
whole_count++; whole_count++;
if (whole > 1e+30f) if (whole > 1e+100)
{ {
status = AF_OVRFLOW; status = AF_OVRFLOW;
goto af_exit; goto af_exit;
@@ -646,6 +538,10 @@ namespace crnlib
while (*buf) while (*buf)
{ {
p = buf;
if (buf >= pEnd)
break;
int i = *buf++; int i = *buf++;
if (i == '+') if (i == '+')
@@ -674,7 +570,7 @@ namespace crnlib
{ {
got_num_flag = 1; got_num_flag = 1;
if ((e = (e * 10) + (i - 48)) > 16) if ((e = (e * 10) + (i - 48)) > 100)
{ {
status = AF_EXPONENT; status = AF_EXPONENT;
goto af_exit; goto af_exit;
@@ -709,552 +605,9 @@ namespace crnlib
whole = -whole; whole = -whole;
value = whole; value = whole;
p = buf;
af_exit: af_exit:
return (status == 0); return (status == 0);
} }
bool string_to_float(const wchar_t*& p, float& value, uint round_digit)
{
CRNLIB_ASSERT(p);
value = 0;
enum { AF_BLANK = 1, AF_SIGN = 2, AF_DPOINT = 3, AF_BADCHAR = 4, AF_OVRFLOW = 5, AF_EXPONENT = 6, AF_NODIGITS = 7 };
const wchar_t* buf = p;
int status = 0;
if (round_digit > 10)
round_digit = 10;
int got_sign_flag = 0;
int got_dp_flag = 0;
int got_num_flag = 0;
int got_e_flag = 0;
int got_e_sign_flag = 0;
int e_sign = 0;
uint whole_count = 0;
uint frac_count = 0;
float whole = 0;
float frac = 0;
float scale = 1;
float exponent = 1;
while (*buf)
{
if (!iswspace(*buf))
break;
buf++;
}
while (*buf)
{
int i = *buf++;
switch (i)
{
case L'e':
case L'E':
{
got_e_flag = 1;
goto exit_while;
}
case L'+':
{
if ((got_num_flag) || (got_sign_flag))
{
status = AF_SIGN;
goto af_exit;
}
got_sign_flag = 1;
break;
}
case L'-':
{
if ((got_num_flag) || (got_sign_flag))
{
status = AF_SIGN;
goto af_exit;
}
got_sign_flag = -1;
break;
}
case L'.':
{
if (got_dp_flag)
{
status = AF_DPOINT;
goto af_exit;
}
got_dp_flag = 1;
break;
}
default:
{
if ((i < L'0') || (i > L'9'))
goto exit_while;
else
{
i -= L'0';
got_num_flag = 1;
if (got_dp_flag)
{
if (frac_count < round_digit)
{
frac = frac * 10.0f + i;
scale = scale * 10.0f;
}
else if (frac_count == round_digit)
{
if (i >= 5) /* check for round */
frac = frac + 1.0f;
}
frac_count++;
}
else
{
whole = whole * 10.0f + i;
whole_count++;
if (whole > 1e+30f)
{
status = AF_OVRFLOW;
goto af_exit;
}
}
}
break;
}
}
}
exit_while:
if (got_e_flag)
{
if ((got_num_flag == 0) && (got_dp_flag))
{
status = AF_EXPONENT;
goto af_exit;
}
int e = 0;
e_sign = 1;
got_num_flag = 0;
got_e_sign_flag = 0;
while (*buf)
{
int i = *buf++;
if (i == L'+')
{
if ((got_num_flag) || (got_e_sign_flag))
{
status = AF_EXPONENT;
goto af_exit;
}
e_sign = 1;
got_e_sign_flag = 1;
}
else if (i == L'-')
{
if ((got_num_flag) || (got_e_sign_flag))
{
status = AF_EXPONENT;
goto af_exit;
}
e_sign = -1;
got_e_sign_flag = 1;
}
else if ((i >= L'0') && (i <= L'9'))
{
got_num_flag = 1;
if ((e = (e * 10) + (i - 48)) > 16)
{
status = AF_EXPONENT;
goto af_exit;
}
}
else
break;
}
for (int i = 1; i <= e; i++) /* compute 10^e */
exponent = exponent * 10.0f;
}
if (((whole_count + frac_count) == 0) && (got_e_flag == 0))
{
status = AF_NODIGITS;
goto af_exit;
}
if (frac)
whole = whole + (frac / scale);
if (got_e_flag)
{
if (e_sign > 0)
whole = whole * exponent;
else
whole = whole / exponent;
}
if (got_sign_flag < 0)
whole = -whole;
value = whole;
p = buf;
af_exit:
return (status == 0);
}
bool split_path(const char* p, dynamic_string* pDrive, dynamic_string* pDir, dynamic_string* pFilename, dynamic_string* pExt)
{
CRNLIB_ASSERT(p);
char drive_buf[_MAX_DRIVE];
char dir_buf[_MAX_DIR];
char fname_buf[_MAX_FNAME];
char ext_buf[_MAX_EXT];
#ifdef _MSC_VER
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
_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;
return true;
}
bool split_path(const wchar_t* p, dynamic_wstring* pDrive, dynamic_wstring* pDir, dynamic_wstring* pFilename, dynamic_wstring* pExt)
{
CRNLIB_ASSERT(p);
wchar_t drive_buf[_MAX_DRIVE];
wchar_t dir_buf[_MAX_DIR];
wchar_t fname_buf[_MAX_FNAME];
wchar_t ext_buf[_MAX_EXT];
#ifdef _MSC_VER
errno_t error = _wsplitpath_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
_wsplitpath(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;
return true;
}
bool 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 split_path(const wchar_t* p, dynamic_wstring& path, dynamic_wstring& filename)
{
dynamic_wstring 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 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 get_pathname(const wchar_t* p, dynamic_wstring& path)
{
dynamic_wstring 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 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;
}
bool get_filename(const wchar_t* p, dynamic_wstring& filename)
{
dynamic_wstring temp_ext;
if (!split_path(p, NULL, NULL, &filename, &temp_ext))
return false;
filename += temp_ext;
return true;
}
void combine_path(dynamic_string& dst, const char* pA, const char* pB)
{
dynamic_string temp;
temp = pA;
if ((!temp.is_empty()) && (pB[0] != '\\') && (pB[0] != '/'))
{
char c = temp[temp.get_len() - 1];
if ((c != '\\') && (c != '/'))
{
temp.append_char('\\');
}
}
temp += pB;
dst.swap(temp);
}
void combine_path(dynamic_wstring& dst, const wchar_t* pA, const wchar_t* pB)
{
dynamic_wstring temp;
temp = pA;
if ((!temp.is_empty()) && (pB[0] != L'\\') && (pB[0] != L'/'))
{
wchar_t c = temp[temp.get_len() - 1];
if ((c != L'\\') && (c != L'/'))
{
temp.append_char(L'\\');
}
}
temp += pB;
dst.swap(temp);
}
void combine_path(dynamic_string& dst, const char* pA, const char* pB, const char* pC)
{
combine_path(dst, pA, pB);
combine_path(dst, dst.get_ptr(), pC);
}
void combine_path(dynamic_wstring& dst, const wchar_t* pA, const wchar_t* pB, const wchar_t* pC)
{
combine_path(dst, pA, pB);
combine_path(dst, dst.get_ptr(), pC);
}
void combine_path(dynamic_wstring& dst, const wchar_t* pA, const wchar_t* pB, const wchar_t* pC, const wchar_t *pD)
{
combine_path(dst, pA, pB);
combine_path(dst, dst.get_ptr(), pC);
combine_path(dst, dst.get_ptr(), pD);
}
bool full_path(dynamic_string& path)
{
#ifndef _XBOX
char buf[CRNLIB_MAX_PATH];
char* p = _fullpath(buf, path.get_ptr(), CRNLIB_MAX_PATH);
if (!p)
return false;
path.set(buf);
#endif
return true;
}
bool full_path(dynamic_wstring& path)
{
#ifndef _XBOX
wchar_t buf[CRNLIB_MAX_PATH];
wchar_t* p = _wfullpath(buf, path.get_ptr(), CRNLIB_MAX_PATH);
if (!p)
return false;
path.set(buf);
#endif
return true;
}
bool get_extension(dynamic_string& filename)
{
int sep = filename.find_right('\\');
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 get_extension(dynamic_wstring& filename)
{
int sep = filename.find_right(L'\\');
if (sep < 0)
sep = filename.find_right(L'/');
int dot = filename.find_right(L'.');
if (dot < sep)
{
filename.clear();
return false;
}
filename.right(dot + 1);
return true;
}
bool remove_extension(dynamic_string& filename)
{
int sep = filename.find_right('\\');
if (sep < 0)
sep = filename.find_right('/');
int dot = filename.find_right('.');
if (dot < sep)
return false;
filename.left(dot);
return true;
}
bool remove_extension(dynamic_wstring& filename)
{
int sep = filename.find_right(L'\\');
if (sep < 0)
sep = filename.find_right(L'/');
int dot = filename.find_right(L'.');
if (dot < sep)
return false;
filename.left(dot);
return true;
}
bool create_path(const dynamic_wstring& path)
{
bool unc = false;
dynamic_wstring cur_path;
const int l = path.get_len();
int n = 0;
while (n < l)
{
const wchar_t c = path.get_ptr()[n];
const bool sep = (c == L'/') || (c == L'\\');
if ((sep) || (n == (l - 1)))
{
if ((n == (l - 1)) && (!sep))
cur_path.append_char(c);
bool valid = false;
if ((cur_path.get_len() > 3) && (cur_path.get_ptr()[1] == L':'))
valid = true;
else if (cur_path.get_len() > 2)
{
if (unc)
valid = true;
unc = true;
}
if (valid)
_wmkdir(cur_path.get_ptr());
}
cur_path.append_char(c);
n++;
}
return true;
}
void trim_trailing_seperator(dynamic_wstring& path)
{
if ( (path.get_len()) && ( (path[path.get_len() - 1] == L'\\') || (path[path.get_len() - 1] == L'/') ) )
path.truncate(path.get_len() - 1);
}
} // namespace crnlib } // namespace crnlib
+19 -43
View File
@@ -2,58 +2,34 @@
// 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 WIN32
#define CRNLIB_PATH_SEPERATOR_CHAR '\\'
#else
#define CRNLIB_PATH_SEPERATOR_CHAR '/'
#endif
namespace crnlib namespace crnlib
{ {
char* crn_strdup(const char* pStr);
int crn_stricmp(const char *p, const char *q);
char* strcpy_safe(char* pDst, uint dst_len, const char* pSrc); char* strcpy_safe(char* pDst, uint dst_len, const char* pSrc);
bool int_to_string(int value, char* pDst, uint len); bool int_to_string(int value, char* pDst, uint len);
bool uint_to_string(uint value, char* pDst, uint len); bool uint_to_string(uint value, char* pDst, uint len);
bool string_to_int(const char*& pBuf, int& value); bool string_to_int(const char*& pBuf, int& value);
bool string_to_int(const wchar_t*& pBuf, int& value);
bool string_to_uint(const char*& pBuf, uint& value); bool string_to_uint(const char*& pBuf, uint& value);
bool string_to_uint(const wchar_t*& pBuf, uint& value);
bool string_to_int64(const char*& pBuf, int64& value); bool string_to_int64(const char*& pBuf, int64& value);
bool string_to_uint64(const char*& pBuf, uint64& value); bool string_to_uint64(const char*& pBuf, uint64& value);
bool string_to_bool(const char* p, bool& value); bool string_to_bool(const char* p, bool& value);
bool string_to_bool(const wchar_t* p, bool& value);
bool string_to_float(const char*& p, float& value, uint round_digit = 512U);
bool string_to_float(const char*& p, float& value, uint round_digit = 10U);
bool string_to_float(const wchar_t*& p, float& value, uint round_digit = 10U); bool string_to_double(const char*& p, double& value, uint round_digit = 512U);
bool string_to_double(const char*& p, const char *pEnd, double& value, uint round_digit = 512U);
bool split_path(const char* p, dynamic_string* pDrive, dynamic_string* pDir, dynamic_string* pFilename, dynamic_string* pExt);
bool split_path(const wchar_t* p, dynamic_wstring* pDrive, dynamic_wstring* pDir, dynamic_wstring* pFilename, dynamic_wstring* pExt);
bool split_path(const char* p, dynamic_string& path, dynamic_string& filename);
bool split_path(const wchar_t* p, dynamic_wstring& path, dynamic_wstring& filename);
bool get_pathname(const char* p, dynamic_string& path);
bool get_pathname(const wchar_t* p, dynamic_wstring& path);
bool get_filename(const char* p, dynamic_string& filename);
bool get_filename(const wchar_t* p, dynamic_wstring& filename);
void combine_path(dynamic_string& dst, const char* pA, const char* pB);
void combine_path(dynamic_wstring& dst, const wchar_t* pA, const wchar_t* pB);
void combine_path(dynamic_string& dst, const char* pA, const char* pB, const char* pC);
void combine_path(dynamic_wstring& dst, const wchar_t* pA, const wchar_t* pB, const wchar_t* pC);
void combine_path(dynamic_wstring& dst, const wchar_t* pA, const wchar_t* pB, const wchar_t* pC, const wchar_t *pD);
bool full_path(dynamic_string& path);
bool full_path(dynamic_wstring& path);
bool get_extension(dynamic_string& filename);
bool get_extension(dynamic_wstring& filename);
bool remove_extension(dynamic_string& filename);
bool remove_extension(dynamic_wstring& filename);
bool create_path(const dynamic_wstring& path);
void trim_trailing_seperator(dynamic_wstring& path);
} // namespace crnlib } // namespace crnlib
+8 -8
View File
@@ -361,7 +361,7 @@ namespace crnlib
if (!max_freq) if (!max_freq)
return false; return false;
if (max_freq <= UINT16_MAX) if (max_freq <= cUINT16_MAX)
{ {
for (uint i = 0; i < total_syms; i++) for (uint i = 0; i < total_syms; i++)
sym_freq16[i] = static_cast<uint16>(pSym_freq[i]); sym_freq16[i] = static_cast<uint16>(pSym_freq[i]);
@@ -381,7 +381,7 @@ namespace crnlib
if (fl < 1) if (fl < 1)
fl = 1; fl = 1;
CRNLIB_ASSERT(fl <= UINT16_MAX); CRNLIB_ASSERT(fl <= cUINT16_MAX);
sym_freq16[i] = static_cast<uint16>(fl); sym_freq16[i] = static_cast<uint16>(fl);
} }
@@ -917,7 +917,7 @@ namespace crnlib
freq++; freq++;
model.m_sym_freq[sym] = static_cast<uint16>(freq); model.m_sym_freq[sym] = static_cast<uint16>(freq);
if (freq == UINT16_MAX) if (freq == cUINT16_MAX)
model.rescale(); model.rescale();
if (--model.m_symbols_until_update == 0) if (--model.m_symbols_until_update == 0)
@@ -1426,8 +1426,8 @@ namespace crnlib
{ {
uint32 t = pTables->m_lookup[m_bit_buf >> (cBitBufSize - pTables->m_table_bits)]; uint32 t = pTables->m_lookup[m_bit_buf >> (cBitBufSize - pTables->m_table_bits)];
CRNLIB_ASSERT(t != UINT32_MAX); CRNLIB_ASSERT(t != cUINT32_MAX);
sym = t & UINT16_MAX; sym = t & cUINT16_MAX;
len = t >> 16; len = t >> 16;
CRNLIB_ASSERT(model.m_code_sizes[sym] == len); CRNLIB_ASSERT(model.m_code_sizes[sym] == len);
@@ -1462,7 +1462,7 @@ namespace crnlib
freq++; freq++;
model.m_sym_freq[sym] = static_cast<uint16>(freq); model.m_sym_freq[sym] = static_cast<uint16>(freq);
if (freq == UINT16_MAX) if (freq == cUINT16_MAX)
model.rescale(); model.rescale();
if (--model.m_symbols_until_update == 0) if (--model.m_symbols_until_update == 0)
@@ -1614,8 +1614,8 @@ namespace crnlib
{ {
uint32 t = pTables->m_lookup[m_bit_buf >> (cBitBufSize - pTables->m_table_bits)]; uint32 t = pTables->m_lookup[m_bit_buf >> (cBitBufSize - pTables->m_table_bits)];
CRNLIB_ASSERT(t != UINT32_MAX); CRNLIB_ASSERT(t != cUINT32_MAX);
sym = t & UINT16_MAX; sym = t & cUINT16_MAX;
len = t >> 16; len = t >> 16;
CRNLIB_ASSERT(model.m_code_sizes[sym] == len); CRNLIB_ASSERT(model.m_code_sizes[sym] == len);
-243
View File
@@ -1,243 +0,0 @@
// File: crn_task_pool.cpp
// See Copyright Notice and license at the end of inc/crnlib.h
#include "crn_core.h"
#include "crn_task_pool.h"
#include <process.h>
#include "crn_winhdr.h"
namespace crnlib
{
task_pool::task_pool() :
m_num_threads(0),
m_num_outstanding_tasks(0),
m_exit_flag(false)
{
utils::zero_object(m_threads);
}
task_pool::task_pool(uint num_threads) :
m_num_threads(0),
m_num_outstanding_tasks(0),
m_exit_flag(false)
{
utils::zero_object(m_threads);
bool status = init(num_threads);
CRNLIB_VERIFY(status);
}
task_pool::~task_pool()
{
deinit();
}
bool task_pool::init(uint num_threads)
{
CRNLIB_ASSERT(num_threads <= cMaxThreads);
num_threads = math::minimum<uint>(num_threads, cMaxThreads);
deinit();
m_task_condition_var.lock();
m_num_threads = num_threads;
bool succeeded = true;
for (uint i = 0; i < num_threads; i++)
{
m_threads[i] = (HANDLE)_beginthreadex(NULL, 32768, thread_func, this, 0, NULL);
CRNLIB_ASSERT(m_threads[i] != 0);
if (!m_threads[i])
{
succeeded = false;
break;
}
}
m_task_condition_var.unlock();
if (!succeeded)
{
deinit();
return false;
}
return true;
}
void task_pool::deinit()
{
if (m_num_threads)
{
m_task_condition_var.lock();
m_exit_flag = true;
m_task_condition_var.unlock();
for (uint i = 0; i < m_num_threads; i++)
{
if (m_threads[i])
{
for ( ; ; )
{
uint32 result = WaitForSingleObject(m_threads[i], 1000);
if (result == WAIT_OBJECT_0)
break;
}
CloseHandle(m_threads[i]);
m_threads[i] = NULL;
}
}
m_num_threads = 0;
m_exit_flag = false;
}
m_tasks.clear();
m_num_outstanding_tasks = 0;
}
uint task_pool::get_num_threads() const
{
return m_num_threads;
}
void task_pool::queue_task(task_callback_func pFunc, uint64 data, void* pData_ptr)
{
CRNLIB_ASSERT(pFunc);
m_task_condition_var.lock();
task tsk;
tsk.m_callback = pFunc;
tsk.m_data = data;
tsk.m_pData_ptr = pData_ptr;
tsk.m_flags = 0;
m_tasks.push_back(tsk);
m_num_outstanding_tasks++;
m_task_condition_var.unlock();
}
// It's the object's responsibility to crnlib_delete pObj within the execute_task() method, if needed!
void task_pool::queue_task(executable_task* pObj, uint64 data, void* pData_ptr)
{
CRNLIB_ASSERT(pObj);
m_task_condition_var.lock();
task tsk;
tsk.m_pObj = pObj;
tsk.m_data = data;
tsk.m_pData_ptr = pData_ptr;
tsk.m_flags = cTaskFlagObject;
m_tasks.push_back(tsk);
m_num_outstanding_tasks++;
m_task_condition_var.unlock();
}
bool task_pool::join_condition_func(void* pCallback_data_ptr, uint64 callback_data)
{
callback_data;
task_pool* pPool = static_cast<task_pool*>(pCallback_data_ptr);
return (!pPool->m_num_outstanding_tasks) || pPool->m_exit_flag;
}
void task_pool::process_task(task& tsk)
{
if (tsk.m_flags & cTaskFlagObject)
tsk.m_pObj->execute_task(tsk.m_data, tsk.m_pData_ptr);
else
tsk.m_callback(tsk.m_data, tsk.m_pData_ptr);
m_task_condition_var.lock();
m_num_outstanding_tasks--;
m_task_condition_var.unlock();
}
void task_pool::join()
{
for ( ; ; )
{
m_task_condition_var.lock();
if (!m_tasks.empty())
{
task tsk(m_tasks.front());
m_tasks.pop_front();
m_task_condition_var.unlock();
process_task(tsk);
}
else
{
int result = m_task_condition_var.wait(join_condition_func, this);
result;
CRNLIB_ASSERT(result >= 0);
m_task_condition_var.unlock();
break;
}
}
}
bool task_pool::wait_condition_func(void* pCallback_data_ptr, uint64 callback_data)
{
callback_data;
task_pool* pPool = static_cast<task_pool*>(pCallback_data_ptr);
return (!pPool->m_tasks.empty()) || pPool->m_exit_flag;
}
unsigned __stdcall task_pool::thread_func(void* pContext)
{
//set_thread_name(GetCurrentThreadId(), "taskpoolhelper");
task_pool* pPool = static_cast<task_pool*>(pContext);
for ( ; ; )
{
pPool->m_task_condition_var.lock();
int result = pPool->m_task_condition_var.wait(wait_condition_func, pPool);
CRNLIB_ASSERT(result >= 0);
if ((result < 0) || (pPool->m_exit_flag))
{
pPool->m_task_condition_var.unlock();
break;
}
if (pPool->m_tasks.empty())
pPool->m_task_condition_var.unlock();
else
{
task tsk(pPool->m_tasks.front());
pPool->m_tasks.pop_front();
pPool->m_task_condition_var.unlock();
pPool->process_task(tsk);
}
}
_endthreadex(0);
return 0;
}
} // namespace crnlib
-140
View File
@@ -1,140 +0,0 @@
// File: crn_task_pool.h
// See Copyright Notice and license at the end of inc/crnlib.h
#pragma once
#include "crn_condition_var.h"
#include <deque>
namespace crnlib
{
class task_pool
{
public:
task_pool();
task_pool(uint num_threads);
~task_pool();
enum { cMaxThreads = 16 };
bool init(uint num_threads);
void deinit();
uint get_num_threads() const;
// C-style task callback
typedef void (*task_callback_func)(uint64 data, void* pData_ptr);
void queue_task(task_callback_func pFunc, uint64 data = 0, void* pData_ptr = NULL);
class executable_task
{
public:
virtual void execute_task(uint64 data, void* pData_ptr) = 0;
};
// It's the caller's responsibility to crnlib_delete pObj within the execute_task() method, if needed!
void queue_task(executable_task* pObj, uint64 data = 0, void* pData_ptr = NULL);
template<typename S, typename T>
inline void queue_object_task(S* pObject, T pObject_method, uint64 data = 0, void* pData_ptr = NULL);
void join();
private:
uint m_num_threads;
uint m_num_outstanding_tasks;
void* m_threads[cMaxThreads];
bool m_exit_flag;
condition_var m_task_condition_var;
enum task_flags
{
cTaskFlagObject = 1
};
struct task
{
uint64 m_data;
void* m_pData_ptr;
union
{
task_callback_func m_callback;
executable_task* m_pObj;
};
uint m_flags;
};
std::deque<task> m_tasks;
void process_task(task& tsk);
static bool join_condition_func(void* pCallback_data_ptr, uint64 callback_data);
static bool wait_condition_func(void* pCallback_data_ptr, uint64 callback_data);
static unsigned __stdcall thread_func(void* pContext);
};
enum object_task_flags
{
cObjectTaskFlagDefault = 0,
cObjectTaskFlagDeleteAfterExecution = 1
};
template<typename T>
class object_task : public task_pool::executable_task
{
public:
object_task(uint flags = cObjectTaskFlagDefault) :
m_pObject(NULL),
m_pMethod(NULL),
m_flags(flags)
{
}
typedef void (T::*object_method_ptr)(uint64 data, void* pData_ptr);
object_task(T* pObject, object_method_ptr pMethod, uint flags = cObjectTaskFlagDefault) :
m_pObject(pObject),
m_pMethod(pMethod),
m_flags(flags)
{
CRNLIB_ASSERT(pObject && pMethod);
}
void init(T* pObject, object_method_ptr pMethod, uint flags = cObjectTaskFlagDefault)
{
CRNLIB_ASSERT(pObject && pMethod);
m_pObject = pObject;
m_pMethod = pMethod;
m_flags = flags;
}
T* get_object() const { return m_pObject; }
object_method_ptr get_method() const { return m_pMethod; }
virtual void execute_task(uint64 data, void* pData_ptr)
{
(m_pObject->*m_pMethod)(data, pData_ptr);
if (m_flags & cObjectTaskFlagDeleteAfterExecution)
crnlib_delete(this);
}
protected:
T* m_pObject;
object_method_ptr m_pMethod;
uint m_flags;
};
template<typename S, typename T>
inline void task_pool::queue_object_task(S* pObject, T pObject_method, uint64 data, void* pData_ptr)
{
queue_task(crnlib_new< object_task<S> >(pObject, pObject_method, cObjectTaskFlagDeleteAfterExecution), data, pData_ptr);
}
} // namespace crnlib
+30 -18
View File
@@ -26,7 +26,7 @@ namespace crnlib
{ {
if (local_params.get_flag(cCRNCompFlagPerceptual)) if (local_params.get_flag(cCRNCompFlagPerceptual))
{ {
//console::warning(L"Output pixel format is swizzled or not RGB, disabling perceptual color metrics"); console::info("Output pixel format is swizzled or not RGB, disabling perceptual color metrics");
// Destination compressed pixel format is swizzled or not RGB at all, so be sure perceptual colorspace metrics are disabled. // Destination compressed pixel format is swizzled or not RGB at all, so be sure perceptual colorspace metrics are disabled.
local_params.set_flag(cCRNCompFlagPerceptual, false); local_params.set_flag(cCRNCompFlagPerceptual, false);
@@ -53,6 +53,18 @@ namespace crnlib
((local_params.m_file_type == cCRNFileTypeCRN) && ((local_params.m_flags & cCRNCompFlagManualPaletteSizes) != 0)) ((local_params.m_file_type == cCRNFileTypeCRN) && ((local_params.m_flags & cCRNCompFlagManualPaletteSizes) != 0))
) )
{ {
if ( (local_params.m_file_type == cCRNFileTypeCRN) ||
((local_params.m_file_type == cCRNFileTypeDDS) && (local_params.m_quality_level < cCRNMaxQualityLevel)) )
{
console::info("Compressing using quality level %i", local_params.m_quality_level);
}
if (local_params.m_format == cCRNFmtDXT3)
{
if (local_params.m_file_type == cCRNFileTypeCRN)
console::warning("CRN format doesn't support DXT3");
else if ((local_params.m_file_type == cCRNFileTypeDDS) && (local_params.m_quality_level < cCRNMaxQualityLevel))
console::warning("Clustered DDS compressor doesn't support DXT3");
}
if (!pTexture_comp->compress_pass(local_params, pActual_bitrate)) if (!pTexture_comp->compress_pass(local_params, pActual_bitrate))
{ {
crnlib_delete(pTexture_comp); crnlib_delete(pTexture_comp);
@@ -95,7 +107,7 @@ namespace crnlib
{ {
if (params.m_flags & cCRNCompFlagDebugging) if (params.m_flags & cCRNCompFlagDebugging)
{ {
console::debug(L"Quality level bracket: [%u, %u]", low_quality, high_quality); console::debug("Quality level bracket: [%u, %u]", low_quality, high_quality);
} }
int trial_quality = (low_quality + high_quality) / 2; int trial_quality = (low_quality + high_quality) / 2;
@@ -137,7 +149,7 @@ namespace crnlib
} }
} }
console::info(L"Compressing to quality level %u", trial_quality); console::info("Compressing to quality level %u", trial_quality);
float bitrate = 0.0f; float bitrate = 0.0f;
@@ -153,7 +165,7 @@ namespace crnlib
highest_bitrate = math::maximum(highest_bitrate, bitrate); highest_bitrate = math::maximum(highest_bitrate, bitrate);
console::info(L"\nTried quality level %u, bpp: %3.3f", trial_quality, bitrate); console::info("\nTried quality level %u, bpp: %3.3f", trial_quality, bitrate);
if ( (best_quality_level < 0) || if ( (best_quality_level < 0) ||
((bitrate <= local_params.m_target_bitrate) && (best_bitrate > local_params.m_target_bitrate)) || ((bitrate <= local_params.m_target_bitrate) && (best_bitrate > local_params.m_target_bitrate)) ||
@@ -165,7 +177,7 @@ namespace crnlib
best_quality_level = trial_quality; best_quality_level = trial_quality;
if (params.m_flags & cCRNCompFlagDebugging) if (params.m_flags & cCRNCompFlagDebugging)
{ {
console::debug(L"Choose new best quality level"); console::debug("Choose new best quality level");
} }
if ((best_bitrate <= local_params.m_target_bitrate) && (fabs(best_bitrate - local_params.m_target_bitrate) < .005f)) if ((best_bitrate <= local_params.m_target_bitrate) && (fabs(best_bitrate - local_params.m_target_bitrate) < .005f))
@@ -188,7 +200,7 @@ namespace crnlib
(highest_bitrate < local_params.m_target_bitrate) && (highest_bitrate < local_params.m_target_bitrate) &&
(fabs(best_bitrate - local_params.m_target_bitrate) >= .005f)) (fabs(best_bitrate - local_params.m_target_bitrate) >= .005f))
{ {
console::info(L"Unable to achieve desired bitrate - disabling adaptive block sizes and retrying search."); console::info("Unable to achieve desired bitrate - disabling adaptive block sizes and retrying search.");
local_params.m_flags &= ~cCRNCompFlagHierarchical; local_params.m_flags &= ~cCRNCompFlagHierarchical;
@@ -214,7 +226,7 @@ namespace crnlib
if (pActual_quality_level) *pActual_quality_level = best_quality_level; if (pActual_quality_level) *pActual_quality_level = best_quality_level;
if (pActual_bitrate) *pActual_bitrate = best_bitrate; if (pActual_bitrate) *pActual_bitrate = best_bitrate;
console::printf(L"Selected quality level %u bpp: %f", best_quality_level, best_bitrate); console::printf("Selected quality level %u bpp: %f", best_quality_level, best_bitrate);
return true; return true;
} }
@@ -310,14 +322,14 @@ namespace crnlib
{ {
if (work_tex.get_num_faces() > 1) if (work_tex.get_num_faces() > 1)
{ {
console::warning(L"Can't crop cubemap textures"); console::warning("Can't crop cubemap textures");
} }
else else
{ {
console::info(L"Cropping input texture from window (%ux%u)-(%ux%u)", window_rect.get_left(), window_rect.get_top(), window_rect.get_right(), window_rect.get_bottom()); console::info("Cropping input texture from window (%ux%u)-(%ux%u)", window_rect.get_left(), window_rect.get_top(), window_rect.get_right(), window_rect.get_bottom());
if (!work_tex.crop(window_rect.get_left(), window_rect.get_top(), window_rect.get_width(), window_rect.get_height())) if (!work_tex.crop(window_rect.get_left(), window_rect.get_top(), window_rect.get_width(), window_rect.get_height()))
console::warning(L"Failed cropping window rect"); console::warning("Failed cropping window rect");
} }
} }
@@ -332,13 +344,13 @@ namespace crnlib
{ {
if (work_tex.get_num_faces() > 1) if (work_tex.get_num_faces() > 1)
{ {
console::warning(L"Can't crop cubemap textures"); console::warning("Can't crop cubemap textures");
} }
else else
{ {
new_width = math::minimum<uint>(mipmap_params.m_clamp_width, new_width); new_width = math::minimum<uint>(mipmap_params.m_clamp_width, new_width);
new_height = math::minimum<uint>(mipmap_params.m_clamp_height, new_height); new_height = math::minimum<uint>(mipmap_params.m_clamp_height, new_height);
console::info(L"Clamping input texture to %ux%u", new_width, new_height); console::info("Clamping input texture to %ux%u", new_width, new_height);
work_tex.crop(0, 0, new_width, new_height); work_tex.crop(0, 0, new_width, new_height);
} }
} }
@@ -420,7 +432,7 @@ namespace crnlib
if ((new_width != (int)work_tex.get_width()) || (new_height != (int)work_tex.get_height())) if ((new_width != (int)work_tex.get_width()) || (new_height != (int)work_tex.get_height()))
{ {
console::info(L"Resampling input texture to %ux%u", new_width, new_height); console::info("Resampling input texture to %ux%u", new_width, new_height);
const char* pFilter = crn_get_mip_filter_name(mipmap_params.m_filter); const char* pFilter = crn_get_mip_filter_name(mipmap_params.m_filter);
@@ -439,7 +451,7 @@ namespace crnlib
if (!work_tex.resize(new_width, new_height, res_params)) if (!work_tex.resize(new_width, new_height, res_params))
{ {
console::error(L"Failed resizing texture!"); console::error("Failed resizing texture!");
return false; return false;
} }
} }
@@ -461,18 +473,18 @@ namespace crnlib
gen_params.m_max_mips = mipmap_params.m_max_levels; gen_params.m_max_mips = mipmap_params.m_max_levels;
gen_params.m_min_mip_size = mipmap_params.m_min_mip_size; gen_params.m_min_mip_size = mipmap_params.m_min_mip_size;
console::info(L"Generating mipmaps using filter \"%S\"", pFilter); console::info("Generating mipmaps using filter \"%s\"", pFilter);
timer tm; timer tm;
tm.start(); tm.start();
if (!work_tex.generate_mipmaps(gen_params, true)) if (!work_tex.generate_mipmaps(gen_params, true))
{ {
console::error(L"Failed generating mipmaps!"); console::error("Failed generating mipmaps!");
return false; return false;
} }
double t = tm.get_elapsed_secs(); double t = tm.get_elapsed_secs();
console::info(L"Generated %u mipmap levels in %3.3fs", work_tex.get_num_levels() - 1, t); console::info("Generated %u mipmap levels in %3.3fs", work_tex.get_num_levels() - 1, t);
} }
return true; return true;
@@ -487,7 +499,7 @@ namespace crnlib
dds_texture work_tex; dds_texture work_tex;
if (!create_dds_tex(params, work_tex)) if (!create_dds_tex(params, work_tex))
{ {
console::error(L"Failed creating DDS texture from crn_comp_params!"); console::error("Failed creating DDS texture from crn_comp_params!");
return false; return false;
} }
+1 -1
View File
@@ -16,7 +16,7 @@ namespace crnlib
itexture_comp() { } itexture_comp() { }
virtual ~itexture_comp() { } virtual ~itexture_comp() { }
virtual const wchar_t *get_ext() const = 0; virtual const char *get_ext() const = 0;
virtual bool compress_init(const crn_comp_params& params) = 0; virtual bool compress_init(const crn_comp_params& params) = 0;
virtual bool compress_pass(const crn_comp_params& params, float *pEffective_bitrate) = 0; virtual bool compress_pass(const crn_comp_params& params, float *pEffective_bitrate) = 0;
+99 -91
View File
@@ -3,7 +3,7 @@
#include "crn_core.h" #include "crn_core.h"
#include "crn_texture_conversion.h" #include "crn_texture_conversion.h"
#include "crn_console.h" #include "crn_console.h"
#include "crn_win32_file_utils.h" #include "crn_file_utils.h"
#include "crn_cfile_stream.h" #include "crn_cfile_stream.h"
#include "crn_image_utils.h" #include "crn_image_utils.h"
#include "crn_texture_comp.h" #include "crn_texture_comp.h"
@@ -26,8 +26,8 @@ namespace crnlib
} }
bool convert_stats::init( bool convert_stats::init(
const wchar_t* pSrc_filename, const char* pSrc_filename,
const wchar_t* pDst_filename, const char* pDst_filename,
dds_texture& src_tex, dds_texture& src_tex,
texture_file_types::format dst_file_type, texture_file_types::format dst_file_type,
bool lzma_stats) bool lzma_stats)
@@ -38,8 +38,8 @@ namespace crnlib
m_pInput_tex = &src_tex; m_pInput_tex = &src_tex;
win32_file_utils::get_file_size(pSrc_filename, m_input_file_size); file_utils::get_file_size(pSrc_filename, m_input_file_size);
win32_file_utils::get_file_size(pDst_filename, m_output_file_size); file_utils::get_file_size(pDst_filename, m_output_file_size);
m_total_input_pixels = 0; m_total_input_pixels = 0;
for (uint i = 0; i < src_tex.get_num_levels(); i++) for (uint i = 0; i < src_tex.get_num_levels(); i++)
@@ -58,12 +58,12 @@ namespace crnlib
vector<uint8> dst_tex_bytes; vector<uint8> dst_tex_bytes;
if (!cfile_stream::read_file_into_array(pDst_filename, dst_tex_bytes)) if (!cfile_stream::read_file_into_array(pDst_filename, dst_tex_bytes))
{ {
console::error(L"Failed loading output file: %s", pDst_filename); console::error("Failed loading output file: %s", pDst_filename);
return false; return false;
} }
if (!dst_tex_bytes.size()) if (!dst_tex_bytes.size())
{ {
console::error(L"Output file is empty: %s", pDst_filename); console::error("Output file is empty: %s", pDst_filename);
return false; return false;
} }
vector<uint8> cmp_tex_bytes; vector<uint8> cmp_tex_bytes;
@@ -76,7 +76,7 @@ namespace crnlib
if (!m_output_tex.load_from_file(pDst_filename, m_dst_file_type)) if (!m_output_tex.load_from_file(pDst_filename, m_dst_file_type))
{ {
console::error(L"Failed loading output file: %s", pDst_filename); console::error("Failed loading output file: %s", pDst_filename);
return false; return false;
} }
@@ -91,12 +91,12 @@ namespace crnlib
return true; return true;
} }
bool convert_stats::print(bool psnr_metrics, bool mip_stats, bool grayscale_sampling, const wchar_t *pCSVStatsFile) const bool convert_stats::print(bool psnr_metrics, bool mip_stats, bool grayscale_sampling, const char *pCSVStatsFile) const
{ {
if (!m_pInput_tex) if (!m_pInput_tex)
return false; return false;
console::info(L"Input texture: %ux%u, Levels: %u, Faces: %u, Format: %s", console::info("Input texture: %ux%u, Levels: %u, Faces: %u, Format: %s",
m_pInput_tex->get_width(), m_pInput_tex->get_width(),
m_pInput_tex->get_height(), m_pInput_tex->get_height(),
m_pInput_tex->get_num_levels(), m_pInput_tex->get_num_levels(),
@@ -104,29 +104,29 @@ namespace crnlib
pixel_format_helpers::get_pixel_format_string(m_pInput_tex->get_format())); pixel_format_helpers::get_pixel_format_string(m_pInput_tex->get_format()));
// Just casting the uint64's filesizes to uint32 here to work around gcc issues - it's not even possible to have files that large anyway. // Just casting the uint64's filesizes to uint32 here to work around gcc issues - it's not even possible to have files that large anyway.
console::info(L"Input pixels: %u, Input file size: %u, Input bits/pixel: %1.3f", console::info("Input pixels: %u, Input file size: %u, Input bits/pixel: %1.3f",
m_total_input_pixels, (uint32)m_input_file_size, (m_input_file_size * 8.0f) / m_total_input_pixels); m_total_input_pixels, (uint32)m_input_file_size, (m_input_file_size * 8.0f) / m_total_input_pixels);
console::info(L"Output texture: %ux%u, Levels: %u, Faces: %u, Format: %s", console::info("Output texture: %ux%u, Levels: %u, Faces: %u, Format: %s",
m_output_tex.get_width(), m_output_tex.get_width(),
m_output_tex.get_height(), m_output_tex.get_height(),
m_output_tex.get_num_levels(), m_output_tex.get_num_levels(),
m_output_tex.get_num_faces(), m_output_tex.get_num_faces(),
pixel_format_helpers::get_pixel_format_string(m_output_tex.get_format())); pixel_format_helpers::get_pixel_format_string(m_output_tex.get_format()));
console::info(L"Output pixels: %u, Output file size: %u, Output bits/pixel: %1.3f", console::info("Output pixels: %u, Output file size: %u, Output bits/pixel: %1.3f",
m_total_output_pixels, (uint32)m_output_file_size, (m_output_file_size * 8.0f) / m_total_output_pixels); m_total_output_pixels, (uint32)m_output_file_size, (m_output_file_size * 8.0f) / m_total_output_pixels);
if (m_output_comp_file_size) if (m_output_comp_file_size)
{ {
console::info(L"LZMA compressed output file size: %u bytes, %1.3f bits/pixel", console::info("LZMA compressed output file size: %u bytes, %1.3f bits/pixel",
(uint32)m_output_comp_file_size, (m_output_comp_file_size * 8.0f) / m_total_output_pixels); (uint32)m_output_comp_file_size, (m_output_comp_file_size * 8.0f) / m_total_output_pixels);
} }
if (psnr_metrics) if (psnr_metrics)
{ {
if ( (m_pInput_tex->get_width() != m_output_tex.get_width()) || (m_pInput_tex->get_height() != m_output_tex.get_height()) || (m_pInput_tex->get_num_faces() != m_output_tex.get_num_faces()) ) if ( (m_pInput_tex->get_width() != m_output_tex.get_width()) || (m_pInput_tex->get_height() != m_output_tex.get_height()) || (m_pInput_tex->get_num_faces() != m_output_tex.get_num_faces()) )
{ {
console::warning(L"Unable to compute image statistics - input/output texture dimensions are different."); console::warning("Unable to compute image statistics - input/output texture dimensions are different.");
} }
else else
{ {
@@ -155,7 +155,7 @@ namespace crnlib
pB = &grayscale_b; pB = &grayscale_b;
} }
console::info(L"Mipmap level %u statistics:", level); console::info("Mipmap level %u statistics:", level);
image_utils::print_image_metrics(*pA, *pB); image_utils::print_image_metrics(*pA, *pB);
if ((pA->has_rgb()) || (pB->has_rgb())) if ((pA->has_rgb()) || (pB->has_rgb()))
@@ -187,23 +187,22 @@ namespace crnlib
image_utils::error_metrics luma_error; image_utils::error_metrics luma_error;
if (rgb_error.compute(*pA, *pB, 0, 3, false) && luma_error.compute(*pA, *pB, 0, 0, true)) if (rgb_error.compute(*pA, *pB, 0, 3, false) && luma_error.compute(*pA, *pB, 0, 0, true))
{ {
FILE *pFile = NULL; bool bCSVStatsFileExists = file_utils::does_file_exist(pCSVStatsFile);
#ifdef _MSC_VER FILE* pFile;
_wfopen_s(&pFile, pCSVStatsFile, L"a"); crn_fopen(&pFile, pCSVStatsFile, "a");
#else
pFile = _wfopen(pCSVStatsFile, L"a");
#endif
if (!pFile) if (!pFile)
console::warning(L"Unable to append to CSV stats file: %s\n", pCSVStatsFile); console::warning("Unable to append to CSV stats file: %s\n", pCSVStatsFile);
else else
{ {
dynamic_wstring filename; if (!bCSVStatsFileExists)
split_path(m_src_filename.get_ptr(), NULL, NULL, &filename, NULL); fprintf(pFile, "name,width,height,miplevels,rgb_rms,luma_rms,effective_output_size,effective_bitrate\n");
dynamic_string filenamea; dynamic_string filename;
file_utils::split_path(m_src_filename.get_ptr(), NULL, NULL, &filename, NULL);
uint64 effective_output_size = m_output_comp_file_size ? m_output_comp_file_size : m_output_file_size; uint64 effective_output_size = m_output_comp_file_size ? m_output_comp_file_size : m_output_file_size;
float bitrate = (effective_output_size * 8.0f) / m_total_output_pixels; float bitrate = (effective_output_size * 8.0f) / m_total_output_pixels;
fprintf(pFile, "%s,%u,%u,%u,%f,%f,%u,%f\n", fprintf(pFile, "%s,%u,%u,%u,%f,%f,%u,%f\n",
filename.as_ansi(filenamea).get_ptr(), filename.get_ptr(),
pB->get_width(), pB->get_height(), m_output_tex.get_num_levels(), pB->get_width(), pB->get_height(), m_output_tex.get_num_levels(),
rgb_error.mRootMeanSquared, luma_error.mRootMeanSquared, rgb_error.mRootMeanSquared, luma_error.mRootMeanSquared,
(uint32)effective_output_size, bitrate); (uint32)effective_output_size, bitrate);
@@ -283,12 +282,12 @@ namespace crnlib
return true; return true;
} }
static bool convert_error(const convert_params& params, const wchar_t* pError_msg) static bool convert_error(const convert_params& params, const char* pError_msg)
{ {
params.m_status = false; params.m_status = false;
params.m_error_message = pError_msg; params.m_error_message = pError_msg;
_wremove(params.m_dst_filename.get_ptr()); remove(params.m_dst_filename.get_ptr());
return false; return false;
} }
@@ -369,55 +368,55 @@ namespace crnlib
static void print_comp_params(const crn_comp_params &comp_params) static void print_comp_params(const crn_comp_params &comp_params)
{ {
console::debug(L"\nTexture conversion compression parameters:"); console::debug("\nTexture conversion compression parameters:");
console::debug(L" Desired bitrate: %3.3f", comp_params.m_target_bitrate); console::debug(" Desired bitrate: %3.3f", comp_params.m_target_bitrate);
console::debug(L" CRN Quality: %i", comp_params.m_quality_level); console::debug(" CRN Quality: %i", comp_params.m_quality_level);
console::debug(L"CRN C endpoints/selectors: %u %u", comp_params.m_crn_color_endpoint_palette_size, comp_params.m_crn_color_selector_palette_size); console::debug("CRN C endpoints/selectors: %u %u", comp_params.m_crn_color_endpoint_palette_size, comp_params.m_crn_color_selector_palette_size);
console::debug(L"CRN A endpoints/selectors: %u %u", comp_params.m_crn_alpha_endpoint_palette_size, comp_params.m_crn_alpha_selector_palette_size); console::debug("CRN A endpoints/selectors: %u %u", comp_params.m_crn_alpha_endpoint_palette_size, comp_params.m_crn_alpha_selector_palette_size);
console::debug(L" DXT both block types: %u, Alpha threshold: %u", comp_params.get_flag(cCRNCompFlagUseBothBlockTypes), comp_params.m_dxt1a_alpha_threshold); console::debug(" DXT both block types: %u, Alpha threshold: %u", comp_params.get_flag(cCRNCompFlagUseBothBlockTypes), comp_params.m_dxt1a_alpha_threshold);
console::debug(L" DXT compression quality: %s", crn_get_dxt_quality_string(comp_params.m_dxt_quality)); console::debug(" DXT compression quality: %s", crn_get_dxt_quality_string(comp_params.m_dxt_quality));
console::debug(L" Perceptual: %u, Large Blocks: %u", comp_params.get_flag(cCRNCompFlagPerceptual), comp_params.get_flag(cCRNCompFlagHierarchical)); console::debug(" Perceptual: %u, Large Blocks: %u", comp_params.get_flag(cCRNCompFlagPerceptual), comp_params.get_flag(cCRNCompFlagHierarchical));
console::debug(L" Compressor: %s", get_dxt_compressor_name(comp_params.m_dxt_compressor_type)); console::debug(" Compressor: %s", get_dxt_compressor_name(comp_params.m_dxt_compressor_type));
console::debug(L" Disable endpoint caching: %u", comp_params.get_flag(cCRNCompFlagDisableEndpointCaching)); console::debug(" Disable endpoint caching: %u", comp_params.get_flag(cCRNCompFlagDisableEndpointCaching));
console::debug(L" Grayscale sampling: %u", comp_params.get_flag(cCRNCompFlagGrayscaleSampling)); console::debug(" Grayscale sampling: %u", comp_params.get_flag(cCRNCompFlagGrayscaleSampling));
console::debug(L" Max helper threads: %u", comp_params.m_num_helper_threads); console::debug(" Max helper threads: %u", comp_params.m_num_helper_threads);
console::debug(L""); console::debug("");
} }
static void print_mipmap_params(const crn_mipmap_params &mipmap_params) static void print_mipmap_params(const crn_mipmap_params &mipmap_params)
{ {
console::debug(L"\nTexture conversion MIP-map parameters:"); console::debug("\nTexture conversion MIP-map parameters:");
console::debug(L" Mode: %s", crn_get_mip_mode_name(mipmap_params.m_mode)); console::debug(" Mode: %s", crn_get_mip_mode_name(mipmap_params.m_mode));
console::debug(L" Filter: %S", crn_get_mip_filter_name(mipmap_params.m_filter)); console::debug(" Filter: %s", crn_get_mip_filter_name(mipmap_params.m_filter));
console::debug(L"Gamma filtering: %u, Gamma: %2.2f", mipmap_params.m_gamma_filtering, mipmap_params.m_gamma); console::debug("Gamma filtering: %u, Gamma: %2.2f", mipmap_params.m_gamma_filtering, mipmap_params.m_gamma);
console::debug(L" Blurriness: %2.2f", mipmap_params.m_blurriness); console::debug(" Blurriness: %2.2f", mipmap_params.m_blurriness);
console::debug(L" Renormalize: %u", mipmap_params.m_renormalize); console::debug(" Renormalize: %u", mipmap_params.m_renormalize);
console::debug(L" Tiled: %u", mipmap_params.m_tiled); console::debug(" Tiled: %u", mipmap_params.m_tiled);
console::debug(L" Max Levels: %u", mipmap_params.m_max_levels); console::debug(" Max Levels: %u", mipmap_params.m_max_levels);
console::debug(L" Min level size: %u", mipmap_params.m_min_mip_size); console::debug(" Min level size: %u", mipmap_params.m_min_mip_size);
console::debug(L" window: %u %u %u %u", mipmap_params.m_window_left, mipmap_params.m_window_top, mipmap_params.m_window_right, mipmap_params.m_window_bottom); console::debug(" window: %u %u %u %u", mipmap_params.m_window_left, mipmap_params.m_window_top, mipmap_params.m_window_right, mipmap_params.m_window_bottom);
console::debug(L" scale mode: %s", crn_get_scale_mode_desc(mipmap_params.m_scale_mode)); console::debug(" scale mode: %s", crn_get_scale_mode_desc(mipmap_params.m_scale_mode));
console::debug(L" scale: %f %f", mipmap_params.m_scale_x, mipmap_params.m_scale_y); console::debug(" scale: %f %f", mipmap_params.m_scale_x, mipmap_params.m_scale_y);
console::debug(L" clamp: %u %u, clamp_scale: %u", mipmap_params.m_clamp_width, mipmap_params.m_clamp_height, mipmap_params.m_clamp_scale); console::debug(" clamp: %u %u, clamp_scale: %u", mipmap_params.m_clamp_width, mipmap_params.m_clamp_height, mipmap_params.m_clamp_scale);
console::debug(L""); console::debug("");
} }
void convert_params::print() void convert_params::print()
{ {
console::debug(L"\nTexture conversion parameters:"); console::debug("\nTexture conversion parameters:");
console::debug(L" Resolution: %ux%u, Faces: %u, Levels: %u, Format: %s", console::debug(" Resolution: %ux%u, Faces: %u, Levels: %u, Format: %s",
m_pInput_texture->get_width(), m_pInput_texture->get_width(),
m_pInput_texture->get_height(), m_pInput_texture->get_height(),
m_pInput_texture->get_num_faces(), m_pInput_texture->get_num_faces(),
m_pInput_texture->get_num_levels(), m_pInput_texture->get_num_levels(),
pixel_format_helpers::get_pixel_format_string(m_pInput_texture->get_format())); pixel_format_helpers::get_pixel_format_string(m_pInput_texture->get_format()));
console::debug(L" texture_type: %s", get_texture_type_desc(m_texture_type)); console::debug(" texture_type: %s", get_texture_type_desc(m_texture_type));
console::debug(L" dst_filename: %s", m_dst_filename.get_ptr()); console::debug(" dst_filename: %s", m_dst_filename.get_ptr());
console::debug(L" dst_file_type: %s", texture_file_types::get_extension(m_dst_file_type)); console::debug(" dst_file_type: %s", texture_file_types::get_extension(m_dst_file_type));
console::debug(L" dst_format: %s", pixel_format_helpers::get_pixel_format_string(m_dst_format)); console::debug(" dst_format: %s", pixel_format_helpers::get_pixel_format_string(m_dst_format));
console::debug(L" quick: %u", m_quick); console::debug(" quick: %u", m_quick);
console::debug(L" use_source_format: %u", m_use_source_format); console::debug(" use_source_format: %u", m_use_source_format);
} }
static bool write_compressed_texture( static bool write_compressed_texture(
@@ -432,19 +431,19 @@ namespace crnlib
crn_format crn_fmt = pixel_format_helpers::convert_pixel_format_to_best_crn_format(dst_format); crn_format crn_fmt = pixel_format_helpers::convert_pixel_format_to_best_crn_format(dst_format);
comp_params.m_format = crn_fmt; comp_params.m_format = crn_fmt;
console::message(L"Writing %s texture to file: \"%s\"", crn_get_format_string(crn_fmt), params.m_dst_filename.get_ptr()); console::message("Writing %s texture to file: \"%s\"", crn_get_format_string(crn_fmt), params.m_dst_filename.get_ptr());
uint32 actual_quality_level; uint32 actual_quality_level;
float actual_bitrate; float actual_bitrate;
bool status = work_tex.write_to_file(params.m_dst_filename.get_ptr(), params.m_dst_file_type, &comp_params, &actual_quality_level, &actual_bitrate); bool status = work_tex.write_to_file(params.m_dst_filename.get_ptr(), params.m_dst_file_type, &comp_params, &actual_quality_level, &actual_bitrate);
if (!status) if (!status)
return convert_error(params, L"Failed writing output file!"); return convert_error(params, "Failed writing output file!");
if (!params.m_no_stats) if (!params.m_no_stats)
{ {
if (!stats.init(params.m_pInput_texture->get_source_filename().get_ptr(), params.m_dst_filename.get_ptr(), *params.m_pIntermediate_texture, params.m_dst_file_type, params.m_lzma_stats)) if (!stats.init(params.m_pInput_texture->get_source_filename().get_ptr(), params.m_dst_filename.get_ptr(), *params.m_pIntermediate_texture, params.m_dst_file_type, params.m_lzma_stats))
{ {
console::warning(L"Unable to compute output statistics for file: %s", params.m_pInput_texture->get_source_filename().get_ptr()); console::warning("Unable to compute output statistics for file: %s", params.m_pInput_texture->get_source_filename().get_ptr());
} }
} }
@@ -471,7 +470,7 @@ namespace crnlib
pack_params.m_num_helper_threads = comp_params.m_num_helper_threads; pack_params.m_num_helper_threads = comp_params.m_num_helper_threads;
pack_params.m_use_transparent_indices_for_black = comp_params.get_flag(cCRNCompFlagUseTransparentIndicesForBlack); pack_params.m_use_transparent_indices_for_black = comp_params.get_flag(cCRNCompFlagUseTransparentIndicesForBlack);
console::info(L"Converting texture format from %s to %s", pixel_format_helpers::get_pixel_format_string(work_tex.get_format()), pixel_format_helpers::get_pixel_format_string(dst_format)); console::info("Converting texture format from %s to %s", pixel_format_helpers::get_pixel_format_string(work_tex.get_format()), pixel_format_helpers::get_pixel_format_string(dst_format));
timer tm; timer tm;
tm.start(); tm.start();
@@ -480,7 +479,7 @@ namespace crnlib
double t = tm.get_elapsed_secs(); double t = tm.get_elapsed_secs();
console::info(L""); console::info("");
if (!status) if (!status)
{ {
@@ -491,11 +490,11 @@ namespace crnlib
} }
else else
{ {
return convert_error(params, L"Failed converting texture to output format!"); return convert_error(params, "Failed converting texture to output format!");
} }
} }
console::info(L"Texture format conversion took %3.3fs", t); console::info("Texture format conversion took %3.3fs", t);
} }
if (params.m_write_mipmaps_to_multiple_files) if (params.m_write_mipmaps_to_multiple_files)
@@ -504,13 +503,13 @@ namespace crnlib
{ {
for (uint l = 0; l < work_tex.get_num_levels(); l++) for (uint l = 0; l < work_tex.get_num_levels(); l++)
{ {
dynamic_wstring filename(params.m_dst_filename.get_ptr()); dynamic_string filename(params.m_dst_filename.get_ptr());
dynamic_wstring drv, dir, fn, ext; dynamic_string drv, dir, fn, ext;
if (!split_path(params.m_dst_filename.get_ptr(), &drv, &dir, &fn, &ext)) if (!file_utils::split_path(params.m_dst_filename.get_ptr(), &drv, &dir, &fn, &ext))
return false; return false;
fn += dynamic_wstring(cVarArg, L"_face%u_mip%u", f, l).get_ptr(); fn += dynamic_string(cVarArg, "_face%u_mip%u", f, l).get_ptr();
filename = drv + dir + fn + ext; filename = drv + dir + fn + ext;
mip_level *pLevel = work_tex.get_level(f, l); mip_level *pLevel = work_tex.get_level(f, l);
@@ -521,25 +520,25 @@ namespace crnlib
dds_texture new_tex; dds_texture new_tex;
new_tex.assign(face); new_tex.assign(face);
console::info(L"Writing texture face %u mip level %u to file %s", f, l, filename.get_ptr()); console::info("Writing texture face %u mip level %u to file %s", f, l, filename.get_ptr());
if (!new_tex.write_to_file(filename.get_ptr(), params.m_dst_file_type, NULL, NULL, NULL)) if (!new_tex.write_to_file(filename.get_ptr(), params.m_dst_file_type, NULL, NULL, NULL))
return convert_error(params, L"Failed writing output file!"); return convert_error(params, "Failed writing output file!");
} }
} }
} }
else else
{ {
console::message(L"Writing texture to file: \"%s\"", params.m_dst_filename.get_ptr()); console::message("Writing texture to file: \"%s\"", params.m_dst_filename.get_ptr());
if (!work_tex.write_to_file(params.m_dst_filename.get_ptr(), params.m_dst_file_type, NULL, NULL, NULL)) if (!work_tex.write_to_file(params.m_dst_filename.get_ptr(), params.m_dst_file_type, NULL, NULL, NULL))
return convert_error(params, L"Failed writing output file!"); return convert_error(params, "Failed writing output file!");
if (!params.m_no_stats) if (!params.m_no_stats)
{ {
if (!stats.init(params.m_pInput_texture->get_source_filename().get_ptr(), params.m_dst_filename.get_ptr(), *params.m_pIntermediate_texture, params.m_dst_file_type, params.m_lzma_stats)) if (!stats.init(params.m_pInput_texture->get_source_filename().get_ptr(), params.m_dst_filename.get_ptr(), *params.m_pIntermediate_texture, params.m_dst_file_type, params.m_lzma_stats))
{ {
console::warning(L"Unable to compute output statistics for file: %s", params.m_pInput_texture->get_source_filename().get_ptr()); console::warning("Unable to compute output statistics for file: %s", params.m_pInput_texture->get_source_filename().get_ptr());
} }
} }
} }
@@ -576,7 +575,7 @@ namespace crnlib
{ {
if ((work_tex.get_comp_flags() & pixel_format_helpers::cCompFlagAValid) == 0) if ((work_tex.get_comp_flags() & pixel_format_helpers::cCompFlagAValid) == 0)
{ {
console::warning(L"Output format is alpha-only, but input doesn't have alpha, so setting alpha to luminance."); console::warning("Output format is alpha-only, but input doesn't have alpha, so setting alpha to luminance.");
work_tex.convert(PIXEL_FMT_A8, crnlib::dxt_image::pack_params()); work_tex.convert(PIXEL_FMT_A8, crnlib::dxt_image::pack_params());
@@ -586,6 +585,15 @@ namespace crnlib
} }
pixel_format dst_format = params.m_dst_format; pixel_format dst_format = params.m_dst_format;
if (pixel_format_helpers::is_dxt(dst_format))
{
if ((params.m_dst_file_type != texture_file_types::cFormatCRN) &&
(params.m_dst_file_type != texture_file_types::cFormatDDS))
{
console::warning("Output file format does not support DXT - automatically choosing pixel format.");
dst_format = PIXEL_FMT_INVALID;
}
}
if (dst_format == PIXEL_FMT_INVALID) if (dst_format == PIXEL_FMT_INVALID)
{ {
@@ -611,15 +619,15 @@ namespace crnlib
{ {
if (perceptual) if (perceptual)
{ {
//console::warning(L"Output pixel format is swizzled or not RGB, disabling perceptual color metrics"); console::message("Output pixel format is swizzled or not RGB, disabling perceptual color metrics");
perceptual = false; perceptual = false;
} }
} }
if (pixel_format_helpers::is_normal_map(dst_format)) if (pixel_format_helpers::is_normal_map(dst_format))
{ {
//if (perceptual) if (perceptual)
//console::warning(L"Output pixel format is intended for normal maps, disabling perceptual color metrics"); console::message("Output pixel format is intended for normal maps, disabling perceptual color metrics");
perceptual = false; perceptual = false;
} }
@@ -639,7 +647,7 @@ namespace crnlib
} }
if (!create_texture_mipmaps(work_tex, comp_params, mipmap_params, generate_mipmaps)) if (!create_texture_mipmaps(work_tex, comp_params, mipmap_params, generate_mipmaps))
return convert_error(params, L"Failed creating texture mipmaps!"); return convert_error(params, "Failed creating texture mipmaps!");
bool formats_differ = work_tex.get_format() != dst_format; bool formats_differ = work_tex.get_format() != dst_format;
if (formats_differ) if (formats_differ)
@@ -666,7 +674,7 @@ namespace crnlib
status = convert_and_write_normal_texture(work_tex, params, comp_params, dst_format, progress_state, formats_differ, perceptual, stats); status = convert_and_write_normal_texture(work_tex, params, comp_params, dst_format, progress_state, formats_differ, perceptual, stats);
} }
console::progress(L""); console::progress("");
if (progress_state.m_canceled) if (progress_state.m_canceled)
{ {
@@ -679,18 +687,18 @@ namespace crnlib
if (status) if (status)
{ {
if (params.m_param_debugging) if (params.m_param_debugging)
console::info(L"Work texture format: %s, desired destination format: %s", pixel_format_helpers::get_pixel_format_string(work_tex.get_format()), pixel_format_helpers::get_pixel_format_string(dst_format)); console::info("Work texture format: %s, desired destination format: %s", pixel_format_helpers::get_pixel_format_string(work_tex.get_format()), pixel_format_helpers::get_pixel_format_string(dst_format));
console::message(L"Texture successfully written in %3.3fs", total_write_time); console::message("Texture successfully written in %3.3fs", total_write_time);
} }
else else
{ {
dynamic_wstring str; dynamic_string str;
if (work_tex.get_last_error().is_empty()) if (work_tex.get_last_error().is_empty())
str.format(L"Failed writing texture to file \"%s\"", params.m_dst_filename.get_ptr()); str.format("Failed writing texture to file \"%s\"", params.m_dst_filename.get_ptr());
else else
str.format(L"Failed writing texture to file \"%s\", Reason: %s", params.m_dst_filename.get_ptr(), work_tex.get_last_error().get_ptr()); str.format("Failed writing texture to file \"%s\", Reason: %s", params.m_dst_filename.get_ptr(), work_tex.get_last_error().get_ptr());
return convert_error(params, str.get_ptr()); return convert_error(params, str.get_ptr());
} }
+10 -10
View File
@@ -16,18 +16,18 @@ namespace crnlib
convert_stats(); convert_stats();
bool init( bool init(
const wchar_t* pSrc_filename, const char* pSrc_filename,
const wchar_t* pDst_filename, const char* pDst_filename,
dds_texture& src_tex, dds_texture& src_tex,
texture_file_types::format dst_file_type, texture_file_types::format dst_file_type,
bool lzma_stats); bool lzma_stats);
bool print(bool psnr_metrics, bool mip_stats, bool grayscale_sampling, const wchar_t *pCSVStatsFile = NULL) const; bool print(bool psnr_metrics, bool mip_stats, bool grayscale_sampling, const char *pCSVStatsFile = NULL) const;
void clear(); void clear();
dynamic_wstring m_src_filename; dynamic_string m_src_filename;
dynamic_wstring m_dst_filename; dynamic_string m_dst_filename;
texture_file_types::format m_dst_file_type; texture_file_types::format m_dst_file_type;
dds_texture* m_pInput_tex; dds_texture* m_pInput_tex;
@@ -58,10 +58,10 @@ namespace crnlib
m_debugging(false), m_debugging(false),
m_param_debugging(false), m_param_debugging(false),
m_no_stats(false), m_no_stats(false),
m_use_source_format(false),
m_lzma_stats(false), m_lzma_stats(false),
m_status(false), m_status(false),
m_canceled(false), m_canceled(false)
m_use_source_format(false)
{ {
} }
@@ -77,7 +77,7 @@ namespace crnlib
texture_type m_texture_type; texture_type m_texture_type;
dynamic_wstring m_dst_filename; dynamic_string m_dst_filename;
texture_file_types::format m_dst_file_type; texture_file_types::format m_dst_file_type;
pixel_format m_dst_format; pixel_format m_dst_format;
@@ -90,7 +90,7 @@ namespace crnlib
// Return parameters // Return parameters
dds_texture* m_pIntermediate_texture; dds_texture* m_pIntermediate_texture;
mutable dynamic_wstring m_error_message; mutable dynamic_string m_error_message;
bool m_write_mipmaps_to_multiple_files; bool m_write_mipmaps_to_multiple_files;
bool m_quick; bool m_quick;
@@ -98,7 +98,7 @@ namespace crnlib
bool m_param_debugging; bool m_param_debugging;
bool m_no_stats; bool m_no_stats;
bool m_use_source_format; bool m_use_source_format;
bool m_lzma_stats; bool m_lzma_stats;
mutable bool m_status; mutable bool m_status;
mutable bool m_canceled; mutable bool m_canceled;
+30 -30
View File
@@ -2,48 +2,48 @@
// 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_texture_file_types.h" #include "crn_texture_file_types.h"
#include "crn_strutils.h" #include "crn_file_utils.h"
namespace crnlib namespace crnlib
{ {
const wchar_t* texture_file_types::get_extension(format fmt) const char* texture_file_types::get_extension(format fmt)
{ {
CRNLIB_ASSERT(fmt < cNumFileFormats); CRNLIB_ASSERT(fmt < cNumFileFormats);
if (fmt >= cNumFileFormats) if (fmt >= cNumFileFormats)
return NULL; return NULL;
static const wchar_t* extensions[cNumFileFormats] = static const char* extensions[cNumFileFormats] =
{ {
L"tga", "tga",
L"png", "png",
L"jpg", "jpg",
L"jpeg", "jpeg",
L"bmp", "bmp",
L"gif", "gif",
L"tif", "tif",
L"tiff", "tiff",
L"ppm", "ppm",
L"pgm", "pgm",
L"dds", "dds",
L"psd", "psd",
L"jp2", "jp2",
L"crn", "crn",
L"<clipboard>", "<clipboard>",
L"<dragdrop>" "<dragdrop>"
}; };
return extensions[fmt]; return extensions[fmt];
} }
texture_file_types::format texture_file_types::determine_file_format(const wchar_t* pFilename) texture_file_types::format texture_file_types::determine_file_format(const char* pFilename)
{ {
dynamic_wstring ext; dynamic_string ext;
if (!split_path(pFilename, NULL, NULL, NULL, &ext)) if (!file_utils::split_path(pFilename, NULL, NULL, NULL, &ext))
return cFormatInvalid; return cFormatInvalid;
if (ext.is_empty()) if (ext.is_empty())
return cFormatInvalid; return cFormatInvalid;
if (ext[0] == L'.') if (ext[0] == '.')
ext.right(1); ext.right(1);
for (uint i = 0; i < cNumFileFormats; i++) for (uint i = 0; i < cNumFileFormats; i++)
@@ -81,21 +81,21 @@ namespace crnlib
return true; return true;
} }
const wchar_t* get_texture_type_desc(texture_type t) const char* get_texture_type_desc(texture_type t)
{ {
switch (t) switch (t)
{ {
case cTextureTypeUnknown: return L"Unknown"; case cTextureTypeUnknown: return "Unknown";
case cTextureTypeRegularMap: return L"2D map"; case cTextureTypeRegularMap: return "2D map";
case cTextureTypeNormalMap: return L"Normal map"; case cTextureTypeNormalMap: return "Normal map";
case cTextureTypeVerticalCrossCubemap: return L"Vertical Cross Cubemap"; case cTextureTypeVerticalCrossCubemap: return "Vertical Cross Cubemap";
case cTextureTypeCubemap: return L"Cubemap"; case cTextureTypeCubemap: return "Cubemap";
default: break; default: break;
} }
CRNLIB_ASSERT(false); CRNLIB_ASSERT(false);
return L"?"; return "?";
} }
} // namespace crnlib } // namespace crnlib
+12 -12
View File
@@ -27,24 +27,24 @@ namespace crnlib
cFormatPSD, cFormatPSD,
cFormatJP2, cFormatJP2,
cFormatCRN, cFormatCRN,
cNumRegularFileFormats, cNumRegularFileFormats,
// Not really a file format // Not really a file format
cFormatClipboard = cNumRegularFileFormats, cFormatClipboard = cNumRegularFileFormats,
cFormatDragDrop, cFormatDragDrop,
cNumFileFormats cNumFileFormats
}; };
static const wchar_t* get_extension(format fmt); static const char* get_extension(format fmt);
static format determine_file_format(const char* pFilename);
static format determine_file_format(const wchar_t* pFilename);
static bool supports_mipmaps(format fmt); static bool supports_mipmaps(format fmt);
static bool supports_alpha(format fmt); static bool supports_alpha(format fmt);
}; };
enum texture_type enum texture_type
{ {
cTextureTypeUnknown = 0, cTextureTypeUnknown = 0,
@@ -55,8 +55,8 @@ namespace crnlib
cNumTextureTypes cNumTextureTypes
}; };
const wchar_t* get_texture_type_desc(texture_type t); const char* get_texture_type_desc(texture_type t);
} // namespace crnlib } // namespace crnlib
+4 -3
View File
@@ -2,6 +2,7 @@
// 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_clusterizer.h" #include "crn_clusterizer.h"
#include "crn_threading.h"
namespace crnlib namespace crnlib
{ {
@@ -43,7 +44,7 @@ namespace crnlib
progress_callback_func pProgress_callback, progress_callback_func pProgress_callback,
void* pProgress_callback_data) void* pProgress_callback_data)
{ {
m_main_thread_id = get_current_thread_id(); m_main_thread_id = crn_get_current_thread_id();
m_canceled = false; m_canceled = false;
m_pProgress_callback = pProgress_callback; m_pProgress_callback = pProgress_callback;
m_pProgress_callback_data = pProgress_callback_data; m_pProgress_callback_data = pProgress_callback_data;
@@ -136,7 +137,7 @@ namespace crnlib
private: private:
task_pool* m_pTask_pool; task_pool* m_pTask_pool;
uint32 m_main_thread_id; crn_thread_id_t m_main_thread_id;
struct create_clusters_task_state struct create_clusters_task_state
{ {
@@ -328,7 +329,7 @@ namespace crnlib
if (m_canceled) if (m_canceled)
return; return;
const bool is_main_thread = (get_current_thread_id() == m_main_thread_id); const bool is_main_thread = (crn_get_current_thread_id() == m_main_thread_id);
const bool quick = false; const bool quick = false;
m_clusterizers[partition_index].generate_codebook( m_clusterizers[partition_index].generate_codebook(
+1
View File
@@ -3,6 +3,7 @@
#include "crn_core.h" #include "crn_core.h"
#include "crn_threaded_resampler.h" #include "crn_threaded_resampler.h"
#include "crn_resample_filters.h" #include "crn_resample_filters.h"
#include "crn_threading.h"
namespace crnlib namespace crnlib
{ {
+20 -20
View File
@@ -3,34 +3,34 @@
#pragma once #pragma once
#include "crn_resampler.h" #include "crn_resampler.h"
#include "crn_vec.h" #include "crn_vec.h"
#include "crn_task_pool.h"
namespace crnlib namespace crnlib
{ {
class task_pool;
class threaded_resampler class threaded_resampler
{ {
CRNLIB_NO_COPY_OR_ASSIGNMENT_OP(threaded_resampler); CRNLIB_NO_COPY_OR_ASSIGNMENT_OP(threaded_resampler);
public: public:
threaded_resampler(task_pool& tp); threaded_resampler(task_pool& tp);
~threaded_resampler(); ~threaded_resampler();
enum pixel_format enum pixel_format
{ {
cPF_Y_F32, cPF_Y_F32,
cPF_RGBX_F32, cPF_RGBX_F32,
cPF_RGBA_F32, cPF_RGBA_F32,
cPF_Total cPF_Total
}; };
struct params struct params
{ {
params() params()
{ {
clear(); clear();
} }
void clear() void clear()
{ {
utils::zero_object(*this); utils::zero_object(*this);
@@ -42,44 +42,44 @@ namespace crnlib
m_filter_x_scale = 1.0f; m_filter_x_scale = 1.0f;
m_filter_y_scale = 1.0f; m_filter_y_scale = 1.0f;
} }
pixel_format m_fmt; pixel_format m_fmt;
const void* m_pSrc_pixels; const void* m_pSrc_pixels;
uint m_src_width; uint m_src_width;
uint m_src_height; uint m_src_height;
uint m_src_pitch; uint m_src_pitch;
void* m_pDst_pixels; void* m_pDst_pixels;
uint m_dst_width; uint m_dst_width;
uint m_dst_height; uint m_dst_height;
uint m_dst_pitch; uint m_dst_pitch;
Resampler::Boundary_Op m_boundary_op; Resampler::Boundary_Op m_boundary_op;
float m_sample_low; float m_sample_low;
float m_sample_high; float m_sample_high;
const char* m_Pfilter_name; const char* m_Pfilter_name;
float m_filter_x_scale; float m_filter_x_scale;
float m_filter_y_scale; float m_filter_y_scale;
}; };
bool resample(const params& p); bool resample(const params& p);
private: private:
task_pool* m_pTask_pool; task_pool* m_pTask_pool;
const params* m_pParams; const params* m_pParams;
Resampler::Contrib_List* m_pX_contribs; Resampler::Contrib_List* m_pX_contribs;
Resampler::Contrib_List* m_pY_contribs; Resampler::Contrib_List* m_pY_contribs;
uint m_bytes_per_pixel; uint m_bytes_per_pixel;
crnlib::vector<vec4F> m_tmp_img; crnlib::vector<vec4F> m_tmp_img;
void free_contrib_lists(); void free_contrib_lists();
void resample_x_task(uint64 data, void* pData_ptr); void resample_x_task(uint64 data, void* pData_ptr);
void resample_y_task(uint64 data, void* pData_ptr); void resample_y_task(uint64 data, void* pData_ptr);
}; };
+10
View File
@@ -0,0 +1,10 @@
// File: crn_threading.h
// See Copyright Notice and license at the end of inc/crnlib.h
#if CRNLIB_USE_WIN32_API
#include "crn_threading_win32.h"
#elif CRNLIB_USE_PTHREADS_API
#include "crn_threading_pthreads.h"
#else
#include "crn_threading_null.h"
#endif
+192
View File
@@ -0,0 +1,192 @@
// File: crn_threading_null.h
// See Copyright Notice and license at the end of include/crnlib.h
#pragma once
#include "crn_atomics.h"
namespace crnlib
{
const uint g_number_of_processors = 1;
inline void crn_threading_init()
{
}
typedef uint64 crn_thread_id_t;
inline crn_thread_id_t crn_get_current_thread_id()
{
return 0;
}
inline void crn_sleep(unsigned int milliseconds)
{
milliseconds;
}
inline uint crn_get_max_helper_threads()
{
return 0;
}
class mutex
{
CRNLIB_NO_COPY_OR_ASSIGNMENT_OP(mutex);
public:
inline mutex(unsigned int spin_count = 0)
{
spin_count;
}
inline ~mutex()
{
}
inline void lock()
{
}
inline void unlock()
{
}
inline void set_spin_count(unsigned int count)
{
count;
}
};
class scoped_mutex
{
scoped_mutex(const scoped_mutex&);
scoped_mutex& operator= (const scoped_mutex&);
public:
inline scoped_mutex(mutex& lock) : m_lock(lock) { m_lock.lock(); }
inline ~scoped_mutex() { m_lock.unlock(); }
private:
mutex& m_lock;
};
// Simple non-recursive spinlock.
class spinlock
{
public:
inline spinlock()
{
}
inline void lock(uint32 max_spins = 4096, bool yielding = true, bool memoryBarrier = true)
{
max_spins, yielding, memoryBarrier;
}
inline void lock_no_barrier(uint32 max_spins = 4096, bool yielding = true)
{
max_spins, yielding;
}
inline void unlock()
{
}
inline void unlock_no_barrier()
{
}
};
class scoped_spinlock
{
scoped_spinlock(const scoped_spinlock&);
scoped_spinlock& operator= (const scoped_spinlock&);
public:
inline scoped_spinlock(spinlock& lock) : m_lock(lock) { m_lock.lock(); }
inline ~scoped_spinlock() { m_lock.unlock(); }
private:
spinlock& m_lock;
};
class semaphore
{
CRNLIB_NO_COPY_OR_ASSIGNMENT_OP(semaphore);
public:
inline semaphore(long initialCount = 0, long maximumCount = 1, const char* pName = NULL)
{
initialCount, maximumCount, pName;
}
inline ~semaphore()
{
}
inline void release(long releaseCount = 1, long *pPreviousCount = NULL)
{
releaseCount, pPreviousCount;
}
inline bool wait(uint32 milliseconds = cUINT32_MAX)
{
milliseconds;
return true;
}
};
class task_pool
{
public:
inline task_pool() { }
inline task_pool(uint num_threads) { num_threads; }
inline ~task_pool() { }
inline bool init(uint num_threads) { num_threads; return true; }
inline void deinit() { }
inline uint get_num_threads() const { return 0; }
inline uint get_num_outstanding_tasks() const { return 0; }
// C-style task callback
typedef void (*task_callback_func)(uint64 data, void* pData_ptr);
inline bool queue_task(task_callback_func pFunc, uint64 data = 0, void* pData_ptr = NULL)
{
pFunc(data, pData_ptr);
return true;
}
class executable_task
{
public:
virtual void execute_task(uint64 data, void* pData_ptr) = 0;
};
// It's the caller's responsibility to delete pObj within the execute_task() method, if needed!
inline bool queue_task(executable_task* pObj, uint64 data = 0, void* pData_ptr = NULL)
{
pObj->execute_task(data, pData_ptr);
return true;
}
template<typename S, typename T>
inline bool queue_object_task(S* pObject, T pObject_method, uint64 data = 0, void* pData_ptr = NULL)
{
(pObject->*pObject_method)(data, pData_ptr);
return true;
}
template<typename S, typename T>
inline bool queue_multiple_object_tasks(S* pObject, T pObject_method, uint64 first_data, uint num_tasks, void* pData_ptr = NULL)
{
for (uint i = 0; i < num_tasks; i++)
{
(pObject->*pObject_method)(first_data + i, pData_ptr);
}
return true;
}
inline void join() { }
};
} // namespace crnlib
+410
View File
@@ -0,0 +1,410 @@
// File: crn_threading_pthreads.cpp
// See Copyright Notice and license at the end of include/crnlib.h
#include "crn_core.h"
#include "crn_threading_pthreads.h"
#include "crn_timer.h"
#if CRNLIB_USE_PTHREADS_API
#ifdef WIN32
#pragma comment(lib, "../ext/libpthread/lib/pthreadVC2.lib")
#include "crn_winhdr.h"
#endif
#ifdef __GNUC__
#include <sys/sysinfo.h>
#endif
#ifdef WIN32
#include <process.h>
#endif
namespace crnlib
{
uint g_number_of_processors = 1;
void crn_threading_init()
{
#ifdef WIN32
SYSTEM_INFO g_system_info;
GetSystemInfo(&g_system_info);
g_number_of_processors = math::maximum<uint>(1U, g_system_info.dwNumberOfProcessors);
#elif defined(__GNUC__)
g_number_of_processors = math::maximum<int>(1, get_nprocs());
#else
g_number_of_processors = 1;
#endif
}
crn_thread_id_t crn_get_current_thread_id()
{
// FIXME: Not portable
return static_cast<crn_thread_id_t>(pthread_self());
}
void crn_sleep(unsigned int milliseconds)
{
#ifdef WIN32
struct timespec interval;
interval.tv_sec = milliseconds / 1000;
interval.tv_nsec = (milliseconds % 1000) * 1000000L;
pthread_delay_np(&interval);
#else
while (milliseconds)
{
int msecs_to_sleep = CRNLIB_MIN(milliseconds, 1000);
usleep(msecs_to_sleep * 1000);
milliseconds -= msecs_to_sleep;
}
#endif
}
mutex::mutex(unsigned int spin_count)
{
spin_count;
if (pthread_mutex_init(&m_mutex, NULL))
crnlib_fail("mutex::mutex: pthread_mutex_init() failed", __FILE__, __LINE__);
#ifdef CRNLIB_BUILD_DEBUG
m_lock_count = 0;
#endif
}
mutex::~mutex()
{
#ifdef CRNLIB_BUILD_DEBUG
if (m_lock_count)
crnlib_assert("mutex::~mutex: mutex is still locked", __FILE__, __LINE__);
#endif
if (pthread_mutex_destroy(&m_mutex))
crnlib_assert("mutex::~mutex: pthread_mutex_destroy() failed", __FILE__, __LINE__);
}
void mutex::lock()
{
pthread_mutex_lock(&m_mutex);
#ifdef CRNLIB_BUILD_DEBUG
m_lock_count++;
#endif
}
void mutex::unlock()
{
#ifdef CRNLIB_BUILD_DEBUG
if (!m_lock_count)
crnlib_assert("mutex::unlock: mutex is not locked", __FILE__, __LINE__);
m_lock_count--;
#endif
pthread_mutex_unlock(&m_mutex);
}
void mutex::set_spin_count(unsigned int count)
{
count;
}
semaphore::semaphore(long initialCount, long maximumCount, const char* pName)
{
maximumCount, pName;
CRNLIB_ASSERT(maximumCount >= initialCount);
if (sem_init(&m_sem, 0, initialCount))
{
CRNLIB_FAIL("semaphore: sem_init() failed");
}
}
semaphore::~semaphore()
{
sem_destroy(&m_sem);
}
void semaphore::release(long releaseCount)
{
CRNLIB_ASSERT(releaseCount >= 1);
int status = 0;
#ifdef WIN32
if (1 == releaseCount)
status = sem_post(&m_sem);
else
status = sem_post_multiple(&m_sem, releaseCount);
#else
while (releaseCount > 0)
{
status = sem_post(&m_sem);
if (status)
break;
releaseCount--;
}
#endif
if (status)
{
CRNLIB_FAIL("semaphore: sem_post() or sem_post_multiple() failed");
}
}
void semaphore::try_release(long releaseCount)
{
CRNLIB_ASSERT(releaseCount >= 1);
#ifdef WIN32
if (1 == releaseCount)
sem_post(&m_sem);
else
sem_post_multiple(&m_sem, releaseCount);
#else
while (releaseCount > 0)
{
sem_post(&m_sem);
releaseCount--;
}
#endif
}
bool semaphore::wait(uint32 milliseconds)
{
int status;
if (milliseconds == cUINT32_MAX)
{
status = sem_wait(&m_sem);
}
else
{
struct timespec interval;
interval.tv_sec = milliseconds / 1000;
interval.tv_nsec = (milliseconds % 1000) * 1000000L;
status = sem_timedwait(&m_sem, &interval);
}
if (status)
{
if (errno != ETIMEDOUT)
{
CRNLIB_FAIL("semaphore: sem_wait() or sem_timedwait() failed");
}
return false;
}
return true;
}
spinlock::spinlock()
{
if (pthread_spin_init(&m_spinlock, 0))
{
CRNLIB_FAIL("spinlock: pthread_spin_init() failed");
}
}
spinlock::~spinlock()
{
pthread_spin_destroy(&m_spinlock);
}
void spinlock::lock()
{
if (pthread_spin_lock(&m_spinlock))
{
CRNLIB_FAIL("spinlock: pthread_spin_lock() failed");
}
}
void spinlock::unlock()
{
if (pthread_spin_unlock(&m_spinlock))
{
CRNLIB_FAIL("spinlock: pthread_spin_unlock() failed");
}
}
task_pool::task_pool() :
m_num_threads(0),
m_tasks_available(0, 32767),
m_all_tasks_completed(0, 1),
m_total_submitted_tasks(0),
m_total_completed_tasks(0),
m_exit_flag(false)
{
utils::zero_object(m_threads);
}
task_pool::task_pool(uint num_threads) :
m_num_threads(0),
m_tasks_available(0, 32767),
m_all_tasks_completed(0, 1),
m_total_submitted_tasks(0),
m_total_completed_tasks(0),
m_exit_flag(false)
{
utils::zero_object(m_threads);
bool status = init(num_threads);
CRNLIB_VERIFY(status);
}
task_pool::~task_pool()
{
deinit();
}
bool task_pool::init(uint num_threads)
{
CRNLIB_ASSERT(num_threads <= cMaxThreads);
num_threads = math::minimum<uint>(num_threads, cMaxThreads);
deinit();
bool succeeded = true;
m_num_threads = 0;
while (m_num_threads < num_threads)
{
int status = pthread_create(&m_threads[m_num_threads], NULL, thread_func, this);
if (status)
{
succeeded = false;
break;
}
m_num_threads++;
}
if (!succeeded)
{
deinit();
return false;
}
return true;
}
void task_pool::deinit()
{
if (m_num_threads)
{
join();
atomic_exchange32(&m_exit_flag, true);
m_tasks_available.release(m_num_threads);
for (uint i = 0; i < m_num_threads; i++)
pthread_join(m_threads[i], NULL);
m_num_threads = 0;
atomic_exchange32(&m_exit_flag, false);
}
m_task_stack.clear();
m_total_submitted_tasks = 0;
m_total_completed_tasks = 0;
}
bool task_pool::queue_task(task_callback_func pFunc, uint64 data, void* pData_ptr)
{
CRNLIB_ASSERT(m_num_threads);
CRNLIB_ASSERT(pFunc);
task tsk;
tsk.m_callback = pFunc;
tsk.m_data = data;
tsk.m_pData_ptr = pData_ptr;
tsk.m_flags = 0;
atomic_increment32(&m_total_submitted_tasks);
if (!m_task_stack.try_push(tsk))
{
atomic_increment32(&m_total_completed_tasks);
return false;
}
m_tasks_available.release(1);
return true;
}
// It's the object's responsibility to delete pObj within the execute_task() method, if needed!
bool task_pool::queue_task(executable_task* pObj, uint64 data, void* pData_ptr)
{
CRNLIB_ASSERT(m_num_threads);
CRNLIB_ASSERT(pObj);
task tsk;
tsk.m_pObj = pObj;
tsk.m_data = data;
tsk.m_pData_ptr = pData_ptr;
tsk.m_flags = cTaskFlagObject;
atomic_increment32(&m_total_submitted_tasks);
if (!m_task_stack.try_push(tsk))
{
atomic_increment32(&m_total_completed_tasks);
return false;
}
m_tasks_available.release(1);
return true;
}
void task_pool::process_task(task& tsk)
{
if (tsk.m_flags & cTaskFlagObject)
tsk.m_pObj->execute_task(tsk.m_data, tsk.m_pData_ptr);
else
tsk.m_callback(tsk.m_data, tsk.m_pData_ptr);
if (atomic_increment32(&m_total_completed_tasks) == m_total_submitted_tasks)
{
// Try to signal the semaphore (the max count is 1 so this may actually fail).
m_all_tasks_completed.try_release();
}
}
void task_pool::join()
{
// Try to steal any outstanding tasks. This could cause one or more worker threads to wake up and immediately go back to sleep, which is wasteful but should be harmless.
task tsk;
while (m_task_stack.pop(tsk))
process_task(tsk);
// At this point the task stack is empty.
// Now wait for all concurrent tasks to complete. The m_all_tasks_completed semaphore has a max count of 1, so it's possible it could have saturated to 1 as the tasks
// where issued and asynchronously completed, so this loop may iterate a few times.
const int total_submitted_tasks = atomic_add32(&m_total_submitted_tasks, 0);
while (m_total_completed_tasks != total_submitted_tasks)
{
// If the previous (m_total_completed_tasks != total_submitted_tasks) check failed the semaphore MUST be eventually signalled once the last task completes.
// So I think this can actually be an INFINITE delay, but it shouldn't really matter if it's 1ms.
m_all_tasks_completed.wait(1);
}
}
void * task_pool::thread_func(void *pContext)
{
task_pool* pPool = static_cast<task_pool*>(pContext);
task tsk;
for ( ; ; )
{
if (!pPool->m_tasks_available.wait())
break;
if (pPool->m_exit_flag)
break;
if (pPool->m_task_stack.pop(tsk))
{
pPool->process_task(tsk);
}
}
return NULL;
}
} // namespace crnlib
#endif // CRNLIB_USE_PTHREADS_API
+347
View File
@@ -0,0 +1,347 @@
// File: crn_threading_pthreads.h
// See Copyright Notice and license at the end of include/crnlib.h
#pragma once
#if CRNLIB_USE_PTHREADS_API
#include "crn_atomics.h"
#if CRNLIB_NO_ATOMICS
#error No atomic operations defined in crn_platform.h!
#endif
#include <pthread.h>
#include <semaphore.h>
#include <unistd.h>
namespace crnlib
{
// g_number_of_processors defaults to 1. Will be higher on multicore machines.
extern uint g_number_of_processors;
void crn_threading_init();
typedef uint64 crn_thread_id_t;
crn_thread_id_t crn_get_current_thread_id();
void crn_sleep(unsigned int milliseconds);
uint crn_get_max_helper_threads();
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:
pthread_mutex_t m_mutex;
#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;
};
class semaphore
{
CRNLIB_NO_COPY_OR_ASSIGNMENT_OP(semaphore);
public:
semaphore(long initialCount = 0, long maximumCount = 1, const char* pName = NULL);
~semaphore();
void release(long releaseCount = 1);
void try_release(long releaseCount = 1);
bool wait(uint32 milliseconds = cUINT32_MAX);
private:
sem_t m_sem;
};
class spinlock
{
public:
spinlock();
~spinlock();
void lock();
void unlock();
private:
pthread_spinlock_t m_spinlock;
};
class scoped_spinlock
{
scoped_spinlock(const scoped_spinlock&);
scoped_spinlock& operator= (const scoped_spinlock&);
public:
inline scoped_spinlock(spinlock& lock) : m_lock(lock) { m_lock.lock(); }
inline ~scoped_spinlock() { m_lock.unlock(); }
private:
spinlock& m_lock;
};
template<typename T, uint cMaxSize>
class tsstack
{
public:
inline tsstack() :
m_top(0)
{
}
inline ~tsstack()
{
}
inline void clear()
{
m_spinlock.lock();
m_top = 0;
m_spinlock.unlock();
}
inline bool try_push(const T& obj)
{
bool result = false;
m_spinlock.lock();
if (m_top < (int)cMaxSize)
{
m_stack[m_top++] = obj;
result = true;
}
m_spinlock.unlock();
return result;
}
inline bool pop(T& obj)
{
bool result = false;
m_spinlock.lock();
if (m_top > 0)
{
obj = m_stack[--m_top];
result = true;
}
m_spinlock.unlock();
return result;
}
private:
spinlock m_spinlock;
T m_stack[cMaxSize];
int m_top;
};
class task_pool
{
public:
task_pool();
task_pool(uint num_threads);
~task_pool();
enum { cMaxThreads = 16 };
bool init(uint num_threads);
void deinit();
inline uint get_num_threads() const { return m_num_threads; }
inline uint32 get_num_outstanding_tasks() const { return m_total_submitted_tasks - m_total_completed_tasks; }
// C-style task callback
typedef void (*task_callback_func)(uint64 data, void* pData_ptr);
bool queue_task(task_callback_func pFunc, uint64 data = 0, void* pData_ptr = NULL);
class executable_task
{
public:
virtual void execute_task(uint64 data, void* pData_ptr) = 0;
};
// It's the caller's responsibility to delete pObj within the execute_task() method, if needed!
bool queue_task(executable_task* pObj, uint64 data = 0, void* pData_ptr = NULL);
template<typename S, typename T>
inline bool queue_object_task(S* pObject, T pObject_method, uint64 data = 0, void* pData_ptr = NULL);
template<typename S, typename T>
inline bool queue_multiple_object_tasks(S* pObject, T pObject_method, uint64 first_data, uint num_tasks, void* pData_ptr = NULL);
void join();
private:
struct task
{
inline task() : m_data(0), m_pData_ptr(NULL), m_pObj(NULL), m_flags(0) { }
uint64 m_data;
void* m_pData_ptr;
union
{
task_callback_func m_callback;
executable_task* m_pObj;
};
uint m_flags;
};
tsstack<task, cMaxThreads> m_task_stack;
uint m_num_threads;
pthread_t m_threads[cMaxThreads];
// Signalled whenever a task is queued up.
semaphore m_tasks_available;
// Signalled when all outstanding tasks are completed.
semaphore m_all_tasks_completed;
enum task_flags
{
cTaskFlagObject = 1
};
volatile atomic32_t m_total_submitted_tasks;
volatile atomic32_t m_total_completed_tasks;
volatile atomic32_t m_exit_flag;
void process_task(task& tsk);
static void* thread_func(void *pContext);
};
enum object_task_flags
{
cObjectTaskFlagDefault = 0,
cObjectTaskFlagDeleteAfterExecution = 1
};
template<typename T>
class object_task : public task_pool::executable_task
{
public:
object_task(uint flags = cObjectTaskFlagDefault) :
m_pObject(NULL),
m_pMethod(NULL),
m_flags(flags)
{
}
typedef void (T::*object_method_ptr)(uint64 data, void* pData_ptr);
object_task(T* pObject, object_method_ptr pMethod, uint flags = cObjectTaskFlagDefault) :
m_pObject(pObject),
m_pMethod(pMethod),
m_flags(flags)
{
CRNLIB_ASSERT(pObject && pMethod);
}
void init(T* pObject, object_method_ptr pMethod, uint flags = cObjectTaskFlagDefault)
{
CRNLIB_ASSERT(pObject && pMethod);
m_pObject = pObject;
m_pMethod = pMethod;
m_flags = flags;
}
T* get_object() const { return m_pObject; }
object_method_ptr get_method() const { return m_pMethod; }
virtual void execute_task(uint64 data, void* pData_ptr)
{
(m_pObject->*m_pMethod)(data, pData_ptr);
if (m_flags & cObjectTaskFlagDeleteAfterExecution)
crnlib_delete(this);
}
protected:
T* m_pObject;
object_method_ptr m_pMethod;
uint m_flags;
};
template<typename S, typename T>
inline bool task_pool::queue_object_task(S* pObject, T pObject_method, uint64 data, void* pData_ptr)
{
object_task<S> *pTask = crnlib_new< object_task<S> >(pObject, pObject_method, cObjectTaskFlagDeleteAfterExecution);
if (!pTask)
return false;
return queue_task(pTask, data, pData_ptr);
}
template<typename S, typename T>
inline bool task_pool::queue_multiple_object_tasks(S* pObject, T pObject_method, uint64 first_data, uint num_tasks, void* pData_ptr)
{
CRNLIB_ASSERT(m_num_threads);
CRNLIB_ASSERT(pObject);
CRNLIB_ASSERT(num_tasks);
if (!num_tasks)
return true;
bool status = true;
uint i;
for (i = 0; i < num_tasks; i++)
{
task tsk;
tsk.m_pObj = crnlib_new< object_task<S> >(pObject, pObject_method, cObjectTaskFlagDeleteAfterExecution);
if (!tsk.m_pObj)
{
status = false;
break;
}
tsk.m_data = first_data + i;
tsk.m_pData_ptr = pData_ptr;
tsk.m_flags = cTaskFlagObject;
atomic_increment32(&m_total_submitted_tasks);
if (!m_task_stack.try_push(tsk))
{
atomic_increment32(&m_total_completed_tasks);
status = false;
break;
}
}
if (i)
{
m_tasks_available.release(i);
}
return status;
}
} // namespace crnlib
#endif // CRNLIB_USE_PTHREADS_API
+429
View File
@@ -0,0 +1,429 @@
// File: crn_win32_threading.cpp
// See Copyright Notice and license at the end of inc/crnlib.h
#include "crn_core.h"
#include "crn_threading_win32.h"
#include "crn_winhdr.h"
#include <process.h>
namespace crnlib
{
uint g_number_of_processors = 1;
void crn_threading_init()
{
SYSTEM_INFO g_system_info;
GetSystemInfo(&g_system_info);
g_number_of_processors = math::maximum<uint>(1U, g_system_info.dwNumberOfProcessors);
}
crn_thread_id_t crn_get_current_thread_id()
{
return static_cast<crn_thread_id_t>(GetCurrentThreadId());
}
void crn_sleep(unsigned int milliseconds)
{
Sleep(milliseconds);
}
uint crn_get_max_helper_threads()
{
if (g_number_of_processors > 1)
{
// use all CPU's
return CRNLIB_MIN((int)task_pool::cMaxThreads, (int)g_number_of_processors - 1);
}
return 0;
}
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;
status = InitializeCriticalSectionAndSpinCount(&m_cs, spin_count);
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);
}
void spinlock::lock(uint32 max_spins, bool yielding)
{
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;
}
}
}
}
CRNLIB_MEMORY_IMPORT_BARRIER
}
void spinlock::unlock()
{
CRNLIB_MEMORY_EXPORT_BARRIER
InterlockedExchange((volatile long*)&m_flag, FALSE);
}
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::try_release(int32 releaseCount, int32 *pPreviousCount)
{
CRNLIB_ASSUME(sizeof(LONG) == sizeof(int32));
return ReleaseSemaphore(m_handle, releaseCount, (LPLONG)pPreviousCount) != 0;
}
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;
}
task_pool::task_pool() :
m_pTask_stack(crnlib_new<ts_task_stack_t>()),
m_num_threads(0),
m_tasks_available(0, 32767),
m_all_tasks_completed(0, 1),
m_total_submitted_tasks(0),
m_total_completed_tasks(0),
m_exit_flag(false)
{
utils::zero_object(m_threads);
}
task_pool::task_pool(uint num_threads) :
m_pTask_stack(crnlib_new<ts_task_stack_t>()),
m_num_threads(0),
m_tasks_available(0, 32767),
m_all_tasks_completed(0, 1),
m_total_submitted_tasks(0),
m_total_completed_tasks(0),
m_exit_flag(false)
{
utils::zero_object(m_threads);
bool status = init(num_threads);
CRNLIB_VERIFY(status);
}
task_pool::~task_pool()
{
deinit();
crnlib_delete(m_pTask_stack);
}
bool task_pool::init(uint num_threads)
{
CRNLIB_ASSERT(num_threads <= cMaxThreads);
num_threads = math::minimum<uint>(num_threads, cMaxThreads);
deinit();
bool succeeded = true;
m_num_threads = 0;
while (m_num_threads < num_threads)
{
m_threads[m_num_threads] = (HANDLE)_beginthreadex(NULL, 32768, thread_func, this, 0, NULL);
CRNLIB_ASSERT(m_threads[m_num_threads] != 0);
if (!m_threads[m_num_threads])
{
succeeded = false;
break;
}
m_num_threads++;
}
if (!succeeded)
{
deinit();
return false;
}
return true;
}
void task_pool::deinit()
{
if (m_num_threads)
{
join();
// Set exit flag, then release all threads. Each should wakeup and exit.
atomic_exchange32(&m_exit_flag, true);
m_tasks_available.release(m_num_threads);
// Now wait for each thread to exit.
for (uint i = 0; i < m_num_threads; i++)
{
if (m_threads[i])
{
for ( ; ; )
{
// Can be an INFINITE delay, but set at 30 seconds so this function always provably exits.
DWORD result = WaitForSingleObject(m_threads[i], 30000);
if ((result == WAIT_OBJECT_0) || (result == WAIT_ABANDONED))
break;
}
CloseHandle(m_threads[i]);
m_threads[i] = NULL;
}
}
m_num_threads = 0;
atomic_exchange32(&m_exit_flag, false);
}
if (m_pTask_stack)
m_pTask_stack->clear();
m_total_submitted_tasks = 0;
m_total_completed_tasks = 0;
}
bool task_pool::queue_task(task_callback_func pFunc, uint64 data, void* pData_ptr)
{
CRNLIB_ASSERT(m_num_threads);
CRNLIB_ASSERT(pFunc);
task tsk;
tsk.m_callback = pFunc;
tsk.m_data = data;
tsk.m_pData_ptr = pData_ptr;
tsk.m_flags = 0;
atomic_increment32(&m_total_submitted_tasks);
if (!m_pTask_stack->try_push(tsk))
{
atomic_increment32(&m_total_completed_tasks);
return false;
}
m_tasks_available.release(1);
return true;
}
// It's the object's responsibility to delete pObj within the execute_task() method, if needed!
bool task_pool::queue_task(executable_task* pObj, uint64 data, void* pData_ptr)
{
CRNLIB_ASSERT(m_num_threads);
CRNLIB_ASSERT(pObj);
task tsk;
tsk.m_pObj = pObj;
tsk.m_data = data;
tsk.m_pData_ptr = pData_ptr;
tsk.m_flags = cTaskFlagObject;
atomic_increment32(&m_total_submitted_tasks);
if (!m_pTask_stack->try_push(tsk))
{
atomic_increment32(&m_total_completed_tasks);
return false;
}
m_tasks_available.release(1);
return true;
}
void task_pool::process_task(task& tsk)
{
if (tsk.m_flags & cTaskFlagObject)
tsk.m_pObj->execute_task(tsk.m_data, tsk.m_pData_ptr);
else
tsk.m_callback(tsk.m_data, tsk.m_pData_ptr);
if (atomic_increment32(&m_total_completed_tasks) == m_total_submitted_tasks)
{
// Try to signal the semaphore (the max count is 1 so this may actually fail).
m_all_tasks_completed.try_release();
}
}
void task_pool::join()
{
// Try to steal any outstanding tasks. This could cause one or more worker threads to wake up and immediately go back to sleep, which is wasteful but should be harmless.
task tsk;
while (m_pTask_stack->pop(tsk))
process_task(tsk);
// At this point the task stack is empty.
// Now wait for all concurrent tasks to complete. The m_all_tasks_completed semaphore has a max count of 1, so it's possible it could have saturated to 1 as the tasks
// where issued and asynchronously completed, so this loop may iterate a few times.
const int total_submitted_tasks = atomic_add32(&m_total_submitted_tasks, 0);
while (m_total_completed_tasks != total_submitted_tasks)
{
// If the previous (m_total_completed_tasks != total_submitted_tasks) check failed the semaphore MUST be eventually signalled once the last task completes.
// So I think this can actually be an INFINITE delay, but it shouldn't really matter if it's 1ms.
m_all_tasks_completed.wait(1);
}
}
unsigned __stdcall task_pool::thread_func(void* pContext)
{
task_pool* pPool = static_cast<task_pool*>(pContext);
for ( ; ; )
{
if (!pPool->m_tasks_available.wait())
break;
if (pPool->m_exit_flag)
break;
task tsk;
if (pPool->m_pTask_stack->pop(tsk))
pPool->process_task(tsk);
}
_endthreadex(0);
return 0;
}
}
+418
View File
@@ -0,0 +1,418 @@
// File: crn_win32_threading.h
// See Copyright Notice and license at the end of inc/crnlib.h
#pragma once
#include "crn_atomics.h"
#if CRNLIB_NO_ATOMICS
#error No atomic operations defined in crn_platform.h!
#endif
namespace crnlib
{
// g_number_of_processors defaults to 1. Will be higher on multicore machines.
extern uint g_number_of_processors;
void crn_threading_init();
typedef uint64 crn_thread_id_t;
crn_thread_id_t crn_get_current_thread_id();
void crn_sleep(unsigned int milliseconds);
uint crn_get_max_helper_threads();
class mutex
{
CRNLIB_NO_COPY_OR_ASSIGNMENT_OP(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;
};
// Simple non-recursive spinlock.
class spinlock
{
CRNLIB_NO_COPY_OR_ASSIGNMENT_OP(spinlock);
public:
inline spinlock() : m_flag(0) { }
void lock(uint32 max_spins = 4096, bool yielding = true);
inline void lock_no_barrier(uint32 max_spins = 4096, bool yielding = true) { lock(max_spins, yielding); }
void unlock();
inline void unlock_no_barrier() { m_flag = CRNLIB_FALSE; }
private:
volatile int32 m_flag;
};
class scoped_spinlock
{
scoped_spinlock(const scoped_spinlock&);
scoped_spinlock& operator= (const scoped_spinlock&);
public:
inline scoped_spinlock(spinlock& lock) : m_lock(lock) { m_lock.lock(); }
inline ~scoped_spinlock() { m_lock.unlock(); }
private:
spinlock& m_lock;
};
class semaphore
{
CRNLIB_NO_COPY_OR_ASSIGNMENT_OP(semaphore);
public:
semaphore(int32 initialCount = 0, int32 maximumCount = 1, const char* pName = NULL);
~semaphore();
inline HANDLE get_handle(void) const { return m_handle; }
void release(int32 releaseCount = 1, int32 *pPreviousCount = NULL);
bool try_release(int32 releaseCount = 1, int32 *pPreviousCount = NULL);
bool wait(uint32 milliseconds = cUINT32_MAX);
private:
HANDLE m_handle;
};
template<typename T>
class tsstack
{
CRNLIB_NO_COPY_OR_ASSIGNMENT_OP(tsstack);
public:
inline tsstack(bool use_freelist = true) :
m_use_freelist(use_freelist)
{
CRNLIB_VERIFY(((ptr_bits_t)this & (CRNLIB_GET_ALIGNMENT(tsstack) - 1)) == 0);
InitializeSListHead(&m_stack_head);
InitializeSListHead(&m_freelist_head);
}
inline ~tsstack()
{
clear();
}
inline void clear()
{
for ( ; ; )
{
node* pNode = (node*)InterlockedPopEntrySList(&m_stack_head);
if (!pNode)
break;
CRNLIB_MEMORY_IMPORT_BARRIER
helpers::destruct(&pNode->m_obj);
crnlib_free(pNode);
}
flush_freelist();
}
inline void flush_freelist()
{
if (!m_use_freelist)
return;
for ( ; ; )
{
node* pNode = (node*)InterlockedPopEntrySList(&m_freelist_head);
if (!pNode)
break;
CRNLIB_MEMORY_IMPORT_BARRIER
crnlib_free(pNode);
}
}
inline bool try_push(const T& obj)
{
node* pNode = alloc_node();
if (!pNode)
return false;
helpers::construct(&pNode->m_obj, obj);
CRNLIB_MEMORY_EXPORT_BARRIER
InterlockedPushEntrySList(&m_stack_head, &pNode->m_slist_entry);
return true;
}
inline bool pop(T& obj)
{
node* pNode = (node*)InterlockedPopEntrySList(&m_stack_head);
if (!pNode)
return false;
CRNLIB_MEMORY_IMPORT_BARRIER
obj = pNode->m_obj;
helpers::destruct(&pNode->m_obj);
free_node(pNode);
return true;
}
private:
SLIST_HEADER m_stack_head;
SLIST_HEADER m_freelist_head;
struct node
{
SLIST_ENTRY m_slist_entry;
T m_obj;
};
bool m_use_freelist;
inline node* alloc_node()
{
node* pNode = m_use_freelist ? (node*)InterlockedPopEntrySList(&m_freelist_head) : NULL;
if (!pNode)
pNode = (node*)crnlib_malloc(sizeof(node));
return pNode;
}
inline void free_node(node* pNode)
{
if (m_use_freelist)
InterlockedPushEntrySList(&m_freelist_head, &pNode->m_slist_entry);
else
crnlib_free(pNode);
}
};
// Simple multithreaded task pool. This class assumes a single global thread will be issuing tasks and joining.
class task_pool
{
CRNLIB_NO_COPY_OR_ASSIGNMENT_OP(task_pool);
public:
task_pool();
task_pool(uint num_threads);
~task_pool();
enum { cMaxThreads = 16 };
bool init(uint num_threads);
void deinit();
inline uint get_num_threads() const { return m_num_threads; }
inline uint32 get_num_outstanding_tasks() const { return m_total_submitted_tasks - m_total_completed_tasks; }
// C-style task callback
typedef void (*task_callback_func)(uint64 data, void* pData_ptr);
bool queue_task(task_callback_func pFunc, uint64 data = 0, void* pData_ptr = NULL);
class executable_task
{
public:
virtual void execute_task(uint64 data, void* pData_ptr) = 0;
};
// It's the caller's responsibility to delete pObj within the execute_task() method, if needed!
bool queue_task(executable_task* pObj, uint64 data = 0, void* pData_ptr = NULL);
template<typename S, typename T>
inline bool queue_object_task(S* pObject, T pObject_method, uint64 data = 0, void* pData_ptr = NULL);
template<typename S, typename T>
inline bool queue_multiple_object_tasks(S* pObject, T pObject_method, uint64 first_data, uint num_tasks, void* pData_ptr = NULL);
// Waits for all outstanding tasks (if any) to complete.
// The calling thread will steal any outstanding tasks from worker threads, if possible.
void join();
private:
struct task
{
//inline task() : m_data(0), m_pData_ptr(NULL), m_pObj(NULL), m_flags(0) { }
uint64 m_data;
void* m_pData_ptr;
union
{
task_callback_func m_callback;
executable_task* m_pObj;
};
uint m_flags;
};
typedef tsstack<task> ts_task_stack_t;
ts_task_stack_t* m_pTask_stack;
uint m_num_threads;
HANDLE m_threads[cMaxThreads];
// Signalled whenever a task is queued up.
semaphore m_tasks_available;
// Signalled when all outstanding tasks are completed.
semaphore m_all_tasks_completed;
enum task_flags
{
cTaskFlagObject = 1
};
volatile atomic32_t m_total_submitted_tasks;
volatile atomic32_t m_total_completed_tasks;
volatile atomic32_t m_exit_flag;
void process_task(task& tsk);
static unsigned __stdcall thread_func(void* pContext);
};
enum object_task_flags
{
cObjectTaskFlagDefault = 0,
cObjectTaskFlagDeleteAfterExecution = 1
};
template<typename T>
class object_task : public task_pool::executable_task
{
public:
object_task(uint flags = cObjectTaskFlagDefault) :
m_pObject(NULL),
m_pMethod(NULL),
m_flags(flags)
{
}
typedef void (T::*object_method_ptr)(uint64 data, void* pData_ptr);
object_task(T* pObject, object_method_ptr pMethod, uint flags = cObjectTaskFlagDefault) :
m_pObject(pObject),
m_pMethod(pMethod),
m_flags(flags)
{
CRNLIB_ASSERT(pObject && pMethod);
}
void init(T* pObject, object_method_ptr pMethod, uint flags = cObjectTaskFlagDefault)
{
CRNLIB_ASSERT(pObject && pMethod);
m_pObject = pObject;
m_pMethod = pMethod;
m_flags = flags;
}
T* get_object() const { return m_pObject; }
object_method_ptr get_method() const { return m_pMethod; }
virtual void execute_task(uint64 data, void* pData_ptr)
{
(m_pObject->*m_pMethod)(data, pData_ptr);
if (m_flags & cObjectTaskFlagDeleteAfterExecution)
crnlib_delete(this);
}
protected:
T* m_pObject;
object_method_ptr m_pMethod;
uint m_flags;
};
template<typename S, typename T>
inline bool task_pool::queue_object_task(S* pObject, T pObject_method, uint64 data, void* pData_ptr)
{
object_task<S> *pTask = crnlib_new< object_task<S> >(pObject, pObject_method, cObjectTaskFlagDeleteAfterExecution);
if (!pTask)
return false;
return queue_task(pTask, data, pData_ptr);
}
template<typename S, typename T>
inline bool task_pool::queue_multiple_object_tasks(S* pObject, T pObject_method, uint64 first_data, uint num_tasks, void* pData_ptr)
{
CRNLIB_ASSERT(m_num_threads);
CRNLIB_ASSERT(pObject);
CRNLIB_ASSERT(num_tasks);
if (!num_tasks)
return true;
bool status = true;
uint i;
for (i = 0; i < num_tasks; i++)
{
task tsk;
tsk.m_pObj = crnlib_new< object_task<S> >(pObject, pObject_method, cObjectTaskFlagDeleteAfterExecution);
if (!tsk.m_pObj)
{
status = false;
break;
}
tsk.m_data = first_data + i;
tsk.m_pData_ptr = pData_ptr;
tsk.m_flags = cTaskFlagObject;
atomic_increment32(&m_total_submitted_tasks);
if (!m_pTask_stack->try_push(tsk))
{
atomic_increment32(&m_total_completed_tasks);
status = false;
break;
}
}
if (i)
{
m_tasks_available.release(i);
}
return status;
}
} // namespace crnlib
+155
View File
@@ -0,0 +1,155 @@
// File: crn_win32_timer.cpp
// See Copyright Notice and license at the end of inc/crnlib.h
#include "crn_core.h"
#include "crn_timer.h"
#include <time.h>
#include "crn_timer.h"
#if CRNLIB_USE_WIN32_API
#include "crn_winhdr.h"
#endif
namespace crnlib
{
unsigned long long timer::g_init_ticks;
unsigned long long timer::g_freq;
double timer::g_inv_freq;
#if defined(CRNLIB_USE_WIN32_API)
inline void query_counter(timer_ticks *pTicks)
{
QueryPerformanceCounter(reinterpret_cast<LARGE_INTEGER*>(pTicks));
}
inline void query_counter_frequency(timer_ticks *pTicks)
{
QueryPerformanceFrequency(reinterpret_cast<LARGE_INTEGER*>(pTicks));
}
#elif defined(__GNUC__)
#include <sys/timex.h>
inline void query_counter(timer_ticks *pTicks)
{
struct timeval cur_time;
gettimeofday(&cur_time, NULL);
*pTicks = static_cast<unsigned long long>(cur_time.tv_sec)*1000000ULL + static_cast<unsigned long long>(cur_time.tv_usec);
}
inline void query_counter_frequency(timer_ticks *pTicks)
{
*pTicks = 1000000;
}
#else
#error Unimplemented
#endif
timer::timer() :
m_start_time(0),
m_stop_time(0),
m_started(false),
m_stopped(false)
{
if (!g_inv_freq)
init();
}
timer::timer(timer_ticks start_ticks)
{
if (!g_inv_freq)
init();
m_start_time = start_ticks;
m_started = true;
m_stopped = false;
}
void timer::start(timer_ticks start_ticks)
{
m_start_time = start_ticks;
m_started = true;
m_stopped = false;
}
void timer::start()
{
query_counter(&m_start_time);
m_started = true;
m_stopped = false;
}
void timer::stop()
{
CRNLIB_ASSERT(m_started);
query_counter(&m_stop_time);
m_stopped = true;
}
double timer::get_elapsed_secs() const
{
CRNLIB_ASSERT(m_started);
if (!m_started)
return 0;
timer_ticks stop_time = m_stop_time;
if (!m_stopped)
query_counter(&stop_time);
timer_ticks delta = stop_time - m_start_time;
return delta * g_inv_freq;
}
timer_ticks timer::get_elapsed_us() const
{
CRNLIB_ASSERT(m_started);
if (!m_started)
return 0;
timer_ticks stop_time = m_stop_time;
if (!m_stopped)
query_counter(&stop_time);
timer_ticks delta = stop_time - m_start_time;
return (delta * 1000000ULL + (g_freq >> 1U)) / g_freq;
}
void timer::init()
{
if (!g_inv_freq)
{
query_counter_frequency(&g_freq);
g_inv_freq = 1.0f / g_freq;
query_counter(&g_init_ticks);
}
}
timer_ticks timer::get_init_ticks()
{
if (!g_inv_freq)
init();
return g_init_ticks;
}
timer_ticks timer::get_ticks()
{
if (!g_inv_freq)
init();
timer_ticks ticks;
query_counter(&ticks);
return ticks - g_init_ticks;
}
double timer::ticks_to_secs(timer_ticks ticks)
{
if (!g_inv_freq)
init();
return ticks * g_inv_freq;
}
} // namespace crnlib
+45
View File
@@ -0,0 +1,45 @@
// File: crn_win32_timer.h
// See Copyright Notice and license at the end of inc/crnlib.h
#pragma once
namespace crnlib
{
typedef unsigned long long timer_ticks;
class timer
{
public:
timer();
timer(timer_ticks start_ticks);
void start();
void start(timer_ticks start_ticks);
void stop();
double get_elapsed_secs() const;
inline double get_elapsed_ms() const { return get_elapsed_secs() * 1000.0f; }
timer_ticks get_elapsed_us() const;
static void init();
static inline timer_ticks get_ticks_per_sec() { return g_freq; }
static timer_ticks get_init_ticks();
static timer_ticks get_ticks();
static double ticks_to_secs(timer_ticks ticks);
static inline double ticks_to_ms(timer_ticks ticks) { return ticks_to_secs(ticks) * 1000.0f; }
static inline double get_secs() { return ticks_to_secs(get_ticks()); }
static inline double get_ms() { return ticks_to_ms(get_ticks()); }
private:
static timer_ticks g_init_ticks;
static timer_ticks g_freq;
static double g_inv_freq;
timer_ticks m_start_time;
timer_ticks m_stop_time;
bool m_started : 1;
bool m_stopped : 1;
};
} // namespace crnlib
+15 -1
View File
@@ -4,6 +4,15 @@
namespace crnlib namespace crnlib
{ {
template<typename T> struct int_traits { enum { cMin = crnlib::cINT32_MIN, cMax = crnlib::cINT32_MAX, cSigned = true }; };
template<> struct int_traits<int8> { enum { cMin = crnlib::cINT8_MIN, cMax = crnlib::cINT8_MAX, cSigned = true }; };
template<> struct int_traits<int16> { enum { cMin = crnlib::cINT16_MIN, cMax = crnlib::cINT16_MAX, cSigned = true }; };
template<> struct int_traits<int32> { enum { cMin = crnlib::cINT32_MIN, cMax = crnlib::cINT32_MAX, cSigned = true }; };
template<> struct int_traits<uint8> { enum { cMin = 0, cMax = crnlib::cUINT8_MAX, cSigned = false }; };
template<> struct int_traits<uint16> { enum { cMin = 0, cMax = crnlib::cUINT16_MAX, cSigned = false }; };
template<> struct int_traits<uint32> { enum { cMin = 0, cMax = crnlib::cUINT32_MAX, cSigned = false }; };
template<typename T> template<typename T>
struct scalar_type struct scalar_type
{ {
@@ -43,8 +52,13 @@ namespace crnlib
CRNLIB_DEFINE_BUILT_IN_TYPE(unsigned int) CRNLIB_DEFINE_BUILT_IN_TYPE(unsigned int)
CRNLIB_DEFINE_BUILT_IN_TYPE(long) CRNLIB_DEFINE_BUILT_IN_TYPE(long)
CRNLIB_DEFINE_BUILT_IN_TYPE(unsigned long) CRNLIB_DEFINE_BUILT_IN_TYPE(unsigned long)
#ifdef __GNUC__
CRNLIB_DEFINE_BUILT_IN_TYPE(long long)
CRNLIB_DEFINE_BUILT_IN_TYPE(unsigned long long)
#else
CRNLIB_DEFINE_BUILT_IN_TYPE(__int64) CRNLIB_DEFINE_BUILT_IN_TYPE(__int64)
CRNLIB_DEFINE_BUILT_IN_TYPE(unsigned __int64) CRNLIB_DEFINE_BUILT_IN_TYPE(unsigned __int64)
#endif
CRNLIB_DEFINE_BUILT_IN_TYPE(float) CRNLIB_DEFINE_BUILT_IN_TYPE(float)
CRNLIB_DEFINE_BUILT_IN_TYPE(double) CRNLIB_DEFINE_BUILT_IN_TYPE(double)
CRNLIB_DEFINE_BUILT_IN_TYPE(long double) CRNLIB_DEFINE_BUILT_IN_TYPE(long double)
@@ -69,7 +83,7 @@ namespace crnlib
#define CRNLIB_IS_SCALAR_TYPE(T) (scalar_type<T>::cFlag) #define CRNLIB_IS_SCALAR_TYPE(T) (scalar_type<T>::cFlag)
#define CRNLIB_IS_BITWISE_COPYABLE(T) ((scalar_type<T>::cFlag) || (bitwise_copyable<T>::cFlag) || CRNLIB_IS_POD(T)) #define CRNLIB_IS_BITWISE_COPYABLE(T) (CRNLIB_IS_SCALAR_TYPE(T) || CRNLIB_IS_POD(T) || (bitwise_copyable<T>::cFlag))
#define CRNLIB_IS_BITWISE_MOVABLE(T) (CRNLIB_IS_BITWISE_COPYABLE(T) || (bitwise_movable<T>::cFlag)) #define CRNLIB_IS_BITWISE_MOVABLE(T) (CRNLIB_IS_BITWISE_COPYABLE(T) || (bitwise_movable<T>::cFlag))
+10 -6
View File
@@ -137,7 +137,7 @@ namespace crnlib
return m_codebook; return m_codebook;
} }
const uint find_best_codebook_entry(const VectorType& v) const uint find_best_codebook_entry(const VectorType& v) const
{ {
uint cur_node_index = 0; uint cur_node_index = 0;
@@ -161,7 +161,7 @@ namespace crnlib
} }
} }
const uint find_best_codebook_entry_fs(const VectorType& v) const uint find_best_codebook_entry_fs(const VectorType& v) const
{ {
float best_dist = math::cNearlyInfinite; float best_dist = math::cNearlyInfinite;
uint best_index = 0; uint best_index = 0;
@@ -222,7 +222,7 @@ namespace crnlib
if (parent_node.m_vectors.size() == 1) if (parent_node.m_vectors.size() == 1)
return; return;
VectorType furthest; VectorType furthest(0);
double furthest_dist = -1.0f; double furthest_dist = -1.0f;
for (uint i = 0; i < parent_node.m_vectors.size(); i++) for (uint i = 0; i < parent_node.m_vectors.size(); i++)
@@ -272,9 +272,13 @@ namespace crnlib
covar[x][y] = covar[x][y] + v[x] * w[y]; covar[x][y] = covar[x][y] + v[x] * w[y];
} }
for (uint x = 0; x < N - 1; x++) if (N > 1)
for (uint y = x + 1; y < N; y++) {
covar[y][x] = covar[x][y]; //for (uint x = 0; x < (N - 1); x++)
for (uint x = 0; x != (N - 1); x++)
for (uint y = x + 1; y < N; y++)
covar[y][x] = covar[x][y];
}
covar /= float(parent_node.m_total_weight); covar /= float(parent_node.m_total_weight);
+27 -22
View File
@@ -12,31 +12,36 @@ namespace crnlib
typedef uint32 uint; typedef uint32 uint;
typedef signed int int32; typedef signed int int32;
typedef unsigned __int64 uint64; #ifdef __GNUC__
typedef signed __int64 int64; typedef unsigned long long uint64;
typedef long long int64;
#else
typedef unsigned __int64 uint64;
typedef signed __int64 int64;
#endif
const uint8 UINT8_MIN = 0; const uint8 cUINT8_MIN = 0;
const uint8 UINT8_MAX = 0xFFU; const uint8 cUINT8_MAX = 0xFFU;
const uint16 UINT16_MIN = 0; const uint16 cUINT16_MIN = 0;
const uint16 UINT16_MAX = 0xFFFFU; const uint16 cUINT16_MAX = 0xFFFFU;
const uint32 UINT32_MIN = 0; const uint32 cUINT32_MIN = 0;
const uint32 UINT32_MAX = 0xFFFFFFFFU; const uint32 cUINT32_MAX = 0xFFFFFFFFU;
const uint64 UINT64_MIN = 0; const uint64 cUINT64_MIN = 0;
const uint64 UINT64_MAX = 0xFFFFFFFFFFFFFFFFULL; //0xFFFFFFFFFFFFFFFFui64; const uint64 cUINT64_MAX = 0xFFFFFFFFFFFFFFFFULL; //0xFFFFFFFFFFFFFFFFui64;
const int8 INT8_MIN = -128; const int8 cINT8_MIN = -128;
const int8 INT8_MAX = 127; const int8 cINT8_MAX = 127;
const int16 INT16_MIN = -32768; const int16 cINT16_MIN = -32768;
const int16 INT16_MAX = 32767; const int16 cINT16_MAX = 32767;
const int32 INT32_MIN = (-2147483647 - 1); const int32 cINT32_MIN = (-2147483647 - 1);
const int32 INT32_MAX = 2147483647; const int32 cINT32_MAX = 2147483647;
const int64 INT64_MIN = (int64)0x8000000000000000ULL; //(-9223372036854775807i64 - 1); const int64 cINT64_MIN = (int64)0x8000000000000000ULL; //(-9223372036854775807i64 - 1);
const int64 INT64_MAX = (int64)0x7FFFFFFFFFFFFFFFULL; // 9223372036854775807i64; const int64 cINT64_MAX = (int64)0x7FFFFFFFFFFFFFFFULL; // 9223372036854775807i64;
#ifdef CRNLIB_PLATFORM_PC_X64 #if CRNLIB_64BIT_POINTERS
typedef unsigned __int64 uint_ptr; typedef uint64 uint_ptr;
typedef unsigned __int64 uint32_ptr; typedef uint64 uint32_ptr;
typedef signed __int64 signed_size_t; typedef int64 signed_size_t;
typedef uint64 ptr_bits_t; typedef uint64 ptr_bits_t;
#else #else
typedef unsigned int uint_ptr; typedef unsigned int uint_ptr;
+13 -1
View File
@@ -37,7 +37,19 @@ namespace crnlib
*pDst++ = swap16(*pSrc++); *pDst++ = swap16(*pSrc++);
} }
} }
void copy_dwords(uint32* pDst, const uint32* pSrc, uint num, bool endian_switch)
{
if (!endian_switch)
memcpy(pDst, pSrc, num << 2U);
else
{
uint32* pDst_end = pDst + num;
while (pDst != pDst_end)
*pDst++ = swap32(*pSrc++);
}
}
uint compute_max_mips(uint width, uint height) uint compute_max_mips(uint width, uint height)
{ {
if ((width | height) == 0) if ((width | height) == 0)
+16 -12
View File
@@ -8,18 +8,21 @@
#define CRNLIB_ARRAYSIZE(x) (sizeof(x)/sizeof(x[0])) #define CRNLIB_ARRAYSIZE(x) (sizeof(x)/sizeof(x[0]))
#ifdef _MSC_VER #ifdef _MSC_VER
extern "C" unsigned long __cdecl _lrotl(unsigned long, int); // Need to explictly extern these with MSVC, but not MinGW.
#pragma intrinsic(_lrotl) extern "C" unsigned long __cdecl _lrotl(unsigned long, int);
#pragma intrinsic(_lrotl)
extern "C" unsigned long __cdecl _lrotr(unsigned long, int); extern "C" unsigned long __cdecl _lrotr(unsigned long, int);
#pragma intrinsic(_lrotr) #pragma intrinsic(_lrotr)
#endif #endif
//#define CRNLIB_ROTATE_LEFT(x, k) (((x) << (k)) | ((x) >> (32-(k)))) #ifdef WIN32
#define CRNLIB_ROTATE_LEFT(x, k) _lrotl(x, k) #define CRNLIB_ROTATE_LEFT(x, k) _lrotl(x, k)
#define CRNLIB_ROTATE_RIGHT(x, k) _lrotr(x, k)
//#define CRNLIB_ROTATE_RIGHT(x, k) (((x) >> (k)) | ((x) << (32-(k)))) #else
#define CRNLIB_ROTATE_RIGHT(x, k) _lrotr(x, k) #define CRNLIB_ROTATE_LEFT(x, k) (((x) << (k)) | ((x) >> (32-(k))))
#define CRNLIB_ROTATE_RIGHT(x, k) (((x) >> (k)) | ((x) << (32-(k))))
#endif
template<class T, size_t N> T decay_array_to_subtype(T (&a)[N]); template<class T, size_t N> T decay_array_to_subtype(T (&a)[N]);
#define CRNLIB_ARRAY_SIZE(X) (sizeof(X) / sizeof(decay_array_to_subtype(X))) #define CRNLIB_ARRAY_SIZE(X) (sizeof(X) / sizeof(decay_array_to_subtype(X)))
@@ -39,12 +42,12 @@ namespace crnlib
template<typename T> inline void zero_object(T& obj) template<typename T> inline void zero_object(T& obj)
{ {
memset(&obj, 0, sizeof(obj)); memset((void*)&obj, 0, sizeof(obj));
} }
template<typename T> inline void zero_this(T* pObj) template<typename T> inline void zero_this(T* pObj)
{ {
memset(pObj, 0, sizeof(*pObj)); memset((void*)pObj, 0, sizeof(*pObj));
} }
inline bool is_bit_set(uint bits, uint mask) inline bool is_bit_set(uint bits, uint mask)
@@ -225,7 +228,8 @@ namespace crnlib
void endian_switch_words(uint16* p, uint num); void endian_switch_words(uint16* p, uint num);
void endian_switch_dwords(uint32* p, uint num); void endian_switch_dwords(uint32* p, uint num);
void copy_words(uint16* pDst, const uint16* pSrc, uint num, bool endian_switch); void copy_words(uint16* pDst, const uint16* pSrc, uint num, bool endian_switch);
void copy_dwords(uint32* pDst, const uint32* pSrc, uint num, bool endian_switch);
uint compute_max_mips(uint width, uint height); uint compute_max_mips(uint width, uint height);
} // namespace utils } // namespace utils
+10 -10
View File
@@ -5,17 +5,17 @@
namespace crnlib namespace crnlib
{ {
const wchar_t* gValueDataTypeStrings[cDTTotal + 1] = const char* gValueDataTypeStrings[cDTTotal + 1] =
{ {
L"invalid", "invalid",
L"string", "string",
L"bool", "bool",
L"int", "int",
L"uint", "uint",
L"float", "float",
L"vec3f", "vec3f",
L"vec3i", "vec3i",
NULL, NULL,
}; };
+40 -40
View File
@@ -2,7 +2,7 @@
// 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_strutils.h" #include "crn_strutils.h"
#include "crn_dynamic_wstring.h" #include "crn_dynamic_string.h"
#include "crn_vec.h" #include "crn_vec.h"
namespace crnlib namespace crnlib
@@ -21,7 +21,7 @@ namespace crnlib
cDTTotal cDTTotal
}; };
extern const wchar_t* gValueDataTypeStrings[cDTTotal + 1]; extern const char* gValueDataTypeStrings[cDTTotal + 1];
class value class value
{ {
@@ -31,13 +31,13 @@ namespace crnlib
{ {
} }
value(const wchar_t* pStr) : value(const char* pStr) :
m_pStr(crnlib_new<dynamic_wstring>(pStr)), m_type(cDTString) m_pStr(crnlib_new<dynamic_string>(pStr)), m_type(cDTString)
{ {
} }
value(const dynamic_wstring& str) : value(const dynamic_string& str) :
m_pStr(crnlib_new<dynamic_wstring>(str)), m_type(cDTString) m_pStr(crnlib_new<dynamic_string>(str)), m_type(cDTString)
{ {
} }
@@ -125,7 +125,7 @@ namespace crnlib
m_type = cDTInvalid; m_type = cDTInvalid;
} }
void set_string(const wchar_t* pStr) void set_string(const char* pStr)
{ {
set_str(pStr); set_str(pStr);
} }
@@ -170,7 +170,7 @@ namespace crnlib
m_pVec3I->set(v); m_pVec3I->set(v);
} }
bool parse(const wchar_t* p) bool parse(const char* p)
{ {
if ((!p) || (!p[0])) if ((!p) || (!p[0]))
{ {
@@ -178,12 +178,12 @@ namespace crnlib
return false; return false;
} }
if (_wcsicmp(p, L"false") == 0) if (_stricmp(p, "false") == 0)
{ {
set_bool(false); set_bool(false);
return true; return true;
} }
else if (_wcsicmp(p, L"true") == 0) else if (_stricmp(p, "true") == 0)
{ {
set_bool(true); set_bool(true);
return true; return true;
@@ -191,7 +191,7 @@ namespace crnlib
if (p[0] == '\"') if (p[0] == '\"')
{ {
dynamic_wstring str; dynamic_string str;
str = p + 1; str = p + 1;
if (!str.is_empty()) if (!str.is_empty())
{ {
@@ -205,21 +205,21 @@ namespace crnlib
} }
} }
if (wcschr(p, L',') != NULL) if (strchr(p, ',') != NULL)
{ {
float fx = 0, fy = 0, fz = 0; float fx = 0, fy = 0, fz = 0;
#ifdef _MSC_VER #ifdef _MSC_VER
if (swscanf_s(p, L"%f,%f,%f", &fx, &fy, &fz) == 3) if (sscanf_s(p, "%f,%f,%f", &fx, &fy, &fz) == 3)
#else #else
if (swscanf(p, L"%f,%f,%f", &fx, &fy, &fz) == 3) if (sscanf(p, "%f,%f,%f", &fx, &fy, &fz) == 3)
#endif #endif
{ {
bool as_float = true; bool as_float = true;
int ix = 0, iy = 0, iz = 0; int ix = 0, iy = 0, iz = 0;
#ifdef _MSC_VER #ifdef _MSC_VER
if (swscanf_s(p, L"%i,%i,%i", &ix, &iy, &iz) == 3) if (sscanf_s(p, "%i,%i,%i", &ix, &iy, &iz) == 3)
#else #else
if (swscanf(p, L"%i,%i,%i", &ix, &iy, &iz) == 3) if (sscanf(p, "%i,%i,%i", &ix, &iy, &iz) == 3)
#endif #endif
{ {
if ((ix == fx) && (iy == fy) && (iz == fz)) if ((ix == fx) && (iy == fy) && (iz == fz))
@@ -235,7 +235,7 @@ namespace crnlib
} }
} }
const wchar_t* q = p; const char* q = p;
bool success = string_to_uint(q, m_uint); bool success = string_to_uint(q, m_uint);
if ((success) && (*q == 0)) if ((success) && (*q == 0))
{ {
@@ -264,18 +264,18 @@ namespace crnlib
return true; return true;
} }
dynamic_wstring& get_as_string(dynamic_wstring& dst) const dynamic_string& get_as_string(dynamic_string& dst) const
{ {
switch (m_type) switch (m_type)
{ {
case cDTInvalid: dst.clear(); break; case cDTInvalid: dst.clear(); break;
case cDTString: dst = *m_pStr; break; case cDTString: dst = *m_pStr; break;
case cDTBool: dst = m_bool ? L"TRUE" : L"FALSE"; break; case cDTBool: dst = m_bool ? "TRUE" : "FALSE"; break;
case cDTInt: dst.format(L"%i", m_int); break; case cDTInt: dst.format("%i", m_int); break;
case cDTUInt: dst.format(L"%u", m_uint); break; case cDTUInt: dst.format("%u", m_uint); break;
case cDTFloat: dst.format(L"%f", m_float); break; case cDTFloat: dst.format("%f", m_float); break;
case cDTVec3F: dst.format(L"%f,%f,%f", (*m_pVec3F)[0], (*m_pVec3F)[1], (*m_pVec3F)[2]); break; case cDTVec3F: dst.format("%f,%f,%f", (*m_pVec3F)[0], (*m_pVec3F)[1], (*m_pVec3F)[2]); break;
case cDTVec3I: dst.format(L"%i,%i,%i", (*m_pVec3I)[0], (*m_pVec3I)[1], (*m_pVec3I)[2]); break; case cDTVec3I: dst.format("%i,%i,%i", (*m_pVec3I)[0], (*m_pVec3I)[1], (*m_pVec3I)[2]); break;
default: break; default: break;
} }
@@ -293,7 +293,7 @@ namespace crnlib
} }
case cDTString: case cDTString:
{ {
const wchar_t* p = m_pStr->get_ptr(); const char* p = m_pStr->get_ptr();
return string_to_int(p, val); return string_to_int(p, val);
} }
case cDTBool: val = m_bool; break; case cDTBool: val = m_bool; break;
@@ -359,7 +359,7 @@ namespace crnlib
} }
case cDTString: case cDTString:
{ {
const wchar_t* p = m_pStr->get_ptr(); const char* p = m_pStr->get_ptr();
return string_to_uint(p, val); return string_to_uint(p, val);
} }
case cDTBool: case cDTBool:
@@ -438,7 +438,7 @@ namespace crnlib
} }
case cDTString: case cDTString:
{ {
const wchar_t* p = m_pStr->get_ptr(); const char* p = m_pStr->get_ptr();
return string_to_bool(p, val); return string_to_bool(p, val);
} }
case cDTBool: case cDTBool:
@@ -497,7 +497,7 @@ namespace crnlib
} }
case cDTString: case cDTString:
{ {
const wchar_t* p = m_pStr->get_ptr(); const char* p = m_pStr->get_ptr();
return string_to_float(p, val); return string_to_float(p, val);
} }
case cDTBool: case cDTBool:
@@ -556,12 +556,12 @@ namespace crnlib
} }
case cDTString: case cDTString:
{ {
const wchar_t* p = m_pStr->get_ptr(); const char* p = m_pStr->get_ptr();
float x = 0, y = 0, z = 0; float x = 0, y = 0, z = 0;
#ifdef _MSC_VER #ifdef _MSC_VER
if (wscanf_s(p, L"%f,%f,%f", &x, &y, &z) == 3) if (sscanf_s(p, "%f,%f,%f", &x, &y, &z) == 3)
#else #else
if (wscanf(p, L"%f,%f,%f", &x, &y, &z) == 3) if (sscanf(p, "%f,%f,%f", &x, &y, &z) == 3)
#endif #endif
{ {
val.set(x, y, z); val.set(x, y, z);
@@ -619,12 +619,12 @@ namespace crnlib
} }
case cDTString: case cDTString:
{ {
const wchar_t* p = m_pStr->get_ptr(); const char* p = m_pStr->get_ptr();
float x = 0, y = 0, z = 0; float x = 0, y = 0, z = 0;
#ifdef _MSC_VER #ifdef _MSC_VER
if (wscanf_s(p, L"%f,%f,%f", &x, &y, &z) == 3) if (sscanf_s(p, "%f,%f,%f", &x, &y, &z) == 3)
#else #else
if (wscanf(p, L"%f,%f,%f", &x, &y, &z) == 3) if (sscanf(p, "%f,%f,%f", &x, &y, &z) == 3)
#endif #endif
{ {
if ((x < INT_MIN) || (x > INT_MAX) || (y < INT_MIN) || (y > INT_MAX) || (z < INT_MIN) || (z > INT_MAX)) if ((x < INT_MIN) || (x > INT_MAX) || (y < INT_MIN) || (y > INT_MAX) || (z < INT_MIN) || (z > INT_MAX))
@@ -963,7 +963,7 @@ namespace crnlib
switch (m_type) switch (m_type)
{ {
case cDTString: case cDTString:
m_pStr = crnlib_new<dynamic_wstring>(); m_pStr = crnlib_new<dynamic_string>();
break; break;
case cDTVec3F: case cDTVec3F:
m_pVec3F = crnlib_new<vec3F>(); m_pVec3F = crnlib_new<vec3F>();
@@ -976,7 +976,7 @@ namespace crnlib
} }
} }
void set_str(const dynamic_wstring& s) void set_str(const dynamic_string& s)
{ {
if (m_type == cDTString) if (m_type == cDTString)
m_pStr->set(s); m_pStr->set(s);
@@ -985,11 +985,11 @@ namespace crnlib
clear_dynamic(); clear_dynamic();
m_type = cDTString; m_type = cDTString;
m_pStr = crnlib_new<dynamic_wstring>(s); m_pStr = crnlib_new<dynamic_string>(s);
} }
} }
void set_str(const wchar_t* p) void set_str(const char* p)
{ {
if (m_type == cDTString) if (m_type == cDTString)
m_pStr->set(p); m_pStr->set(p);
@@ -998,7 +998,7 @@ namespace crnlib
clear_dynamic(); clear_dynamic();
m_type = cDTString; m_type = cDTString;
m_pStr = crnlib_new<dynamic_wstring>(p); m_pStr = crnlib_new<dynamic_string>(p);
} }
} }
@@ -1013,7 +1013,7 @@ namespace crnlib
vec3F* m_pVec3F; vec3F* m_pVec3F;
vec3I* m_pVec3I; vec3I* m_pVec3I;
dynamic_wstring* m_pStr; dynamic_string* m_pStr;
uint m_union[cUnionSize]; uint m_union[cUnionSize];
}; };

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