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.
#include "crn_core.h"
#include "crn_arealist.h"
#include <stdio.h>
#define RECT_DEBUG
@@ -20,7 +19,7 @@ namespace crnlib
#ifdef _MSC_VER
_vsnprintf_s(buf, sizeof(buf), pMsg, args);
#else
_vsnprintf(buf, sizeof(buf), pMsg, args);
vsnprintf(buf, sizeof(buf), pMsg, args);
#endif
va_end(args);
+8 -16
View File
@@ -1,8 +1,9 @@
// File: crn_assert.cpp
// See Copyright Notice and license at the end of inc/crnlib.h
#include "crn_core.h"
#if CRNLIB_USE_WIN32_API
#include "crn_winhdr.h"
#include <stdio.h>
#endif
static bool g_fail_exceptions;
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];
#if defined(WIN32) && defined(_MSC_VER)
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);
printf(buf);
fputs(buf, stderr);
if (crnlib_is_debugger_present())
crnlib_debug_break();
@@ -34,22 +31,21 @@ void crnlib_fail(const char* pExp, const char* pFile, unsigned line)
{
char buf[512];
#if defined(WIN32) && defined(_MSC_VER)
sprintf_s(buf, sizeof(buf), "%s(%u): Failure: \"%s\"\n", pFile, line, pExp);
#else
sprintf(buf, "%s(%u): Failure: \"%s\"\n", pFile, line, pExp);
#endif
crnlib_output_debug_string(buf);
printf(buf);
fputs(buf, stderr);
if (crnlib_is_debugger_present())
crnlib_debug_break();
#if CRNLIB_USE_WIN32_API
if (g_fail_exceptions)
RaiseException(CRNLIB_FAIL_EXCEPTION_CODE, 0, 0, NULL);
else if (g_exit_on_failure)
else
#endif
if (g_exit_on_failure)
exit(EXIT_FAILURE);
}
@@ -58,11 +54,7 @@ void trace(const char* pFmt, va_list args)
if (crnlib_is_debugger_present())
{
char buf[512];
#if defined(WIN32) && defined(_MSC_VER)
vsprintf_s(buf, sizeof(buf), pFmt, args);
#else
vsprintf(buf, pFmt, args);
#endif
crnlib_output_debug_string(buf);
}
+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
#pragma once
#include "crn_data_stream.h"
#include <stdio.h>
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)
{
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)
{
open(pFilename, attribs, open_existing);
@@ -55,7 +54,7 @@ namespace crnlib
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(pFilename);
@@ -67,17 +66,17 @@ namespace crnlib
m_has_ownership = has_ownership;
m_attribs = static_cast<uint16>(attribs);
m_ofs = _ftelli64(m_pFile);
_fseeki64(m_pFile, 0, SEEK_END);
m_size = _ftelli64(m_pFile);
_fseeki64(m_pFile, m_ofs, SEEK_SET);
m_ofs = crn_ftell(m_pFile);
crn_fseek(m_pFile, 0, SEEK_END);
m_size = crn_ftell(m_pFile);
crn_fseek(m_pFile, m_ofs, SEEK_SET);
m_opened = true;
return true;
}
bool open(const 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);
@@ -85,13 +84,13 @@ namespace crnlib
m_attribs = static_cast<uint16>(attribs);
const wchar_t* pMode;
const char* pMode;
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())
pMode = open_existing ? L"ab" : L"wb";
pMode = open_existing ? "ab" : "wb";
else if (is_readable())
pMode = L"rb";
pMode = "rb";
else
{
set_error();
@@ -99,11 +98,7 @@ namespace crnlib
}
FILE* pFile = NULL;
#ifdef _MSC_VER
_wfopen_s(&pFile, pFilename, pMode);
#else
pFile = _wfopen(pFilename, pMode);
#endif
crn_fopen(&pFile, pFilename, pMode);
m_has_ownership = true;
if (!pFile)
@@ -209,7 +204,7 @@ namespace crnlib
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();
return false;
@@ -221,7 +216,7 @@ namespace crnlib
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);
if (!in_stream.is_opened())
@@ -229,7 +224,7 @@ namespace crnlib
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);
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(); }
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;
@@ -170,7 +170,7 @@ namespace crnlib
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;
@@ -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;
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)
{
VectorType furthest;
VectorType furthest(0);
double furthest_dist = -1.0f;
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;
for (uint i = 0; i < parent_node.m_vectors.size(); i++)
+14 -14
View File
@@ -11,8 +11,8 @@ namespace crnlib
{
cSigned = false,
cFloat = false,
cMin = UINT8_MIN,
cMax = UINT8_MAX
cMin = cUINT8_MIN,
cMax = cUINT8_MAX
};
};
@@ -22,8 +22,8 @@ namespace crnlib
{
cSigned = true,
cFloat = false,
cMin = INT16_MIN,
cMax = INT16_MAX
cMin = cINT16_MIN,
cMax = cINT16_MAX
};
};
@@ -33,8 +33,8 @@ namespace crnlib
{
cSigned = false,
cFloat = false,
cMin = UINT16_MIN,
cMax = UINT16_MAX
cMin = cUINT16_MIN,
cMax = cUINT16_MAX
};
};
@@ -44,8 +44,8 @@ namespace crnlib
{
cSigned = true,
cFloat = false,
cMin = INT32_MIN,
cMax = INT32_MAX
cMin = cINT32_MIN,
cMax = cINT32_MAX
};
};
@@ -55,8 +55,8 @@ namespace crnlib
{
cSigned = false,
cFloat = false,
cMin = UINT32_MIN,
cMax = UINT32_MAX
cMin = cUINT32_MIN,
cMax = cUINT32_MAX
};
};
@@ -66,8 +66,8 @@ namespace crnlib
{
cSigned = false,
cFloat = true,
cMin = INT32_MIN,
cMax = INT32_MAX
cMin = cINT32_MIN,
cMax = cINT32_MAX
};
};
@@ -77,8 +77,8 @@ namespace crnlib
{
cSigned = false,
cFloat = true,
cMin = INT32_MIN,
cMax = INT32_MAX
cMin = cINT32_MIN,
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
#include "crn_core.h"
#include "crn_win32_console.h"
#include "crn_colorized_console.h"
#ifdef CRNLIB_USE_WIN32_API
#include "crn_winhdr.h"
#endif
namespace crnlib
{
void win32_console::init()
void colorized_console::init()
{
console::init();
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::deinit();
}
void win32_console::tick()
void colorized_console::tick()
{
}
#ifdef CRNLIB_PLATFORM_PC
bool win32_console::console_output_func(eConsoleMessageType type, const wchar_t* pMsg, void* pData)
#ifdef CRNLIB_USE_WIN32_API
bool colorized_console::console_output_func(eConsoleMessageType type, const char* pMsg, void* pData)
{
pData;
@@ -50,26 +52,26 @@ namespace crnlib
switch (type)
{
case cDebugConsoleMessage:
wprintf(L"Debug: %s", pMsg);
printf("Debug: %s", pMsg);
break;
case cWarningConsoleMessage:
wprintf(L"Warning: %s", pMsg);
printf("Warning: %s", pMsg);
break;
case cErrorConsoleMessage:
wprintf(L"Error: %s", pMsg);
printf("Error: %s", pMsg);
break;
default:
wprintf(L"%s", pMsg);
printf("%s", pMsg);
break;
}
}
else
{
wprintf(L"%s", pMsg);
printf("%s", pMsg);
}
if (console::get_crlf())
wprintf(L"\n");
printf("\n");
if (INVALID_HANDLE_VALUE != cons)
SetConsoleTextAttribute(cons, FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE);
@@ -77,8 +79,9 @@ namespace crnlib
return true;
}
#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())
return true;
@@ -87,26 +90,26 @@ namespace crnlib
switch (type)
{
case cDebugConsoleMessage:
wprintf(L"Debug: %s", pMsg);
printf("Debug: %s", pMsg);
break;
case cWarningConsoleMessage:
wprintf(L"Warning: %s", pMsg);
printf("Warning: %s", pMsg);
break;
case cErrorConsoleMessage:
wprintf(L"Error: %s", pMsg);
printf("Error: %s", pMsg);
break;
default:
wprintf(L"%s", pMsg);
printf("%s", pMsg);
break;
}
}
else
{
wprintf(L"%s", pMsg);
printf("%s", pMsg);
}
if (console::get_crlf())
wprintf(L"\n");
printf("\n");
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
#pragma once
#include "crn_console.h"
#include "crn_event.h"
namespace crnlib
{
class win32_console
class colorized_console
{
public:
static void init();
static void deinit();
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
+157 -124
View File
@@ -5,41 +5,67 @@
#include "crn_console.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
{
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()
{
}
void command_line_params::clear()
{
m_params.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_quote = false;
uint ofs = 0;
dynamic_wstring str;
dynamic_string str;
while (p[ofs])
{
const wchar_t c = p[ofs];
const char c = p[ofs];
if (within_param)
{
if (within_quote)
{
if (c == L'"')
if (c == '"')
within_quote = false;
str.append_char(c);
}
else if ((c == L' ') || (c == L'\t'))
else if ((c == ' ') || (c == '\t'))
{
if (!str.is_empty())
{
@@ -50,141 +76,144 @@ namespace crnlib
}
else
{
if (c == L'"')
if (c == '"')
within_quote = true;
str.append_char(c);
}
}
else if ((c != L' ') && (c != L'\t'))
else if ((c != ' ') && (c != '\t'))
{
within_param = true;
if (c == L'"')
if (c == '"')
within_quote = true;
str.append_char(c);
}
ofs++;
}
if (within_quote)
{
console::error(L"Unmatched quote in command line \"%s\"", p);
console::error("Unmatched quote in command line \"%s\"", p);
return false;
}
if (!str.is_empty())
params.push_back(str);
return true;
}
bool command_line_params::load_string_file(const 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;
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;
}
dynamic_string ansi_str;
for ( ; ; )
{
if (!in_stream.read_line(ansi_str))
break;
ansi_str.trim();
if (ansi_str.is_empty())
continue;
strings.push_back(dynamic_wstring(ansi_str.get_ptr()));
strings.push_back(dynamic_string(ansi_str.get_ptr()));
}
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);
m_params = params;
uint arg_index = 0;
while (arg_index < params.size())
{
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())
continue;
if ((src_param[0] == L'/') || (src_param[0] == L'-'))
#if CRNLIB_CMD_LINE_ALLOW_SLASH_PARAMS
if ((src_param[0] == '/') || (src_param[0] == '-'))
#else
if (src_param[0] == '-')
#endif
{
if (src_param.get_len() < 2)
{
console::error(L"Invalid command line parameter: \"%s\"", src_param.get_ptr());
console::error("Invalid command line parameter: \"%s\"", src_param.get_ptr());
return false;
}
dynamic_wstring key_str(src_param);
dynamic_string key_str(src_param);
key_str.right(1);
int modifier = 0;
wchar_t c = key_str[key_str.get_len() - 1];
if (c == L'+')
char c = key_str[key_str.get_len() - 1];
if (c == '+')
modifier = 1;
else if (c == L'-')
else if (c == '-')
modifier = -1;
if (modifier)
key_str.left(key_str.get_len() - 1);
uint param_index;
for (param_index = 0; param_index < n; param_index++)
if (key_str == pParam_desc[param_index].m_pName)
break;
if (param_index == n)
{
console::error(L"Unrecognized command line parameter: \"%s\"", src_param.get_ptr());
return false;
console::error("Unrecognized command line parameter: \"%s\"", src_param.get_ptr());
return false;
}
const param_desc& desc = pParam_desc[param_index];
const uint cMaxValues = 16;
dynamic_wstring val_str[cMaxValues];
dynamic_string val_str[cMaxValues];
uint num_val_strs = 0;
if (desc.m_num_values)
{
if (desc.m_num_values)
{
CRNLIB_ASSERT(desc.m_num_values <= cMaxValues);
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());
return false;
console::error("Expected %u value(s) after command line parameter: \"%s\"", desc.m_num_values, src_param.get_ptr());
return false;
}
for (uint v = 0; v < desc.m_num_values; v++)
val_str[num_val_strs++] = params[arg_index++];
}
dynamic_wstring_array strings;
if ((desc.m_support_listing_file) && (val_str[0].get_len() >= 2) && (val_str[0][0] == L'@'))
}
dynamic_string_array strings;
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.unquote();
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;
}
}
@@ -196,7 +225,7 @@ namespace crnlib
strings.push_back(val_str[v]);
}
}
param_value pv;
pv.m_values.swap(strings);
pv.m_index = cur_arg_index;
@@ -209,18 +238,18 @@ namespace crnlib
pv.m_values.push_back(src_param);
pv.m_values.back().unquote();
pv.m_index = cur_arg_index;
m_param_map.insert(std::make_pair(g_empty_dynamic_wstring, pv));
m_param_map.insert(std::make_pair(g_empty_dynamic_string, pv));
}
}
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);
dynamic_wstring_array p;
dynamic_string_array p;
if (!split_params(pCmd_line, p))
return 0;
@@ -232,110 +261,114 @@ namespace crnlib
return parse(p, n, pParam_desc);
}
bool command_line_params::is_param(uint index) const
{
CRNLIB_ASSERT(index < m_params.size());
if (index >= m_params.size())
return false;
const dynamic_wstring& w = m_params[index];
const dynamic_string& w = m_params[index];
if (w.is_empty())
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);
if (pUnmatched_indices)
{
pUnmatched_indices->resize(m_params.size());
for (uint i = 0; i < m_params.size(); i++)
(*pUnmatched_indices)[i] = i;
}
uint n = 0;
for (uint i = 0; i < num_keys; i++)
{
const wchar_t* pKey = ppKeys[i];
const char* pKey = ppKeys[i];
param_map_const_iterator begin, end;
find(pKey, begin, end);
while (begin != end)
{
if (pIterators)
if (pIterators)
pIterators->push_back(begin);
if (pUnmatched_indices)
{
int k = pUnmatched_indices->find(begin->second.m_index);
if (k >= 0)
pUnmatched_indices->erase_unordered(k);
}
n++;
begin++;
}
}
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);
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;
find(pKey, begin, end);
uint n = 0;
while (begin != end)
{
n++;
begin++;
}
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;
find(pKey, begin, end);
if (begin == end)
return m_param_map.end();
uint n = 0;
while ((begin != end) && (n != index))
{
n++;
begin++;
}
if (begin == end)
return m_param_map.end();
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;
}
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);
@@ -344,76 +377,76 @@ namespace crnlib
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);
if (it == end())
return def;
if (it->second.m_modifier)
return it->second.m_modifier > 0;
else
return true;
}
int command_line_params::get_value_as_int(const wchar_t* pKey, uint index, int def, int l, int h, uint value_index) const
int command_line_params::get_value_as_int(const char* pKey, uint index, int def, int l, int h, uint value_index) const
{
param_map_const_iterator it = get_param(pKey, index);
if ((it == end()) || (value_index >= it->second.m_values.size()))
return def;
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))
{
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;
}
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;
}
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;
}
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);
if ((it == end()) || (value_index >= it->second.m_values.size()))
return def;
float val;
const wchar_t* p = it->second.m_values[value_index].get_ptr();
const char* p = it->second.m_values[value_index].get_ptr();
if (!string_to_float(p, val))
{
crnlib::console::warning(L"Invalid value specified for float parameter \"%s\", using default value of %f", pKey, def);
crnlib::console::warning("Invalid value specified for float parameter \"%s\", using default value of %f", pKey, def);
return def;
}
if (val < l)
{
crnlib::console::warning(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;
}
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;
}
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);
if ((it == end()) || (value_index >= it->second.m_values.size()))
@@ -425,13 +458,13 @@ namespace crnlib
value = it->second.m_values[value_index];
return true;
}
const dynamic_wstring& command_line_params::get_value_as_string_or_empty(const wchar_t* pKey, uint index, uint value_index) const
const dynamic_string& command_line_params::get_value_as_string_or_empty(const char* pKey, uint index, uint value_index) const
{
param_map_const_iterator it = get_param(pKey, index);
if ((it == end()) || (value_index >= it->second.m_values.size()))
return g_empty_dynamic_wstring;
return g_empty_dynamic_string;
return it->second.m_values[value_index];
}
+49 -47
View File
@@ -6,77 +6,79 @@
namespace crnlib
{
void get_command_line(dynamic_string& cmd_line, int argc, char *argv[]);
class command_line_params
{
public:
struct param_value
{
param_value() : m_index(0), m_modifier(0) { }
dynamic_wstring_array m_values;
inline param_value() : m_index(0), m_modifier(0) { }
dynamic_string_array m_values;
uint m_index;
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::iterator param_map_iterator;
command_line_params();
void clear();
static bool split_params(const wchar_t* p, dynamic_wstring_array& params);
static bool split_params(const char* p, dynamic_string_array& params);
struct param_desc
{
const wchar_t* m_pName;
const char* m_pName;
uint m_num_values;
bool m_support_listing_file;
};
bool parse(const dynamic_wstring_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);
const dynamic_wstring_array& get_array() const { return m_params; }
bool parse(const dynamic_string_array& params, uint n, const param_desc* pParam_desc);
bool parse(const char* pCmd_line, uint n, const param_desc* pParam_desc, bool skip_first_param = true);
const dynamic_string_array& get_array() const { return m_params; }
bool is_param(uint index) const;
const param_map& get_map() const { return m_param_map; }
uint get_num_params() const { return static_cast<uint>(m_param_map.size()); }
param_map_const_iterator begin() const { return m_param_map.begin(); }
param_map_const_iterator end() const { return m_param_map.end(); }
uint find(uint num_keys, const wchar_t** 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;
uint get_count(const wchar_t* pKey) const;
uint find(uint num_keys, const char** ppKeys, crnlib::vector<param_map_const_iterator>* pIterators, crnlib::vector<uint>* pUnmatched_indices) const;
void find(const char* pKey, param_map_const_iterator& begin, param_map_const_iterator& end) const;
uint get_count(const char* pKey) const;
// Returns end() if param cannot be found, or index is out of range.
param_map_const_iterator get_param(const wchar_t* pKey, uint index) const;
bool has_key(const wchar_t* pKey) const { return get_param(pKey, 0) != end(); }
bool has_value(const wchar_t* pKey, uint index) const;
uint get_num_values(const wchar_t* pKey, uint index) const;
bool get_value_as_bool(const wchar_t* pKey, uint index = 0, bool def = false) const;
int get_value_as_int(const wchar_t* pKey, uint index, int def, int l = INT_MIN, int h = INT_MAX, uint value_index = 0) const;
float get_value_as_float(const wchar_t* pKey, uint index, float def = 0.0f, float l = -math::cNearlyInfinite, float h = math::cNearlyInfinite, uint value_index = 0) const;
bool get_value_as_string(const wchar_t* pKey, uint index, dynamic_wstring& 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;
param_map_const_iterator get_param(const char* pKey, uint index) const;
bool has_key(const char* pKey) const { return get_param(pKey, 0) != end(); }
bool has_value(const char* pKey, uint index) const;
uint get_num_values(const char* pKey, uint index) const;
bool get_value_as_bool(const char* pKey, uint index = 0, bool def = false) const;
int get_value_as_int(const char* pKey, uint index, int def, int l = INT_MIN, int h = INT_MAX, uint value_index = 0) const;
float get_value_as_float(const char* pKey, uint index, float def = 0.0f, float l = -math::cNearlyInfinite, float h = math::cNearlyInfinite, uint value_index = 0) const;
bool get_value_as_string(const char* pKey, uint index, dynamic_string& value, uint value_index = 0) const;
const dynamic_string& get_value_as_string_or_empty(const char* pKey, uint index = 0, uint value_index = 0) const;
private:
dynamic_wstring_array m_params;
param_map m_param_map;
static bool load_string_file(const wchar_t* pFilename, dynamic_wstring_array& strings);
dynamic_string_array m_params;
param_map m_param_map;
static bool load_string_file(const char* pFilename, dynamic_string_array& strings);
};
} // 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
{
CRNLIB_NO_COPY_OR_ASSIGNMENT_OP(crn_comp);
public:
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_pass(const crn_comp_params& params, float *pEffective_bitrate);
virtual void compress_deinit();
virtual const crnlib::vector<uint8>& get_comp_data() const { return m_comp_data; }
virtual crnlib::vector<uint8>& get_comp_data() { return m_comp_data; }
uint get_comp_data_size() const { return m_comp_data.size(); }
const uint8* get_comp_data_ptr() const { return m_comp_data.size() ? &m_comp_data[0] : NULL; }
private:
task_pool m_task_pool;
const crn_comp_params* m_pParams;
image_u8 m_images[cCRNMaxFaces][cCRNMaxLevels];
struct
struct level_tag
{
uint m_width, m_height;
uint m_chunk_width, m_chunk_height;
@@ -50,130 +50,130 @@ namespace crnlib
uint m_first_chunk;
uint m_group_first_chunk;
} m_levels[cCRNMaxLevels];
struct mip_group
{
mip_group() : m_first_chunk(0), m_num_chunks(0) { }
uint m_first_chunk;
uint m_num_chunks;
};
crnlib::vector<mip_group> m_mip_groups;
enum comp
enum comp
{
cColor,
cAlpha0,
cAlpha1,
cNumComps
};
bool m_has_comp[cNumComps];
struct chunk_detail
{
chunk_detail() { utils::zero_object(*this); }
uint m_first_endpoint_index;
uint m_first_selector_index;
};
typedef crnlib::vector<chunk_detail> chunk_detail_vec;
chunk_detail_vec m_chunk_details;
crnlib::vector<uint> m_endpoint_indices[cNumComps];
crnlib::vector<uint> m_selector_indices[cNumComps];
uint m_total_chunks;
dxt_hc::pixel_chunk_vec m_chunks;
crnd::crn_header m_crn_header;
crnlib::vector<uint8> m_comp_data;
dxt_hc m_hvq;
symbol_histogram m_chunk_encoding_hist;
symbol_histogram m_chunk_encoding_hist;
static_huffman_data_model m_chunk_encoding_dm;
symbol_histogram m_endpoint_index_hist[2];
static_huffman_data_model m_endpoint_index_dm[2]; // color, alpha
symbol_histogram m_selector_index_hist[2];
symbol_histogram m_selector_index_hist[2];
static_huffman_data_model m_selector_index_dm[2]; // color, alpha
crnlib::vector<uint8> m_packed_chunks[cCRNMaxLevels];
crnlib::vector<uint8> m_packed_data_models;
crnlib::vector<uint8> m_packed_color_endpoints;
crnlib::vector<uint8> m_packed_color_selectors;
crnlib::vector<uint8> m_packed_color_selectors;
crnlib::vector<uint8> m_packed_alpha_endpoints;
crnlib::vector<uint8> m_packed_alpha_selectors;
crnlib::vector<uint8> m_packed_alpha_selectors;
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);
static float color_endpoint_similarity_func(uint index_a, uint index_b, void* pContext);
static float alpha_endpoint_similarity_func(uint index_a, uint index_b, void* pContext);
void sort_color_endpoint_codebook(crnlib::vector<uint>& remapping, const crnlib::vector<uint>& endpoints);
void sort_alpha_endpoint_codebook(crnlib::vector<uint>& remapping, const crnlib::vector<uint>& endpoints);
bool pack_color_endpoints(crnlib::vector<uint8>& data, const crnlib::vector<uint>& remapping, const crnlib::vector<uint>& endpoint_indices, uint trial_index);
bool pack_alpha_endpoints(crnlib::vector<uint8>& data, const crnlib::vector<uint>& remapping, const crnlib::vector<uint>& endpoint_indices, uint trial_index);
static float color_selector_similarity_func(uint index_a, uint index_b, void* pContext);
static float alpha_selector_similarity_func(uint index_a, uint index_b, void* pContext);
void sort_selector_codebook(crnlib::vector<uint>& remapping, const crnlib::vector<dxt_hc::selectors>& selectors, const uint8* pTo_linear);
bool pack_selectors(
crnlib::vector<uint8>& packed_data,
const crnlib::vector<uint>& selector_indices,
const crnlib::vector<dxt_hc::selectors>& selectors,
const crnlib::vector<dxt_hc::selectors>& selectors,
const crnlib::vector<uint>& remapping,
uint max_selector_value,
const uint8* pTo_linear,
uint trial_index);
bool alias_images();
void create_chunks();
bool quantize_chunks();
void create_chunk_indices();
bool pack_chunks(
uint first_chunk, uint num_chunks,
bool clear_histograms,
symbol_codec* pCodec,
const crnlib::vector<uint>* pColor_endpoint_remap,
const crnlib::vector<uint>* pColor_endpoint_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);
bool pack_chunks_simulation(
uint first_chunk, uint num_chunks,
uint& total_bits,
const crnlib::vector<uint>* pColor_endpoint_remap,
const crnlib::vector<uint>* pColor_endpoint_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);
void optimize_color_endpoint_codebook_task(uint64 data, void* pData_ptr);
bool optimize_color_endpoint_codebook(crnlib::vector<uint>& remapping);
void optimize_color_selector_codebook_task(uint64 data, void* pData_ptr);
bool optimize_color_selector_codebook(crnlib::vector<uint>& remapping);
void optimize_alpha_endpoint_codebook_task(uint64 data, void* pData_ptr);
bool optimize_alpha_endpoint_codebook(crnlib::vector<uint>& remapping);
void optimize_alpha_selector_codebook_task(uint64 data, void* pData_ptr);
bool optimize_alpha_selector_codebook(crnlib::vector<uint>& remapping);
bool create_comp_data();
bool pack_data_models();
bool update_progress(uint phase_index, uint subphase_index, uint subphase_total);
bool compress_internal();
static void append_vec(crnlib::vector<uint8>& a, const void* p, uint size);
static void append_vec(crnlib::vector<uint8>& a, const crnlib::vector<uint8>& b);
};
-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_console.h"
#include "crn_data_stream.h"
#include "crn_threading.h"
namespace crnlib
{
@@ -48,7 +49,7 @@ namespace crnlib
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();
@@ -56,12 +57,8 @@ namespace crnlib
m_num_messages[type]++;
wchar_t buf[cConsoleBufSize];
#ifdef _MSC_VER
vswprintf_s(buf, cConsoleBufSize, p, args);
#else
vswprintf(buf, p, args);
#endif
char buf[cConsoleBufSize];
vsprintf_s(buf, cConsoleBufSize, p, args);
bool handled = false;
@@ -72,48 +69,38 @@ namespace crnlib
handled = true;
}
const wchar_t* pPrefix = NULL;
const char* pPrefix = NULL;
if (m_prefixes)
{
switch (type)
{
case cDebugConsoleMessage: pPrefix = L"Debug: "; break;
case cWarningConsoleMessage: pPrefix = L"Warning: "; break;
case cErrorConsoleMessage: pPrefix = L"Error: "; break;
case cDebugConsoleMessage: pPrefix = "Debug: "; break;
case cWarningConsoleMessage: pPrefix = "Warning: "; break;
case cErrorConsoleMessage: pPrefix = "Error: "; break;
default: break;
}
}
if ((!m_output_disabled) && (!handled))
{
#ifdef _XBOX
if (pPrefix)
OutputDebugStringW(pPrefix);
OutputDebugStringW(buf);
if (m_crlf)
OutputDebugStringW(L"\n");
#else
if (pPrefix)
::wprintf(pPrefix);
::wprintf(m_crlf ? L"%s\n" : L"%s", buf);
#endif
::printf("%s", pPrefix);
::printf(m_crlf ? "%s\n" : "%s", buf);
}
if ((type != cProgressConsoleMessage) && (m_pLog_stream))
{
// Yes this is bad.
dynamic_wstring utf16_buf(buf);
dynamic_string tmp_buf(buf);
dynamic_string ansi_buf;
utf16_buf.as_ansi(ansi_buf);
ansi_buf.translate_lf_to_crlf();
tmp_buf.translate_lf_to_crlf();
m_pLog_stream->printf(m_crlf ? "%s\r\n" : "%s", ansi_buf.get_ptr());
m_pLog_stream->printf(m_crlf ? "%s\r\n" : "%s", tmp_buf.get_ptr());
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_start(args, p);
@@ -121,7 +108,7 @@ namespace crnlib
va_end(args);
}
void console::printf(const wchar_t* p, ...)
void console::printf(const char* p, ...)
{
va_list args;
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_start(args, p);
@@ -180,7 +167,7 @@ namespace crnlib
va_end(args);
}
void console::info(const wchar_t* p, ...)
void console::info(const char* p, ...)
{
va_list args;
va_start(args, p);
@@ -188,7 +175,7 @@ namespace crnlib
va_end(args);
}
void console::message(const wchar_t* p, ...)
void console::message(const char* p, ...)
{
va_list args;
va_start(args, p);
@@ -196,7 +183,7 @@ namespace crnlib
va_end(args);
}
void console::cons(const wchar_t* p, ...)
void console::cons(const char* p, ...)
{
va_list args;
va_start(args, p);
@@ -204,7 +191,7 @@ namespace crnlib
va_end(args);
}
void console::debug(const wchar_t* p, ...)
void console::debug(const char* p, ...)
{
va_list args;
va_start(args, p);
@@ -212,7 +199,7 @@ namespace crnlib
va_end(args);
}
void console::warning(const wchar_t* p, ...)
void console::warning(const char* p, ...)
{
va_list args;
va_start(args, p);
@@ -220,7 +207,7 @@ namespace crnlib
va_end(args);
}
void console::error(const wchar_t* p, ...)
void console::error(const char* p, ...)
{
va_list args;
va_start(args, p);
+65 -34
View File
@@ -3,92 +3,123 @@
#pragma once
#include "crn_dynamic_string.h"
#ifdef WIN32
#include <tchar.h>
#include <conio.h>
#endif
namespace crnlib
{
class dynamic_string;
class data_stream;
class mutex;
enum eConsoleMessageType
{
cDebugConsoleMessage, // debugging messages
cProgressConsoleMessage, // progress messages
cInfoConsoleMessage, // ordinary messages
cInfoConsoleMessage, // ordinary messages
cConsoleConsoleMessage, // user console output
cMessageConsoleMessage, // high importance messages
cWarningConsoleMessage, // warnings
cErrorConsoleMessage, // errors
cCMTTotal
};
typedef bool (*console_output_func)(eConsoleMessageType type, const wchar_t* pMsg, void* pData);
class console
typedef bool (*console_output_func)(eConsoleMessageType type, const char* pMsg, void* pData);
class console
{
public:
static void init();
static void deinit();
static bool is_initialized() { return m_pMutex != NULL; }
static void set_default_category(eConsoleMessageType category);
static eConsoleMessageType get_default_category();
static void add_console_output_func(console_output_func pFunc, void* pData);
static void remove_console_output_func(console_output_func pFunc);
static void printf(const wchar_t* p, ...);
static void vprintf(eConsoleMessageType type, const wchar_t* p, va_list args);
static void printf(eConsoleMessageType type, const wchar_t* p, ...);
static void cons(const wchar_t* p, ...);
static void debug(const wchar_t* p, ...);
static void progress(const wchar_t* p, ...);
static void info(const wchar_t* p, ...);
static void message(const wchar_t* p, ...);
static void warning(const wchar_t* p, ...);
static void error(const wchar_t* p, ...);
static void printf(const char* p, ...);
static void vprintf(eConsoleMessageType type, const char* p, va_list args);
static void printf(eConsoleMessageType type, const char* p, ...);
static void cons(const char* p, ...);
static void debug(const char* p, ...);
static void progress(const char* p, ...);
static void info(const char* p, ...);
static void message(const char* p, ...);
static void warning(const char* p, ...);
static void error(const char* p, ...);
// FIXME: All console state is currently global!
static void disable_prefixes();
static void enable_prefixes();
static bool get_prefixes() { return m_prefixes; }
static void disable_crlf();
static void enable_crlf();
static bool get_crlf() { return m_crlf; }
static void disable_output() { m_output_disabled = true; }
static void enable_output() { m_output_disabled = false; }
static bool get_output_disabled() { return m_output_disabled; }
static void set_log_stream(data_stream* pStream) { m_pLog_stream = pStream; }
static data_stream* get_log_stream() { return m_pLog_stream; }
static uint get_num_messages(eConsoleMessageType type) { return m_num_messages[type]; }
private:
private:
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_output_func m_func;
void* m_pData;
};
static crnlib::vector<console_func> m_output_funcs;
static bool m_crlf, m_prefixes, m_output_disabled;
static data_stream* m_pLog_stream;
static mutex* m_pMutex;
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
+10 -3
View File
@@ -1,7 +1,14 @@
// File: crn_core.cpp
// See Copyright Notice and license at the end of inc/crnlib.h
#include "crn_core.h"
#include "crn_winhdr.h"
char *g_copyright_str = "Copyright (c) 2010-2012 Rich Geldreich and Tenacious Software LLC";
char *g_sig_str = "C8cfRlaorj0wLtnMSxrBJxTC85rho2L9hUZKHcBL";
#if CRNLIB_USE_WIN32_API
#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: 4127) // conditional expression is constant
#pragma warning (disable: 4793) // function compiled as native
#pragma warning (disable: 4324) // structure was padded due to __declspec(align())
#endif
#if defined(WIN32)
#if 0
#if defined(WIN32) && !defined(CRNLIB_ANSI_CPLUSPLUS)
// MSVC or MinGW, x86 or x64, Win32 API's for threading and Win32 Interlocked API's or GCC built-ins for atomic ops.
#ifdef NDEBUG
// Ensure checked iterators are disabled.
#define _SECURE_SCL 0
#define _HAS_ITERATOR_DEBUGGING 0
#endif
#ifndef _DLL
// If we're using the DLL form of the run-time libs, we're also going to be enabling exceptions because we'll be building CLR apps.
// Otherwise, we disable exceptions for a small (up to 5%) speed boost.
// Otherwise, we disable exceptions for a small speed boost.
#define _HAS_EXCEPTIONS 0
#endif
#endif
//#define _CRT_SECURE_NO_WARNINGS
#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
#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_64BIT_POINTERS 1
#define CRNLIB_CPU_HAS_64BIT_REGISTERS 1
@@ -48,15 +44,99 @@
#define CRNLIB_CPU_HAS_64BIT_REGISTERS 0
#define CRNLIB_LITTLE_ENDIAN_CPU 1
#endif
#define CRNLIB_USE_UNALIGNED_INT_LOADS 1
#define CRNLIB_RESTRICT __restrict
#define CRNLIB_FORCE_INLINE __forceinline
#if defined(_MSC_VER) || defined(__MINGW32__) || defined(__MINGW64__)
#define CRNLIB_USE_MSVC_INTRINSICS 1
#endif
#define CRNLIB_INT64_FORMAT_SPECIFIER "%I64i"
#define CRNLIB_UINT64_FORMAT_SPECIFIER "%I64u"
#define CRNLIB_STDCALL __stdcall
#define CRNLIB_MEMORY_IMPORT_BARRIER
#define CRNLIB_MEMORY_EXPORT_BARRIER
#elif defined(__GNUC__) && !defined(CRNLIB_ANSI_CPLUSPLUS)
// GCC x86 or x64, pthreads for threading and GCC built-ins for atomic ops.
#define CRNLIB_PLATFORM_PC 1
#if defined(_WIN64) || defined(__MINGW64__) || defined(_LP64) || defined(__LP64__)
#define CRNLIB_PLATFORM_PC_X64 1
#define CRNLIB_64BIT_POINTERS 1
#define CRNLIB_CPU_HAS_64BIT_REGISTERS 1
#else
#define CRNLIB_PLATFORM_PC_X86 1
#define CRNLIB_64BIT_POINTERS 0
#define CRNLIB_CPU_HAS_64BIT_REGISTERS 0
#endif
#define CRNLIB_USE_UNALIGNED_INT_LOADS 1
#define CRNLIB_LITTLE_ENDIAN_CPU 1
#define CRNLIB_USE_PTHREADS_API 1
#define CRNLIB_USE_GCC_ATOMIC_BUILTINS 1
#define CRNLIB_RESTRICT
#define CRNLIB_FORCE_INLINE inline __attribute__((__always_inline__,__gnu_inline__))
#define CRNLIB_INT64_FORMAT_SPECIFIER "%lli"
#define CRNLIB_UINT64_FORMAT_SPECIFIER "%llu"
#define CRNLIB_STDCALL
#define CRNLIB_MEMORY_IMPORT_BARRIER
#define CRNLIB_MEMORY_EXPORT_BARRIER
#else
// Vanilla ANSI-C/C++
// No threading support, unaligned loads are NOT okay.
#if defined(_WIN64) || defined(__MINGW64__) || defined(_LP64) || defined(__LP64__)
#define CRNLIB_64BIT_POINTERS 1
#define CRNLIB_CPU_HAS_64BIT_REGISTERS 1
#else
#define CRNLIB_64BIT_POINTERS 0
#define CRNLIB_CPU_HAS_64BIT_REGISTERS 0
#endif
#define CRNLIB_USE_UNALIGNED_INT_LOADS 0
#if __BIG_ENDIAN__
#define CRNLIB_BIG_ENDIAN_CPU 1
#else
#define CRNLIB_LITTLE_ENDIAN_CPU 1
#endif
#define CRNLIB_USE_GCC_ATOMIC_BUILTINS 0
#define CRNLIB_USE_WIN32_ATOMIC_FUNCTIONS 0
#define CRNLIB_RESTRICT
#define CRNLIB_FORCE_INLINE inline
#define CRNLIB_INT64_FORMAT_SPECIFIER "%I64i"
#define CRNLIB_UINT64_FORMAT_SPECIFIER "%I64u"
#define CRNLIB_STDCALL
#define CRNLIB_MEMORY_IMPORT_BARRIER
#define CRNLIB_MEMORY_EXPORT_BARRIER
#endif
#define CRNLIB_SLOW_STRING_LEN_CHECKS 1
#include <stdlib.h>
#include <stdio.h>
#include <limits.h>
#include <math.h>
#include <stdarg.h>
#include <string.h>
#include <algorithm>
#include <locale>
#include <memory.h>
#include <limits.h>
#include <algorithm>
#include <errno.h>
#ifdef min
#undef min
@@ -78,16 +158,15 @@
#ifndef NDEBUG
#define NDEBUG
#endif
#ifdef DEBUG
#error DEBUG cannot be defined in CRNLIB_BUILD_RELEASE
#endif
#endif
#include "crn_platform.h"
#if defined(WIN32)
#include "crn_mutex.h"
#endif
#include "crn_assert.h"
#include "crn_types.h"
#include "crn_assert.h"
#include "crn_platform.h"
#include "crn_helpers.h"
#include "crn_traits.h"
#include "crn_mem.h"
@@ -95,9 +174,5 @@
#include "crn_utils.h"
#include "crn_hash.h"
#include "crn_vector.h"
#include "crn_win32_timer.h"
#include "crn_win32_threading.h"
#include "crn_timer.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
#include "crn_core.h"
#include "crn_data_stream.h"
#include <stdio.h>
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_attribs(static_cast<uint16>(attribs)),
m_opened(false), m_error(false), m_got_cr(false)
@@ -85,28 +84,11 @@ namespace crnlib
va_list args;
va_start(args, p);
char buf[4096];
#ifdef _MSC_VER
int l = vsprintf_s(buf, sizeof(buf), p, args);
#else
int l = vsprintf(buf, p, args);
#endif
va_end(args);
if (l < 0)
return false;
return write(buf, l) == static_cast<uint>(l);
}
bool data_stream::printf(const wchar_t* p, ...)
{
va_list args;
va_start(args, p);
dynamic_wstring buf;
dynamic_string buf;
buf.format_args(p, args);
va_end(args);
return write(buf.get_ptr(), buf.get_len() * sizeof(wchar_t)) == buf.get_len() * sizeof(wchar_t);
return write(buf.get_ptr(), buf.get_len() * sizeof(char)) == buf.get_len() * sizeof(char);
}
bool data_stream::write_line(const dynamic_string& str)
@@ -117,14 +99,6 @@ namespace crnlib
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)
{
if (buf.size() < get_remaining())
+31 -33
View File
@@ -10,82 +10,80 @@ namespace crnlib
cDataStreamWritable = 2,
cDataStreamSeekable = 4
};
const int64 DATA_STREAM_SIZE_UNKNOWN = INT64_MAX;
const int64 DATA_STREAM_SIZE_INFINITE = UINT64_MAX;
const int64 DATA_STREAM_SIZE_UNKNOWN = cINT64_MAX;
const int64 DATA_STREAM_SIZE_INFINITE = cUINT64_MAX;
class data_stream
{
data_stream(const data_stream&);
data_stream& operator= (const data_stream&);
public:
data_stream();
data_stream(const wchar_t* pName, uint attribs);
data_stream(const char* pName, uint attribs);
virtual ~data_stream() { }
virtual data_stream *get_parent() { return NULL; }
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 bool is_opened() const { return m_opened; }
inline bool is_readable() const { return utils::is_bit_set(m_attribs, cDataStreamReadable); }
inline bool is_writable() const { return utils::is_bit_set(m_attribs, cDataStreamWritable); }
inline bool is_seekable() const { return utils::is_bit_set(m_attribs, cDataStreamSeekable); }
inline bool get_error() const { return m_error; }
inline const dynamic_wstring& get_name() const { return m_name; }
inline void set_name(const wchar_t* pName) { m_name.set(pName); }
inline const dynamic_string& get_name() const { return m_name; }
inline void set_name(const char* pName) { m_name.set(pName); }
virtual uint read(void* pBuf, uint len) = 0;
virtual uint64 skip(uint64 len);
virtual uint write(const void* pBuf, uint len) = 0;
virtual bool flush() = 0;
virtual bool is_size_known() const { return true; }
// Returns DATA_STREAM_SIZE_UNKNOWN if size hasn't been determined yet, or DATA_STREAM_SIZE_INFINITE for infinite streams.
virtual uint64 get_size() = 0;
virtual uint64 get_remaining() = 0;
virtual uint64 get_ofs() = 0;
virtual bool seek(int64 ofs, bool relative) = 0;
virtual const void* get_ptr() const { return NULL; }
inline int read_byte() { uint8 c; if (read(&c, 1) != 1) return -1; return c; }
inline bool write_byte(uint8 c) { return write(&c, 1) == 1; }
bool read_line(dynamic_string& str);
bool printf(const char* p, ...);
bool printf(const wchar_t* p, ...);
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 read_array(vector<uint8>& buf);
bool write_array(const vector<uint8>& buf);
protected:
dynamic_wstring m_name;
dynamic_string m_name;
attribs_t m_attribs;
bool m_opened : 1;
bool m_error : 1;
bool m_got_cr : 1;
inline void set_error() { m_error = true; }
inline void clear_error() { m_error = false; }
inline void post_seek() { m_got_cr = false; }
};
} // namespace crnlib
+4 -4
View File
@@ -15,7 +15,7 @@ namespace crnlib
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_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 crnlib::vector<uint8>& get_comp_data() { return m_comp_data; }
private:
dds_texture m_src_tex;
dds_texture m_packed_tex;
@@ -31,7 +31,7 @@ namespace crnlib
crnlib::vector<uint8> m_comp_data;
const crn_comp_params* m_pParams;
pixel_format m_pixel_fmt;
dxt_image::pack_params m_pack_params;
@@ -39,7 +39,7 @@ namespace crnlib
qdxt1_params m_q1_params;
qdxt5_params m_q5_params;
dds_texture::qdxt_state *m_pQDXT_state;
void clear();
bool create_dds_tex(dds_texture &dds_tex);
bool convert_to_dxt(const crn_comp_params& params);
+74 -74
View File
@@ -216,7 +216,7 @@ namespace crnlib
if (m_pImage->is_grayscale())
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;
return true;
@@ -380,7 +380,7 @@ namespace crnlib
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);
if (!out_stream.is_opened())
@@ -390,7 +390,7 @@ namespace crnlib
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);
if (!in_stream.is_opened())
@@ -417,7 +417,7 @@ namespace crnlib
clear();
set_last_error(L"Not a DDS file");
set_last_error("Not a DDS file");
uint8 hdr[4];
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;
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;
}
@@ -468,7 +468,7 @@ namespace crnlib
}
else if (desc.ddsCaps.dwCaps2 & DDSCAPS2_VOLUME)
{
set_last_error(L"Volume textures unsupported");
set_last_error("Volume textures unsupported");
return false;
}
}
@@ -479,7 +479,7 @@ namespace crnlib
// nvdxt just hangs
// dxtex.exe just makes all-white textures
// So screw it.
set_last_error(L"Palettized textures unsupported");
set_last_error("Palettized textures unsupported");
return false;
}
@@ -555,7 +555,7 @@ namespace crnlib
}
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());
return false;
}
@@ -563,7 +563,7 @@ namespace crnlib
}
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;
}
else if (desc.ddpfPixelFormat.dwFlags & DDPF_RGB)
@@ -597,7 +597,7 @@ namespace crnlib
}
else
{
set_last_error(L"Unsupported format");
set_last_error("Unsupported format");
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 = pixel_format_helpers::get_bpp(m_format);
set_last_error(L"Load failed");
set_last_error("Load failed");
uint default_pitch;
if (desc.ddpfPixelFormat.dwFlags & DDPF_FOURCC)
@@ -620,19 +620,19 @@ namespace crnlib
uint pitch = desc.lPitch;
if (!pitch)
pitch = default_pitch;
#if 0
#if 0
else if (pitch & 3)
{
// 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
// 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
// Check for obviously wacky source pitches (probably a corrupted/invalid file).
else if (pitch > default_pitch * 8)
{
set_last_error(L"Invalid pitch");
set_last_error("Invalid pitch");
return false;
}
@@ -869,11 +869,11 @@ namespace crnlib
{
if (!m_width)
{
set_last_error(L"Nothing to write");
set_last_error("Nothing to write");
return false;
}
set_last_error(L"Write_dds() failed");
set_last_error("Write_dds() failed");
if (!serializer.write("DDS ", sizeof(uint32)))
return false;
@@ -1017,7 +1017,7 @@ namespace crnlib
desc.lPitch = (desc.dwWidth * bits_per_pixel) >> 3;
desc.dwFlags |= DDSD_LINEARSIZE;
}
if (!c_crnlib_little_endian_platform)
utils::endian_switch_dwords(reinterpret_cast<uint32*>(&desc), sizeof(desc) / sizeof(uint32));
@@ -1257,7 +1257,7 @@ namespace crnlib
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();
@@ -2029,7 +2029,7 @@ namespace crnlib
{
dxt1_blocks.resize(state.m_pixel_blocks.size());
float pow_mul = 1.0f;
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
@@ -2099,7 +2099,7 @@ namespace crnlib
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();
@@ -2108,11 +2108,11 @@ namespace crnlib
if (file_format == texture_file_types::cFormatInvalid)
{
set_last_error(L"Unrecognized image format extension");
set_last_error("Unrecognized image format extension");
return false;
}
set_last_error(L"Image file load failed");
set_last_error("Image file load failed");
bool success = false;
switch (file_format)
@@ -2143,7 +2143,7 @@ namespace crnlib
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;
@@ -2153,7 +2153,7 @@ namespace crnlib
{
crnlib_delete(pImg);
set_last_error(L"Failed loading image file");
set_last_error("Failed loading image file");
return false;
}
@@ -2166,12 +2166,12 @@ namespace crnlib
return true;
}
bool dds_texture::load_dds(const wchar_t* pFilename)
bool dds_texture::load_dds(const char* pFilename)
{
cfile_stream in_stream;
if (!in_stream.open(pFilename))
{
set_last_error(L"Failed opening file");
set_last_error("Failed opening file");
return false;
}
@@ -2188,11 +2188,11 @@ namespace crnlib
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();
set_last_error(L"Image file load failed");
set_last_error("Image file load failed");
if ((!pData) || (data_size < 1)) return false;
@@ -2200,14 +2200,14 @@ namespace crnlib
tex_info.m_struct_size = sizeof(crnd::crn_texture_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;
}
const pixel_format dds_fmt = (pixel_format)crnd::crnd_crn_format_to_fourcc(tex_info.m_format);
if (dds_fmt == PIXEL_FMT_INVALID)
{
set_last_error(L"Unsupported DXT format");
set_last_error("Unsupported DXT format");
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.
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;
double total_time = 0.0f;
@@ -2305,7 +2305,7 @@ namespace crnlib
#if 0
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);
}
#endif
@@ -2321,19 +2321,19 @@ namespace crnlib
return true;
}
bool dds_texture::load_crn(const wchar_t* pFilename)
bool dds_texture::load_crn(const char* pFilename)
{
cfile_stream in_stream;
if (!in_stream.open(pFilename))
{
set_last_error(L"Failed opening CRN file");
set_last_error("Failed opening CRN file");
return false;
}
crnlib::vector<uint8> 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;
}
@@ -2343,7 +2343,7 @@ namespace crnlib
}
bool dds_texture::write_to_file(
const wchar_t* pFilename,
const char* pFilename,
texture_file_types::format file_format,
crn_comp_params* pCRN_comp_params,
uint32 *pActual_quality_level, float *pActual_bitrate)
@@ -2353,7 +2353,7 @@ namespace crnlib
if (!is_valid())
{
set_last_error(L"Unable to save empty texture");
set_last_error("Unable to save empty texture");
return false;
}
@@ -2386,26 +2386,26 @@ namespace crnlib
return success;
}
bool dds_texture::save_regular(const wchar_t* pFilename)
bool dds_texture::save_regular(const char* pFilename)
{
image_u8 tmp;
image_u8* pLevel_image = get_level_image(0, 0, tmp);
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 true;
}
bool dds_texture::save_dds(const wchar_t* pFilename)
bool dds_texture::save_dds(const char* pFilename)
{
cfile_stream out_stream;
if (!out_stream.open(pFilename, cDataStreamWritable | cDataStreamSeekable))
{
set_last_error(L"Unable to open file");
set_last_error("Unable to open file");
return false;
}
@@ -2413,7 +2413,7 @@ namespace crnlib
if (!write_dds(serializer))
{
set_last_error(L"File write failed");
set_last_error("File write failed");
return false;
}
@@ -2422,34 +2422,34 @@ namespace crnlib
void dds_texture::print_crn_comp_params(const crn_comp_params& p)
{
console::debug(L"CRN compression params:");
console::debug(L" File Type: %s", crn_get_file_type_ext(p.m_file_type));
console::debug(L" Quality level: %u", p.m_quality_level);
console::debug(L" Target Bitrate: %f", p.m_target_bitrate);
console::debug(L" Faces: %u", p.m_faces);
console::debug(L" Width: %u", p.m_width);
console::debug(L" Height: %u", p.m_height);
console::debug(L" Levels: %u", p.m_levels);
console::debug(L" 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(L"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(L"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(L"Flags:");
console::debug(L" Perceptual: %u", p.get_flag(cCRNCompFlagPerceptual));
console::debug(L" Hierarchical: %u", p.get_flag(cCRNCompFlagHierarchical));
console::debug(L" UseBothBlockTypes: %u", p.get_flag(cCRNCompFlagUseBothBlockTypes));
console::debug(L" UseTransparentIndicesForBlack: %u", p.get_flag(cCRNCompFlagUseTransparentIndicesForBlack));
console::debug(L" DisableEndpointCaching: %u", p.get_flag(cCRNCompFlagDisableEndpointCaching));
console::debug(L"GrayscaleSampling: %u", p.get_flag(cCRNCompFlagGrayscaleSampling));
console::debug(L" UseDXT1ATransparency: %u", p.get_flag(cCRNCompFlagDXT1AForTransparency));
console::debug(L"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(L"NumHelperThreads: %u", p.m_num_helper_threads);
console::debug("CRN compression params:");
console::debug(" File Type: %s", crn_get_file_type_ext(p.m_file_type));
console::debug(" Quality level: %u", p.m_quality_level);
console::debug(" Target Bitrate: %f", p.m_target_bitrate);
console::debug(" Faces: %u", p.m_faces);
console::debug(" Width: %u", p.m_width);
console::debug(" Height: %u", p.m_height);
console::debug(" Levels: %u", p.m_levels);
console::debug(" Pixel Format: %s", crn_get_format_string(p.m_format));
console::debug("Use manual CRN palette sizes: %u", p.get_flag(cCRNCompFlagManualPaletteSizes));
console::debug("Color endpoints: %u", p.m_crn_color_endpoint_palette_size);
console::debug("Color selectors: %u", p.m_crn_color_selector_palette_size);
console::debug("Alpha endpoints: %u", p.m_crn_alpha_endpoint_palette_size);
console::debug("Alpha selectors: %u", p.m_crn_alpha_selector_palette_size);
console::debug("Flags:");
console::debug(" Perceptual: %u", p.get_flag(cCRNCompFlagPerceptual));
console::debug(" Hierarchical: %u", p.get_flag(cCRNCompFlagHierarchical));
console::debug(" UseBothBlockTypes: %u", p.get_flag(cCRNCompFlagUseBothBlockTypes));
console::debug(" UseTransparentIndicesForBlack: %u", p.get_flag(cCRNCompFlagUseTransparentIndicesForBlack));
console::debug(" DisableEndpointCaching: %u", p.get_flag(cCRNCompFlagDisableEndpointCaching));
console::debug("GrayscaleSampling: %u", p.get_flag(cCRNCompFlagGrayscaleSampling));
console::debug(" UseDXT1ATransparency: %u", p.get_flag(cCRNCompFlagDXT1AForTransparency));
console::debug("AdaptiveTileColorPSNRDerating: %2.2fdB", p.m_crn_adaptive_tile_color_psnr_derating);
console::debug("AdaptiveTileAlphaPSNRDerating: %2.2fdB", p.m_crn_adaptive_tile_alpha_psnr_derating);
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);
@@ -2458,7 +2458,7 @@ namespace crnlib
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;
}
@@ -2487,32 +2487,32 @@ namespace crnlib
crnlib::vector<uint8> comp_data;
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;
}
double total_time = t.get_elapsed_secs();
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;
if (!out_stream.open(pFilename, cDataStreamWritable | cDataStreamSeekable))
{
set_last_error(L"Failed opening file");
set_last_error("Failed opening file");
return false;
}
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;
}
if (!out_stream.close())
{
set_last_error(L"Failed writing to file");
set_last_error("Failed writing to file");
return false;
}
+78 -78
View File
@@ -15,7 +15,7 @@
namespace crnlib
{
extern const vec2I g_vertical_cross_image_offsets[6];
class mip_level
{
friend class dds_texture;
@@ -23,29 +23,29 @@ namespace crnlib
public:
mip_level();
~mip_level();
mip_level(const mip_level& other);
mip_level& operator= (const mip_level& rhs);
// Assumes ownership.
void assign(image_u8* p, pixel_format fmt = PIXEL_FMT_INVALID);
void assign(dxt_image* p, pixel_format fmt = PIXEL_FMT_INVALID);
void clear();
inline uint get_width() const { return m_width; }
inline uint get_height() const { return m_height; }
inline uint get_total_pixels() const { return m_width * m_height; }
inline image_u8* get_image() const { return m_pImage; }
inline dxt_image* get_dxt_image() const { return m_pDXTImage; }
image_u8* get_unpacked_image(image_u8& tmp, bool uncook) const;
inline bool is_packed() const { return m_pDXTImage != NULL; }
inline bool is_valid() const { return (m_pImage != NULL) || (m_pDXTImage != NULL); }
inline pixel_format_helpers::component_flags get_comp_flags() const { return m_comp_flags; }
inline void set_comp_flags(pixel_format_helpers::component_flags comp_flags) { m_comp_flags = comp_flags; }
@@ -53,35 +53,35 @@ namespace crnlib
inline void set_format(pixel_format fmt) { m_format = fmt; }
bool convert(pixel_format fmt, bool cook, const dxt_image::pack_params& p);
bool pack_to_dxt(const image_u8& img, pixel_format fmt, bool cook, const dxt_image::pack_params& p);
bool pack_to_dxt(pixel_format fmt, bool cook, const dxt_image::pack_params& p);
bool pack_to_dxt(pixel_format fmt, bool cook, const dxt_image::pack_params& p);
bool unpack_from_dxt(bool uncook = true);
bool set_alpha_to_luma();
bool convert(image_utils::conversion_type conv_type);
private:
uint m_width;
uint m_height;
pixel_format_helpers::component_flags m_comp_flags;
pixel_format m_format;
image_u8* m_pImage;
dxt_image* m_pDXTImage;
void cook_image(image_u8& img) const;
void uncook_image(image_u8& img) const;
};
// A face is an array of mip_level ptr's.
typedef crnlib::vector<mip_level*> mip_ptr_vec;
// And an array of one, six, or N faces make up a texture.
typedef crnlib::vector<mip_ptr_vec> face_vec;
class dds_texture
{
public:
@@ -93,8 +93,8 @@ namespace crnlib
dds_texture& operator= (const dds_texture& rhs);
void clear();
void init(uint width, uint height, uint levels, uint faces, pixel_format fmt, const wchar_t* pName);
void init(uint width, uint height, uint levels, uint faces, pixel_format fmt, const char* pName);
// Assumes ownership.
void assign(face_vec& faces);
@@ -109,10 +109,10 @@ namespace crnlib
inline bool is_valid() const { return m_faces.size() > 0; }
const dynamic_wstring& get_name() const { return m_name; }
void set_name(const dynamic_wstring& name) { m_name = name; }
const dynamic_string& get_name() const { return m_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; }
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 mip_level* get_level(uint face, uint mip) { return m_faces[face][mip]; }
bool has_alpha() const;
bool is_normal_map() const;
bool is_vertical_cross() const;
bool is_packed() const;
bool is_packed() 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(); }
// Loading/saving
bool read_dds(const wchar_t* pFilename);
bool read_dds(const char* pFilename);
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 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.
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(
const wchar_t* pFilename,
texture_file_types::format file_format,
const char* pFilename,
texture_file_types::format file_format,
crn_comp_params* pCRN_comp_params,
uint32 *pActual_quality_level, float *pActual_bitrate);
// Conversion
bool convert(pixel_format fmt, bool cook, const dxt_image::pack_params& p);
bool convert(pixel_format fmt, const dxt_image::pack_params& p);
@@ -168,16 +168,16 @@ namespace crnlib
bool convert(image_utils::conversion_type conv_type);
bool unpack_from_dxt(bool uncook = true);
bool set_alpha_to_luma();
bool set_alpha_to_luma();
void discard_mipmaps();
void discard_mips();
struct resample_params
{
resample_params() :
resample_params() :
m_pFilter("kaiser"),
m_wrapping(false),
m_srgb(false),
@@ -186,8 +186,8 @@ namespace crnlib
m_gamma(1.75f), // or 2.2f
m_multithreaded(true)
{
}
}
const char* m_pFilter;
bool m_wrapping;
bool m_srgb;
@@ -196,45 +196,45 @@ namespace crnlib
float m_gamma;
bool m_multithreaded;
};
bool resize(uint new_width, uint new_height, const resample_params& params);
struct generate_mipmap_params : public resample_params
{
generate_mipmap_params() :
generate_mipmap_params() :
resample_params(),
m_min_mip_size(1),
m_max_mips(0)
{
}
}
uint m_min_mip_size;
uint m_max_mips; // actually the max # of total levels
};
bool generate_mipmaps(const generate_mipmap_params& params, bool force);
bool crop(uint x, uint y, uint width, uint height);
bool vertical_cross_to_cubemap();
// Low-level clustered DXT (QDXT) compression
struct qdxt_state
{
qdxt_state(task_pool& tp) : m_fmt(PIXEL_FMT_INVALID), m_qdxt1(tp), m_qdxt5a(tp), m_qdxt5b(tp)
{
}
pixel_format m_fmt;
qdxt1 m_qdxt1;
qdxt5 m_qdxt5a;
qdxt5 m_qdxt5b;
crnlib::vector<dxt_pixel_block> m_pixel_blocks;
qdxt1_params m_qdxt1_params;
qdxt5_params m_qdxt5_params[2];
bool m_has_blocks[3];
void clear()
{
m_fmt = PIXEL_FMT_INVALID;
@@ -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(qdxt_state& state, dds_texture& dst_tex, const qdxt1_params& dxt1_params, const qdxt5_params& dxt5_params);
void swap(dds_texture& img);
bool check() const;
private:
dynamic_wstring m_name;
dynamic_string m_name;
uint m_width;
uint m_height;
pixel_format_helpers::component_flags m_comp_flags;
pixel_format m_format;
face_vec m_faces;
texture_file_types::format m_source_file_type;
mutable dynamic_wstring m_last_error;
mutable dynamic_string m_last_error;
inline void clear_last_error() const { m_last_error.clear(); }
inline void set_last_error(const wchar_t* p) const { m_last_error = p; }
inline void set_last_error(const char* p) const { m_last_error = p; }
void free_all_mips();
bool read_dds_internal(data_stream_serializer& serializer);
bool load_regular(const wchar_t* pFilename, texture_file_types::format file_format);
bool load_dds(const wchar_t* pFilename);
bool load_crn(const wchar_t* pFilename);
bool load_regular(const char* pFilename, texture_file_types::format file_format);
bool load_dds(const char* pFilename);
bool load_crn(const char* pFilename);
void print_crn_comp_params(const crn_comp_params& p);
bool save_regular(const wchar_t* pFilename);
bool save_dds(const wchar_t* pFilename);
bool save_comp_texture(const wchar_t* pFilename, const crn_comp_params &comp_params, uint32 *pActual_quality_level, float *pActual_bitrate);
bool save_regular(const char* pFilename);
bool save_dds(const char* pFilename);
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)
{
a.swap(b);
}
a.swap(b);
}
} // 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_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_dxt1_from_linear[cDXT1SelectorValues] = { 0U, 2U, 3U, 1U };
const uint8 g_dxt1_to_linear[cDXT1SelectorValues] = { 0U, 3U, 1U, 2U };
const uint8 g_six_alpha_invert_table[cDXT5SelectorValues] = { 1, 0, 5, 4, 3, 2, 6, 7 };
const uint8 g_eight_alpha_invert_table[cDXT5SelectorValues] = { 1, 0, 7, 6, 5, 4, 3, 2 };
const wchar_t* get_dxt_format_string(dxt_format fmt)
const char* get_dxt_format_string(dxt_format fmt)
{
switch (fmt)
{
case cDXT1: return L"DXT1";
case cDXT1A: return L"DXT1A";
case cDXT3: return L"DXT3";
case cDXT5: return L"DXT5";
case cDXT5A: return L"DXT5A";
case cDXN_XY: return L"DXN_XY";
case cDXN_YX: return L"DXN_YX";
case cDXT1: return "DXT1";
case cDXT1A: return "DXT1A";
case cDXT3: return "DXT3";
case cDXT5: return "DXT5";
case cDXT5A: return "DXT5A";
case cDXN_XY: return "DXN_XY";
case cDXN_YX: return "DXN_YX";
default: break;
}
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)
{
case cCRNDXTCompressorCRN: return L"CRN";
case cCRNDXTCompressorCRNF: return L"CRNF";
case cCRNDXTCompressorRYG: return L"RYG";
case cCRNDXTCompressorCRN: return "CRN";
case cCRNDXTCompressorCRNF: return "CRNF";
case cCRNDXTCompressorRYG: return "RYG";
#if CRNLIB_SUPPORT_ATI_COMPRESS
case cCRNDXTCompressorATI: return "ATI";
#endif
default: break;
}
CRNLIB_ASSERT(false);
return L"?";
return "?";
}
uint get_dxt_format_bits_per_pixel(dxt_format fmt)
+58 -58
View File
@@ -1,6 +1,6 @@
// File: crn_dxt.h
// See Copyright Notice and license at the end of inc/crnlib.h
#pragma once
#pragma once
#include "../inc/crnlib.h"
#include "crn_color.h"
#include "crn_vec.h"
@@ -25,7 +25,7 @@ namespace crnlib
cDXT1SelectorBits = 2U,
cDXT1SelectorValues = 1U << cDXT1SelectorBits,
cDXT1SelectorMask = cDXT1SelectorValues - 1U,
cDXTBlockShift = 2U,
cDXTBlockSize = 1U << cDXTBlockShift
};
@@ -33,28 +33,28 @@ namespace crnlib
enum dxt_format
{
cDXTInvalid = -1,
// cDXT1/1A must appear first!
cDXT1,
cDXT1A,
cDXT3,
cDXT5,
cDXT1,
cDXT1A,
cDXT3,
cDXT5,
cDXT5A,
cDXN_XY, // inverted relative to standard ATI2, 360's DXN
cDXN_YX // standard ATI2
};
const float cDXT1MaxLinearValue = 3.0f;
const float cDXT1InvMaxLinearValue = 1.0f/3.0f;
const float cDXT5MaxLinearValue = 7.0f;
const float cDXT5InvMaxLinearValue = 1.0f/7.0f;
// Converts DXT1 raw color selector index to a linear value.
extern const uint8 g_dxt1_to_linear[cDXT1SelectorValues];
// Converts DXT5 raw alpha selector index to a linear value.
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).
extern const uint8 g_dxt5_from_linear[cDXT5SelectorValues];
extern const uint8 g_dxt5_alpha6_to_linear[cDXT5SelectorValues];
extern const uint8 g_six_alpha_invert_table[cDXT5SelectorValues];
extern const uint8 g_eight_alpha_invert_table[cDXT5SelectorValues];
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);
bool get_dxt_format_has_alpha(dxt_format fmt);
const wchar_t* get_dxt_quality_string(crn_dxt_quality q);
const wchar_t* get_dxt_compressor_name(crn_dxt_compressor_type c);
const char* get_dxt_quality_string(crn_dxt_quality q);
const char* get_dxt_compressor_name(crn_dxt_compressor_type c);
struct dxt1_block
{
uint8 m_low_color[2];
uint8 m_high_color[2];
enum { cNumSelectorBytes = 4 };
uint8 m_selectors[cNumSelectorBytes];
inline void clear()
{
utils::zero_this(this);
}
// These methods assume the in-memory rep is in LE byte order.
inline uint get_low_color() const
{
@@ -100,73 +100,73 @@ namespace crnlib
{
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[1] = static_cast<uint8>((c >> 8) & 0xFF);
}
inline void set_high_color(uint16 c)
{
m_high_color[0] = static_cast<uint8>(c & 0xFF);
m_high_color[1] = static_cast<uint8>((c >> 8) & 0xFF);
}
inline bool is_constant_color_block() const { return get_low_color() == get_high_color(); }
inline bool is_alpha_block() const { return get_low_color() <= get_high_color(); }
inline bool is_non_alpha_block() const { return !is_alpha_block(); }
inline uint get_selector(uint x, uint y) const
{
CRNLIB_ASSERT((x < 4U) && (y < 4U));
return (m_selectors[y] >> (x * cDXT1SelectorBits)) & cDXT1SelectorMask;
}
inline void set_selector(uint x, uint y, uint val)
{
CRNLIB_ASSERT((x < 4U) && (y < 4U) && (val < 4U));
m_selectors[y] &= (~(cDXT1SelectorMask << (x * cDXT1SelectorBits)));
m_selectors[y] |= (val << (x * cDXT1SelectorBits));
}
static uint16 pack_color(const color_quad_u8& color, bool scaled, uint bias = 127U);
static uint16 pack_color(uint r, uint g, uint b, bool scaled, uint bias = 127U);
static color_quad_u8 unpack_color(uint16 packed_color, bool scaled, uint alpha = 255U);
static void unpack_color(uint& r, uint& g, uint& b, uint16 packed_color, bool scaled);
static uint get_block_colors3(color_quad_u8* pDst, uint16 color0, uint16 color1);
static uint get_block_colors3_round(color_quad_u8* pDst, uint16 color0, uint16 color1);
static uint get_block_colors4(color_quad_u8* pDst, uint16 color0, uint16 color1);
static uint get_block_colors4_round(color_quad_u8* pDst, uint16 color0, uint16 color1);
// pDst must point to an array at least cDXT1SelectorValues long.
static uint get_block_colors(color_quad_u8* pDst, uint16 color0, uint16 color1);
static uint get_block_colors_round(color_quad_u8* pDst, uint16 color0, uint16 color1);
static color_quad_u8 unpack_endpoint(uint32 endpoints, uint index, bool scaled, uint alpha = 255U);
static uint pack_endpoints(uint lo, uint hi);
static void get_block_colors_NV5x(color_quad_u8* pDst, uint16 packed_col0, uint16 packed_col1, bool color4);
};
CRNLIB_DEFINE_BITWISE_COPYABLE(dxt1_block);
struct dxt3_block
{
enum { cNumAlphaBytes = 8 };
uint8 m_alpha[cNumAlphaBytes];
void set_alpha(uint x, uint y, uint value, bool scaled);
uint get_alpha(uint x, uint y, bool scaled) const;
};
CRNLIB_DEFINE_BITWISE_COPYABLE(dxt3_block);
struct dxt5_block
{
uint8 m_endpoints[2];
@@ -189,23 +189,23 @@ namespace crnlib
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);
}
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);
}
inline bool is_alpha6_block() const { return get_low_alpha() <= get_high_alpha(); }
uint get_endpoints_as_word() const { return m_endpoints[0] | (m_endpoints[1] << 8); }
uint get_selectors_as_word(uint index) { CRNLIB_ASSERT(index < 3); return m_selectors[index * 2] | (m_selectors[index * 2 + 1] << 8); }
inline uint get_selector(uint x, uint y) const
{
CRNLIB_ASSERT((x < 4U) && (y < 4U));
@@ -244,7 +244,7 @@ namespace crnlib
if (byte_index < (cNumSelectorBytes - 1))
m_selectors[byte_index + 1] = static_cast<uint8>(v >> 8);
}
enum { cMaxSelectorValues = 8 };
// Results written to alpha channel.
@@ -260,19 +260,19 @@ namespace crnlib
static uint unpack_endpoint(uint packed, uint index);
static uint pack_endpoints(uint lo, uint hi);
};
CRNLIB_DEFINE_BITWISE_COPYABLE(dxt5_block);
struct dxt_pixel_block
{
color_quad_u8 m_pixels[cDXTBlockSize][cDXTBlockSize]; // [y][x]
inline void clear()
{
utils::zero_object(*this);
utils::zero_object(*this);
}
};
};
CRNLIB_DEFINE_BITWISE_COPYABLE(dxt_pixel_block);
} // 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
{
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_selectors.resize(0);
m_error = UINT64_MAX;
m_error = cUINT64_MAX;
m_alpha_block = false;
m_valid = false;
}
+1 -1
View File
@@ -62,7 +62,7 @@ namespace crnlib
m_trial_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++)
{
+1 -1
View File
@@ -20,7 +20,7 @@ namespace crnlib
m_pParams = &p;
m_pResults = &r;
r.m_error = UINT64_MAX;
r.m_error = cUINT64_MAX;
r.m_low_color = 0;
r.m_high_color = 0;
+1 -1
View File
@@ -19,7 +19,7 @@ namespace crnlib
m_num_pixels(0),
m_pSelectors(NULL),
m_alpha_comp_index(0),
m_error_to_beat(UINT64_MAX),
m_error_to_beat(cUINT64_MAX),
m_dxt1_selectors(true),
m_perceptual(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])
{
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)
return;
@@ -623,7 +623,7 @@ namespace crnlib
{
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)
return;
}
+40 -40
View File
@@ -33,7 +33,7 @@ namespace crnlib
m_has_color_blocks(false),
m_has_alpha0_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_pTask_pool(NULL),
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)
{
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);
@@ -335,7 +335,7 @@ namespace crnlib
if (m_canceled)
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))
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++)
{
@@ -664,15 +664,15 @@ namespace crnlib
#if CRNLIB_ENABLE_DEBUG_MESSAGES
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++)
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++)
console::info(L"%u ", m_encoding_hist[e] * cChunkBlockWidth * cChunkBlockHeight);
console::info("%u ", m_encoding_hist[e] * cChunkBlockWidth * cChunkBlockHeight);
}
#endif
@@ -689,7 +689,7 @@ namespace crnlib
if (m_canceled)
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))
return;
@@ -719,7 +719,7 @@ namespace crnlib
#if CRNLIB_ENABLE_DEBUG_MESSAGES
if (m_params.m_debugging)
console::info(L"Generating color training vectors");
console::info("Generating color training vectors");
#endif
const float r_scale = .5f;
@@ -804,7 +804,7 @@ namespace crnlib
#if CRNLIB_ENABLE_DEBUG_MESSAGES
if (m_params.m_debugging)
console::info(L"Begin color cluster analysis");
console::info("Begin color cluster analysis");
timer t;
t.start();
#endif
@@ -816,7 +816,7 @@ namespace crnlib
if (m_params.m_debugging)
{
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
@@ -824,7 +824,7 @@ namespace crnlib
#if CRNLIB_ENABLE_DEBUG_MESSAGES
if (m_params.m_debugging)
console::info(L"Begin color cluster assignment");
console::info("Begin color cluster assignment");
#endif
assign_color_endpoint_clusters_state state(vq, training_vecs);
@@ -850,7 +850,7 @@ namespace crnlib
#if CRNLIB_ENABLE_DEBUG_MESSAGES
if (m_params.m_debugging)
console::info(L"Completed color cluster assignment");
console::info("Completed color cluster assignment");
#endif
return true;
@@ -868,7 +868,7 @@ namespace crnlib
if (m_canceled)
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))
return;
@@ -899,7 +899,7 @@ namespace crnlib
#if CRNLIB_ENABLE_DEBUG_MESSAGES
if (m_params.m_debugging)
console::info(L"Generating alpha training vectors");
console::info("Generating alpha training vectors");
#endif
determine_alpha_endpoint_clusters_state state;
@@ -966,7 +966,7 @@ namespace crnlib
#if CRNLIB_ENABLE_DEBUG_MESSAGES
if (m_params.m_debugging)
console::info(L"Begin alpha cluster analysis");
console::info("Begin alpha cluster analysis");
timer t;
t.start();
#endif
@@ -978,7 +978,7 @@ namespace crnlib
if (m_params.m_debugging)
{
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
@@ -986,7 +986,7 @@ namespace crnlib
#if CRNLIB_ENABLE_DEBUG_MESSAGES
if (m_params.m_debugging)
console::info(L"Begin alpha cluster assignment");
console::info("Begin alpha cluster assignment");
#endif
for (uint i = 0; i <= m_pTask_pool->get_num_threads(); i++)
@@ -1013,7 +1013,7 @@ namespace crnlib
#if CRNLIB_ENABLE_DEBUG_MESSAGES
if (m_params.m_debugging)
console::info(L"Completed alpha cluster assignment");
console::info("Completed alpha cluster assignment");
#endif
return true;
@@ -1040,7 +1040,7 @@ namespace crnlib
if (m_canceled)
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()))
return;
@@ -1151,7 +1151,7 @@ namespace crnlib
if (m_params.m_debugging)
{
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
}
@@ -1163,7 +1163,7 @@ namespace crnlib
#if CRNLIB_ENABLE_DEBUG_MESSAGES
if (m_params.m_debugging)
console::info(L"Computing optimal color cluster endpoints");
console::info("Computing optimal color cluster endpoints");
#endif
for (uint i = 0; i <= m_pTask_pool->get_num_threads(); i++)
@@ -1192,7 +1192,7 @@ namespace crnlib
if (m_canceled)
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()))
return;
@@ -1311,7 +1311,7 @@ namespace crnlib
if (m_params.m_debugging)
{
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
}
@@ -1323,7 +1323,7 @@ namespace crnlib
#if CRNLIB_ENABLE_DEBUG_MESSAGES
if (m_params.m_debugging)
console::info(L"Computing optimal alpha cluster endpoints");
console::info("Computing optimal alpha cluster endpoints");
#endif
for (uint i = 0; i <= m_pTask_pool->get_num_threads(); i++)
@@ -1461,7 +1461,7 @@ namespace crnlib
if (m_canceled)
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))
return;
@@ -1632,7 +1632,7 @@ namespace crnlib
{
#if CRNLIB_ENABLE_DEBUG_MESSAGES
if (m_params.m_debugging)
console::info(L"Computing selector training vectors");
console::info("Computing selector training vectors");
#endif
const uint cColorDistToWeight = 2000;
@@ -1775,7 +1775,7 @@ namespace crnlib
if (m_params.m_debugging)
{
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
@@ -1827,7 +1827,7 @@ namespace crnlib
#if CRNLIB_ENABLE_DEBUG_MESSAGES
if (m_params.m_debugging)
console::info(L"Refining quantized color selectors");
console::info("Refining quantized color selectors");
#endif
uint total_refined_selectors = 0;
@@ -1917,7 +1917,7 @@ namespace crnlib
#if CRNLIB_ENABLE_DEBUG_MESSAGES
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
return true;
@@ -1930,7 +1930,7 @@ namespace crnlib
#if CRNLIB_ENABLE_DEBUG_MESSAGES
if (m_params.m_debugging)
console::info(L"Refining quantized alpha selectors");
console::info("Refining quantized alpha selectors");
#endif
uint total_refined_selectors = 0;
@@ -2021,7 +2021,7 @@ namespace crnlib
#if CRNLIB_ENABLE_DEBUG_MESSAGES
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
return true;
@@ -2037,7 +2037,7 @@ namespace crnlib
#if CRNLIB_ENABLE_DEBUG_MESSAGES
if (m_params.m_debugging)
console::info(L"Refining quantized color endpoints");
console::info("Refining quantized color endpoints");
#endif
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 (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
return true;
@@ -2153,7 +2153,7 @@ namespace crnlib
uint total_refined_pixels = 0;
#if CRNLIB_ENABLE_DEBUG_MESSAGES
if (m_params.m_debugging)
console::info(L"Refining quantized alpha endpoints");
console::info("Refining quantized alpha endpoints");
#endif
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 (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
return true;
@@ -2515,7 +2515,7 @@ namespace crnlib
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)
return true;
+6 -7
View File
@@ -9,8 +9,7 @@
#include "crn_image.h"
#include "crn_dxt_hc_common.h"
#include "crn_tree_clusterizer.h"
#include "crn_task_pool.h"
#include "crn_spinlock.h"
#include "crn_threading.h"
#define CRN_NO_FUNCTION_DEFINITIONS
#include "../inc/crnlib.h"
@@ -163,8 +162,8 @@ namespace crnlib
uint8 m_selectors[cBlockPixelHeight][cBlockPixelWidth];
uint8 get_by_index(uint i) const { CRNLIB_ASSERT(i < (cBlockPixelWidth * cBlockPixelHeight)); return *(&m_selectors[0][0] + i); }
void set_by_index(uint i, uint v) { CRNLIB_ASSERT(i < (cBlockPixelWidth * cBlockPixelHeight)); *(&m_selectors[0][0] + i) = static_cast<uint8>(v); }
uint8 get_by_index(uint i) const { CRNLIB_ASSERT(i < (cBlockPixelWidth * cBlockPixelHeight)); const uint8* p = (const uint8*)m_selectors; return *(p + i); }
void set_by_index(uint i, uint v) { CRNLIB_ASSERT(i < (cBlockPixelWidth * cBlockPixelHeight)); uint8* p = (uint8*)m_selectors; *(p + i) = static_cast<uint8>(v); }
};
typedef crnlib::vector<selectors> selectors_vec;
@@ -272,9 +271,9 @@ namespace crnlib
};
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(
dxt1_endpoint_optimizer::results& results,
@@ -350,7 +349,7 @@ namespace crnlib
pixel_chunk_vec m_dbg_chunk_pixels_final;
uint32 m_main_thread_id;
crn_thread_id_t m_main_thread_id;
bool m_canceled;
task_pool* m_pTask_pool;
+9 -9
View File
@@ -7,8 +7,8 @@
#endif
#include "crn_ryg_dxt.hpp"
#include "crn_dxt_fast.h"
#include "crn_task_pool.h"
#include "crn_console.h"
#include "crn_threading.h"
#if CRNLIB_SUPPORT_ATI_COMPRESS
#ifdef _DLL
@@ -216,8 +216,8 @@ namespace crnlib
dxt_format m_fmt;
const image_u8* m_pImg;
const dxt_image::pack_params* m_pParams;
uint32 m_main_thread;
int32 m_canceled;
crn_thread_id_t m_main_thread;
atomic32_t m_canceled;
};
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 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;
@@ -252,7 +252,7 @@ namespace crnlib
prev_progress_percentage = progress_percentage;
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;
}
}
@@ -351,7 +351,7 @@ namespace crnlib
if (fmt == cDXT1A)
{
options.bDXT1UseAlpha = TRUE;
options.bDXT1UseAlpha = true;
options.nAlphaThreshold = (ATI_TC_BYTE)p.m_dxt1a_alpha_threshold;
}
options.bDisableMultiThreading = (p.m_num_helper_threads == 0);
@@ -370,7 +370,7 @@ namespace crnlib
if (p.m_perceptual)
{
options.bUseChannelWeighting = TRUE;
options.bUseChannelWeighting = true;
options.fWeightingRed = .212671f;
options.fWeightingGreen = .715160f;
options.fWeightingBlue = .072169f;
@@ -405,7 +405,7 @@ namespace crnlib
init_params.m_fmt = fmt;
init_params.m_pImg = &img;
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;
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
{
uint l, h;
uint l = 0, h = 0;
get_block_endpoints(block_x, block_y, element_index, l, h);
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_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_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_le_word(uint index, uint val) { CRNLIB_ASSERT((index < 4) && (val <= cUINT16_MAX)); m_bytes[index*2] = static_cast<uint8>(val & 0xFF); m_bytes[index * 2 + 1] = static_cast<uint8>((val >> 8) & 0xFF); }
void set_be_word(uint index, uint val) { CRNLIB_ASSERT((index < 4) && (val <= cUINT16_MAX)); m_bytes[index*2+1] = static_cast<uint8>(val & 0xFF); m_bytes[index * 2] = static_cast<uint8>((val >> 8) & 0xFF); }
void clear()
{
+53 -53
View File
@@ -8,32 +8,32 @@ namespace crnlib
class dynamic_stream : public data_stream
{
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),
m_ofs(0)
{
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),
m_ofs(0)
{
open(pBuf, size, pName, attribs);
}
dynamic_stream() :
dynamic_stream() :
data_stream(),
m_ofs(0)
{
open();
}
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();
@@ -41,24 +41,24 @@ namespace crnlib
m_buf.clear();
m_buf.resize(initial_size);
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);
return true;
}
bool reopen(const wchar_t* pName, uint attribs)
bool reopen(const char* pName, uint attribs)
{
if (!m_opened)
{
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);
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)
{
@@ -70,14 +70,14 @@ namespace crnlib
memcpy(&m_buf[0], pBuf, size);
}
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);
return true;
}
return false;
}
virtual bool close()
{
if (m_opened)
@@ -87,10 +87,10 @@ namespace crnlib
m_ofs = 0;
return true;
}
return false;
}
const crnlib::vector<uint8>& get_buf() const { return m_buf; }
crnlib::vector<uint8>& get_buf() { return m_buf; }
@@ -101,102 +101,102 @@ namespace crnlib
m_buf.reserve(size);
}
}
virtual const void* get_ptr() const { return m_buf.empty() ? NULL : &m_buf[0]; }
virtual uint read(void* pBuf, uint len)
{
CRNLIB_ASSERT(pBuf && (len <= 0x7FFFFFFF));
if ((!m_opened) || (!is_readable()) || (!len))
return 0;
CRNLIB_ASSERT(m_ofs <= m_buf.size());
uint bytes_left = m_buf.size() - m_ofs;
len = math::minimum<uint>(len, bytes_left);
if (len)
memcpy(pBuf, &m_buf[m_ofs], len);
m_ofs += len;
return len;
}
virtual uint write(const void* pBuf, uint len)
{
CRNLIB_ASSERT(pBuf && (len <= 0x7FFFFFFF));
if ((!m_opened) || (!is_writable()) || (!len))
return 0;
CRNLIB_ASSERT(m_ofs <= m_buf.size());
uint new_ofs = m_ofs + len;
if (new_ofs > m_buf.size())
m_buf.resize(new_ofs);
memcpy(&m_buf[m_ofs], pBuf, len);
m_ofs = new_ofs;
return len;
}
virtual bool flush()
{
if (!m_opened)
return false;
return true;
}
virtual uint64 get_size()
{
virtual uint64 get_size()
{
if (!m_opened)
return 0;
return m_buf.size();
return m_buf.size();
}
virtual uint64 get_remaining()
{
if (!m_opened)
return 0;
CRNLIB_ASSERT(m_ofs <= m_buf.size());
return m_buf.size() - m_ofs;
}
virtual uint64 get_ofs()
virtual uint64 get_ofs()
{
if (!m_opened)
return 0;
return m_ofs;
}
virtual bool seek(int64 ofs, bool relative)
virtual bool seek(int64 ofs, bool relative)
{
if ((!m_opened) || (!is_seekable()))
return false;
int64 new_ofs = relative ? (m_ofs + ofs) : ofs;
if (new_ofs < 0)
return false;
else if (new_ofs > m_buf.size())
return false;
m_ofs = static_cast<uint>(new_ofs);
post_seek();
return true;
}
private:
crnlib::vector<uint8> m_buf;
uint m_ofs;
+38 -65
View File
@@ -1,10 +1,7 @@
// File: crn_dynamic_string.cpp
// See Copyright Notice and license at the end of inc/crnlib.h
#include "crn_core.h"
#include "crn_dynamic_string.h"
#include "crn_dynamic_wstring.h"
#include "crn_winhdr.h"
#include <stdio.h>
#include "crn_strutils.h"
namespace crnlib
{
@@ -43,51 +40,6 @@ namespace crnlib
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()
{
check();
@@ -133,7 +85,7 @@ namespace crnlib
{
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)
return -1;
@@ -153,9 +105,9 @@ namespace crnlib
CRNLIB_ASSERT(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();
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)
{
if ((new_len >= UINT16_MAX) || (!fill_char))
if ((new_len >= cUINT16_MAX) || (!fill_char))
{
CRNLIB_ASSERT(0);
return false;
}
uint cur_len = m_len;
@@ -226,22 +181,41 @@ namespace crnlib
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)
{
CRNLIB_ASSERT(pBuf);
if (buf_size >= UINT16_MAX)
if (buf_size >= cUINT16_MAX)
{
clear();
return *this;
}
#ifdef CRNLIB_BUILD_DEBUG
if ((buf_size) && (memchr(pBuf, 0, buf_size) != NULL))
{
CRNLIB_ASSERT(0);
clear();
return *this;
}
#endif
if (ensure_buf(buf_size, false))
{
@@ -569,9 +543,12 @@ namespace crnlib
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_buf_size == cUINT16_MAX) || math::is_power_of_2((uint32)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);
#endif
}
}
#endif
@@ -580,9 +557,9 @@ namespace crnlib
{
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)
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)
{
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)
{
@@ -625,8 +602,9 @@ namespace crnlib
{
uint buf_left = buf_size;
if (m_len > UINT16_MAX)
return -1;
//if (m_len > cUINT16_MAX)
// return -1;
CRNLIB_ASSUME(sizeof(m_len) == sizeof(uint16));
if (!utils::write_val((uint16)m_len, pBuf, buf_left, little_endian))
return -1;
@@ -687,9 +665,4 @@ namespace crnlib
swap(tmp);
}
dynamic_string& dynamic_string::operator= (const dynamic_wstring& rhs)
{
return set(rhs.get_ptr());
}
} // namespace crnlib
+19 -9
View File
@@ -4,12 +4,9 @@
namespace crnlib
{
class dynamic_wstring;
enum { cMaxDynamicStringLen = cUINT16_MAX - 1 };
class dynamic_string
{
friend class dynamic_wstring;
public:
inline dynamic_string() : m_buf_size(0), m_len(0), m_pStr(NULL) { }
dynamic_string(eVarArg dummy, const char* p, ...);
@@ -19,25 +16,26 @@ namespace crnlib
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.
void clear();
void optimize();
// Truncates the string to 0 chars, but does not free the buffer.
void empty();
inline const char *assume_ownership() { const char *p = m_pStr; m_pStr = NULL; m_len = 0; m_buf_size = 0; return p; }
inline uint get_len() const { return m_len; }
inline bool is_empty() const { return !m_len; }
inline const char* get_ptr() const { return m_pStr ? m_pStr : ""; }
inline const char* c_str() const { return get_ptr(); }
inline const char* get_ptr_raw() const { return m_pStr; }
inline char* get_ptr_raw() { return m_pStr; }
inline char front() const { return m_len ? m_pStr[0] : '\0'; }
inline char back() const { return m_len ? m_pStr[m_len - 1] : '\0'; }
inline char 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)); }
@@ -74,7 +72,6 @@ namespace crnlib
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_wstring& rhs);
dynamic_string& operator= (const char* p) { return set(p); }
dynamic_string& set_char(uint index, char c);
@@ -130,6 +127,9 @@ namespace crnlib
void translate_lf_to_crlf();
static inline char *create_raw_buffer(uint& buf_size_in_chars);
static inline void free_raw_buffer(char *p) { crnlib_delete_array(p); }
dynamic_string& set_from_raw_buf_and_assume_ownership(char *pBuf, uint buf_size_in_chars, uint len_in_chars);
private:
uint16 m_buf_size;
uint16 m_len;
@@ -160,4 +160,14 @@ namespace crnlib
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
-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
// See Copyright Notice and license at the end of inc/crnlib.h
#pragma once
#include "crn_winhdr.h"
namespace crnlib
{
@@ -11,22 +10,25 @@ namespace crnlib
struct file_desc
{
inline file_desc() : m_is_dir(false) { }
dynamic_wstring m_fullname;
dynamic_wstring m_base;
dynamic_wstring m_rel;
dynamic_wstring m_name;
dynamic_string m_fullname;
dynamic_string m_base;
dynamic_string m_rel;
dynamic_string m_name;
bool m_is_dir;
inline bool operator== (const file_desc& other) const { return m_fullname == other.m_fullname; }
inline bool operator< (const file_desc& other) const { return m_fullname < other.m_fullname; }
inline operator size_t() const { return static_cast<size_t>(m_fullname); }
};
typedef crnlib::vector<file_desc> file_desc_vec;
find_files() : m_last_error(S_OK) { }
inline find_files()
{
m_last_error = 0; // S_OK;
}
enum flags
{
@@ -36,19 +38,22 @@ namespace crnlib
cFlagAllowHidden = 8
};
bool find(const wchar_t* pBasepath, const wchar_t* pFilespec, uint flags = cFlagAllowFiles);
bool find(const wchar_t* pSpec, uint flags = cFlagAllowFiles);
inline HRESULT get_last_error() const { return m_last_error; }
bool find(const char* pBasepath, const char* pFilespec, uint flags = cFlagAllowFiles);
bool find(const char* pSpec, uint flags = cFlagAllowFiles);
// An HRESULT under Win32. FIXME: Abstract this better?
inline int64 get_last_error() const { return m_last_error; }
const file_desc_vec& get_files() const { return m_files; }
private:
file_desc_vec m_files;
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
+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>
void construct_array(T* p, uint n)
inline void construct_array(T* p, uint n)
{
T* q = p + n;
for ( ; p != q; ++p)
@@ -38,7 +38,7 @@ namespace crnlib
}
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;
for ( ; p != q; ++p)
+3 -3
View File
@@ -228,7 +228,7 @@ namespace crnlib
sym_freq& sf = state.syms0[num_used_syms];
sf.m_left = (uint16)i;
sf.m_right = UINT16_MAX;
sf.m_right = cUINT16_MAX;
sf.m_freq = freq;
num_used_syms++;
}
@@ -263,8 +263,8 @@ namespace crnlib
#else
// Dummy node
sym_freq& sf = state.syms0[num_used_syms];
sf.m_left = UINT16_MAX;
sf.m_right = UINT16_MAX;
sf.m_left = cUINT16_MAX;
sf.m_right = cUINT16_MAX;
sf.m_freq = UINT_MAX;
uint next_internal_node = num_used_syms + 1;
+39 -35
View File
@@ -6,6 +6,8 @@
#include "crn_resampler.h"
#include "crn_threaded_resampler.h"
#include "crn_strutils.h"
#include "crn_file_utils.h"
#include "crn_threading.h"
#define STBI_HEADER_FILE_ONLY
#include "crn_stb_image.cpp"
@@ -18,10 +20,10 @@ namespace crnlib
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;
unsigned char* pData = stbi_load_w(pFilename, &x, &y, &n, 4);
unsigned char* pData = stbi_load(pFilename, &x, &y, &n, 4);
if (!pData)
return false;
@@ -66,20 +68,20 @@ namespace crnlib
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())
return false;
bool bSaveBMP = false;
dynamic_wstring ext(pFilename);
if (get_extension(ext))
dynamic_string ext(pFilename);
if (file_utils::get_extension(ext))
{
if (ext == L"bmp")
if (ext == "bmp")
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;
}
}
@@ -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))
{
@@ -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
{
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;
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;
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())
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;
@@ -259,13 +261,13 @@ namespace crnlib
if (pFilename)
{
dynamic_wstring str(pFilename);
dynamic_string str(pFilename);
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;
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;
}
@@ -712,32 +714,34 @@ namespace crnlib
if (!total_blocks)
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;
}
void print_ssim(const image_u8& src_img, const image_u8& dst_img)
{
double y_ssim = compute_ssim(src_img, dst_img, -1);
console::printf(L"Luma MSSIM: %f, Scaled: %f", y_ssim, (y_ssim - .8f) / .2f);
src_img;
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);
//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);
//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);
//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)
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
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)
@@ -808,35 +812,35 @@ namespace crnlib
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()) )
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;
if (src_img.has_rgb() || dst_img.has_rgb())
{
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.print(L"RGB Average");
error_metrics.print("RGB Average");
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.print(L"Red ");
error_metrics.print("Red ");
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.print(L"Blue ");
error_metrics.print("Blue ");
}
if (src_img.has_alpha() || dst_img.has_alpha())
{
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
{
enum pixel_format;
namespace image_utils
{
bool load_from_file_stb(const wchar_t* pFilename, image_u8& img);
enum
bool load_from_file_stb(const char* pFilename, image_u8& img);
enum
{
cSaveIgnoreAlpha = 1,
cSaveGrayscale = 2
@@ -19,18 +19,18 @@ namespace crnlib
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 load_from_file(image_u8& dest, const wchar_t* pFilename, int flags = 0);
bool save_to_file_stb(const char* pFilename, const image_u8& img, uint save_flags = 0, int comp_index = cSaveLuma);
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 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);
struct resample_params
{
resample_params() :
@@ -46,7 +46,7 @@ namespace crnlib
m_multithreaded(true)
{
}
uint m_dst_width;
uint m_dst_height;
const char* m_pFilter;
@@ -58,40 +58,40 @@ namespace crnlib
float m_source_gamma;
bool m_multithreaded;
};
bool resample_single_thread(const image_u8& src, image_u8& dst, const resample_params& params);
bool resample_multithreaded(const image_u8& src, image_u8& dst, const resample_params& params);
bool resample(const image_u8& src, image_u8& dst, const resample_params& params);
bool compute_delta(image_u8& dest, image_u8& a, image_u8& b, uint scale = 2);
class error_metrics
{
public:
error_metrics() { utils::zero_this(this); }
void print(const wchar_t* pName) const;
void print(const char* pName) const;
// If num_channels==0, luma error is computed.
// If pHist != NULL, it must point to a 256 entry array.
bool compute(const image_u8& a, const image_u8& b, uint first_channel, uint num_channels, bool average_component_error = true);
uint mMax;
double mMean;
double mMeanSquared;
double mRootMeanSquared;
double mPeakSNR;
inline bool operator== (const error_metrics& other) const
{
return mPeakSNR == other.mPeakSNR;
}
inline bool operator< (const error_metrics& other) const
{
return mPeakSNR < other.mPeakSNR;
}
inline bool operator> (const error_metrics& other) const
{
return mPeakSNR > other.mPeakSNR;
@@ -99,43 +99,43 @@ namespace crnlib
};
void print_image_metrics(const image_u8& src_img, const image_u8& dst_img);
double compute_block_ssim(uint n, const uint8* pX, const uint8* pY);
double compute_ssim(const image_u8& a, const image_u8& b, int channel_index);
void print_ssim(const image_u8& src_img, const image_u8& dst_img);
enum conversion_type
{
cConversion_Invalid = -1,
cConversion_To_CCxY,
cConversion_From_CCxY,
cConversion_To_xGxR,
cConversion_From_xGxR,
cConversion_To_xGBR,
cConversion_From_xGBR,
cConversion_To_AGBR,
cConversion_From_AGBR,
cConversion_XY_to_XYZ,
cConversion_Y_To_A,
cConversion_A_To_RGBA,
cConversion_Y_To_RGB,
cConversionTotal
};
void convert_image(image_u8& img, conversion_type conv_type);
image_utils::conversion_type get_conversion_type(bool cooking, pixel_format fmt);
image_utils::conversion_type get_image_conversion_type_from_crn_format(crn_format fmt);
double compute_std_dev(uint n, const color_quad_u8* pPixels, uint first_channel, uint num_channels);
}
}
+39 -34
View File
@@ -4,17 +4,18 @@
#include "crn_lzma_codec.h"
#include "crn_strutils.h"
#include "crn_checksum.h"
#include "lzma_lzmalib.h"
#include "lzma_LzmaLib.h"
#include "crn_threading.h"
namespace crnlib
{
lzma_codec::lzma_codec() :
lzma_codec::lzma_codec() :
m_pCompress(LzmaCompress),
m_pUncompress(LzmaUncompress)
{
CRNLIB_ASSUME(cLZMAPropsSize == LZMA_PROPS_SIZE);
}
lzma_codec::~lzma_codec()
{
}
@@ -23,29 +24,29 @@ namespace crnlib
{
if (n > 1024U*1024U*1024U)
return false;
uint max_comp_size = n + math::maximum<uint>(128, n >> 8);
buf.resize(sizeof(header) + max_comp_size);
header* pHDR = reinterpret_cast<header*>(&buf[0]);
uint8* pComp_data = &buf[sizeof(header)];
utils::zero_object(*pHDR);
pHDR->m_uncomp_size = n;
pHDR->m_adler32 = adler32(p, n);
if (n)
{
size_t destLen = 0;
size_t outPropsSize = 0;
int status = SZ_ERROR_INPUT_EOF;
for (uint trial = 0; trial < 3; trial++)
{
destLen = max_comp_size;
outPropsSize = cLZMAPropsSize;
status = (*m_pCompress)(pComp_data, &destLen, reinterpret_cast<const unsigned char*>(p), n,
pHDR->m_lzma_props, &outPropsSize,
-1, /* 0 <= level <= 9, default = 5 */
@@ -54,83 +55,87 @@ namespace crnlib
-1, /* 0 <= lp <= 4, default = 0 */
-1, /* 0 <= pb <= 4, default = 2 */
-1, /* 5 <= fb <= 273, default = 32 */
#ifdef WIN32
(g_number_of_processors > 1) ? 2 : 1
#else
1
#endif
);
if (status != SZ_ERROR_OUTPUT_EOF)
break;
max_comp_size += ((n+1)/2);
buf.resize(sizeof(header) + max_comp_size);
pHDR = reinterpret_cast<header*>(&buf[0]);
pComp_data = &buf[sizeof(header)];
}
if (status != SZ_OK)
if (status != SZ_OK)
{
buf.clear();
return false;
}
pHDR->m_comp_size = static_cast<uint>(destLen);
buf.resize(CRNLIB_SIZEOF_U32(header) + static_cast<uint32>(destLen));
}
}
pHDR->m_sig = header::cSig;
pHDR->m_checksum = static_cast<uint8>(adler32((uint8*)pHDR + header::cChecksumSkipBytes, sizeof(header) - header::cChecksumSkipBytes));
return true;
}
bool lzma_codec::unpack(const void* p, uint n, crnlib::vector<uint8>& buf)
{
buf.resize(0);
if (n < sizeof(header))
return false;
const header& hdr = *static_cast<const header*>(p);
if (hdr.m_sig != header::cSig)
return false;
if (static_cast<uint8>(adler32((const uint8*)&hdr + header::cChecksumSkipBytes, sizeof(hdr) - header::cChecksumSkipBytes)) != hdr.m_checksum)
return false;
if (!hdr.m_uncomp_size)
return true;
if (!hdr.m_comp_size)
return false;
if (hdr.m_uncomp_size > 1024U*1024U*1024U)
return false;
if (!buf.try_resize(hdr.m_uncomp_size))
if (!buf.try_resize(hdr.m_uncomp_size))
return false;
const uint8* pComp_data = static_cast<const uint8*>(p) + sizeof(header);
size_t srcLen = n - sizeof(header);
if (srcLen < hdr.m_comp_size)
return false;
size_t destLen = hdr.m_uncomp_size;
int status = (*m_pUncompress)(&buf[0], &destLen, pComp_data, &srcLen,
hdr.m_lzma_props, cLZMAPropsSize);
hdr.m_lzma_props, cLZMAPropsSize);
if ((status != SZ_OK) || (destLen != hdr.m_uncomp_size))
{
buf.clear();
return false;
return false;
}
if (adler32(&buf[0], buf.size()) != hdr.m_adler32)
{
buf.clear();
return false;
}
return true;
}
+3 -3
View File
@@ -12,14 +12,14 @@ namespace crnlib
~lzma_codec();
// 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 unpack(const void* p, uint n, crnlib::vector<uint8>& buf);
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 */
int level, /* 0 <= level <= 9, default = 5 */
unsigned dictSize, /* default = (1 << 24) */
@@ -30,7 +30,7 @@ namespace crnlib
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);
LzmaCompressFuncPtr m_pCompress;
+8
View File
@@ -216,6 +216,14 @@ namespace crnlib
void compute_lower_pow2_dim(int& width, int& height);
void compute_upper_pow2_dim(int& width, int& height);
inline bool equal_tol(float a, float b, float t)
{
return fabs(a - b) < ((maximum(fabs(a), fabs(b)) + 1.0f) * t);
}
inline bool equal_tol(double a, double b, double t)
{
return fabs(a - b) < ((maximum(fabs(a), fabs(b)) + 1.0f) * t);
}
}
} // namespace crnlib
+92 -11
View File
@@ -1,15 +1,16 @@
// File: crn_mem.cpp
// See Copyright Notice and license at the end of inc/crnlib.h
#include "crn_core.h"
#include "crn_spinlock.h"
#include "crn_console.h"
#include "../inc/crnlib.h"
#include <malloc.h>
#if CRNLIB_USE_WIN32_API
#include "crn_winhdr.h"
#endif
#define CRNLIB_MEM_STATS 0
#ifndef CRNLIB_USE_WIN32_API
#if !CRNLIB_USE_WIN32_API
#define _msize malloc_usable_size
#endif
@@ -59,7 +60,7 @@ namespace crnlib
return new_total_allocated;
}
#endif // CRNLIB_MEM_STATS
static void* crnlib_default_realloc(void* p, size_t size, size_t* pActual_size, bool movable, void* pUser_data)
{
pUser_data;
@@ -88,7 +89,6 @@ namespace crnlib
#ifdef WIN32
p_new = ::_expand(p, size);
#else
p_new = NULL;
#endif
@@ -121,15 +121,96 @@ namespace crnlib
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_msize_func g_pMSize = crnlib_default_msize;
#endif
static void* g_pUser_data;
void crnlib_mem_error(const char* p_msg)
{
crnlib_assert(p_msg, __FILE__, __LINE__);
}
void* crnlib_malloc(size_t size)
{
return crnlib_malloc(size, NULL);
}
void* crnlib_malloc(size_t size, size_t* pActual_size)
{
size = (size + sizeof(uint32) - 1U) & ~(sizeof(uint32) - 1U);
@@ -182,7 +263,7 @@ namespace crnlib
size_t cur_size = p ? (*g_pMSize)(p, g_pUser_data) : 0;
CRNLIB_ASSERT(!p || (cur_size >= sizeof(uint32)));
#endif
if ((size) && (size < sizeof(uint32)))
if ((size) && (size < sizeof(uint32)))
size = sizeof(uint32);
size_t actual_size = size;
@@ -253,19 +334,19 @@ namespace crnlib
return (*g_pMSize)(p, g_pUser_data);
}
void crnlib_print_mem_stats()
{
#if CRNLIB_MEM_STATS
if (console::is_initialized())
{
console::debug(L"crnlib_print_mem_stats:");
console::debug(L"Current blocks: %u, allocated: %I64u, max ever allocated: %I64i", g_total_blocks, (int64)g_total_allocated, (int64)g_max_allocated);
console::debug("crnlib_print_mem_stats:");
console::debug("Current blocks: %u, allocated: " CRNLIB_INT64_FORMAT_SPECIFIER ", max ever allocated: " CRNLIB_INT64_FORMAT_SPECIFIER, g_total_blocks, (int64)g_total_allocated, (int64)g_max_allocated);
}
else
{
printf("crnlib_print_mem_stats:\n");
printf("Current blocks: %u, allocated: %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
}
+25 -1
View File
@@ -14,7 +14,8 @@ namespace crnlib
const uint32 CRNLIB_MAX_POSSIBLE_BLOCK_SIZE = 0x7FFF0000U;
#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_calloc(size_t count, size_t size, size_t* pActual_size = NULL);
void crnlib_free(void* p);
@@ -183,3 +184,26 @@ 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];
}
const wchar_t* 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)
const char* get_pixel_format_string(pixel_format fmt)
{
switch (fmt)
{
@@ -99,27 +70,7 @@ namespace crnlib
return "?";
}
const wchar_t* 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)
const char* get_crn_format_string(crn_format fmt)
{
switch (fmt)
{
+2 -4
View File
@@ -12,11 +12,9 @@ namespace crnlib
uint get_num_formats();
pixel_format get_pixel_format_by_index(uint index);
const wchar_t* get_pixel_format_string(pixel_format fmt);
const char* get_pixel_format_stringa(pixel_format fmt);
const char* get_pixel_format_string(pixel_format fmt);
const wchar_t* get_crn_format_string(crn_format fmt);
const char* get_crn_format_stringa(crn_format fmt);
const char* get_crn_format_string(crn_format fmt);
inline bool is_grayscale(pixel_format fmt)
{
+78 -5
View File
@@ -1,6 +1,73 @@
// File: crn_platform.cpp
// See Copyright Notice and license at the end of inc/crnlib.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"
bool crnlib_is_debugger_present(void)
@@ -8,12 +75,18 @@ bool crnlib_is_debugger_present(void)
return IsDebuggerPresent() != 0;
}
void crnlib_debug_break(void)
{
DebugBreak();
}
void crnlib_output_debug_string(const char* 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
#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);
void crnlib_debug_break(void);
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
void crnlib_assert(const char* pExp, const char* pFile, unsigned line);
void crnlib_fail(const char* pExp, const char* pFile, unsigned line);
#if CRNLIB_LITTLE_ENDIAN_CPU
const bool c_crnlib_little_endian_platform = true;
#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];
if (c)
{
CRNLIB_ASSERT(next_code[c] <= UINT16_MAX);
CRNLIB_ASSERT(next_code[c] <= cUINT16_MAX);
pCodes[i] = static_cast<uint16>(next_code[c]++);
CRNLIB_ASSERT(math::total_bits(pCodes[i]) <= pCodesizes[i]);
@@ -300,7 +300,7 @@ namespace crnlib
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);
}
+14 -13
View File
@@ -61,7 +61,7 @@ namespace crnlib
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_pBlocks = pBlocks;
@@ -99,6 +99,11 @@ namespace crnlib
if (debugging)
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_x = 0; chunk_x < num_chunks_x; chunk_x++)
@@ -197,13 +202,8 @@ namespace crnlib
if (mean_squared)
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)
// 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 );
peak_snr = peak_snr - color_derating;
@@ -306,7 +306,7 @@ namespace crnlib
#if GENERATE_DEBUG_IMAGES
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
} // level
@@ -440,7 +440,7 @@ namespace crnlib
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))
return;
@@ -547,7 +547,8 @@ namespace crnlib
{
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++)
{
@@ -646,7 +647,7 @@ namespace crnlib
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))
return;
@@ -681,7 +682,7 @@ namespace crnlib
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++)
{
@@ -809,7 +810,7 @@ namespace crnlib
{
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_pDst_elements = pDst_elements;
@@ -824,7 +825,7 @@ namespace crnlib
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 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_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());
+40 -42
View File
@@ -2,8 +2,6 @@
// See Copyright Notice and license at the end of inc/crnlib.h
#pragma once
#include "crn_dxt.h"
#include "crn_task_pool.h"
#include "crn_spinlock.h"
#include "crn_hash_map.h"
#include "crn_clusterizer.h"
#include "crn_hash.h"
@@ -17,8 +15,8 @@ namespace crnlib
qdxt1_params()
{
clear();
}
}
void clear()
{
m_quality_level = cMaxQuality;
@@ -44,27 +42,27 @@ namespace crnlib
m_quality_level = quality_level;
m_dxt1a_alpha_threshold = pp.m_dxt1a_alpha_threshold;
}
enum { cMaxQuality = cCRNMaxQualityLevel };
uint m_quality_level;
uint m_dxt1a_alpha_threshold;
crn_dxt_quality m_dxt_quality;
bool m_perceptual;
bool m_use_alpha_blocks;
bool m_hierarchical;
struct mip_desc
{
uint m_first_block;
uint m_block_width;
uint m_block_height;
};
uint m_num_mips;
enum { cMaxMips = 128 };
mip_desc m_mip_desc[cMaxMips];
typedef bool (*progress_callback_func)(uint percentage_completed, void* pProgress_data);
progress_callback_func m_pProgress_func;
void* m_pProgress_data;
@@ -75,67 +73,67 @@ namespace crnlib
class qdxt1
{
CRNLIB_NO_COPY_OR_ASSIGNMENT_OP(qdxt1);
public:
qdxt1(task_pool& task_pool);
~qdxt1();
void clear();
bool init(uint n, const dxt_pixel_block* pBlocks, const qdxt1_params& params);
uint get_num_blocks() const { return m_num_blocks; }
const dxt_pixel_block* get_blocks() const { return m_pBlocks; }
bool pack(dxt1_block* pDst_elements, uint elements_per_block, const qdxt1_params& params, float quality_power_mul);
private:
task_pool* m_pTask_pool;
uint32 m_main_thread_id;
crn_thread_id_t m_main_thread_id;
bool m_canceled;
uint m_progress_start;
uint m_progress_range;
uint m_num_blocks;
const dxt_pixel_block* m_pBlocks;
dxt1_block* m_pDst_elements;
uint m_elements_per_block;
qdxt1_params m_params;
uint m_max_selector_clusters;
int m_prev_percentage_complete;
typedef vec<6, float> vec6F;
typedef clusterizer<vec6F> vec6F_clusterizer;
vec6F_clusterizer m_endpoint_clusterizer;
crnlib::vector< crnlib::vector<uint> > m_endpoint_cluster_indices;
typedef vec<16, float> vec16F;
typedef threaded_clusterizer<vec16F> vec16F_clusterizer;
typedef vec16F_clusterizer::weighted_vec weighted_selector_vec;
typedef vec16F_clusterizer::weighted_vec_array weighted_selector_vec_array;
vec16F_clusterizer m_selector_clusterizer;
crnlib::vector< crnlib::vector<uint> > m_cached_selector_cluster_indices[qdxt1_params::cMaxQuality + 1];
struct cluster_id
{
cluster_id() : m_hash(0)
{
}
cluster_id(const crnlib::vector<uint>& indices)
{
set(indices);
}
void set(const crnlib::vector<uint>& indices)
{
m_cells.resize(indices.size());
@@ -145,29 +143,29 @@ namespace crnlib
std::sort(m_cells.begin(), m_cells.end());
m_hash = fast_hash(&m_cells[0], sizeof(m_cells[0]) * m_cells.size());
m_hash = fast_hash(&m_cells[0], sizeof(m_cells[0]) * m_cells.size());
}
bool operator< (const cluster_id& rhs) const
{
return m_cells < rhs.m_cells;
}
bool operator== (const cluster_id& rhs) const
{
if (m_hash != rhs.m_hash)
if (m_hash != rhs.m_hash)
return false;
return m_cells == rhs.m_cells;
}
crnlib::vector<uint32> m_cells;
size_t m_hash;
operator size_t() const { return m_hash; }
};
typedef crnlib::hash_map<cluster_id, uint> cluster_hash;
cluster_hash m_cluster_hash;
spinlock m_cluster_hash_lock;
@@ -178,10 +176,10 @@ namespace crnlib
void pack_endpoints_task(uint64 data, void* pData_ptr);
void optimize_selectors_task(uint64 data, void* pData_ptr);
bool create_selector_clusters(uint max_selector_clusters, crnlib::vector< crnlib::vector<uint> >& selector_cluster_indices);
inline dxt1_block& get_block(uint index) const { return m_pDst_elements[index * m_elements_per_block]; }
};
CRNLIB_DEFINE_BITWISE_MOVABLE(qdxt1::cluster_id);
} // namespace crnlib
+7 -6
View File
@@ -62,7 +62,7 @@ namespace crnlib
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_pBlocks = pBlocks;
@@ -286,7 +286,7 @@ namespace crnlib
#if QDXT5_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
} // level
@@ -419,7 +419,7 @@ namespace crnlib
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))
return;
@@ -444,7 +444,8 @@ namespace crnlib
{
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++)
{
@@ -521,7 +522,7 @@ namespace crnlib
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))
return;
@@ -735,7 +736,7 @@ namespace crnlib
{
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_pDst_elements = pDst_elements;
+13 -15
View File
@@ -1,8 +1,6 @@
// File: crn_qdxt5.h
// See Copyright Notice and license at the end of inc/crnlib.h
#pragma once
#include "crn_task_pool.h"
#include "crn_spinlock.h"
#include "crn_hash_map.h"
#include "crn_clusterizer.h"
#include "crn_hash.h"
@@ -17,23 +15,23 @@ namespace crnlib
qdxt5_params()
{
clear();
}
}
void clear()
{
m_quality_level = cMaxQuality;
m_dxt_quality = cCRNDXTQualityUber;
m_pProgress_func = NULL;
m_pProgress_data = NULL;
m_num_mips = 0;
m_hierarchical = true;
utils::zero_object(m_mip_desc);
m_comp_index = 3;
m_progress_start = 0;
m_progress_range = 100;
m_use_both_block_types = true;
}
@@ -50,7 +48,7 @@ namespace crnlib
uint m_quality_level;
crn_dxt_quality m_dxt_quality;
bool m_hierarchical;
struct mip_desc
{
uint m_first_block;
@@ -67,20 +65,20 @@ namespace crnlib
void* m_pProgress_data;
uint m_progress_start;
uint m_progress_range;
uint m_comp_index;
bool m_use_both_block_types;
};
class qdxt5
{
CRNLIB_NO_COPY_OR_ASSIGNMENT_OP(qdxt5);
public:
qdxt5(task_pool& task_pool);
~qdxt5();
void clear();
bool init(uint n, const dxt_pixel_block* pBlocks, const qdxt5_params& params);
@@ -92,7 +90,7 @@ namespace crnlib
private:
task_pool* m_pTask_pool;
uint32 m_main_thread_id;
crn_thread_id_t m_main_thread_id;
bool m_canceled;
uint m_progress_start;
@@ -146,7 +144,7 @@ namespace crnlib
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
@@ -156,7 +154,7 @@ namespace crnlib
bool operator== (const cluster_id& rhs) const
{
if (m_hash != rhs.m_hash)
if (m_hash != rhs.m_hash)
return false;
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());
}
uint64 random::urand64()
{
uint64 result = urand32();
result <<= 32ULL;
result |= urand32();
return result;
}
uint32 random::fast_urand32()
{
return m_well512.next();
@@ -317,6 +324,13 @@ namespace crnlib
return SHR3 ^ CONG;
}
uint64 fast_random::urand64()
{
uint64 result = urand32();
result <<= 32ULL;
result |= urand32();
return result;
}
int fast_random::irand(int l, int h)
{
CRNLIB_ASSERT(l < h);
+2
View File
@@ -63,6 +63,7 @@ namespace crnlib
void seed(uint32 i1, uint32 i2, uint32 i3);
uint32 urand32();
uint64 urand64();
// "Fast" variant uses no multiplies.
uint32 fast_urand32();
@@ -99,6 +100,7 @@ namespace crnlib
void seed(uint32 i);
uint32 urand32();
uint64 urand64();
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).
// 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);
#ifdef _MSC_VER
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);
#ifdef _MSC_VER
extern int stbi_write_tga_w (wchar_t const *filename, int x, int y, int comp, const void *data);
#endif
#endif
// PRIMARY API - works on images of any type
// load image by filename, open file, or memory buffer
#ifndef STBI_NO_STDIO
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);
#endif
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);
#endif
@@ -227,7 +233,7 @@ extern void stbi_ldr_to_hdr_scale(float scale);
// get a VERY brief reason for failure
// NOT THREADSAFE
extern char *stbi_failure_reason (void);
extern const char *stbi_failure_reason (void);
// free the loaded image -- this is just stb_free()
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
static char *failure_reason;
static const char *failure_reason;
char *stbi_failure_reason(void)
const char *stbi_failure_reason(void)
{
return failure_reason;
}
static int e(char *str)
static int e(const char *str)
{
failure_reason = str;
return 0;
@@ -485,6 +491,7 @@ unsigned char *stbi_load(char const *filename, int *x, int *y, int *comp, int re
return result;
}
#ifdef _MSC_VER
unsigned char *stbi_load_w(wchar_t const *filename, int *x, int *y, int *comp, int req_comp)
{
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);
return result;
}
#endif
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
if (s->img_file) {
fread(buffer, 1, n, s->img_file);
size_t nr = fread(buffer, 1, n, s->img_file); nr;
return;
}
#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)
{
out, in_far, w, hs;
return in_near;
}
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
int 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)
{
hs, in_far;
// need to generate two samples horizontally for every one in input
int i;
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)
{
hs;
// need to generate 2x2 samples for every one in input
int i,t0,t1;
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)
{
in_far;
// resample with nearest-neighbor
int i,j;
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);
if (!a->out) return e("outofmem", "Out of memory");
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");
}
else // interlaced:
{
if (raw_len < (img_n * x + 1) * y) return e("not enough pixels","Corrupt PNG");
}
}
for (j=0; j < y; ++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)
{
len;
uint32 i, pixel_count = a->s.img_x * a->s.img_y;
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;
int i, j;
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_repeating = 0;
int read_next_pixel = 1;
@@ -3402,6 +3420,7 @@ int stbi_psd_test_file(FILE *f)
{
stbi s;
int r,n = ftell(f);
memset(&s, 0, sizeof(s));
start_file(&s, f);
r = psd_test(&s);
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
static int hdr_test(stbi *s)
{
char *signature = "#?RADIANCE\n";
const char *signature = "#?RADIANCE\n";
int i;
for (i=0; signature[i]; ++i)
if (get8(s) != signature[i])
@@ -3628,6 +3647,7 @@ int stbi_hdr_test_file(FILE *f)
{
stbi s;
int r,n = ftell(f);
memset(&s, 0, sizeof(s));
start_file(&s, f);
r = hdr_test(&s);
fseek(f,n,SEEK_SET);
@@ -3639,7 +3659,8 @@ int stbi_hdr_test_file(FILE *f)
static char *hdr_gettoken(stbi *z, char *buffer)
{
int len=0;
char *s = buffer, c = '\0';
//char *s = buffer;
char c = '\0';
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);
switch (comp) {
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;
case 4:
if (!write_alpha) {
for (k=0; k < 3; ++k)
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;
}
/* FALLTHROUGH */
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;
}
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;
}
#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, ...)
{
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;
}
#endif
int stbi_write_bmp(char const *filename, int x, int y, int comp, const void *data)
{
int pad = (-x*3) & 3;
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
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 pad = (-x*3) & 3;
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
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 has_alpha = !(comp & 1);
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 has_alpha = !(comp & 1);
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?
// 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
#include "crn_core.h"
#include "crn_strutils.h"
#include <direct.h>
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)
{
CRNLIB_ASSERT(pDst && pSrc && dst_len);
@@ -164,76 +181,6 @@ namespace crnlib
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)
{
value = 0;
@@ -348,50 +295,6 @@ namespace crnlib
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)
{
value = 0;
@@ -467,77 +370,66 @@ namespace crnlib
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)
{
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);
value = 0;
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;
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)
round_digit = 10;
double whole = 0, frac = 0, scale = 1, exponent = 1;
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;
if (p >= pEnd)
{
status = AF_NODIGITS;
goto af_exit;
}
while (*buf)
{
if (!isspace(*buf))
break;
buf++;
if (++buf >= pEnd)
{
status = AF_NODIGITS;
goto af_exit;
}
}
p = buf;
while (*buf)
{
p = buf;
if (buf >= pEnd)
break;
int i = *buf++;
switch (i)
@@ -616,7 +508,7 @@ namespace crnlib
whole_count++;
if (whole > 1e+30f)
if (whole > 1e+100)
{
status = AF_OVRFLOW;
goto af_exit;
@@ -646,6 +538,10 @@ namespace crnlib
while (*buf)
{
p = buf;
if (buf >= pEnd)
break;
int i = *buf++;
if (i == '+')
@@ -674,7 +570,7 @@ namespace crnlib
{
got_num_flag = 1;
if ((e = (e * 10) + (i - 48)) > 16)
if ((e = (e * 10) + (i - 48)) > 100)
{
status = AF_EXPONENT;
goto af_exit;
@@ -709,552 +605,9 @@ namespace crnlib
whole = -whole;
value = whole;
p = buf;
af_exit:
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
+19 -43
View File
@@ -2,58 +2,34 @@
// See Copyright Notice and license at the end of inc/crnlib.h
#pragma once
#ifdef WIN32
#define CRNLIB_PATH_SEPERATOR_CHAR '\\'
#else
#define CRNLIB_PATH_SEPERATOR_CHAR '/'
#endif
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);
bool int_to_string(int 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 wchar_t*& pBuf, int& 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_uint64(const char*& pBuf, uint64& 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 = 10U);
bool string_to_float(const wchar_t*& p, float& value, uint round_digit = 10U);
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);
bool string_to_float(const char*& p, float& value, uint round_digit = 512U);
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);
} // namespace crnlib
+8 -8
View File
@@ -361,7 +361,7 @@ namespace crnlib
if (!max_freq)
return false;
if (max_freq <= UINT16_MAX)
if (max_freq <= cUINT16_MAX)
{
for (uint i = 0; i < total_syms; i++)
sym_freq16[i] = static_cast<uint16>(pSym_freq[i]);
@@ -381,7 +381,7 @@ namespace crnlib
if (fl < 1)
fl = 1;
CRNLIB_ASSERT(fl <= UINT16_MAX);
CRNLIB_ASSERT(fl <= cUINT16_MAX);
sym_freq16[i] = static_cast<uint16>(fl);
}
@@ -917,7 +917,7 @@ namespace crnlib
freq++;
model.m_sym_freq[sym] = static_cast<uint16>(freq);
if (freq == UINT16_MAX)
if (freq == cUINT16_MAX)
model.rescale();
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)];
CRNLIB_ASSERT(t != UINT32_MAX);
sym = t & UINT16_MAX;
CRNLIB_ASSERT(t != cUINT32_MAX);
sym = t & cUINT16_MAX;
len = t >> 16;
CRNLIB_ASSERT(model.m_code_sizes[sym] == len);
@@ -1462,7 +1462,7 @@ namespace crnlib
freq++;
model.m_sym_freq[sym] = static_cast<uint16>(freq);
if (freq == UINT16_MAX)
if (freq == cUINT16_MAX)
model.rescale();
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)];
CRNLIB_ASSERT(t != UINT32_MAX);
sym = t & UINT16_MAX;
CRNLIB_ASSERT(t != cUINT32_MAX);
sym = t & cUINT16_MAX;
len = t >> 16;
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))
{
//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.
local_params.set_flag(cCRNCompFlagPerceptual, false);
@@ -53,6 +53,18 @@ namespace crnlib
((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))
{
crnlib_delete(pTexture_comp);
@@ -95,7 +107,7 @@ namespace crnlib
{
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;
@@ -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;
@@ -153,7 +165,7 @@ namespace crnlib
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) ||
((bitrate <= local_params.m_target_bitrate) && (best_bitrate > local_params.m_target_bitrate)) ||
@@ -165,7 +177,7 @@ namespace crnlib
best_quality_level = trial_quality;
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))
@@ -188,7 +200,7 @@ namespace crnlib
(highest_bitrate < local_params.m_target_bitrate) &&
(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;
@@ -214,7 +226,7 @@ namespace crnlib
if (pActual_quality_level) *pActual_quality_level = best_quality_level;
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;
}
@@ -310,14 +322,14 @@ namespace crnlib
{
if (work_tex.get_num_faces() > 1)
{
console::warning(L"Can't crop cubemap textures");
console::warning("Can't crop cubemap textures");
}
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()))
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)
{
console::warning(L"Can't crop cubemap textures");
console::warning("Can't crop cubemap textures");
}
else
{
new_width = math::minimum<uint>(mipmap_params.m_clamp_width, new_width);
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);
}
}
@@ -420,7 +432,7 @@ namespace crnlib
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);
@@ -439,7 +451,7 @@ namespace crnlib
if (!work_tex.resize(new_width, new_height, res_params))
{
console::error(L"Failed resizing texture!");
console::error("Failed resizing texture!");
return false;
}
}
@@ -461,18 +473,18 @@ namespace crnlib
gen_params.m_max_mips = mipmap_params.m_max_levels;
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;
tm.start();
if (!work_tex.generate_mipmaps(gen_params, true))
{
console::error(L"Failed generating mipmaps!");
console::error("Failed generating mipmaps!");
return false;
}
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;
@@ -487,7 +499,7 @@ namespace crnlib
dds_texture 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;
}
+1 -1
View File
@@ -16,7 +16,7 @@ namespace crnlib
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_pass(const crn_comp_params& params, float *pEffective_bitrate) = 0;
+99 -91
View File
@@ -3,7 +3,7 @@
#include "crn_core.h"
#include "crn_texture_conversion.h"
#include "crn_console.h"
#include "crn_win32_file_utils.h"
#include "crn_file_utils.h"
#include "crn_cfile_stream.h"
#include "crn_image_utils.h"
#include "crn_texture_comp.h"
@@ -26,8 +26,8 @@ namespace crnlib
}
bool convert_stats::init(
const wchar_t* pSrc_filename,
const wchar_t* pDst_filename,
const char* pSrc_filename,
const char* pDst_filename,
dds_texture& src_tex,
texture_file_types::format dst_file_type,
bool lzma_stats)
@@ -38,8 +38,8 @@ namespace crnlib
m_pInput_tex = &src_tex;
win32_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(pSrc_filename, m_input_file_size);
file_utils::get_file_size(pDst_filename, m_output_file_size);
m_total_input_pixels = 0;
for (uint i = 0; i < src_tex.get_num_levels(); i++)
@@ -58,12 +58,12 @@ namespace crnlib
vector<uint8> 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;
}
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;
}
vector<uint8> cmp_tex_bytes;
@@ -76,7 +76,7 @@ namespace crnlib
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;
}
@@ -91,12 +91,12 @@ namespace crnlib
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)
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_height(),
m_pInput_tex->get_num_levels(),
@@ -104,29 +104,29 @@ namespace crnlib
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.
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);
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_height(),
m_output_tex.get_num_levels(),
m_output_tex.get_num_faces(),
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);
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);
}
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()) )
{
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
{
@@ -155,7 +155,7 @@ namespace crnlib
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);
if ((pA->has_rgb()) || (pB->has_rgb()))
@@ -187,23 +187,22 @@ namespace crnlib
image_utils::error_metrics luma_error;
if (rgb_error.compute(*pA, *pB, 0, 3, false) && luma_error.compute(*pA, *pB, 0, 0, true))
{
FILE *pFile = NULL;
#ifdef _MSC_VER
_wfopen_s(&pFile, pCSVStatsFile, L"a");
#else
pFile = _wfopen(pCSVStatsFile, L"a");
#endif
bool bCSVStatsFileExists = file_utils::does_file_exist(pCSVStatsFile);
FILE* pFile;
crn_fopen(&pFile, pCSVStatsFile, "a");
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
{
dynamic_wstring filename;
split_path(m_src_filename.get_ptr(), NULL, NULL, &filename, NULL);
dynamic_string filenamea;
if (!bCSVStatsFileExists)
fprintf(pFile, "name,width,height,miplevels,rgb_rms,luma_rms,effective_output_size,effective_bitrate\n");
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;
float bitrate = (effective_output_size * 8.0f) / m_total_output_pixels;
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(),
rgb_error.mRootMeanSquared, luma_error.mRootMeanSquared,
(uint32)effective_output_size, bitrate);
@@ -283,12 +282,12 @@ namespace crnlib
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_error_message = pError_msg;
_wremove(params.m_dst_filename.get_ptr());
remove(params.m_dst_filename.get_ptr());
return false;
}
@@ -369,55 +368,55 @@ namespace crnlib
static void print_comp_params(const crn_comp_params &comp_params)
{
console::debug(L"\nTexture conversion compression parameters:");
console::debug(L" Desired bitrate: %3.3f", comp_params.m_target_bitrate);
console::debug(L" 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(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(L" 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(L" 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(L" Disable endpoint caching: %u", comp_params.get_flag(cCRNCompFlagDisableEndpointCaching));
console::debug(L" Grayscale sampling: %u", comp_params.get_flag(cCRNCompFlagGrayscaleSampling));
console::debug(L" Max helper threads: %u", comp_params.m_num_helper_threads);
console::debug(L"");
console::debug("\nTexture conversion compression parameters:");
console::debug(" Desired bitrate: %3.3f", comp_params.m_target_bitrate);
console::debug(" CRN Quality: %i", comp_params.m_quality_level);
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("CRN A endpoints/selectors: %u %u", comp_params.m_crn_alpha_endpoint_palette_size, comp_params.m_crn_alpha_selector_palette_size);
console::debug(" DXT both block types: %u, Alpha threshold: %u", comp_params.get_flag(cCRNCompFlagUseBothBlockTypes), comp_params.m_dxt1a_alpha_threshold);
console::debug(" DXT compression quality: %s", crn_get_dxt_quality_string(comp_params.m_dxt_quality));
console::debug(" Perceptual: %u, Large Blocks: %u", comp_params.get_flag(cCRNCompFlagPerceptual), comp_params.get_flag(cCRNCompFlagHierarchical));
console::debug(" Compressor: %s", get_dxt_compressor_name(comp_params.m_dxt_compressor_type));
console::debug(" Disable endpoint caching: %u", comp_params.get_flag(cCRNCompFlagDisableEndpointCaching));
console::debug(" Grayscale sampling: %u", comp_params.get_flag(cCRNCompFlagGrayscaleSampling));
console::debug(" Max helper threads: %u", comp_params.m_num_helper_threads);
console::debug("");
}
static void print_mipmap_params(const crn_mipmap_params &mipmap_params)
{
console::debug(L"\nTexture conversion MIP-map parameters:");
console::debug(L" 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(L"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(L" Renormalize: %u", mipmap_params.m_renormalize);
console::debug(L" Tiled: %u", mipmap_params.m_tiled);
console::debug(L" Max Levels: %u", mipmap_params.m_max_levels);
console::debug(L" 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(L" 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(L" 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("\nTexture conversion MIP-map parameters:");
console::debug(" Mode: %s", crn_get_mip_mode_name(mipmap_params.m_mode));
console::debug(" Filter: %s", crn_get_mip_filter_name(mipmap_params.m_filter));
console::debug("Gamma filtering: %u, Gamma: %2.2f", mipmap_params.m_gamma_filtering, mipmap_params.m_gamma);
console::debug(" Blurriness: %2.2f", mipmap_params.m_blurriness);
console::debug(" Renormalize: %u", mipmap_params.m_renormalize);
console::debug(" Tiled: %u", mipmap_params.m_tiled);
console::debug(" Max Levels: %u", mipmap_params.m_max_levels);
console::debug(" Min level size: %u", mipmap_params.m_min_mip_size);
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(" scale mode: %s", crn_get_scale_mode_desc(mipmap_params.m_scale_mode));
console::debug(" scale: %f %f", mipmap_params.m_scale_x, mipmap_params.m_scale_y);
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("");
}
void convert_params::print()
{
console::debug(L"\nTexture conversion parameters:");
console::debug(L" Resolution: %ux%u, Faces: %u, Levels: %u, Format: %s",
console::debug("\nTexture conversion parameters:");
console::debug(" Resolution: %ux%u, Faces: %u, Levels: %u, Format: %s",
m_pInput_texture->get_width(),
m_pInput_texture->get_height(),
m_pInput_texture->get_num_faces(),
m_pInput_texture->get_num_levels(),
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(L" 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(L" dst_format: %s", pixel_format_helpers::get_pixel_format_string(m_dst_format));
console::debug(L" quick: %u", m_quick);
console::debug(L" use_source_format: %u", m_use_source_format);
console::debug(" texture_type: %s", get_texture_type_desc(m_texture_type));
console::debug(" dst_filename: %s", m_dst_filename.get_ptr());
console::debug(" dst_file_type: %s", texture_file_types::get_extension(m_dst_file_type));
console::debug(" dst_format: %s", pixel_format_helpers::get_pixel_format_string(m_dst_format));
console::debug(" quick: %u", m_quick);
console::debug(" use_source_format: %u", m_use_source_format);
}
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);
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;
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);
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 (!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_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;
tm.start();
@@ -480,7 +479,7 @@ namespace crnlib
double t = tm.get_elapsed_secs();
console::info(L"");
console::info("");
if (!status)
{
@@ -491,11 +490,11 @@ namespace crnlib
}
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)
@@ -504,13 +503,13 @@ namespace crnlib
{
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;
if (!split_path(params.m_dst_filename.get_ptr(), &drv, &dir, &fn, &ext))
dynamic_string drv, dir, fn, ext;
if (!file_utils::split_path(params.m_dst_filename.get_ptr(), &drv, &dir, &fn, &ext))
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;
mip_level *pLevel = work_tex.get_level(f, l);
@@ -521,25 +520,25 @@ namespace crnlib
dds_texture new_tex;
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))
return convert_error(params, L"Failed writing output file!");
return convert_error(params, "Failed writing output file!");
}
}
}
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))
return convert_error(params, L"Failed writing output file!");
return convert_error(params, "Failed writing output file!");
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))
{
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)
{
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());
@@ -586,6 +585,15 @@ namespace crnlib
}
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)
{
@@ -611,15 +619,15 @@ namespace crnlib
{
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;
}
}
if (pixel_format_helpers::is_normal_map(dst_format))
{
//if (perceptual)
//console::warning(L"Output pixel format is intended for normal maps, disabling perceptual color metrics");
if (perceptual)
console::message("Output pixel format is intended for normal maps, disabling perceptual color metrics");
perceptual = false;
}
@@ -639,7 +647,7 @@ namespace crnlib
}
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;
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);
}
console::progress(L"");
console::progress("");
if (progress_state.m_canceled)
{
@@ -679,18 +687,18 @@ namespace crnlib
if (status)
{
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
{
dynamic_wstring str;
dynamic_string str;
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
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());
}
+10 -10
View File
@@ -16,18 +16,18 @@ namespace crnlib
convert_stats();
bool init(
const wchar_t* pSrc_filename,
const wchar_t* pDst_filename,
const char* pSrc_filename,
const char* pDst_filename,
dds_texture& src_tex,
texture_file_types::format dst_file_type,
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();
dynamic_wstring m_src_filename;
dynamic_wstring m_dst_filename;
dynamic_string m_src_filename;
dynamic_string m_dst_filename;
texture_file_types::format m_dst_file_type;
dds_texture* m_pInput_tex;
@@ -58,10 +58,10 @@ namespace crnlib
m_debugging(false),
m_param_debugging(false),
m_no_stats(false),
m_use_source_format(false),
m_lzma_stats(false),
m_status(false),
m_canceled(false),
m_use_source_format(false)
m_canceled(false)
{
}
@@ -77,7 +77,7 @@ namespace crnlib
texture_type m_texture_type;
dynamic_wstring m_dst_filename;
dynamic_string m_dst_filename;
texture_file_types::format m_dst_file_type;
pixel_format m_dst_format;
@@ -90,7 +90,7 @@ namespace crnlib
// Return parameters
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_quick;
@@ -98,7 +98,7 @@ namespace crnlib
bool m_param_debugging;
bool m_no_stats;
bool m_use_source_format;
bool m_lzma_stats;
mutable bool m_status;
mutable bool m_canceled;
+30 -30
View File
@@ -2,48 +2,48 @@
// See Copyright Notice and license at the end of inc/crnlib.h
#include "crn_core.h"
#include "crn_texture_file_types.h"
#include "crn_strutils.h"
#include "crn_file_utils.h"
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);
if (fmt >= cNumFileFormats)
return NULL;
static const wchar_t* extensions[cNumFileFormats] =
static const char* extensions[cNumFileFormats] =
{
L"tga",
L"png",
L"jpg",
L"jpeg",
L"bmp",
L"gif",
L"tif",
L"tiff",
L"ppm",
L"pgm",
L"dds",
L"psd",
L"jp2",
L"crn",
L"<clipboard>",
L"<dragdrop>"
"tga",
"png",
"jpg",
"jpeg",
"bmp",
"gif",
"tif",
"tiff",
"ppm",
"pgm",
"dds",
"psd",
"jp2",
"crn",
"<clipboard>",
"<dragdrop>"
};
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;
if (!split_path(pFilename, NULL, NULL, NULL, &ext))
dynamic_string ext;
if (!file_utils::split_path(pFilename, NULL, NULL, NULL, &ext))
return cFormatInvalid;
if (ext.is_empty())
return cFormatInvalid;
if (ext[0] == L'.')
if (ext[0] == '.')
ext.right(1);
for (uint i = 0; i < cNumFileFormats; i++)
@@ -81,21 +81,21 @@ namespace crnlib
return true;
}
const wchar_t* get_texture_type_desc(texture_type t)
const char* get_texture_type_desc(texture_type t)
{
switch (t)
{
case cTextureTypeUnknown: return L"Unknown";
case cTextureTypeRegularMap: return L"2D map";
case cTextureTypeNormalMap: return L"Normal map";
case cTextureTypeVerticalCrossCubemap: return L"Vertical Cross Cubemap";
case cTextureTypeCubemap: return L"Cubemap";
case cTextureTypeUnknown: return "Unknown";
case cTextureTypeRegularMap: return "2D map";
case cTextureTypeNormalMap: return "Normal map";
case cTextureTypeVerticalCrossCubemap: return "Vertical Cross Cubemap";
case cTextureTypeCubemap: return "Cubemap";
default: break;
}
CRNLIB_ASSERT(false);
return L"?";
return "?";
}
} // namespace crnlib
+12 -12
View File
@@ -27,24 +27,24 @@ namespace crnlib
cFormatPSD,
cFormatJP2,
cFormatCRN,
cNumRegularFileFormats,
// Not really a file format
// Not really a file format
cFormatClipboard = cNumRegularFileFormats,
cFormatDragDrop,
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_alpha(format fmt);
};
};
enum texture_type
{
cTextureTypeUnknown = 0,
@@ -55,8 +55,8 @@ namespace crnlib
cNumTextureTypes
};
const wchar_t* get_texture_type_desc(texture_type t);
const char* get_texture_type_desc(texture_type t);
} // namespace crnlib
+4 -3
View File
@@ -2,6 +2,7 @@
// See Copyright Notice and license at the end of inc/crnlib.h
#pragma once
#include "crn_clusterizer.h"
#include "crn_threading.h"
namespace crnlib
{
@@ -43,7 +44,7 @@ namespace crnlib
progress_callback_func pProgress_callback,
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_pProgress_callback = pProgress_callback;
m_pProgress_callback_data = pProgress_callback_data;
@@ -136,7 +137,7 @@ namespace crnlib
private:
task_pool* m_pTask_pool;
uint32 m_main_thread_id;
crn_thread_id_t m_main_thread_id;
struct create_clusters_task_state
{
@@ -328,7 +329,7 @@ namespace crnlib
if (m_canceled)
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;
m_clusterizers[partition_index].generate_codebook(
+1
View File
@@ -3,6 +3,7 @@
#include "crn_core.h"
#include "crn_threaded_resampler.h"
#include "crn_resample_filters.h"
#include "crn_threading.h"
namespace crnlib
{
+20 -20
View File
@@ -3,34 +3,34 @@
#pragma once
#include "crn_resampler.h"
#include "crn_vec.h"
#include "crn_task_pool.h"
namespace crnlib
{
class task_pool;
class threaded_resampler
{
CRNLIB_NO_COPY_OR_ASSIGNMENT_OP(threaded_resampler);
public:
threaded_resampler(task_pool& tp);
~threaded_resampler();
enum pixel_format
{
cPF_Y_F32,
cPF_RGBX_F32,
cPF_RGBA_F32,
cPF_Total
};
struct params
{
params()
{
clear();
}
void clear()
{
utils::zero_object(*this);
@@ -42,44 +42,44 @@ namespace crnlib
m_filter_x_scale = 1.0f;
m_filter_y_scale = 1.0f;
}
pixel_format m_fmt;
const void* m_pSrc_pixels;
uint m_src_width;
uint m_src_height;
uint m_src_pitch;
void* m_pDst_pixels;
uint m_dst_width;
uint m_dst_height;
uint m_dst_pitch;
Resampler::Boundary_Op m_boundary_op;
float m_sample_low;
float m_sample_high;
const char* m_Pfilter_name;
float m_filter_x_scale;
float m_filter_y_scale;
};
};
bool resample(const params& p);
private:
task_pool* m_pTask_pool;
const params* m_pParams;
Resampler::Contrib_List* m_pX_contribs;
Resampler::Contrib_List* m_pY_contribs;
uint m_bytes_per_pixel;
crnlib::vector<vec4F> m_tmp_img;
void free_contrib_lists();
void resample_x_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
{
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>
struct scalar_type
{
@@ -43,8 +52,13 @@ namespace crnlib
CRNLIB_DEFINE_BUILT_IN_TYPE(unsigned int)
CRNLIB_DEFINE_BUILT_IN_TYPE(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(unsigned __int64)
#endif
CRNLIB_DEFINE_BUILT_IN_TYPE(float)
CRNLIB_DEFINE_BUILT_IN_TYPE(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_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))
+10 -6
View File
@@ -137,7 +137,7 @@ namespace crnlib
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;
@@ -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;
uint best_index = 0;
@@ -222,7 +222,7 @@ namespace crnlib
if (parent_node.m_vectors.size() == 1)
return;
VectorType furthest;
VectorType furthest(0);
double furthest_dist = -1.0f;
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];
}
for (uint x = 0; x < N - 1; x++)
for (uint y = x + 1; y < N; y++)
covar[y][x] = covar[x][y];
if (N > 1)
{
//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);
+27 -22
View File
@@ -12,31 +12,36 @@ namespace crnlib
typedef uint32 uint;
typedef signed int int32;
typedef unsigned __int64 uint64;
typedef signed __int64 int64;
#ifdef __GNUC__
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 UINT8_MAX = 0xFFU;
const uint16 UINT16_MIN = 0;
const uint16 UINT16_MAX = 0xFFFFU;
const uint32 UINT32_MIN = 0;
const uint32 UINT32_MAX = 0xFFFFFFFFU;
const uint64 UINT64_MIN = 0;
const uint64 UINT64_MAX = 0xFFFFFFFFFFFFFFFFULL; //0xFFFFFFFFFFFFFFFFui64;
const uint8 cUINT8_MIN = 0;
const uint8 cUINT8_MAX = 0xFFU;
const uint16 cUINT16_MIN = 0;
const uint16 cUINT16_MAX = 0xFFFFU;
const uint32 cUINT32_MIN = 0;
const uint32 cUINT32_MAX = 0xFFFFFFFFU;
const uint64 cUINT64_MIN = 0;
const uint64 cUINT64_MAX = 0xFFFFFFFFFFFFFFFFULL; //0xFFFFFFFFFFFFFFFFui64;
const int8 INT8_MIN = -128;
const int8 INT8_MAX = 127;
const int16 INT16_MIN = -32768;
const int16 INT16_MAX = 32767;
const int32 INT32_MIN = (-2147483647 - 1);
const int32 INT32_MAX = 2147483647;
const int64 INT64_MIN = (int64)0x8000000000000000ULL; //(-9223372036854775807i64 - 1);
const int64 INT64_MAX = (int64)0x7FFFFFFFFFFFFFFFULL; // 9223372036854775807i64;
const int8 cINT8_MIN = -128;
const int8 cINT8_MAX = 127;
const int16 cINT16_MIN = -32768;
const int16 cINT16_MAX = 32767;
const int32 cINT32_MIN = (-2147483647 - 1);
const int32 cINT32_MAX = 2147483647;
const int64 cINT64_MIN = (int64)0x8000000000000000ULL; //(-9223372036854775807i64 - 1);
const int64 cINT64_MAX = (int64)0x7FFFFFFFFFFFFFFFULL; // 9223372036854775807i64;
#ifdef CRNLIB_PLATFORM_PC_X64
typedef unsigned __int64 uint_ptr;
typedef unsigned __int64 uint32_ptr;
typedef signed __int64 signed_size_t;
#if CRNLIB_64BIT_POINTERS
typedef uint64 uint_ptr;
typedef uint64 uint32_ptr;
typedef int64 signed_size_t;
typedef uint64 ptr_bits_t;
#else
typedef unsigned int uint_ptr;
+13 -1
View File
@@ -37,7 +37,19 @@ namespace crnlib
*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)
{
if ((width | height) == 0)
+16 -12
View File
@@ -8,18 +8,21 @@
#define CRNLIB_ARRAYSIZE(x) (sizeof(x)/sizeof(x[0]))
#ifdef _MSC_VER
extern "C" unsigned long __cdecl _lrotl(unsigned long, int);
#pragma intrinsic(_lrotl)
// Need to explictly extern these with MSVC, but not MinGW.
extern "C" unsigned long __cdecl _lrotl(unsigned long, int);
#pragma intrinsic(_lrotl)
extern "C" unsigned long __cdecl _lrotr(unsigned long, int);
#pragma intrinsic(_lrotr)
extern "C" unsigned long __cdecl _lrotr(unsigned long, int);
#pragma intrinsic(_lrotr)
#endif
//#define CRNLIB_ROTATE_LEFT(x, k) (((x) << (k)) | ((x) >> (32-(k))))
#define CRNLIB_ROTATE_LEFT(x, k) _lrotl(x, k)
//#define CRNLIB_ROTATE_RIGHT(x, k) (((x) >> (k)) | ((x) << (32-(k))))
#define CRNLIB_ROTATE_RIGHT(x, k) _lrotr(x, k)
#ifdef WIN32
#define CRNLIB_ROTATE_LEFT(x, k) _lrotl(x, k)
#define CRNLIB_ROTATE_RIGHT(x, k) _lrotr(x, k)
#else
#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]);
#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)
{
memset(&obj, 0, sizeof(obj));
memset((void*)&obj, 0, sizeof(obj));
}
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)
@@ -225,7 +228,8 @@ namespace crnlib
void endian_switch_words(uint16* 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_dwords(uint32* pDst, const uint32* pSrc, uint num, bool endian_switch);
uint compute_max_mips(uint width, uint height);
} // namespace utils
+10 -10
View File
@@ -5,17 +5,17 @@
namespace crnlib
{
const wchar_t* gValueDataTypeStrings[cDTTotal + 1] =
const char* gValueDataTypeStrings[cDTTotal + 1] =
{
L"invalid",
L"string",
L"bool",
L"int",
L"uint",
L"float",
L"vec3f",
L"vec3i",
"invalid",
"string",
"bool",
"int",
"uint",
"float",
"vec3f",
"vec3i",
NULL,
};
+40 -40
View File
@@ -2,7 +2,7 @@
// See Copyright Notice and license at the end of inc/crnlib.h
#pragma once
#include "crn_strutils.h"
#include "crn_dynamic_wstring.h"
#include "crn_dynamic_string.h"
#include "crn_vec.h"
namespace crnlib
@@ -21,7 +21,7 @@ namespace crnlib
cDTTotal
};
extern const wchar_t* gValueDataTypeStrings[cDTTotal + 1];
extern const char* gValueDataTypeStrings[cDTTotal + 1];
class value
{
@@ -31,13 +31,13 @@ namespace crnlib
{
}
value(const wchar_t* pStr) :
m_pStr(crnlib_new<dynamic_wstring>(pStr)), m_type(cDTString)
value(const char* pStr) :
m_pStr(crnlib_new<dynamic_string>(pStr)), m_type(cDTString)
{
}
value(const dynamic_wstring& str) :
m_pStr(crnlib_new<dynamic_wstring>(str)), m_type(cDTString)
value(const dynamic_string& str) :
m_pStr(crnlib_new<dynamic_string>(str)), m_type(cDTString)
{
}
@@ -125,7 +125,7 @@ namespace crnlib
m_type = cDTInvalid;
}
void set_string(const wchar_t* pStr)
void set_string(const char* pStr)
{
set_str(pStr);
}
@@ -170,7 +170,7 @@ namespace crnlib
m_pVec3I->set(v);
}
bool parse(const wchar_t* p)
bool parse(const char* p)
{
if ((!p) || (!p[0]))
{
@@ -178,12 +178,12 @@ namespace crnlib
return false;
}
if (_wcsicmp(p, L"false") == 0)
if (_stricmp(p, "false") == 0)
{
set_bool(false);
return true;
}
else if (_wcsicmp(p, L"true") == 0)
else if (_stricmp(p, "true") == 0)
{
set_bool(true);
return true;
@@ -191,7 +191,7 @@ namespace crnlib
if (p[0] == '\"')
{
dynamic_wstring str;
dynamic_string str;
str = p + 1;
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;
#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
if (swscanf(p, L"%f,%f,%f", &fx, &fy, &fz) == 3)
if (sscanf(p, "%f,%f,%f", &fx, &fy, &fz) == 3)
#endif
{
bool as_float = true;
int ix = 0, iy = 0, iz = 0;
#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
if (swscanf(p, L"%i,%i,%i", &ix, &iy, &iz) == 3)
if (sscanf(p, "%i,%i,%i", &ix, &iy, &iz) == 3)
#endif
{
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);
if ((success) && (*q == 0))
{
@@ -264,18 +264,18 @@ namespace crnlib
return true;
}
dynamic_wstring& get_as_string(dynamic_wstring& dst) const
dynamic_string& get_as_string(dynamic_string& dst) const
{
switch (m_type)
{
case cDTInvalid: dst.clear(); break;
case cDTString: dst = *m_pStr; break;
case cDTBool: dst = m_bool ? L"TRUE" : L"FALSE"; break;
case cDTInt: dst.format(L"%i", m_int); break;
case cDTUInt: dst.format(L"%u", m_uint); break;
case cDTFloat: dst.format(L"%f", m_float); break;
case cDTVec3F: dst.format(L"%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 cDTBool: dst = m_bool ? "TRUE" : "FALSE"; break;
case cDTInt: dst.format("%i", m_int); break;
case cDTUInt: dst.format("%u", m_uint); break;
case cDTFloat: dst.format("%f", m_float); break;
case cDTVec3F: dst.format("%f,%f,%f", (*m_pVec3F)[0], (*m_pVec3F)[1], (*m_pVec3F)[2]); break;
case cDTVec3I: dst.format("%i,%i,%i", (*m_pVec3I)[0], (*m_pVec3I)[1], (*m_pVec3I)[2]); break;
default: break;
}
@@ -293,7 +293,7 @@ namespace crnlib
}
case cDTString:
{
const wchar_t* p = m_pStr->get_ptr();
const char* p = m_pStr->get_ptr();
return string_to_int(p, val);
}
case cDTBool: val = m_bool; break;
@@ -359,7 +359,7 @@ namespace crnlib
}
case cDTString:
{
const wchar_t* p = m_pStr->get_ptr();
const char* p = m_pStr->get_ptr();
return string_to_uint(p, val);
}
case cDTBool:
@@ -438,7 +438,7 @@ namespace crnlib
}
case cDTString:
{
const wchar_t* p = m_pStr->get_ptr();
const char* p = m_pStr->get_ptr();
return string_to_bool(p, val);
}
case cDTBool:
@@ -497,7 +497,7 @@ namespace crnlib
}
case cDTString:
{
const wchar_t* p = m_pStr->get_ptr();
const char* p = m_pStr->get_ptr();
return string_to_float(p, val);
}
case cDTBool:
@@ -556,12 +556,12 @@ namespace crnlib
}
case cDTString:
{
const wchar_t* p = m_pStr->get_ptr();
const char* p = m_pStr->get_ptr();
float x = 0, y = 0, z = 0;
#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
if (wscanf(p, L"%f,%f,%f", &x, &y, &z) == 3)
if (sscanf(p, "%f,%f,%f", &x, &y, &z) == 3)
#endif
{
val.set(x, y, z);
@@ -619,12 +619,12 @@ namespace crnlib
}
case cDTString:
{
const wchar_t* p = m_pStr->get_ptr();
const char* p = m_pStr->get_ptr();
float x = 0, y = 0, z = 0;
#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
if (wscanf(p, L"%f,%f,%f", &x, &y, &z) == 3)
if (sscanf(p, "%f,%f,%f", &x, &y, &z) == 3)
#endif
{
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)
{
case cDTString:
m_pStr = crnlib_new<dynamic_wstring>();
m_pStr = crnlib_new<dynamic_string>();
break;
case cDTVec3F:
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)
m_pStr->set(s);
@@ -985,11 +985,11 @@ namespace crnlib
clear_dynamic();
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)
m_pStr->set(p);
@@ -998,7 +998,7 @@ namespace crnlib
clear_dynamic();
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;
vec3I* m_pVec3I;
dynamic_wstring* m_pStr;
dynamic_string* m_pStr;
uint m_union[cUnionSize];
};

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