Update to the latest thekla_atlas
parent
a2770ecd8e
commit
1623d7d782
|
@ -274,6 +274,8 @@ HEADERS += thirdparty/thekla_atlas/extern/poshlib/posh.h
|
|||
SOURCES += thirdparty/thekla_atlas/src/thekla/thekla_atlas.cpp
|
||||
HEADERS += thirdparty/thekla_atlas/src/thekla/thekla_atlas.h
|
||||
|
||||
HEADERS += thirdparty/thekla_atlas/src/nvcore/nvcore.h
|
||||
|
||||
HEADERS += thirdparty/thekla_atlas/src/nvcore/Stream.h
|
||||
|
||||
SOURCES += thirdparty/thekla_atlas/src/nvcore/Debug.cpp
|
||||
|
|
|
@ -23,3 +23,32 @@ add_executable(
|
|||
target_link_libraries(
|
||||
thekla_atlas_test
|
||||
nvmesh)
|
||||
|
||||
set(CMAKE_DEBUG_POSTFIX d)
|
||||
|
||||
set(CMAKE_WINDOWS_EXPORT_ALL_SYMBOLS ON)
|
||||
set(CMAKE_SHARED_LINKER_FLAGS "-Wl,--export-all-symbols")
|
||||
|
||||
add_library(libthekla_atlas
|
||||
src/thekla/thekla_atlas.cpp
|
||||
)
|
||||
|
||||
install(TARGETS libthekla_atlas DESTINATION lib/static)
|
||||
|
||||
get_property(HEADER_DIRS DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} PROPERTY INCLUDE_DIRECTORIES)
|
||||
|
||||
configure_file(theklaAtlasConfig.cmake.in ${CMAKE_CURRENT_BINARY_DIR}/theklaAtlasConfig.cmake @ONLY)
|
||||
install(FILES ${CMAKE_CURRENT_BINARY_DIR}/theklaAtlasConfig.cmake DESTINATION .)
|
||||
|
||||
file(GLOB HEADERS src/*.h)
|
||||
install(FILES ${HEADERS} DESTINATION include)
|
||||
file(GLOB HEADERS src/thekla/*.h)
|
||||
install(FILES ${HEADERS} DESTINATION include/thekla)
|
||||
file(GLOB HEADERS src/nvcore/*.h)
|
||||
install(FILES ${HEADERS} DESTINATION include/nvcore)
|
||||
file(GLOB HEADERS src/nvimage/*.h)
|
||||
install(FILES ${HEADERS} DESTINATION include/nvimage)
|
||||
file(GLOB HEADERS src/nvmesh/*.h)
|
||||
install(FILES ${HEADERS} DESTINATION include/nvmesh)
|
||||
file(GLOB HEADERS src/nvmath/*.h)
|
||||
install(FILES ${HEADERS} DESTINATION include/nvmath)
|
||||
|
|
|
@ -179,6 +179,4 @@ namespace nv
|
|||
|
||||
} // nv namespace
|
||||
|
||||
#include "Array.inl"
|
||||
|
||||
#endif // NV_CORE_ARRAY_H
|
||||
|
|
|
@ -12,6 +12,9 @@
|
|||
#include <string.h> // memmove
|
||||
#include <new> // for placement new
|
||||
|
||||
/////// Changes in Dust3D Begin /////////////
|
||||
#include "Vector.inl"
|
||||
/////// Changes in Dust3D End /////////////
|
||||
|
||||
|
||||
namespace nv
|
||||
|
|
|
@ -40,7 +40,7 @@ namespace nv
|
|||
{
|
||||
public:
|
||||
|
||||
BitArray() {}
|
||||
BitArray() : m_size(0){}
|
||||
BitArray(uint sz) {
|
||||
resize(sz);
|
||||
}
|
||||
|
@ -237,7 +237,7 @@ namespace nv
|
|||
private:
|
||||
|
||||
// Number of bits stored.
|
||||
uint m_size;
|
||||
uint m_size = 0;
|
||||
|
||||
// Array of bits.
|
||||
Array<uint> m_wordArray;
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
PROJECT(nvcore)
|
||||
set(CMAKE_DEBUG_POSTFIX d)
|
||||
|
||||
SET(CORE_SRCS
|
||||
nvcore.h
|
||||
|
|
|
@ -106,6 +106,7 @@ namespace
|
|||
struct sigaction s_old_sigtrap;
|
||||
struct sigaction s_old_sigfpe;
|
||||
struct sigaction s_old_sigbus;
|
||||
struct sigaction s_old_sigill;
|
||||
|
||||
#endif
|
||||
|
||||
|
@ -431,9 +432,9 @@ namespace
|
|||
pSymbol->SizeOfStruct = sizeof(IMAGEHLP_SYMBOL64);
|
||||
pSymbol->MaxNameLength = MAX_STRING_LEN;
|
||||
|
||||
DWORD64 dwDisplacement;
|
||||
DWORD64 dwDisplacement64;
|
||||
|
||||
if (SymGetSymFromAddr64(hProcess, ip, &dwDisplacement, pSymbol))
|
||||
if (SymGetSymFromAddr64(hProcess, ip, &dwDisplacement64, pSymbol))
|
||||
{
|
||||
pSymbol->Name[MAX_STRING_LEN-1] = 0;
|
||||
|
||||
|
@ -455,8 +456,8 @@ namespace
|
|||
IMAGEHLP_LINE64 theLine = { 0 };
|
||||
theLine.SizeOfStruct = sizeof(theLine);
|
||||
|
||||
DWORD dwDisplacement;
|
||||
if (!SymGetLineFromAddr64(hProcess, ip, &dwDisplacement, &theLine))
|
||||
DWORD dwDisplacement32;
|
||||
if (!SymGetLineFromAddr64(hProcess, ip, &dwDisplacement32, &theLine))
|
||||
{
|
||||
// Do not print unknown symbols anymore.
|
||||
//break;
|
||||
|
@ -679,6 +680,9 @@ namespace
|
|||
# elif NV_CPU_ARM
|
||||
ucontext_t * ucp = (ucontext_t *)secret;
|
||||
return (void *) ucp->uc_mcontext->__ss.__pc;
|
||||
# elif NV_CPU_ARM_64
|
||||
ucontext_t * ucp = (ucontext_t *)secret;
|
||||
return (void *) ucp->uc_mcontext->__ss.__pc;
|
||||
# else
|
||||
# error "Unknown CPU"
|
||||
# endif
|
||||
|
@ -785,7 +789,7 @@ namespace
|
|||
}
|
||||
#endif // defined(NV_HAVE_EXECINFO_H)
|
||||
|
||||
exit(0);
|
||||
exit(EXIT_FAILURE + 2);
|
||||
}
|
||||
|
||||
#endif // defined(NV_HAVE_SIGNAL_H)
|
||||
|
@ -933,14 +937,23 @@ namespace
|
|||
// Assert handler method.
|
||||
virtual int assertion(const char * exp, const char * file, int line, const char * func, const char * msg, va_list arg)
|
||||
{
|
||||
int ret = NV_ABORT_EXIT;
|
||||
int ret = NV_ABORT_IGNORE;
|
||||
|
||||
if( func != NULL ) {
|
||||
nvDebug( "*** Assertion failed: %s\n On file: %s\n On function: %s\n On line: %d\n ", exp, file, func, line );
|
||||
StringBuilder error_string;
|
||||
error_string.format("*** Assertion failed: %s\n On file: %s\n On line: %d\n", exp, file, line );
|
||||
if (func != NULL) {
|
||||
error_string.appendFormat(" On function: %s\n", func);
|
||||
}
|
||||
else {
|
||||
nvDebug( "*** Assertion failed: %s\n On file: %s\n On line: %d\n ", exp, file, line );
|
||||
if (msg != NULL) {
|
||||
error_string.append(" Message: ");
|
||||
va_list tmp;
|
||||
va_copy(tmp, arg);
|
||||
error_string.appendFormatList(msg, tmp);
|
||||
va_end(tmp);
|
||||
error_string.append("\n");
|
||||
}
|
||||
nvDebug("%s", error_string.str());
|
||||
|
||||
|
||||
#if _DEBUG
|
||||
if (debug::isDebuggerPresent()) {
|
||||
|
@ -1173,7 +1186,7 @@ void debug::enableSigHandler(bool interactive)
|
|||
s_interactive = interactive;
|
||||
|
||||
#if (NV_OS_WIN32 && NV_CC_MSVC) || NV_OS_DURANGO
|
||||
if (interactive) {
|
||||
if (!interactive) {
|
||||
#if NV_OS_WIN32
|
||||
// Do not display message boxes on error.
|
||||
// http://msdn.microsoft.com/en-us/library/windows/desktop/ms680621(v=vs.85).aspx
|
||||
|
@ -1224,6 +1237,8 @@ void debug::enableSigHandler(bool interactive)
|
|||
sigaction(SIGTRAP, &sa, &s_old_sigtrap);
|
||||
sigaction(SIGFPE, &sa, &s_old_sigfpe);
|
||||
sigaction(SIGBUS, &sa, &s_old_sigbus);
|
||||
sigaction(SIGILL, &sa, &s_old_sigill);
|
||||
|
||||
|
||||
#endif
|
||||
}
|
||||
|
@ -1249,6 +1264,7 @@ void debug::disableSigHandler()
|
|||
sigaction(SIGTRAP, &s_old_sigtrap, NULL);
|
||||
sigaction(SIGFPE, &s_old_sigfpe, NULL);
|
||||
sigaction(SIGBUS, &s_old_sigbus, NULL);
|
||||
sigaction(SIGILL, &s_old_sigill, NULL);
|
||||
|
||||
#endif
|
||||
}
|
||||
|
|
|
@ -12,6 +12,8 @@
|
|||
# ifdef __APPLE__
|
||||
# include <TargetConditionals.h>
|
||||
# include <signal.h>
|
||||
# include <sys/types.h> // getpid
|
||||
# include <unistd.h>
|
||||
# endif
|
||||
#endif
|
||||
|
||||
|
@ -43,10 +45,22 @@
|
|||
//# define nvDebugBreak() __asm { int 3 }
|
||||
# elif NV_OS_ORBIS
|
||||
# define nvDebugBreak() __debugbreak()
|
||||
# elif NV_OS_IOS && TARGET_OS_IPHONE
|
||||
# define nvDebugBreak() raise(SIGINT)
|
||||
# elif NV_CC_CLANG
|
||||
# define nvDebugBreak() __builtin_debugtrap()
|
||||
# if NV_OS_IOS
|
||||
# if NV_CPU_ARM_64
|
||||
# if __clang_major__ >= 9
|
||||
# define nvDebugBreak() asm volatile("svc #0x80") // IC: "svc 0" doesn't seem to work anymore.
|
||||
# else
|
||||
# define nvDebugBreak() asm volatile("svc 0")
|
||||
# endif
|
||||
# elif NV_CPU_ARM
|
||||
# define nvDebugBreak() asm("trap")
|
||||
# else // simulator?
|
||||
# define nvDebugBreak() __builtin_debugtrap()
|
||||
# endif
|
||||
# else
|
||||
# define nvDebugBreak() __builtin_debugtrap()
|
||||
# endif
|
||||
# elif NV_CC_GNUC
|
||||
//# define nvDebugBreak() __builtin_debugtrap() // Does GCC have debugtrap?
|
||||
# define nvDebugBreak() __builtin_trap()
|
||||
|
@ -98,12 +112,14 @@
|
|||
} \
|
||||
NV_MULTI_LINE_MACRO_END
|
||||
|
||||
// IC: When using this macro in llvm/ios you can ignore future hits typing 'expr ignoreAll=true' in the console.
|
||||
// GCC, LLVM need "##" before the __VA_ARGS__, MSVC doesn't care
|
||||
#define nvAssertMacroWithIgnoreAll(exp,...) \
|
||||
NV_MULTI_LINE_MACRO_BEGIN \
|
||||
static bool ignoreAll = false; \
|
||||
if (!ignoreAll && !nvExpect(exp)) { \
|
||||
int _result = nvAbort(#exp, __FILE__, __LINE__, __FUNC__, ##__VA_ARGS__); \
|
||||
/*nvDebug("Type 'expr ignoreAll=true' to ignore future hits\n");*/ \
|
||||
if (_result == NV_ABORT_DEBUG) { \
|
||||
nvDebugBreak(); \
|
||||
} else if (_result == NV_ABORT_IGNORE) { \
|
||||
|
@ -124,7 +140,7 @@
|
|||
#define nvCheckMacro(exp) \
|
||||
(\
|
||||
(exp) ? true : ( \
|
||||
(nvAbort(#exp, __FILE__, __LINE__, __FUNC__) == NV_ABORT_DEBUG) ? (nvDebugBreak(), true) : ( false ) \
|
||||
(nvAbort(#exp, __FILE__, __LINE__, __FUNC__) == NV_ABORT_DEBUG) ? ([](){nvDebugBreak();}(), true) : ( false ) \
|
||||
) \
|
||||
)
|
||||
|
||||
|
@ -199,11 +215,15 @@ namespace nv
|
|||
if (ptr == NULL) return true;
|
||||
if (reinterpret_cast<uint64>(ptr) < 0x10000ULL) return false;
|
||||
if (reinterpret_cast<uint64>(ptr) >= 0x000007FFFFFEFFFFULL) return false;
|
||||
#elif NV_CPU_ARM_64
|
||||
if (ptr == NULL) return true;
|
||||
if (reinterpret_cast<uint64>(ptr) < 0x10000ULL) return false;
|
||||
if (reinterpret_cast<uint64>(ptr) >= 0x000007FFFFFEFFFFULL) return false;
|
||||
#else
|
||||
if (reinterpret_cast<uintptr_t>(ptr) == 0xcccccccc) return false;
|
||||
if (reinterpret_cast<uintptr_t>(ptr) == 0xcdcdcdcd) return false;
|
||||
if (reinterpret_cast<uintptr_t>(ptr) == 0xdddddddd) return false;
|
||||
if (reinterpret_cast<uintptr_t>(ptr) == 0xffffffff) return false;
|
||||
if (reinterpret_cast<uint32>(ptr) == 0xcccccccc) return false;
|
||||
if (reinterpret_cast<uint32>(ptr) == 0xcdcdcdcd) return false;
|
||||
if (reinterpret_cast<uint32>(ptr) == 0xdddddddd) return false;
|
||||
if (reinterpret_cast<uint32>(ptr) == 0xffffffff) return false;
|
||||
#endif
|
||||
return true;
|
||||
}
|
||||
|
|
|
@ -27,8 +27,8 @@
|
|||
#define NV_FASTCALL __attribute__((fastcall))
|
||||
#define NV_FORCEINLINE __attribute__((always_inline)) inline
|
||||
#define NV_DEPRECATED __attribute__((deprecated))
|
||||
#if NV_OS_IOS
|
||||
#define NV_THREAD_LOCAL // @@ IC: Looks like iOS does not have support for TLS declarations.
|
||||
#if 0 //Apple finally added TLS support to iOS!// NV_OS_IOS
|
||||
#define NV_THREAD_LOCAL
|
||||
#else
|
||||
#define NV_THREAD_LOCAL __thread
|
||||
#endif
|
||||
|
|
|
@ -73,3 +73,31 @@ bool FileSystem::removeFile(const char * path)
|
|||
// @@ Use unlink or remove?
|
||||
return remove(path) == 0;
|
||||
}
|
||||
|
||||
|
||||
#include "StdStream.h" // for fileOpen
|
||||
|
||||
bool FileSystem::copyFile(const char * src, const char * dst) {
|
||||
|
||||
FILE * fsrc = fileOpen(src, "rb");
|
||||
if (fsrc == NULL) return false;
|
||||
NV_ON_RETURN(fclose(fsrc));
|
||||
|
||||
FILE * fdst = fileOpen(dst, "wb");
|
||||
if (fdst == NULL) return false;
|
||||
NV_ON_RETURN(fclose(fdst));
|
||||
|
||||
char buffer[1024];
|
||||
size_t n;
|
||||
|
||||
while ((n = fread(buffer, sizeof(char), sizeof(buffer), fsrc)) > 0) {
|
||||
if (fwrite(buffer, sizeof(char), n, fdst) != n) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
|
|
@ -15,7 +15,7 @@ namespace nv
|
|||
NVCORE_API bool createDirectory(const char * path);
|
||||
NVCORE_API bool changeDirectory(const char * path);
|
||||
NVCORE_API bool removeFile(const char * path);
|
||||
|
||||
NVCORE_API bool copyFile(const char * src, const char * dst);
|
||||
} // FileSystem namespace
|
||||
|
||||
} // nv namespace
|
||||
|
|
|
@ -5,10 +5,12 @@
|
|||
#include "Utils.h"
|
||||
|
||||
#include <stdlib.h>
|
||||
/////// Changes in Dust3D Begin /////////////
|
||||
#if defined(__APPLE__)
|
||||
#else
|
||||
#include <malloc.h>
|
||||
#endif
|
||||
/////// Changes in Dust3D End /////////////
|
||||
|
||||
#define USE_EFENCE 0
|
||||
|
||||
|
|
|
@ -526,6 +526,28 @@ StringBuilder & StringBuilder::copy( const StringBuilder & s )
|
|||
return *this;
|
||||
}
|
||||
|
||||
void StringBuilder::removeChar(char c)
|
||||
{
|
||||
char * src = strchr(m_str, c);
|
||||
if (src) {
|
||||
char * dst = src;
|
||||
src++;
|
||||
while (*src) {
|
||||
*dst++ = *src++;
|
||||
}
|
||||
*dst = '\0';
|
||||
}
|
||||
}
|
||||
|
||||
void StringBuilder::replaceChars(char c, char x)
|
||||
{
|
||||
char * src = m_str;
|
||||
while (*src) {
|
||||
if (*src == c) *src = x;
|
||||
src++;
|
||||
}
|
||||
}
|
||||
|
||||
bool StringBuilder::endsWith(const char * str) const
|
||||
{
|
||||
uint l = uint(strlen(str));
|
||||
|
@ -540,7 +562,7 @@ bool StringBuilder::beginsWith(const char * str) const
|
|||
return strncmp(m_str, str, l) == 0;
|
||||
}
|
||||
|
||||
// Find given char starting from the end.
|
||||
// Find given char starting from the end. Why not use strrchr!?
|
||||
char * StringBuilder::reverseFind(char c)
|
||||
{
|
||||
int length = (int)strlen(m_str) - 1;
|
||||
|
|
|
@ -125,19 +125,22 @@ namespace nv
|
|||
StringBuilder & toLower();
|
||||
StringBuilder & toUpper();
|
||||
|
||||
void removeChar(char c);
|
||||
void replaceChars(char c, char x);
|
||||
|
||||
bool endsWith(const char * str) const;
|
||||
bool beginsWith(const char * str) const;
|
||||
|
||||
char * reverseFind(char c);
|
||||
|
||||
void reset();
|
||||
bool isNull() const { return m_size == 0; }
|
||||
NV_FORCEINLINE bool isNull() const { return m_size == 0; }
|
||||
|
||||
// const char * accessors
|
||||
//operator const char * () const { return m_str; }
|
||||
//operator char * () { return m_str; }
|
||||
const char * str() const { return m_str; }
|
||||
char * str() { return m_str; }
|
||||
NV_FORCEINLINE const char * str() const { return m_str; }
|
||||
NV_FORCEINLINE char * str() { return m_str; }
|
||||
|
||||
char * release(); // Release ownership of string.
|
||||
void acquire(char *); // Take ownership of string.
|
||||
|
@ -283,25 +286,25 @@ namespace nv
|
|||
/// Equal operator.
|
||||
bool operator==( const String & str ) const
|
||||
{
|
||||
return strMatch(str.data, data);
|
||||
return strEqual(str.data, data);
|
||||
}
|
||||
|
||||
/// Equal operator.
|
||||
bool operator==( const char * str ) const
|
||||
{
|
||||
return strMatch(str, data);
|
||||
return strEqual(str, data);
|
||||
}
|
||||
|
||||
/// Not equal operator.
|
||||
bool operator!=( const String & str ) const
|
||||
{
|
||||
return !strMatch(str.data, data);
|
||||
return !strEqual(str.data, data);
|
||||
}
|
||||
|
||||
/// Not equal operator.
|
||||
bool operator!=( const char * str ) const
|
||||
{
|
||||
return !strMatch(str, data);
|
||||
return !strEqual(str, data);
|
||||
}
|
||||
|
||||
/// Returns true if this string is the null string.
|
||||
|
|
|
@ -72,6 +72,11 @@ namespace nv
|
|||
//template <> inline uint32 U32<uint8>(uint8 x) { return x; }
|
||||
template <> inline uint32 U32<int8>(int8 x) { nvDebugCheck(x >= 0); return (uint32)x; }
|
||||
|
||||
#if NV_OS_DARWIN
|
||||
template <> inline uint32 U32<unsigned long>(unsigned long x) { nvDebugCheck(x <= NV_UINT32_MAX); return (uint32)x; }
|
||||
template <> inline uint32 U32<long>(long x) { nvDebugCheck(x >= 0 && x <= NV_UINT32_MAX); return (uint32)x; }
|
||||
#endif
|
||||
|
||||
// int32 casts:
|
||||
template <typename T> inline int32 I32(T x) { return x; }
|
||||
template <> inline int32 I32<uint64>(uint64 x) { nvDebugCheck(x <= NV_INT32_MAX); return (int32)x; }
|
||||
|
@ -120,11 +125,11 @@ namespace nv
|
|||
// int8 casts:
|
||||
template <typename T> inline int8 I8(T x) { return x; }
|
||||
template <> inline int8 I8<uint64>(uint64 x) { nvDebugCheck(x <= NV_INT8_MAX); return (int8)x; }
|
||||
template <> inline int8 I8<int64>(int64 x) { nvDebugCheck(x >= NV_INT8_MIN && x <= NV_UINT8_MAX); return (int8)x; }
|
||||
template <> inline int8 I8<int64>(int64 x) { nvDebugCheck(x >= NV_INT8_MIN && x <= NV_INT8_MAX); return (int8)x; }
|
||||
template <> inline int8 I8<uint32>(uint32 x) { nvDebugCheck(x <= NV_INT8_MAX); return (int8)x; }
|
||||
template <> inline int8 I8<int32>(int32 x) { nvDebugCheck(x >= NV_INT8_MIN && x <= NV_UINT8_MAX); return (int8)x; }
|
||||
template <> inline int8 I8<int32>(int32 x) { nvDebugCheck(x >= NV_INT8_MIN && x <= NV_INT8_MAX); return (int8)x; }
|
||||
template <> inline int8 I8<uint16>(uint16 x) { nvDebugCheck(x <= NV_INT8_MAX); return (int8)x; }
|
||||
template <> inline int8 I8<int16>(int16 x) { nvDebugCheck(x >= NV_INT8_MIN && x <= NV_UINT8_MAX); return (int8)x; }
|
||||
template <> inline int8 I8<int16>(int16 x) { nvDebugCheck(x >= NV_INT8_MIN && x <= NV_INT8_MAX); return (int8)x; }
|
||||
template <> inline int8 I8<uint8>(uint8 x) { nvDebugCheck(x <= NV_INT8_MAX); return (int8)x; }
|
||||
//template <> inline int8 I8<int8>(int8 x) { return x; }
|
||||
|
||||
|
|
|
@ -84,9 +84,9 @@
|
|||
|
||||
// Threading:
|
||||
// some platforms don't implement __thread or similar for thread-local-storage
|
||||
#if NV_OS_UNIX || NV_OS_ORBIS || NV_OS_IOS //ACStodoIOS darwin instead of ios?
|
||||
#if NV_OS_UNIX || NV_OS_ORBIS || NV_OS_IOS
|
||||
# define NV_OS_USE_PTHREAD 1
|
||||
# if NV_OS_IOS
|
||||
# if 0 //Apple finally added TLS support to iOS!// NV_OS_IOS
|
||||
# define NV_OS_HAS_TLS_QUALIFIER 0
|
||||
# else
|
||||
# define NV_OS_HAS_TLS_QUALIFIER 1
|
||||
|
@ -114,6 +114,8 @@
|
|||
# define NV_CPU_PPC 1
|
||||
#elif defined POSH_CPU_STRONGARM
|
||||
# define NV_CPU_ARM 1
|
||||
#elif defined POSH_CPU_AARCH64
|
||||
# define NV_CPU_ARM_64 1
|
||||
#else
|
||||
# error "Unsupported CPU"
|
||||
#endif
|
||||
|
@ -151,10 +153,16 @@
|
|||
#endif
|
||||
|
||||
// Endiannes:
|
||||
#define NV_LITTLE_ENDIAN POSH_LITTLE_ENDIAN
|
||||
#define NV_BIG_ENDIAN POSH_BIG_ENDIAN
|
||||
#define NV_ENDIAN_STRING POSH_ENDIAN_STRING
|
||||
|
||||
// @@ POSH endian detection is broken for arm64 on iOS. They are bi-endian and iOS sets all their processors to little endian by default.
|
||||
#if NV_OS_IOS
|
||||
# define NV_LITTLE_ENDIAN 1
|
||||
# define NV_BIG_ENDIAN 0
|
||||
# define NV_ENDIAN_STRING "little"
|
||||
#else
|
||||
# define NV_LITTLE_ENDIAN POSH_LITTLE_ENDIAN
|
||||
# define NV_BIG_ENDIAN POSH_BIG_ENDIAN
|
||||
# define NV_ENDIAN_STRING POSH_ENDIAN_STRING
|
||||
#endif
|
||||
|
||||
// Define the right printf prefix for size_t arguments:
|
||||
#if POSH_64BIT_POINTER
|
||||
|
@ -311,6 +319,24 @@ template <typename T, size_t N> char (&ArraySizeHelper(T (&array)[N]))[N];
|
|||
NV_STRING_JOIN3(AtStartup_, __LINE__, Instance); \
|
||||
}
|
||||
|
||||
namespace nv {
|
||||
template <typename F>
|
||||
struct ScopeExit {
|
||||
ScopeExit(F f) : f(f) {}
|
||||
~ScopeExit() { f(); }
|
||||
F f;
|
||||
};
|
||||
|
||||
template <typename F>
|
||||
ScopeExit<F> MakeScopeExit(F f) {
|
||||
return ScopeExit<F>(f);
|
||||
};
|
||||
}
|
||||
|
||||
#define NV_ON_RETURN(code) \
|
||||
auto NV_STRING_JOIN2(scope_exit_, __LINE__) = nv::MakeScopeExit([=](){code;})
|
||||
|
||||
|
||||
// Indicate the compiler that the parameter is not used to suppress compier warnings.
|
||||
#if NV_CC_MSVC
|
||||
#define NV_UNUSED(a) ((a)=(a))
|
||||
|
@ -318,6 +344,14 @@ template <typename T, size_t N> char (&ArraySizeHelper(T (&array)[N]))[N];
|
|||
#define NV_UNUSED(a) _Pragma(NV_STRING(unused(a)))
|
||||
#endif
|
||||
|
||||
#if NV_CC_GNUC || NV_CC_CLANG
|
||||
#define NV_LIKELY(x) __builtin_expect(!!(x), 1)
|
||||
#define NV_UNLIKELY(x) __builtin_expect(!!(x), 0)
|
||||
#else
|
||||
#define NV_LIKELY(x) x
|
||||
#define NV_UNLIKELY(x) x
|
||||
#endif
|
||||
|
||||
// Null index. @@ Move this somewhere else... it's only used by nvmesh.
|
||||
//const unsigned int NIL = unsigned int(~0);
|
||||
#define NIL uint(~0)
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
PROJECT(nvimage)
|
||||
set(CMAKE_DEBUG_POSTFIX d)
|
||||
|
||||
SET(IMAGE_SRCS
|
||||
nvimage.h
|
||||
|
|
|
@ -7,6 +7,10 @@
|
|||
#include "nvimage.h"
|
||||
#include "nvcore/Debug.h"
|
||||
|
||||
#if NV_USE_ALTIVEC
|
||||
#undef pixel
|
||||
#endif
|
||||
|
||||
namespace nv
|
||||
{
|
||||
class Color32;
|
||||
|
|
|
@ -99,7 +99,5 @@ namespace nv
|
|||
|
||||
} // nv namespace
|
||||
|
||||
#include "Box.inl"
|
||||
|
||||
|
||||
#endif // NV_MATH_BOX_H
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
PROJECT(nvmath)
|
||||
set(CMAKE_DEBUG_POSTFIX d)
|
||||
|
||||
SET(MATH_SRCS
|
||||
nvmath.h
|
||||
|
|
|
@ -7,12 +7,9 @@
|
|||
#include "nvcore/RadixSort.h"
|
||||
#include "nvcore/Array.inl"
|
||||
|
||||
using namespace nv;
|
||||
#include <float.h>
|
||||
|
||||
inline static float triangleArea(Vector2::Arg v1, Vector2::Arg v2, Vector2::Arg v3)
|
||||
{
|
||||
return 0.5f * (v3.x * v1.y + v1.x * v2.y + v2.x * v3.y - v2.x * v1.y - v3.x * v2.y - v1.x * v3.y);
|
||||
}
|
||||
using namespace nv;
|
||||
|
||||
|
||||
// Compute the convex hull using Graham Scan.
|
||||
|
@ -61,7 +58,7 @@ void nv::convexHull(const Array<Vector2> & input, Array<Vector2> & output, float
|
|||
Vector2 b = output[output.count()-1];
|
||||
Vector2 c = top[i];
|
||||
|
||||
float area = triangleArea(a, b, c);
|
||||
float area = triangleArea(a, b, c); // * 0.5
|
||||
|
||||
if (area >= -epsilon) {
|
||||
output.popBack();
|
||||
|
@ -82,7 +79,7 @@ void nv::convexHull(const Array<Vector2> & input, Array<Vector2> & output, float
|
|||
Vector2 b = output[output.count()-1];
|
||||
Vector2 c = bottom[i];
|
||||
|
||||
float area = triangleArea(a, b, c);
|
||||
float area = triangleArea(a, b, c); // * 0.5
|
||||
|
||||
if (area >= -epsilon) {
|
||||
output.popBack();
|
||||
|
@ -99,6 +96,63 @@ void nv::convexHull(const Array<Vector2> & input, Array<Vector2> & output, float
|
|||
output.popBack();
|
||||
}
|
||||
|
||||
|
||||
void nv::reduceConvexHullToNSides(Array<Vector2> *input, uint num_sides) {
|
||||
|
||||
while (input->size() > num_sides) {
|
||||
// find the shortest side and merge it with its shorter neighbor.
|
||||
// we'll see how this goes... if it's not satisfactory, we could also merge
|
||||
// based partially on the "flatness" of adjacent edges.
|
||||
int shortest_index = 0;
|
||||
float shortest_length = nv::length((*input)[1] - (*input)[0]);
|
||||
|
||||
for (uint i = 1; i < input->size(); i++) {
|
||||
nv::Vector2 p1 = (*input)[i];
|
||||
nv::Vector2 p2 = (*input)[(i + 1) % input->size()];
|
||||
float length = nv::length(p2 - p1);
|
||||
|
||||
if (length < shortest_length) {
|
||||
shortest_index = i;
|
||||
shortest_length = length;
|
||||
}
|
||||
}
|
||||
|
||||
int prev_index = (shortest_index + input->size() - 1) % input->size();
|
||||
int next_index = (shortest_index + 1) % input->size();
|
||||
int after_index = (next_index + 1) % input->size();
|
||||
float prev_len = nv::length((*input)[prev_index] - (*input)[shortest_index]);
|
||||
float next_len = nv::length((*input)[next_index] - (*input)[after_index]);
|
||||
|
||||
if (prev_len < next_len) {
|
||||
input->removeAt(shortest_index);
|
||||
} else {
|
||||
input->removeAt(next_index);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool nv::isClockwise(const Array<Vector2> &input) {
|
||||
nv::Vector2 d1 = input[1] - input[0];
|
||||
nv::Vector2 d2 = input[2] - input[0];
|
||||
nv::Vector3 normal = cross(Vector3(d1.x, d1.y, 0), Vector3(d2.x, d2.y, 0));
|
||||
return (normal.z < 0.0f);
|
||||
}
|
||||
|
||||
void nv::flipWinding(Array<Vector2> *input) {
|
||||
int start = 0;
|
||||
int end = input->size() - 1;
|
||||
|
||||
while (end > start) {
|
||||
nv::Vector2 swap = (*input)[start];
|
||||
(*input)[start] = (*input)[end];
|
||||
(*input)[end] = swap;
|
||||
start++;
|
||||
end--;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*
|
||||
void testConvexHull() {
|
||||
|
||||
|
@ -118,3 +172,280 @@ void testConvexHull() {
|
|||
}
|
||||
*/
|
||||
|
||||
|
||||
|
||||
struct Line {
|
||||
Vector2 v;
|
||||
Vector2 d;
|
||||
};
|
||||
|
||||
|
||||
bool intersect(const Line &line0, const Line &line1, Vector2 * point)
|
||||
{
|
||||
float d = triangleArea(line0.d, line1.d);
|
||||
if (fabsf(d) < NV_EPSILON) // Parallel lines
|
||||
return false;
|
||||
|
||||
float t = triangleArea(line1.d, line0.v - line1.v) / d;
|
||||
|
||||
if (t < 0.5f) // Intersects on the wrong side
|
||||
return false;
|
||||
|
||||
*point = line0.v + t * line0.d;
|
||||
return true;
|
||||
}
|
||||
|
||||
static inline Line buildLine(const Array<Vector2> & vertices, uint i0, uint i1) {
|
||||
Line line;
|
||||
line.v = vertices[i0];
|
||||
line.d = vertices[i1] - vertices[i0]; // @@ Normalize?
|
||||
return line;
|
||||
}
|
||||
|
||||
|
||||
static bool buildPolygon(const Array<Vector2> & vertices, const Array<uint> & edges, Array<Vector2> & output) {
|
||||
|
||||
const uint vertexCount = vertices.count();
|
||||
const uint edgeCount = edges.count();
|
||||
|
||||
output.clear();
|
||||
output.reserve(edgeCount);
|
||||
|
||||
// Intersect each edge against the next.
|
||||
Line first, prev, current;
|
||||
Vector2 point;
|
||||
|
||||
first = prev = buildLine(vertices, 0, 1);
|
||||
|
||||
for (uint i = 1; i < edgeCount; i++) {
|
||||
current = buildLine(vertices, edges[i], (edges[i]+1) % vertexCount);
|
||||
|
||||
if (!intersect(prev, current, &point)) {
|
||||
return false;
|
||||
}
|
||||
output.append(point);
|
||||
|
||||
prev = current;
|
||||
}
|
||||
|
||||
if (!intersect(current, first, &point)) {
|
||||
return false;
|
||||
}
|
||||
output.append(point);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// Triangulate polygon and sum triangle areas.
|
||||
static float polygonArea(const Array<Vector2> & vertices) {
|
||||
|
||||
float area = 0;
|
||||
Vector2 v0 = vertices[0];
|
||||
|
||||
for (uint i = 2; i < vertices.count(); i++)
|
||||
{
|
||||
Vector2 v1 = vertices[i];
|
||||
Vector2 v2 = vertices[i-1];
|
||||
|
||||
area += triangleArea(v0, v1, v2);
|
||||
}
|
||||
|
||||
return area * 0.5f;
|
||||
}
|
||||
|
||||
// @@ Test this!
|
||||
static bool next(Array<uint> & edges, uint vertexCount) {
|
||||
int count = edges.count();
|
||||
|
||||
uint previous = vertexCount;
|
||||
|
||||
for (int i = count-1; i >= 0; i--) {
|
||||
uint e = edges[i];
|
||||
if (e + 1 < previous) {
|
||||
// increment current and reset remainder of the sequence.
|
||||
for (; i < count; i++) {
|
||||
edges[i] = ++e;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
previous = e;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
|
||||
// Given a convex hull, finds best fit polygon with the given number of edges.
|
||||
// Brute force implementation, tries all possible edges, but may not arrive to best result, because edges of best fit polygon are not necessarily aligned to convex hull edges.
|
||||
bool nv::bestFitPolygon(const Array<Vector2> & hullVertices, uint edgeCount, Array<Vector2> * bestPolygon) {
|
||||
uint vertexCount = hullVertices.count();
|
||||
|
||||
// Not a valid polygon.
|
||||
if (edgeCount <= 2) return false;
|
||||
|
||||
// Hull has same or less vertices that desired polygon.
|
||||
if (edgeCount >= vertexCount) return false;
|
||||
|
||||
bestPolygon->reserve(edgeCount);
|
||||
float bestArea = FLT_MAX;
|
||||
|
||||
if (edgeCount == 4) {
|
||||
// Try with axis aligned box first.
|
||||
Vector2 box_min(FLT_MAX);
|
||||
Vector2 box_max(-FLT_MAX);
|
||||
|
||||
for (uint i = 0; i < hullVertices.count(); i++) {
|
||||
box_min.x = min(box_min.x, hullVertices[i].x);
|
||||
box_min.y = min(box_min.y, hullVertices[i].y);
|
||||
box_max.x = max(box_max.x, hullVertices[i].x);
|
||||
box_max.y = max(box_max.y, hullVertices[i].y);
|
||||
}
|
||||
|
||||
bestArea = (box_max.x - box_min.x) * (box_max.y - box_min.y);
|
||||
|
||||
bestPolygon->append(Vector2(box_min.x, box_min.y));
|
||||
bestPolygon->append(Vector2(box_min.x, box_max.y));
|
||||
bestPolygon->append(Vector2(box_max.x, box_max.y));
|
||||
bestPolygon->append(Vector2(box_max.x, box_min.y));
|
||||
}
|
||||
|
||||
|
||||
// Select all possible combinations of consecutive edges.
|
||||
|
||||
// For example, for groups of 3 out of 5 we want:
|
||||
|
||||
// 012
|
||||
// 013
|
||||
// 014
|
||||
// 023
|
||||
// 024
|
||||
// 034
|
||||
// 123
|
||||
// 124
|
||||
// 134
|
||||
|
||||
|
||||
Array<uint> edges(edgeCount);
|
||||
|
||||
// Init edge sequence.
|
||||
for (uint i = 0; i < edgeCount; i++) {
|
||||
edges.append(i);
|
||||
}
|
||||
|
||||
// Traverse sequence testing all
|
||||
Array<Vector2> polygon(edgeCount);
|
||||
do {
|
||||
if (buildPolygon(hullVertices, edges, polygon)) {
|
||||
float area = polygonArea(polygon);
|
||||
if (area < bestArea) {
|
||||
bestArea = area;
|
||||
*bestPolygon = polygon;
|
||||
}
|
||||
}
|
||||
} while (next(edges, vertexCount));
|
||||
|
||||
return bestArea < FLT_MAX;
|
||||
}
|
||||
|
||||
|
||||
static bool pointInTriangle(const Vector2 & p, const Vector2 & a, const Vector2 & b, const Vector2 & c)
|
||||
{
|
||||
return triangleArea(a, b, p) >= 0.00001f &&
|
||||
triangleArea(b, c, p) >= 0.00001f &&
|
||||
triangleArea(c, a, p) >= 0.00001f;
|
||||
}
|
||||
|
||||
void nv::triangulate(const Array<Vector2> & input, Array<uint> * output) {
|
||||
|
||||
const uint edgeCount = input.count();
|
||||
nvDebugCheck(edgeCount >= 3);
|
||||
|
||||
output->clear(); // @@ Do we want to clear?
|
||||
output->reserve(edgeCount);
|
||||
|
||||
if (edgeCount == 3) {
|
||||
// Simple case for triangles.
|
||||
output->append(0);
|
||||
output->append(1);
|
||||
output->append(2);
|
||||
}
|
||||
else {
|
||||
Array<int> polygonVertices;
|
||||
Array<float> polygonAngles;
|
||||
|
||||
polygonVertices.resize(edgeCount);
|
||||
polygonAngles.resize(edgeCount);
|
||||
|
||||
for (uint i = 0; i < edgeCount; ++i) {
|
||||
polygonVertices[i] = i;
|
||||
}
|
||||
|
||||
while (polygonVertices.size() > 2) {
|
||||
uint size = polygonVertices.size();
|
||||
|
||||
// Update polygon angles. @@ Update only those that have changed.
|
||||
float minAngle = 2 * PI;
|
||||
uint bestEar = 0; // Use first one if none of them is valid.
|
||||
bool bestIsValid = false;
|
||||
for (uint i = 0; i < size; i++) {
|
||||
uint i0 = i;
|
||||
uint i1 = (i+1) % size; // @@ Use Sean's polygon interation trick.
|
||||
uint i2 = (i+2) % size;
|
||||
|
||||
Vector2 p0 = input[polygonVertices[i0]];
|
||||
Vector2 p1 = input[polygonVertices[i1]];
|
||||
Vector2 p2 = input[polygonVertices[i2]];
|
||||
|
||||
float d = clamp(dot(p0-p1, p2-p1) / (length(p0-p1) * length(p2-p1)), -1.0f, 1.0f);
|
||||
float angle = acosf(d);
|
||||
|
||||
float area = triangleArea(p0, p1, p2);
|
||||
if (area < 0.0f) angle = 2.0f * PI - angle;
|
||||
|
||||
polygonAngles[i1] = angle;
|
||||
|
||||
if (angle < minAngle || !bestIsValid) {
|
||||
|
||||
// Make sure this is a valid ear, if not, skip this point.
|
||||
bool valid = true;
|
||||
for (uint j = 0; j < size; j++) {
|
||||
if (j == i0 || j == i1 || j == i2) continue;
|
||||
Vector2 p = input[polygonVertices[j]];
|
||||
|
||||
if (pointInTriangle(p, p0, p1, p2)) {
|
||||
valid = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (valid || !bestIsValid) {
|
||||
minAngle = angle;
|
||||
bestEar = i1;
|
||||
bestIsValid = valid;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
nvDebugCheck(minAngle <= 2 * PI);
|
||||
|
||||
// Clip best ear:
|
||||
|
||||
uint i0 = (bestEar+size-1) % size;
|
||||
uint i1 = (bestEar+0) % size;
|
||||
uint i2 = (bestEar+1) % size;
|
||||
|
||||
int v0 = polygonVertices[i0];
|
||||
int v1 = polygonVertices[i1];
|
||||
int v2 = polygonVertices[i2];
|
||||
|
||||
output->append(v0);
|
||||
output->append(v1);
|
||||
output->append(v2);
|
||||
|
||||
polygonVertices.removeAt(i1);
|
||||
polygonAngles.removeAt(i1);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -12,6 +12,16 @@ namespace nv {
|
|||
|
||||
void convexHull(const Array<Vector2> & input, Array<Vector2> & output, float epsilon = 0);
|
||||
|
||||
//ACS: moved these down from collision_volume.cpp
|
||||
bool isClockwise(const Array<Vector2> & input);
|
||||
void reduceConvexHullToNSides(Array<Vector2> *input, uint num_sides);
|
||||
void flipWinding(Array<Vector2> *input);
|
||||
|
||||
bool bestFitPolygon(const Array<Vector2> & input, uint vertexCount, Array<Vector2> * output);
|
||||
|
||||
// Basic ear-clipping algorithm.
|
||||
void triangulate(const Array<Vector2> & input, Array<uint> * output);
|
||||
|
||||
} // namespace nv
|
||||
|
||||
#endif // NV_MATH_CONVEXHULL_H
|
||||
|
|
|
@ -57,7 +57,7 @@ static bool ludcmp(float **a, int n, int *indx, float *d)
|
|||
}
|
||||
a[i][j]=sum;
|
||||
|
||||
float dum = vv[i]*fabs(sum);
|
||||
float dum = vv[i]*fabsf(sum);
|
||||
if (dum >= big) {
|
||||
// Is the figure of merit for the pivot better than the best so far?
|
||||
big = dum;
|
||||
|
@ -197,6 +197,36 @@ bool nv::solveLU(const Matrix3 & A, const Vector3 & b, Vector3 * x)
|
|||
return true;
|
||||
}
|
||||
|
||||
bool nv::solveLU(const Matrix2 & A, const Vector2 & b, Vector2 * x)
|
||||
{
|
||||
nvDebugCheck(x != NULL);
|
||||
|
||||
float m[2][2];
|
||||
float *a[2] = {m[0], m[1]};
|
||||
int idx[2];
|
||||
float d;
|
||||
|
||||
for (int y = 0; y < 2; y++) {
|
||||
for (int x = 0; x < 2; x++) {
|
||||
a[x][y] = A(x, y);
|
||||
}
|
||||
}
|
||||
|
||||
// Create LU decomposition.
|
||||
if (!ludcmp(a, 2, idx, &d)) {
|
||||
// Singular matrix.
|
||||
return false;
|
||||
}
|
||||
|
||||
// Init solution.
|
||||
*x = b;
|
||||
|
||||
// Do back substitution.
|
||||
lubksb(a, 2, idx, x->component);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
bool nv::solveCramer(const Matrix & A, const Vector4 & b, Vector4 * x)
|
||||
{
|
||||
|
@ -223,6 +253,22 @@ bool nv::solveCramer(const Matrix3 & A, const Vector3 & b, Vector3 * x)
|
|||
return true;
|
||||
}
|
||||
|
||||
bool nv::solveCramer(const Matrix2 & A, const Vector2 & b, Vector2 * x)
|
||||
{
|
||||
nvDebugCheck(x != NULL);
|
||||
|
||||
const float det = A.determinant();
|
||||
if (equal(det, 0.0f)) { // @@ Use input epsilon.
|
||||
return false;
|
||||
}
|
||||
|
||||
Matrix2 Ai = inverseCramer(A);
|
||||
|
||||
*x = transform(Ai, b);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
|
||||
// Inverse using gaussian elimination. From Jon's code.
|
||||
|
@ -238,8 +284,8 @@ Matrix nv::inverse(const Matrix & m) {
|
|||
for (i=0; i<4; i++) { /* eliminate in column i, below diag */
|
||||
max = -1.;
|
||||
for (k=i; k<4; k++) /* find pivot for column i */
|
||||
if (fabs(A(k, i)) > max) {
|
||||
max = fabs(A(k, i));
|
||||
if (fabsf(A(k, i)) > max) {
|
||||
max = fabsf(A(k, i));
|
||||
j = k;
|
||||
}
|
||||
if (max<=0.) return B; /* if no nonzero pivot, PUNT */
|
||||
|
@ -293,8 +339,8 @@ Matrix3 nv::inverse(const Matrix3 & m) {
|
|||
for (i=0; i<3; i++) { /* eliminate in column i, below diag */
|
||||
max = -1.;
|
||||
for (k=i; k<3; k++) /* find pivot for column i */
|
||||
if (fabs(A(k, i)) > max) {
|
||||
max = fabs(A(k, i));
|
||||
if (fabsf(A(k, i)) > max) {
|
||||
max = fabsf(A(k, i));
|
||||
j = k;
|
||||
}
|
||||
if (max<=0.) return B; /* if no nonzero pivot, PUNT */
|
||||
|
|
|
@ -14,6 +14,46 @@ namespace nv
|
|||
{
|
||||
enum identity_t { identity };
|
||||
|
||||
// 2x2 matrix.
|
||||
class NVMATH_CLASS Matrix2
|
||||
{
|
||||
public:
|
||||
Matrix2();
|
||||
explicit Matrix2(float f);
|
||||
explicit Matrix2(identity_t);
|
||||
Matrix2(const Matrix2 & m);
|
||||
Matrix2(Vector2::Arg v0, Vector2::Arg v1);
|
||||
Matrix2(float a, float b, float c, float d);
|
||||
|
||||
float data(uint idx) const;
|
||||
float & data(uint idx);
|
||||
float get(uint row, uint col) const;
|
||||
float operator()(uint row, uint col) const;
|
||||
float & operator()(uint row, uint col);
|
||||
|
||||
Vector2 row(uint i) const;
|
||||
Vector2 column(uint i) const;
|
||||
|
||||
void operator*=(float s);
|
||||
void operator/=(float s);
|
||||
void operator+=(const Matrix2 & m);
|
||||
void operator-=(const Matrix2 & m);
|
||||
|
||||
void scale(float s);
|
||||
void scale(Vector2::Arg s);
|
||||
float determinant() const;
|
||||
|
||||
private:
|
||||
float m_data[4];
|
||||
};
|
||||
|
||||
// Solve equation system using LU decomposition and back-substitution.
|
||||
extern bool solveLU(const Matrix2 & m, const Vector2 & b, Vector2 * x);
|
||||
|
||||
// Solve equation system using Cramer's inverse.
|
||||
extern bool solveCramer(const Matrix2 & A, const Vector2 & b, Vector2 * x);
|
||||
|
||||
|
||||
// 3x3 matrix.
|
||||
class NVMATH_CLASS Matrix3
|
||||
{
|
||||
|
@ -52,6 +92,8 @@ namespace nv
|
|||
// Solve equation system using Cramer's inverse.
|
||||
extern bool solveCramer(const Matrix3 & A, const Vector3 & b, Vector3 * x);
|
||||
|
||||
extern Matrix3 inverse(const Matrix3 & m);
|
||||
|
||||
|
||||
// 4x4 matrix.
|
||||
class NVMATH_CLASS Matrix
|
||||
|
@ -106,7 +148,6 @@ namespace nv
|
|||
|
||||
// Compute inverse using Gaussian elimination and partial pivoting.
|
||||
extern Matrix inverse(const Matrix & m);
|
||||
extern Matrix3 inverse(const Matrix3 & m);
|
||||
|
||||
} // nv namespace
|
||||
|
||||
|
|
|
@ -8,6 +8,199 @@
|
|||
|
||||
namespace nv
|
||||
{
|
||||
inline Matrix2::Matrix2() {}
|
||||
|
||||
inline Matrix2::Matrix2(float f)
|
||||
{
|
||||
for(int i = 0; i < 4; i++) {
|
||||
m_data[i] = f;
|
||||
}
|
||||
}
|
||||
|
||||
inline Matrix2::Matrix2(identity_t)
|
||||
{
|
||||
for(int i = 0; i < 2; i++) {
|
||||
for(int j = 0; j < 2; j++) {
|
||||
m_data[2*j+i] = (i == j) ? 1.0f : 0.0f;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
inline Matrix2::Matrix2(const Matrix2 & m)
|
||||
{
|
||||
for(int i = 0; i < 4; i++) {
|
||||
m_data[i] = m.m_data[i];
|
||||
}
|
||||
}
|
||||
|
||||
inline Matrix2::Matrix2(Vector2::Arg v0, Vector2::Arg v1)
|
||||
{
|
||||
m_data[0] = v0.x; m_data[1] = v0.y;
|
||||
m_data[2] = v1.x; m_data[3] = v1.y;
|
||||
}
|
||||
|
||||
inline Matrix2::Matrix2(float a, float b, float c, float d)
|
||||
{
|
||||
m_data[0] = a; m_data[1] = b;
|
||||
m_data[2] = c; m_data[3] = d;
|
||||
}
|
||||
|
||||
inline float Matrix2::data(uint idx) const
|
||||
{
|
||||
nvDebugCheck(idx < 4);
|
||||
return m_data[idx];
|
||||
}
|
||||
inline float & Matrix2::data(uint idx)
|
||||
{
|
||||
nvDebugCheck(idx < 4);
|
||||
return m_data[idx];
|
||||
}
|
||||
inline float Matrix2::get(uint row, uint col) const
|
||||
{
|
||||
nvDebugCheck(row < 2 && col < 2);
|
||||
return m_data[col * 2 + row];
|
||||
}
|
||||
inline float Matrix2::operator()(uint row, uint col) const
|
||||
{
|
||||
nvDebugCheck(row < 2 && col < 2);
|
||||
return m_data[col * 2 + row];
|
||||
}
|
||||
inline float & Matrix2::operator()(uint row, uint col)
|
||||
{
|
||||
nvDebugCheck(row < 2 && col < 2);
|
||||
return m_data[col * 2 + row];
|
||||
}
|
||||
|
||||
inline Vector2 Matrix2::row(uint i) const
|
||||
{
|
||||
nvDebugCheck(i < 2);
|
||||
return Vector2(get(i, 0), get(i, 1));
|
||||
}
|
||||
inline Vector2 Matrix2::column(uint i) const
|
||||
{
|
||||
nvDebugCheck(i < 2);
|
||||
return Vector2(get(0, i), get(1, i));
|
||||
}
|
||||
|
||||
inline void Matrix2::operator*=(float s)
|
||||
{
|
||||
for(int i = 0; i < 4; i++) {
|
||||
m_data[i] *= s;
|
||||
}
|
||||
}
|
||||
|
||||
inline void Matrix2::operator/=(float s)
|
||||
{
|
||||
float is = 1.0f /s;
|
||||
for(int i = 0; i < 4; i++) {
|
||||
m_data[i] *= is;
|
||||
}
|
||||
}
|
||||
|
||||
inline void Matrix2::operator+=(const Matrix2 & m)
|
||||
{
|
||||
for(int i = 0; i < 4; i++) {
|
||||
m_data[i] += m.m_data[i];
|
||||
}
|
||||
}
|
||||
|
||||
inline void Matrix2::operator-=(const Matrix2 & m)
|
||||
{
|
||||
for(int i = 0; i < 4; i++) {
|
||||
m_data[i] -= m.m_data[i];
|
||||
}
|
||||
}
|
||||
|
||||
inline Matrix2 operator+(const Matrix2 & a, const Matrix2 & b)
|
||||
{
|
||||
Matrix2 m = a;
|
||||
m += b;
|
||||
return m;
|
||||
}
|
||||
|
||||
inline Matrix2 operator-(const Matrix2 & a, const Matrix2 & b)
|
||||
{
|
||||
Matrix2 m = a;
|
||||
m -= b;
|
||||
return m;
|
||||
}
|
||||
|
||||
inline Matrix2 operator*(const Matrix2 & a, float s)
|
||||
{
|
||||
Matrix2 m = a;
|
||||
m *= s;
|
||||
return m;
|
||||
}
|
||||
|
||||
inline Matrix2 operator*(float s, const Matrix2 & a)
|
||||
{
|
||||
Matrix2 m = a;
|
||||
m *= s;
|
||||
return m;
|
||||
}
|
||||
|
||||
inline Matrix2 operator/(const Matrix2 & a, float s)
|
||||
{
|
||||
Matrix2 m = a;
|
||||
m /= s;
|
||||
return m;
|
||||
}
|
||||
|
||||
inline Matrix2 mul(const Matrix2 & a, const Matrix2 & b)
|
||||
{
|
||||
Matrix2 m;
|
||||
|
||||
for(int i = 0; i < 2; i++) {
|
||||
const float ai0 = a(i,0), ai1 = a(i,1);
|
||||
m(i, 0) = ai0 * b(0,0) + ai1 * b(1,0);
|
||||
m(i, 1) = ai0 * b(0,1) + ai1 * b(1,1);
|
||||
}
|
||||
|
||||
return m;
|
||||
}
|
||||
|
||||
inline Matrix2 operator*(const Matrix2 & a, const Matrix2 & b)
|
||||
{
|
||||
return mul(a, b);
|
||||
}
|
||||
|
||||
// Transform the given 3d vector with the given matrix.
|
||||
inline Vector2 transform(const Matrix2 & m, const Vector2 & p)
|
||||
{
|
||||
return Vector2(p.x * m(0,0) + p.y * m(0,1),
|
||||
p.x * m(1,0) + p.y * m(1,1));
|
||||
}
|
||||
|
||||
inline void Matrix2::scale(float s)
|
||||
{
|
||||
for (int i = 0; i < 4; i++) {
|
||||
m_data[i] *= s;
|
||||
}
|
||||
}
|
||||
|
||||
inline void Matrix2::scale(Vector2::Arg s)
|
||||
{
|
||||
m_data[0] *= s.x; m_data[1] *= s.x;
|
||||
m_data[2] *= s.y; m_data[3] *= s.y;
|
||||
}
|
||||
|
||||
inline float Matrix2::determinant() const
|
||||
{
|
||||
return get(0,0) * get(1,1) - get(0,1) * get(1,0);
|
||||
}
|
||||
|
||||
// Inverse using Cramer's rule.
|
||||
inline Matrix2 inverseCramer(const Matrix2 & m)
|
||||
{
|
||||
const float det = m.determinant();
|
||||
if (equal(det, 0.0f, 0.0f)) {
|
||||
return Matrix2(0);
|
||||
}
|
||||
|
||||
return m * (1/det);
|
||||
}
|
||||
|
||||
|
||||
inline Matrix3::Matrix3() {}
|
||||
|
||||
inline Matrix3::Matrix3(float f)
|
||||
|
@ -536,7 +729,7 @@ namespace nv
|
|||
// Get perspective matrix.
|
||||
inline Matrix perspective(float fovy, float aspect, float zNear, float zFar)
|
||||
{
|
||||
float xmax = zNear * tan(fovy / 2);
|
||||
float xmax = zNear * tanf(fovy / 2);
|
||||
float xmin = -xmax;
|
||||
|
||||
float ymax = xmax / aspect;
|
||||
|
@ -548,7 +741,7 @@ namespace nv
|
|||
// Get inverse perspective matrix.
|
||||
inline Matrix perspectiveInverse(float fovy, float aspect, float zNear, float zFar)
|
||||
{
|
||||
float xmax = zNear * tan(fovy / 2);
|
||||
float xmax = zNear * tanf(fovy / 2);
|
||||
float xmin = -xmax;
|
||||
|
||||
float ymax = xmax / aspect;
|
||||
|
@ -560,7 +753,7 @@ namespace nv
|
|||
// Get infinite perspective matrix.
|
||||
inline Matrix perspective(float fovy, float aspect, float zNear)
|
||||
{
|
||||
float x = zNear * tan(fovy / 2);
|
||||
float x = zNear * tanf(fovy / 2);
|
||||
float y = x / aspect;
|
||||
return frustum( -x, x, -y, y, zNear );
|
||||
}
|
||||
|
|
|
@ -65,7 +65,7 @@ void ProximityGrid::init(const Box & box, uint count) {
|
|||
else {
|
||||
// Ideally we want one cell per point.
|
||||
float cellVolume = volume / count;
|
||||
cellWidth = pow(cellVolume, 1.0f / 3.0f);
|
||||
cellWidth = powf(cellVolume, 1.0f / 3.0f);
|
||||
}
|
||||
|
||||
nvDebugCheck(cellWidth != 0);
|
||||
|
|
|
@ -22,6 +22,7 @@ namespace nv
|
|||
Quaternion(Vector4::Arg v);
|
||||
|
||||
const Quaternion & operator=(Quaternion::Arg v);
|
||||
const Quaternion & operator*=(float s);
|
||||
|
||||
Vector4 asVector() const;
|
||||
|
||||
|
@ -47,6 +48,13 @@ namespace nv
|
|||
w = v.w;
|
||||
return *this;
|
||||
}
|
||||
inline const Quaternion & Quaternion::operator*=(float s) {
|
||||
x *= s;
|
||||
y *= s;
|
||||
z *= s;
|
||||
w *= s;
|
||||
return *this;
|
||||
}
|
||||
|
||||
inline Vector4 Quaternion::asVector() const { return Vector4(x, y, z, w); }
|
||||
|
||||
|
@ -170,15 +178,15 @@ namespace nv
|
|||
/// Transform vector.
|
||||
inline Vector3 transform(Quaternion::Arg q, Vector3::Arg v)
|
||||
{
|
||||
//Quaternion t = q * v * conjugate(q);
|
||||
//return imag(t);
|
||||
Quaternion t = q * v * conjugate(q);
|
||||
return imag(t);
|
||||
|
||||
// Faster method by Fabian Giesen and others:
|
||||
// http://molecularmusings.wordpress.com/2013/05/24/a-faster-quaternion-vector-multiplication/
|
||||
// http://mollyrocket.com/forums/viewtopic.php?t=833&sid=3a84e00a70ccb046cfc87ac39881a3d0
|
||||
|
||||
Vector3 t = 2 * cross(imag(q), v);
|
||||
return v + q.w * t + cross(imag(q), t);
|
||||
//Vector3 t = 2 * cross(imag(q), v);
|
||||
//return v + q.w * t + cross(imag(q), t);
|
||||
}
|
||||
|
||||
// @@ Not tested.
|
||||
|
@ -207,6 +215,72 @@ namespace nv
|
|||
}
|
||||
}
|
||||
|
||||
inline Quaternion fromMatrix(const Matrix3 & m) {
|
||||
#if 0 // IC: There must be a bug in this code:
|
||||
if (m(2, 2) < 0) {
|
||||
if (m(0, 0) < m(1,1)) {
|
||||
float t = 1 - m(0, 0) - m(1, 1) - m(2, 2);
|
||||
return Quaternion(t, m(0,1)+m(1,0), m(2,0)+m(0,2), m(1,2)-m(2,1));
|
||||
}
|
||||
else {
|
||||
float t = 1 - m(0, 0) + m(1, 1) - m(2, 2);
|
||||
return Quaternion(t, m(0,1) + m(1,0), m(1,2) + m(2,1), m(2,0) - m(0,2));
|
||||
}
|
||||
}
|
||||
else {
|
||||
if (m(0, 0) < -m(1, 1)) {
|
||||
float t = 1 - m(0, 0) - m(1, 1) + m(2, 2);
|
||||
return Quaternion(t, m(2,0) + m(0,2), m(1,2) + m(2,1), m(0,1) - m(1,0));
|
||||
}
|
||||
else {
|
||||
float t = 1 + m(0, 0) + m(1, 1) + m(2, 2);
|
||||
return Quaternion(t, m(1,2) - m(2,1), m(2,0) - m(0,2), m(0,1) - m(1,0));
|
||||
}
|
||||
}
|
||||
#else
|
||||
Quaternion q;
|
||||
float tr = m(0,0) + m(1,1) + m(2,2);
|
||||
if (tr > 0) {
|
||||
float s = sqrtf(tr + 1.0f);
|
||||
float p = 0.5f / s;
|
||||
q.x = (m(2,1) - m(1,2)) * p;
|
||||
q.y = (m(0,2) - m(2,0)) * p;
|
||||
q.z = (m(1,0) - m(0,1)) * p;
|
||||
q.w = s * 0.5f;
|
||||
}
|
||||
else if ((m(0,0) >= m(1,1)) && (m(0,0) >= m(2,2))) {
|
||||
float s = sqrtf(m(0,0) - m(1,1) - m(2,2) + 1.0f);
|
||||
float p = 0.5f / s;
|
||||
q.x = s * 0.5f;
|
||||
q.y = (m(1,0) + m(0,1)) * p;
|
||||
q.z = (m(2,0) + m(0,2)) * p;
|
||||
q.w = (m(2,1) - m(1,2)) * p;
|
||||
}
|
||||
else if ((m(1,1) >= m(0,0)) && (m(1,1) >= m(2,2))) {
|
||||
float s = sqrtf(m(1,1) - m(2,2) - m(0,0) + 1.0f);
|
||||
float p = 0.5f / s;
|
||||
q.x = (m(0,1) + m(1,0)) * p;
|
||||
q.y = s * 0.5f;
|
||||
q.z = (m(2,1) + m(1,2)) * p;
|
||||
q.w = (m(0,2) - m(2,0)) * p;
|
||||
}
|
||||
else if ((m(2,2) >= m(0,0)) && (m(2,2) >= m(1,1))) {
|
||||
float s = sqrtf(m(2,2) - m(0,0) - m(1,1) + 1.0f);
|
||||
float p = 0.5f / s;
|
||||
q.x = (m(0,2) + m(2,0)) * p;
|
||||
q.y = (m(1,2) + m(2,1)) * p;
|
||||
q.z = s * 0.5f;
|
||||
q.w = (m(1,0) - m(0,1)) * p;
|
||||
}
|
||||
return q;
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
} // nv namespace
|
||||
|
||||
|
|
|
@ -146,6 +146,4 @@ template <typename T> T to(const nv::Vector2 & v) { NV_COMPILER_CHECK(sizeof(T)
|
|||
template <typename T> T to(const nv::Vector3 & v) { NV_COMPILER_CHECK(sizeof(T) == sizeof(nv::Vector3)); return T(v.x, v.y, v.z); }
|
||||
template <typename T> T to(const nv::Vector4 & v) { NV_COMPILER_CHECK(sizeof(T) == sizeof(nv::Vector4)); return T(v.x, v.y, v.z, v.w); }
|
||||
|
||||
#include "Vector.inl"
|
||||
|
||||
#endif // NV_MATH_VECTOR_H
|
||||
|
|
|
@ -53,8 +53,7 @@ namespace nv
|
|||
return (val<0) ? ftoi_ceil_xs(val) : ftoi_floor_xs(val);
|
||||
}
|
||||
|
||||
|
||||
#if NV_USE_SSE
|
||||
#if NV_CPU_X86 || NV_CPU_X86_64
|
||||
|
||||
NV_FORCEINLINE int ftoi_round_sse(float f) {
|
||||
return _mm_cvt_ss2si(_mm_set_ss(f));
|
||||
|
@ -64,6 +63,12 @@ namespace nv
|
|||
return _mm_cvtt_ss2si(_mm_set_ss(f));
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
#if NV_USE_SSE
|
||||
|
||||
NV_FORCEINLINE int ftoi_round(float val) {
|
||||
return ftoi_round_sse(val);
|
||||
}
|
||||
|
|
|
@ -14,6 +14,12 @@
|
|||
#include <float.h> // finite, isnan
|
||||
#endif
|
||||
|
||||
#if NV_CPU_X86 || NV_CPU_X86_64
|
||||
//#include <intrin.h>
|
||||
#include <xmmintrin.h>
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
// Function linkage
|
||||
#if NVMATH_SHARED
|
||||
|
@ -36,33 +42,36 @@
|
|||
#endif
|
||||
|
||||
#ifndef NV_USE_SSE
|
||||
// 1=SSE, 2=SSE2
|
||||
# if NV_CPU_X86_64
|
||||
// x64 always supports at least SSE2
|
||||
# define NV_USE_SSE 2
|
||||
# elif NV_CC_MSVC && defined(_M_IX86_FP)
|
||||
// Also on x86 with the /arch:SSE flag in MSVC.
|
||||
# define NV_USE_SSE _M_IX86_FP
|
||||
# elif defined(__SSE2__)
|
||||
# define NV_USE_SSE 2
|
||||
# define NV_USE_SSE _M_IX86_FP // 1=SSE, 2=SS2
|
||||
# elif defined(__SSE__)
|
||||
# define NV_USE_SSE 1
|
||||
# elif defined(__SSE2__)
|
||||
# define NV_USE_SSE 2
|
||||
# else
|
||||
// Otherwise we assume no SSE.
|
||||
# define NV_USE_SSE 0
|
||||
# endif
|
||||
#endif
|
||||
|
||||
#if NV_USE_SSE
|
||||
#include <xmmintrin.h>
|
||||
// Temporarily disable SSE to make things compile for now
|
||||
#if TARGET_OS_TV
|
||||
#undef NV_USE_SSE
|
||||
#define NV_USE_SSE 0
|
||||
#endif
|
||||
|
||||
|
||||
// Internally set NV_USE_SIMD when either altivec or sse is available.
|
||||
#if NV_USE_ALTIVEC && NV_USE_SSE
|
||||
# error "Cannot enable both altivec and sse!"
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
#ifndef PI
|
||||
#define PI float(3.1415926535897932384626433833)
|
||||
#endif
|
||||
|
@ -169,10 +178,8 @@ namespace nv
|
|||
{
|
||||
#if NV_OS_WIN32 || NV_OS_XBOX || NV_OS_DURANGO
|
||||
return _finite(f) != 0;
|
||||
#elif NV_OS_DARWIN || NV_OS_FREEBSD || NV_OS_OPENBSD || NV_OS_ORBIS
|
||||
#elif NV_OS_DARWIN || NV_OS_FREEBSD || NV_OS_OPENBSD || NV_OS_ORBIS || NV_OS_LINUX
|
||||
return isfinite(f);
|
||||
#elif NV_OS_LINUX
|
||||
return finitef(f);
|
||||
#else
|
||||
# error "isFinite not supported"
|
||||
#endif
|
||||
|
@ -184,10 +191,8 @@ namespace nv
|
|||
{
|
||||
#if NV_OS_WIN32 || NV_OS_XBOX || NV_OS_DURANGO
|
||||
return _isnan(f) != 0;
|
||||
#elif NV_OS_DARWIN || NV_OS_FREEBSD || NV_OS_OPENBSD || NV_OS_ORBIS
|
||||
#elif NV_OS_DARWIN || NV_OS_FREEBSD || NV_OS_OPENBSD || NV_OS_ORBIS || NV_OS_LINUX
|
||||
return isnan(f);
|
||||
#elif NV_OS_LINUX
|
||||
return isnanf(f);
|
||||
#else
|
||||
# error "isNan not supported"
|
||||
#endif
|
||||
|
@ -221,7 +226,7 @@ namespace nv
|
|||
|
||||
inline float frac(float f)
|
||||
{
|
||||
return f - floor(f);
|
||||
return f - floorf(f);
|
||||
}
|
||||
|
||||
inline float floatRound(float f)
|
||||
|
|
|
@ -1,9 +1,11 @@
|
|||
// This code is in the public domain -- Ignacio Castaño <castano@gmail.com>
|
||||
|
||||
#include "BaseMesh.h"
|
||||
#include "Stream.h"
|
||||
#include "nvcore/Stream.h"
|
||||
#include "nvmath/TypeSerialization.h"
|
||||
|
||||
/////// Changes in Dust3D Begin /////////////
|
||||
#include "Array.inl"
|
||||
/////// Changes in Dust3D End /////////////
|
||||
|
||||
namespace nv
|
||||
{
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
PROJECT(nvmesh)
|
||||
set(CMAKE_DEBUG_POSTFIX d)
|
||||
|
||||
SET(MESH_SRCS
|
||||
nvmesh.h
|
||||
|
|
|
@ -77,6 +77,7 @@ namespace
|
|||
|
||||
String name;
|
||||
uint faceCount;
|
||||
bool doubleSided = false;
|
||||
};
|
||||
|
||||
struct Vertex
|
||||
|
@ -141,6 +142,7 @@ struct MeshBuilder::PrivateData
|
|||
Array<Face> faceArray;
|
||||
|
||||
uint maxFaceIndexCount;
|
||||
bool detect_duplicate_faces = true;
|
||||
};
|
||||
|
||||
|
||||
|
@ -221,7 +223,7 @@ void MeshBuilder::endGroup()
|
|||
}
|
||||
|
||||
// Add named material, check for uniquenes.
|
||||
uint MeshBuilder::addMaterial(const char * name)
|
||||
uint MeshBuilder::addMaterial(const char * name, bool doubleSided)
|
||||
{
|
||||
uint index;
|
||||
if (d->materialMap.get(name, &index)) {
|
||||
|
@ -232,6 +234,7 @@ uint MeshBuilder::addMaterial(const char * name)
|
|||
d->materialMap.add(name, index);
|
||||
|
||||
Material material(name);
|
||||
material.doubleSided = doubleSided;
|
||||
d->materialArray.append(material);
|
||||
}
|
||||
return index;
|
||||
|
@ -297,7 +300,7 @@ uint MeshBuilder::addVertex(const Vector3 & pos, const Vector3 & nor, const Vect
|
|||
#endif
|
||||
|
||||
// Return true if the face is valid and was added to the mesh.
|
||||
bool MeshBuilder::endPolygon()
|
||||
bool MeshBuilder::endPolygon(bool check_duplicates/*=true*/)
|
||||
{
|
||||
const Face & face = d->faceArray.back();
|
||||
const uint count = face.indexCount;
|
||||
|
@ -353,6 +356,61 @@ bool MeshBuilder::endPolygon()
|
|||
|
||||
}
|
||||
|
||||
if (!invalid) {
|
||||
|
||||
Array<Vector3> faceVertices;
|
||||
faceVertices.reserve(4);
|
||||
|
||||
for (uint i = 0; i < face.indexCount; i++) {
|
||||
uint v = d->indexArray[face.firstIndex + i];
|
||||
uint p = d->vertexArray[v].pos;
|
||||
faceVertices.append(d->posArray[p]);
|
||||
}
|
||||
|
||||
if (check_duplicates) {
|
||||
|
||||
uint faceCount = d->faceArray.count() - 1;
|
||||
for (uint f = 0; f < faceCount; f++) {
|
||||
const Face & other = d->faceArray[f];
|
||||
|
||||
// Skip faces with different vertex count.
|
||||
if (other.indexCount != face.indexCount) {
|
||||
continue;
|
||||
}
|
||||
|
||||
const uint orientationCount = (face.material != NIL && d->materialArray[face.material].doubleSided) ? 2 : 1;
|
||||
|
||||
// Compare face vertices in all valid permutations.
|
||||
bool duplicateFace;
|
||||
for (uint orientation = 0; orientation < orientationCount; orientation++) {
|
||||
for (uint order = 0; order < face.indexCount; order++) {
|
||||
duplicateFace = true;
|
||||
for (uint i = 0; i < other.indexCount; i++) {
|
||||
uint v = d->indexArray[other.firstIndex + i];
|
||||
uint p = d->vertexArray[v].pos;
|
||||
|
||||
uint idx = orientation ? (i + order) % face.indexCount : (face.indexCount - 1 - i + order) % face.indexCount;
|
||||
|
||||
if (!equal(faceVertices[idx], d->posArray[p], 0.0f)) {
|
||||
duplicateFace = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (duplicateFace) {
|
||||
goto duplicate;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
duplicate:
|
||||
if (duplicateFace) {
|
||||
invalid = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (invalid)
|
||||
{
|
||||
d->indexArray.resize(d->indexArray.size() - count);
|
||||
|
|
|
@ -36,7 +36,7 @@ namespace nv
|
|||
void beginGroup(uint id);
|
||||
void endGroup();
|
||||
|
||||
uint addMaterial(const char * name);
|
||||
uint addMaterial(const char * name, bool deleteDuplicateFaces);
|
||||
void beginMaterial(uint id);
|
||||
void endMaterial();
|
||||
|
||||
|
@ -44,7 +44,7 @@ namespace nv
|
|||
uint addVertex(uint p, uint n = NIL, uint t0 = NIL, uint t1 = NIL, uint c0 = NIL, uint c1 = NIL, uint c2 = NIL);
|
||||
uint addVertex(const Vector3 & p);
|
||||
//uint addVertex(const Vector3 & p, const Vector3 & n, const Vector2 & t0 = Vector2(0), const Vector2 & t1 = Vector2(0), const Vector4 & c0 = Vector4(0), const Vector4 & c1 = Vector4(0));
|
||||
bool endPolygon();
|
||||
bool endPolygon(bool check_duplicates = true);
|
||||
|
||||
uint weldPositions();
|
||||
uint weldNormals();
|
||||
|
|
|
@ -1,7 +1,10 @@
|
|||
// This code is in the public domain -- Ignacio Castaño <castano@gmail.com>
|
||||
|
||||
#include "QuadTriMesh.h"
|
||||
#include "Stream.h"
|
||||
#include "nvcore/Stream.h"
|
||||
/////// Changes in Dust3D Begin /////////////
|
||||
#include "Array.inl"
|
||||
/////// Changes in Dust3D End /////////////
|
||||
|
||||
using namespace nv;
|
||||
|
||||
|
|
|
@ -157,6 +157,7 @@ namespace nv
|
|||
float scale = 1.0f;
|
||||
uint vertexMapWidth;
|
||||
uint vertexMapHeight;
|
||||
bool blockAligned = true;
|
||||
|
||||
private:
|
||||
|
||||
|
|
|
@ -114,9 +114,12 @@ namespace
|
|||
for (int j = 0; j < h; j++) {
|
||||
for (int i = 0; i < w; i++) {
|
||||
Color32 color = bitmap.pixel(i, j);
|
||||
fwrite(&color.r, 1, 1, fp);
|
||||
fwrite(&color.g, 1, 1, fp);
|
||||
fwrite(&color.b, 1, 1, fp);
|
||||
uint8 r = color.r; // current version of apple's llvm compiling for arm64 doesn't like taking the address of a bit-field. Workaround by using the stack
|
||||
uint8 g = color.g;
|
||||
uint8 b = color.b;
|
||||
fwrite(&r, 1, 1, fp);
|
||||
fwrite(&g, 1, 1, fp);
|
||||
fwrite(&b, 1, 1, fp);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -378,6 +381,8 @@ static void computeBoundingBox(Chart * chart, Vector2 * majorAxis, Vector2 * min
|
|||
|
||||
void AtlasPacker::packCharts(int quality, float texelsPerUnit, bool blockAligned, bool conservative)
|
||||
{
|
||||
nvDebugCheck(texelsPerUnit > 0.0f);
|
||||
|
||||
const uint chartCount = m_atlas->chartCount();
|
||||
if (chartCount == 0) return;
|
||||
|
||||
|
@ -416,7 +421,7 @@ void AtlasPacker::packCharts(int quality, float texelsPerUnit, bool blockAligned
|
|||
//chartOrderArray[c] = chartArea;
|
||||
|
||||
// Compute chart scale
|
||||
float parametricArea = fabs(chart->computeParametricArea()); // @@ There doesn't seem to be anything preventing parametric area to be negative.
|
||||
float parametricArea = fabsf(chart->computeParametricArea()); // @@ There doesn't seem to be anything preventing parametric area to be negative.
|
||||
if (parametricArea < NV_EPSILON) {
|
||||
// When the parametric area is too small we use a rough approximation to prevent divisions by very small numbers.
|
||||
Vector2 bounds = chart->computeParametricBounds();
|
||||
|
@ -499,7 +504,7 @@ void AtlasPacker::packCharts(int quality, float texelsPerUnit, bool blockAligned
|
|||
if (extents.x > 0) {
|
||||
int cw = ftoi_ceil(extents.x);
|
||||
|
||||
if (blockAligned) {
|
||||
if (blockAligned && chart->blockAligned) {
|
||||
// Align all chart extents to 4x4 blocks, but taking padding into account.
|
||||
if (conservative) {
|
||||
cw = align(cw + 2, 4) - 2;
|
||||
|
@ -517,7 +522,7 @@ void AtlasPacker::packCharts(int quality, float texelsPerUnit, bool blockAligned
|
|||
if (extents.y > 0) {
|
||||
int ch = ftoi_ceil(extents.y);
|
||||
|
||||
if (blockAligned) {
|
||||
if (blockAligned && chart->blockAligned) {
|
||||
// Align all chart extents to 4x4 blocks, but taking padding into account.
|
||||
if (conservative) {
|
||||
ch = align(ch + 2, 4) - 2;
|
||||
|
@ -613,6 +618,8 @@ void AtlasPacker::packCharts(int quality, float texelsPerUnit, bool blockAligned
|
|||
BitMap chart_bitmap;
|
||||
|
||||
if (chart->isVertexMapped()) {
|
||||
chart->blockAligned = false;
|
||||
|
||||
// Init all bits to 1.
|
||||
chart_bitmap.resize(ftoi_ceil(chartExtents[c].x), ftoi_ceil(chartExtents[c].y), /*initValue=*/true);
|
||||
|
||||
|
@ -650,10 +657,14 @@ void AtlasPacker::packCharts(int quality, float texelsPerUnit, bool blockAligned
|
|||
}
|
||||
}
|
||||
|
||||
if (!chart->blockAligned) {
|
||||
int k = 1;
|
||||
}
|
||||
|
||||
int best_x, best_y;
|
||||
int best_cw, best_ch; // Includes padding now.
|
||||
int best_r;
|
||||
findChartLocation(quality, &chart_bitmap, chartExtents[c], w, h, &best_x, &best_y, &best_cw, &best_ch, &best_r);
|
||||
findChartLocation(quality, &chart_bitmap, chartExtents[c], w, h, &best_x, &best_y, &best_cw, &best_ch, &best_r, chart->blockAligned);
|
||||
|
||||
/*if (w < best_x + best_cw || h < best_y + best_ch)
|
||||
{
|
||||
|
@ -849,7 +860,7 @@ void AtlasPacker::packCharts(int quality, float texelsPerUnit, bool blockAligned
|
|||
// is occupied at this point. At the end we have many small charts and a large atlas with sparse holes. Finding those holes randomly is slow. A better approach would be to
|
||||
// start stacking large charts as if they were tetris pieces. Once charts get small try to place them randomly. It may be interesting to try a intermediate strategy, first try
|
||||
// along one axis and then try exhaustively along that axis.
|
||||
void AtlasPacker::findChartLocation(int quality, const BitMap * bitmap, Vector2::Arg extents, int w, int h, int * best_x, int * best_y, int * best_w, int * best_h, int * best_r)
|
||||
void AtlasPacker::findChartLocation(int quality, const BitMap * bitmap, Vector2::Arg extents, int w, int h, int * best_x, int * best_y, int * best_w, int * best_h, int * best_r, bool blockAligned)
|
||||
{
|
||||
int attempts = 256;
|
||||
if (quality == 1) attempts = 4096;
|
||||
|
@ -859,20 +870,23 @@ void AtlasPacker::findChartLocation(int quality, const BitMap * bitmap, Vector2:
|
|||
|
||||
if (quality == 0 || w*h < attempts)
|
||||
{
|
||||
findChartLocation_bruteForce(bitmap, extents, w, h, best_x, best_y, best_w, best_h, best_r);
|
||||
findChartLocation_bruteForce(bitmap, extents, w, h, best_x, best_y, best_w, best_h, best_r, blockAligned);
|
||||
}
|
||||
else
|
||||
{
|
||||
findChartLocation_random(bitmap, extents, w, h, best_x, best_y, best_w, best_h, best_r, attempts);
|
||||
findChartLocation_random(bitmap, extents, w, h, best_x, best_y, best_w, best_h, best_r, attempts, blockAligned);
|
||||
}
|
||||
}
|
||||
|
||||
#define BLOCK_SIZE 4
|
||||
|
||||
void AtlasPacker::findChartLocation_bruteForce(const BitMap * bitmap, Vector2::Arg extents, int w, int h, int * best_x, int * best_y, int * best_w, int * best_h, int * best_r)
|
||||
void AtlasPacker::findChartLocation_bruteForce(const BitMap * bitmap, Vector2::Arg extents, int w, int h, int * best_x, int * best_y, int * best_w, int * best_h, int * best_r, bool blockAligned)
|
||||
{
|
||||
int best_metric = INT_MAX;
|
||||
|
||||
int step_size = blockAligned ? BLOCK_SIZE : 1;
|
||||
|
||||
|
||||
// Try two different orientations.
|
||||
for (int r = 0; r < 2; r++)
|
||||
{
|
||||
|
@ -880,9 +894,9 @@ void AtlasPacker::findChartLocation_bruteForce(const BitMap * bitmap, Vector2::A
|
|||
int ch = bitmap->height();
|
||||
if (r & 1) swap(cw, ch);
|
||||
|
||||
for (int y = 0; y <= h + 1; y += BLOCK_SIZE) // + 1 to extend atlas in case atlas full.
|
||||
for (int y = 0; y <= h + 1; y += step_size) // + 1 to extend atlas in case atlas full.
|
||||
{
|
||||
for (int x = 0; x <= w + 1; x += BLOCK_SIZE) // + 1 not really necessary here.
|
||||
for (int x = 0; x <= w + 1; x += step_size) // + 1 not really necessary here.
|
||||
{
|
||||
// Early out.
|
||||
int area = max(w, x+cw) * max(h, y+ch);
|
||||
|
@ -923,7 +937,7 @@ done:
|
|||
}
|
||||
|
||||
|
||||
void AtlasPacker::findChartLocation_random(const BitMap * bitmap, Vector2::Arg extents, int w, int h, int * best_x, int * best_y, int * best_w, int * best_h, int * best_r, int minTrialCount)
|
||||
void AtlasPacker::findChartLocation_random(const BitMap * bitmap, Vector2::Arg extents, int w, int h, int * best_x, int * best_y, int * best_w, int * best_h, int * best_r, int minTrialCount, bool blockAligned)
|
||||
{
|
||||
int best_metric = INT_MAX;
|
||||
|
||||
|
@ -933,8 +947,10 @@ void AtlasPacker::findChartLocation_random(const BitMap * bitmap, Vector2::Arg e
|
|||
int x = m_rand.getRange(w + 1); // + 1 to extend atlas in case atlas full. We may want to use a higher number to increase probability of extending atlas.
|
||||
int y = m_rand.getRange(h + 1); // + 1 to extend atlas in case atlas full.
|
||||
|
||||
x = align(x, BLOCK_SIZE);
|
||||
y = align(y, BLOCK_SIZE);
|
||||
if (blockAligned) {
|
||||
x = align(x, BLOCK_SIZE);
|
||||
y = align(y, BLOCK_SIZE);
|
||||
}
|
||||
|
||||
int cw = bitmap->width();
|
||||
int ch = bitmap->height();
|
||||
|
|
|
@ -28,9 +28,9 @@ namespace nv
|
|||
|
||||
private:
|
||||
|
||||
void findChartLocation(int quality, const BitMap * bitmap, Vector2::Arg extents, int w, int h, int * best_x, int * best_y, int * best_w, int * best_h, int * best_r);
|
||||
void findChartLocation_bruteForce(const BitMap * bitmap, Vector2::Arg extents, int w, int h, int * best_x, int * best_y, int * best_w, int * best_h, int * best_r);
|
||||
void findChartLocation_random(const BitMap * bitmap, Vector2::Arg extents, int w, int h, int * best_x, int * best_y, int * best_w, int * best_h, int * best_r, int minTrialCount);
|
||||
void findChartLocation(int quality, const BitMap * bitmap, Vector2::Arg extents, int w, int h, int * best_x, int * best_y, int * best_w, int * best_h, int * best_r, bool blockAligned);
|
||||
void findChartLocation_bruteForce(const BitMap * bitmap, Vector2::Arg extents, int w, int h, int * best_x, int * best_y, int * best_w, int * best_h, int * best_r, bool blockAligned);
|
||||
void findChartLocation_random(const BitMap * bitmap, Vector2::Arg extents, int w, int h, int * best_x, int * best_y, int * best_w, int * best_h, int * best_r, int minTrialCount, bool blockAligned);
|
||||
|
||||
void drawChartBitmapDilate(const Chart * chart, BitMap * bitmap, int padding);
|
||||
void drawChartBitmap(const Chart * chart, BitMap * bitmap, const Vector2 & scale, const Vector2 & offset);
|
||||
|
|
|
@ -2,7 +2,9 @@
|
|||
|
||||
#include "ConformalMap.h"
|
||||
#include "Util.h"
|
||||
|
||||
/////// Changes in Dust3D Begin /////////////
|
||||
#include "Array.inl"
|
||||
/////// Changes in Dust3D End /////////////
|
||||
#include <nvmath/Sparse.h>
|
||||
#include <nvmath/Vector.inl>
|
||||
#include <nvmath/Solver.h>
|
||||
|
|
|
@ -116,7 +116,7 @@ namespace nv
|
|||
centroidx += f * (v[k].x + v[k+1].x);
|
||||
centroidy += f * (v[k].y + v[k+1].y);
|
||||
}
|
||||
m_area = 0.5f * fabs(m_area);
|
||||
m_area = 0.5f * fabsf(m_area);
|
||||
if (m_area==0) {
|
||||
m_centroid = Vector2(0.0f);
|
||||
} else {
|
||||
|
|
|
@ -1,7 +1,10 @@
|
|||
// This code is in the public domain -- castanyo@yahoo.es
|
||||
|
||||
#include <nvcore/RadixSort.h>
|
||||
|
||||
/////// Changes in Dust3D Begin /////////////
|
||||
#include "Array.inl"
|
||||
#include "nvmath/Box.inl"
|
||||
/////// Changes in Dust3D End /////////////
|
||||
#include <nvmesh/weld/Snap.h>
|
||||
#include <nvmesh/TriMesh.h>
|
||||
#include <nvmesh/geometry/Bounds.h>
|
||||
|
|
|
@ -2,7 +2,9 @@
|
|||
|
||||
#include <nvmesh/TriMesh.h>
|
||||
#include <nvmesh/QuadTriMesh.h>
|
||||
|
||||
/////// Changes in Dust3D Begin /////////////
|
||||
#include "Array.inl"
|
||||
/////// Changes in Dust3D End /////////////
|
||||
#include <nvmesh/weld/VertexWeld.h>
|
||||
#include <nvmesh/weld/Weld.h>
|
||||
|
||||
|
|
|
@ -111,7 +111,7 @@ inline void reverseXRefs(Array<uint> & xrefs, uint count)
|
|||
//
|
||||
struct WeldN
|
||||
{
|
||||
uint vertexSize;
|
||||
const uint vertexSize;
|
||||
|
||||
WeldN(uint n) : vertexSize(n) {}
|
||||
|
||||
|
|
|
@ -1,21 +1,39 @@
|
|||
|
||||
// Thekla Atlas Generator
|
||||
|
||||
#if THEKLA_ATLAS_SHARED
|
||||
#if _WIN32
|
||||
#define DLL_EXPORT __declspec(dllexport)
|
||||
#define DLL_IMPORT __declspec(dllimport)
|
||||
#else
|
||||
#define DLL_EXPORT
|
||||
#define DLL_IMPORT
|
||||
#endif
|
||||
#ifdef THEKLA_ATLAS_EXPORTS
|
||||
#define THEKLA_ATLAS_API DLL_EXPORT
|
||||
#else
|
||||
#define THEKLA_ATLAS_API DLL_IMPORT
|
||||
#endif
|
||||
#else
|
||||
#define THEKLA_ATLAS_API
|
||||
#endif
|
||||
|
||||
|
||||
namespace Thekla {
|
||||
|
||||
enum Atlas_Charter {
|
||||
Atlas_Charter_Witness, // Options: threshold
|
||||
Atlas_Charter_Extract, // Options: ---
|
||||
Atlas_Charter_Witness,
|
||||
Atlas_Charter_Extract,
|
||||
Atlas_Charter_Default = Atlas_Charter_Witness
|
||||
};
|
||||
|
||||
enum Atlas_Mapper {
|
||||
Atlas_Mapper_LSCM, // Options: ---
|
||||
Atlas_Mapper_LSCM,
|
||||
Atlas_Mapper_Default = Atlas_Mapper_LSCM
|
||||
};
|
||||
|
||||
enum Atlas_Packer {
|
||||
Atlas_Packer_Witness, // Options: texel_area
|
||||
Atlas_Packer_Witness,
|
||||
Atlas_Packer_Default = Atlas_Packer_Witness
|
||||
};
|
||||
|
||||
|
@ -92,11 +110,11 @@ enum Atlas_Error {
|
|||
Atlas_Error_Not_Implemented,
|
||||
};
|
||||
|
||||
void atlas_set_default_options(Atlas_Options * options);
|
||||
THEKLA_ATLAS_API void atlas_set_default_options(Atlas_Options * options);
|
||||
|
||||
Atlas_Output_Mesh * atlas_generate(const Atlas_Input_Mesh * input, const Atlas_Options * options, Atlas_Error * error);
|
||||
THEKLA_ATLAS_API Atlas_Output_Mesh * atlas_generate(const Atlas_Input_Mesh * input, const Atlas_Options * options, Atlas_Error * error);
|
||||
|
||||
void atlas_free(Atlas_Output_Mesh * output);
|
||||
THEKLA_ATLAS_API void atlas_free(Atlas_Output_Mesh * output);
|
||||
|
||||
|
||||
/*
|
||||
|
|
|
@ -54,5 +54,4 @@ int main(int argc, char * argv[]) {
|
|||
atlas_free(output_mesh);
|
||||
|
||||
return 0;
|
||||
|
||||
}
|
||||
|
|
|
@ -58,36 +58,63 @@ Obj_Mesh * obj_mesh_load(const char * filename, const Obj_Load_Options * options
|
|||
return NULL;
|
||||
}
|
||||
|
||||
printf("%lu shapes\n", shapes.size());
|
||||
printf("%lu materials\n", materials.size());
|
||||
printf("%zu shapes\n", shapes.size());
|
||||
printf("%zu materials\n", materials.size());
|
||||
|
||||
assert(shapes.size() > 0);
|
||||
|
||||
Obj_Mesh* mesh = new Obj_Mesh();
|
||||
|
||||
mesh->vertex_count = shapes[0].mesh.positions.size() / 3;
|
||||
mesh->vertex_array = new Obj_Vertex[mesh->vertex_count];
|
||||
for (int nvert = 0; nvert < mesh->vertex_count; nvert++) {
|
||||
mesh->vertex_array[nvert].position[0] = shapes[0].mesh.positions[nvert * 3];
|
||||
mesh->vertex_array[nvert].position[1] = shapes[0].mesh.positions[nvert * 3 + 1];
|
||||
mesh->vertex_array[nvert].position[2] = shapes[0].mesh.positions[nvert * 3 + 2];
|
||||
mesh->vertex_array[nvert].normal[0] = shapes[0].mesh.normals[nvert * 3];
|
||||
mesh->vertex_array[nvert].normal[1] = shapes[0].mesh.normals[nvert * 3 + 1];
|
||||
mesh->vertex_array[nvert].normal[2] = shapes[0].mesh.normals[nvert * 3 + 2];
|
||||
mesh->vertex_array[nvert].uv[0] = 0;
|
||||
mesh->vertex_array[nvert].uv[1] = 0;
|
||||
mesh->vertex_array[nvert].first_colocal = nvert;
|
||||
// Count vertices and faces in all shapes.
|
||||
mesh->vertex_count = 0;
|
||||
mesh->face_count = 0;
|
||||
for (int s = 0; s < shapes.size(); s++) {
|
||||
mesh->vertex_count += (int)shapes[s].mesh.positions.size() / 3;
|
||||
mesh->face_count += (int)shapes[s].mesh.indices.size() / 3;
|
||||
}
|
||||
|
||||
mesh->face_count = shapes[0].mesh.indices.size() / 3;
|
||||
mesh->face_array = new Obj_Face[mesh->face_count];
|
||||
for (int nface = 0; nface < mesh->face_count; nface++) {
|
||||
mesh->face_array[nface].material_index = 0;
|
||||
mesh->face_array[nface].vertex_index[0] = shapes[0].mesh.indices[nface * 3];
|
||||
mesh->face_array[nface].vertex_index[1] = shapes[0].mesh.indices[nface * 3 + 1];
|
||||
mesh->face_array[nface].vertex_index[2] = shapes[0].mesh.indices[nface * 3 + 2];
|
||||
mesh->vertex_array = new Obj_Vertex[mesh->vertex_count];
|
||||
for (int s = 0, nv = 0; s < shapes.size(); s++) {
|
||||
const int shape_vertex_count = (int)shapes[s].mesh.positions.size() / 3;
|
||||
|
||||
for (int v = 0; v < shape_vertex_count; v++) {
|
||||
mesh->vertex_array[nv+v].position[0] = shapes[s].mesh.positions[v * 3 + 0];
|
||||
mesh->vertex_array[nv+v].position[1] = shapes[s].mesh.positions[v * 3 + 1];
|
||||
mesh->vertex_array[nv+v].position[2] = shapes[s].mesh.positions[v * 3 + 2];
|
||||
mesh->vertex_array[nv+v].normal[0] = shapes[s].mesh.normals[v * 3 + 0];
|
||||
mesh->vertex_array[nv+v].normal[1] = shapes[s].mesh.normals[v * 3 + 1];
|
||||
mesh->vertex_array[nv+v].normal[2] = shapes[s].mesh.normals[v * 3 + 2];
|
||||
mesh->vertex_array[nv+v].uv[0] = shapes[s].mesh.texcoords[v * 3 + 0]; // The input UVs are provided as a hint to the chart generator.
|
||||
mesh->vertex_array[nv+v].uv[1] = shapes[s].mesh.texcoords[v * 3 + 1];
|
||||
mesh->vertex_array[nv+v].first_colocal = nv+v;
|
||||
|
||||
// Link colocals. You probably want to do this more efficiently! Sort by one axis or use a hash or grid.
|
||||
for (int vv = 0; vv < v; vv++) {
|
||||
if (mesh->vertex_array[nv+v].position[0] == mesh->vertex_array[nv+vv].position[0] &&
|
||||
mesh->vertex_array[nv+v].position[1] == mesh->vertex_array[nv+vv].position[1] &&
|
||||
mesh->vertex_array[nv+v].position[2] == mesh->vertex_array[nv+vv].position[2])
|
||||
{
|
||||
mesh->vertex_array[nv+v].first_colocal = nv+vv;
|
||||
}
|
||||
}
|
||||
}
|
||||
nv += shape_vertex_count;
|
||||
}
|
||||
|
||||
mesh->face_array = new Obj_Face[mesh->face_count];
|
||||
for (int s = 0, nf = 0; s < shapes.size(); s++) {
|
||||
const int shape_face_count = (int)shapes[s].mesh.indices.size() / 3;
|
||||
for (int f = 0; f < shape_face_count; f++) {
|
||||
mesh->face_array[nf+f].material_index = 0;
|
||||
mesh->face_array[nf+f].vertex_index[0] = shapes[s].mesh.indices[f * 3 + 0];
|
||||
mesh->face_array[nf+f].vertex_index[1] = shapes[s].mesh.indices[f * 3 + 1];
|
||||
mesh->face_array[nf+f].vertex_index[2] = shapes[s].mesh.indices[f * 3 + 2];
|
||||
}
|
||||
nf += shape_face_count;
|
||||
}
|
||||
|
||||
// @@ Add support for obj materials! Charter also uses material boundaries as a hint to cut charts.
|
||||
|
||||
printf("Reading %d verts\n", mesh->vertex_count);
|
||||
printf("Reading %d triangles\n", mesh->face_count);
|
||||
|
||||
|
|
|
@ -0,0 +1,21 @@
|
|||
set(THEKLA_ATLAS_INCLUDE_DIRS "@CMAKE_INSTALL_PREFIX@/include")
|
||||
set(THEKLA_ATLAS_LIBRARIES @CMAKE_INSTALL_PREFIX@/lib/static/libthekla_atlas.lib
|
||||
@CMAKE_INSTALL_PREFIX@/lib/static/nvcore.lib
|
||||
@CMAKE_INSTALL_PREFIX@/lib/static/nvimage.lib
|
||||
@CMAKE_INSTALL_PREFIX@/lib/static/nvmath.lib
|
||||
@CMAKE_INSTALL_PREFIX@/lib/static/nvmesh.lib
|
||||
)
|
||||
set(THEKLA_ATLAS_LIBRARIES_DEBUG @CMAKE_INSTALL_PREFIX@/lib/static/libTHEKLA_ATLAS@CMAKE_DEBUG_POSTFIX@.lib
|
||||
@CMAKE_INSTALL_PREFIX@/lib/static/nvcore@CMAKE_DEBUG_POSTFIX@.lib
|
||||
@CMAKE_INSTALL_PREFIX@/lib/static/nvimage@CMAKE_DEBUG_POSTFIX@.lib
|
||||
@CMAKE_INSTALL_PREFIX@/lib/static/nvmath@CMAKE_DEBUG_POSTFIX@.lib
|
||||
@CMAKE_INSTALL_PREFIX@/lib/static/nvmesh@CMAKE_DEBUG_POSTFIX@.lib
|
||||
)
|
||||
set(THEKLA_ATLAS_LIBRARIES_RELEASE @CMAKE_INSTALL_PREFIX@/lib/static/libthekla_atlas.lib
|
||||
@CMAKE_INSTALL_PREFIX@/lib/static/nvcore.lib
|
||||
@CMAKE_INSTALL_PREFIX@/lib/static/nvimage.lib
|
||||
@CMAKE_INSTALL_PREFIX@/lib/static/nvmath.lib
|
||||
@CMAKE_INSTALL_PREFIX@/lib/static/nvmesh.lib
|
||||
)
|
||||
set(THEKLA_ATLAS_COMPILE_DEFINITIONS @COMPILE_DEFINITIONS@)
|
||||
set(THEKLA_ATLAS_FOUND 1)
|
Loading…
Reference in New Issue