Compare commits
4 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 8182078d6f | |||
| a8011e9d7f | |||
| 02faca16c4 | |||
| f63e26aee6 |
@@ -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>
|
||||
@@ -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
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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
@@ -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())
|
||||
|
||||
@@ -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
@@ -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
@@ -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];
|
||||
}
|
||||
|
||||
|
||||
@@ -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
File diff suppressed because it is too large
Load Diff
+52
-52
@@ -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);
|
||||
};
|
||||
|
||||
@@ -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
|
||||
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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"
|
||||
|
||||
|
||||
|
||||
@@ -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
@@ -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
|
||||
|
||||
|
||||
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
File diff suppressed because it is too large
Load Diff
+2
-2
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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++)
|
||||
{
|
||||
|
||||
@@ -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;
|
||||
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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
@@ -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
@@ -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;
|
||||
|
||||
|
||||
@@ -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])
|
||||
|
||||
@@ -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
@@ -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;
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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
@@ -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
@@ -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
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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
@@ -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
@@ -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); \
|
||||
}
|
||||
|
||||
@@ -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
|
||||
@@ -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)
|
||||
{
|
||||
|
||||
@@ -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
@@ -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
@@ -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
|
||||
}
|
||||
|
||||
@@ -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
@@ -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
@@ -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
|
||||
|
||||
@@ -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
@@ -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;
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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);
|
||||
|
||||
|
||||
@@ -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
|
||||
@@ -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
@@ -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
@@ -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
@@ -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
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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
|
||||
@@ -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
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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());
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
|
||||
@@ -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(
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
#include "crn_core.h"
|
||||
#include "crn_threaded_resampler.h"
|
||||
#include "crn_resample_filters.h"
|
||||
#include "crn_threading.h"
|
||||
|
||||
namespace crnlib
|
||||
{
|
||||
|
||||
@@ -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);
|
||||
};
|
||||
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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
|
||||
@@ -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
@@ -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))
|
||||
|
||||
|
||||
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
Reference in New Issue
Block a user