From 645eda8fd4f7720ff58d097ca718001583a57662 Mon Sep 17 00:00:00 2001 From: castano Date: Tue, 16 Oct 2007 20:53:12 +0000 Subject: [PATCH] Merge internal repository. Delete TODO list, use issue list instead. --- NVIDIA_Texture_Tools_TODO.txt | 20 --- cmake/FindCUDA.cmake | 1 - cmake/FindCg.cmake | 258 +++++++++++++++++----------------- cmake/FindDirectX.cmake | 32 +++++ cmake/FindMaya.cmake | 67 +++++++++ cmake/FindOpenEXR.cmake | 55 ++++++++ src/CMakeLists.txt | 26 ++++ src/nvconfig.h.in | 3 + src/nvcore/CMakeLists.txt | 1 + src/nvcore/Containers.h | 2 +- src/nvcore/Debug.cpp | 8 +- src/nvcore/StdStream.h | 11 ++ src/nvcore/Stream.h | 9 +- src/nvcore/Tokenizer.h | 4 + src/nvimage/FloatImage.h | 11 ++ src/nvimage/ImageIO.cpp | 203 ++++++++++++++++++++++++-- src/nvimage/ImageIO.h | 18 ++- src/nvmath/Box.h | 11 ++ src/nvmath/CMakeLists.txt | 4 +- src/nvmath/Quaternion.h | 128 +++++++++++++++++ src/nvmath/TriBox.cpp | 226 +++++++++++++++++++++++++++++ src/nvmath/Triangle.cpp | 171 ++++++++++++++++++++++ src/nvmath/Triangle.h | 149 ++++++++++++++++++++ src/nvmath/Vector.h | 67 ++++++++- 24 files changed, 1302 insertions(+), 183 deletions(-) delete mode 100644 NVIDIA_Texture_Tools_TODO.txt create mode 100644 cmake/FindDirectX.cmake create mode 100644 cmake/FindMaya.cmake create mode 100644 cmake/FindOpenEXR.cmake create mode 100644 src/nvmath/Quaternion.h create mode 100644 src/nvmath/TriBox.cpp create mode 100644 src/nvmath/Triangle.cpp create mode 100644 src/nvmath/Triangle.h diff --git a/NVIDIA_Texture_Tools_TODO.txt b/NVIDIA_Texture_Tools_TODO.txt deleted file mode 100644 index 0dcb5ca..0000000 --- a/NVIDIA_Texture_Tools_TODO.txt +++ /dev/null @@ -1,20 +0,0 @@ - -Short term: - - Improve quality of fast compressors. - - More accelerated compressors. - - Accelerate mipmap generation. - - Generic RGB pixel format conversion. - - Do not assume that alpha is used for transparency. - -Longer term: - - support for DXT1a format. - - support for correct cubemap filtering. - - support for correct cubemap borders and atlas borders. (Crytek request) - - support for 3d textures & 3d compression. - - Add support for occlusion map, horizon map & bent normal map generation. - - Add support for accurate normal map mipmap computation. Using lighting integrals. - - Add support for YCoCg and JPEG-LS color transforms. Add high quality DXT5-RGB compression. - - Add full support for mirror wrap mode. - - Generation of cone maps for relief mapping. - - Add min/max box mipmap filters. - diff --git a/cmake/FindCUDA.cmake b/cmake/FindCUDA.cmake index 603310e..c86437d 100644 --- a/cmake/FindCUDA.cmake +++ b/cmake/FindCUDA.cmake @@ -53,7 +53,6 @@ FIND_LIBRARY (CUDA_RUNTIME_LIBRARY ${CUDA_COMPILER_DIR} DOC "The CUDA runtime library") - IF (CUDA_INCLUDE_PATH AND CUDA_LIBRARY AND CUDA_RUNTIME_LIBRARY) SET (CUDA_FOUND 1 CACHE STRING "Set to 1 if CUDA is found, 0 otherwise") ELSE (CUDA_INCLUDE_PATH AND CUDA_LIBRARY AND CUDA_RUNTIME_LIBRARY) diff --git a/cmake/FindCg.cmake b/cmake/FindCg.cmake index 8378d4a..302026f 100644 --- a/cmake/FindCg.cmake +++ b/cmake/FindCg.cmake @@ -1,129 +1,129 @@ -# -# Try to find nVidia's Cg compiler, runtime libraries, and include path. -# Once done this will define -# -# CG_FOUND =system has NVidia Cg and it can be used. -# CG_INCLUDE_PATH = directory where cg.h resides -# CG_LIBRARY = full path to libCg.so (Cg.DLL on win32) -# CG_GL_LIBRARY = full path to libCgGL.so (CgGL.dll on win32) -# CG_COMPILER = full path to cgc (cgc.exe on win32) -# - -# On OSX default to using the framework version of Cg. - -IF (APPLE) - INCLUDE(${CMAKE_ROOT}/Modules/CMakeFindFrameworks.cmake) - SET(CG_FRAMEWORK_INCLUDES) - CMAKE_FIND_FRAMEWORKS(Cg) - IF (Cg_FRAMEWORKS) - FOREACH(dir ${Cg_FRAMEWORKS}) - SET(CG_FRAMEWORK_INCLUDES ${CG_FRAMEWORK_INCLUDES} - ${dir}/Headers ${dir}/PrivateHeaders) - ENDFOREACH(dir) - - # Find the include dir - FIND_PATH(CG_INCLUDE_PATH cg.h - ${CG_FRAMEWORK_INCLUDES} - ) - - # Since we are using Cg framework, we must link to it. - # Note, we use weak linking, so that it works even when Cg is not available. - SET(CG_LIBRARY "-weak_framework Cg" CACHE STRING "Cg library") - SET(CG_GL_LIBRARY "-weak_framework Cg" CACHE STRING "Cg GL library") - ENDIF (Cg_FRAMEWORKS) - FIND_PROGRAM(CG_COMPILER cgc - /usr/bin - /usr/local/bin - DOC "The Cg compiler" - ) -ELSE (APPLE) - IF (WIN32) - FIND_PROGRAM( CG_COMPILER cgc - $ENV{CG_BIN_PATH} - $ENV{PROGRAMFILES}/NVIDIA\ Corporation/Cg/bin - $ENV{PROGRAMFILES}/Cg - ${PROJECT_SOURCE_DIR}/../Cg - DOC "The Cg Compiler" - ) - IF (CG_COMPILER) - GET_FILENAME_COMPONENT(CG_COMPILER_DIR ${CG_COMPILER} PATH) - GET_FILENAME_COMPONENT(CG_COMPILER_SUPER_DIR ${CG_COMPILER_DIR} PATH) - ELSE (CG_COMPILER) - SET (CG_COMPILER_DIR .) - SET (CG_COMPILER_SUPER_DIR ..) - ENDIF (CG_COMPILER) - FIND_PATH( CG_INCLUDE_PATH Cg/cg.h - $ENV{CG_INC_PATH} - $ENV{PROGRAMFILES}/NVIDIA\ Corporation/Cg/include - $ENV{PROGRAMFILES}/Cg - ${PROJECT_SOURCE_DIR}/../Cg - ${CG_COMPILER_SUPER_DIR}/include - ${CG_COMPILER_DIR} - DOC "The directory where Cg/cg.h resides" - ) - FIND_LIBRARY( CG_LIBRARY - NAMES Cg - PATHS - $ENV{CG_LIB_PATH} - $ENV{PROGRAMFILES}/NVIDIA\ Corporation/Cg/lib - $ENV{PROGRAMFILES}/Cg - ${PROJECT_SOURCE_DIR}/../Cg - ${CG_COMPILER_SUPER_DIR}/lib - ${CG_COMPILER_DIR} - DOC "The Cg runtime library" - ) - FIND_LIBRARY( CG_GL_LIBRARY - NAMES CgGL - PATHS - $ENV{PROGRAMFILES}/NVIDIA\ Corporation/Cg/lib - $ENV{PROGRAMFILES}/Cg - ${PROJECT_SOURCE_DIR}/../Cg - ${CG_COMPILER_SUPER_DIR}/lib - ${CG_COMPILER_DIR} - DOC "The Cg runtime library" - ) - ELSE (WIN32) - FIND_PROGRAM( CG_COMPILER cgc - /usr/bin - /usr/local/bin - DOC "The Cg Compiler" - ) - GET_FILENAME_COMPONENT(CG_COMPILER_DIR "${CG_COMPILER}" PATH) - GET_FILENAME_COMPONENT(CG_COMPILER_SUPER_DIR "${CG_COMPILER_DIR}" PATH) - FIND_PATH( CG_INCLUDE_PATH Cg/cg.h - /usr/include - /usr/local/include - ${CG_COMPILER_SUPER_DIR}/include - DOC "The directory where Cg/cg.h resides" - ) - FIND_LIBRARY( CG_LIBRARY Cg - PATHS - /usr/lib64 - /usr/lib - /usr/local/lib64 - /usr/local/lib - ${CG_COMPILER_SUPER_DIR}/lib64 - ${CG_COMPILER_SUPER_DIR}/lib - DOC "The Cg runtime library" - ) - SET(CG_LIBRARY ${CG_LIBRARY} -lpthread) - FIND_LIBRARY( CG_GL_LIBRARY CgGL - PATHS - /usr/lib64 - /usr/lib - /usr/local/lib64 - /usr/local/lib - ${CG_COMPILER_SUPER_DIR}/lib64 - ${CG_COMPILER_SUPER_DIR}/lib - DOC "The Cg runtime library" - ) - ENDIF (WIN32) -ENDIF (APPLE) - -IF (CG_INCLUDE_PATH) - SET( CG_FOUND 1 CACHE STRING "Set to 1 if CG is found, 0 otherwise") -ELSE (CG_INCLUDE_PATH) - SET( CG_FOUND 0 CACHE STRING "Set to 1 if CG is found, 0 otherwise") -ENDIF (CG_INCLUDE_PATH) - -MARK_AS_ADVANCED( CG_FOUND ) +# +# Try to find NVIDIA's Cg compiler, runtime libraries, and include path. +# Once done this will define +# +# CG_FOUND =system has NVIDIA Cg and it can be used. +# CG_INCLUDE_PATH = directory where cg.h resides +# CG_LIBRARY = full path to libCg.so (Cg.DLL on win32) +# CG_GL_LIBRARY = full path to libCgGL.so (CgGL.dll on win32) +# CG_COMPILER = full path to cgc (cgc.exe on win32) +# + +# On OSX default to using the framework version of Cg. + +IF (APPLE) + INCLUDE(${CMAKE_ROOT}/Modules/CMakeFindFrameworks.cmake) + SET(CG_FRAMEWORK_INCLUDES) + CMAKE_FIND_FRAMEWORKS(Cg) + IF (Cg_FRAMEWORKS) + FOREACH(dir ${Cg_FRAMEWORKS}) + SET(CG_FRAMEWORK_INCLUDES ${CG_FRAMEWORK_INCLUDES} + ${dir}/Headers ${dir}/PrivateHeaders) + ENDFOREACH(dir) + + # Find the include dir + FIND_PATH(CG_INCLUDE_PATH cg.h + ${CG_FRAMEWORK_INCLUDES} + ) + + # Since we are using Cg framework, we must link to it. + # Note, we use weak linking, so that it works even when Cg is not available. + SET(CG_LIBRARY "-weak_framework Cg" CACHE STRING "Cg library") + SET(CG_GL_LIBRARY "-weak_framework Cg" CACHE STRING "Cg GL library") + ENDIF (Cg_FRAMEWORKS) + FIND_PROGRAM(CG_COMPILER cgc + /usr/bin + /usr/local/bin + DOC "The Cg compiler" + ) +ELSE (APPLE) + IF (WIN32) + FIND_PROGRAM( CG_COMPILER cgc + $ENV{CG_BIN_PATH} + $ENV{PROGRAMFILES}/NVIDIA\ Corporation/Cg/bin + $ENV{PROGRAMFILES}/Cg + ${PROJECT_SOURCE_DIR}/../Cg + DOC "The Cg Compiler" + ) + IF (CG_COMPILER) + GET_FILENAME_COMPONENT(CG_COMPILER_DIR ${CG_COMPILER} PATH) + GET_FILENAME_COMPONENT(CG_COMPILER_SUPER_DIR ${CG_COMPILER_DIR} PATH) + ELSE (CG_COMPILER) + SET (CG_COMPILER_DIR .) + SET (CG_COMPILER_SUPER_DIR ..) + ENDIF (CG_COMPILER) + FIND_PATH( CG_INCLUDE_PATH Cg/cg.h + $ENV{CG_INC_PATH} + $ENV{PROGRAMFILES}/NVIDIA\ Corporation/Cg/include + $ENV{PROGRAMFILES}/Cg + ${PROJECT_SOURCE_DIR}/../Cg + ${CG_COMPILER_SUPER_DIR}/include + ${CG_COMPILER_DIR} + DOC "The directory where Cg/cg.h resides" + ) + FIND_LIBRARY( CG_LIBRARY + NAMES Cg + PATHS + $ENV{CG_LIB_PATH} + $ENV{PROGRAMFILES}/NVIDIA\ Corporation/Cg/lib + $ENV{PROGRAMFILES}/Cg + ${PROJECT_SOURCE_DIR}/../Cg + ${CG_COMPILER_SUPER_DIR}/lib + ${CG_COMPILER_DIR} + DOC "The Cg runtime library" + ) + FIND_LIBRARY( CG_GL_LIBRARY + NAMES CgGL + PATHS + $ENV{PROGRAMFILES}/NVIDIA\ Corporation/Cg/lib + $ENV{PROGRAMFILES}/Cg + ${PROJECT_SOURCE_DIR}/../Cg + ${CG_COMPILER_SUPER_DIR}/lib + ${CG_COMPILER_DIR} + DOC "The Cg runtime library" + ) + ELSE (WIN32) + FIND_PROGRAM( CG_COMPILER cgc + /usr/bin + /usr/local/bin + DOC "The Cg Compiler" + ) + GET_FILENAME_COMPONENT(CG_COMPILER_DIR "${CG_COMPILER}" PATH) + GET_FILENAME_COMPONENT(CG_COMPILER_SUPER_DIR "${CG_COMPILER_DIR}" PATH) + FIND_PATH( CG_INCLUDE_PATH Cg/cg.h + /usr/include + /usr/local/include + ${CG_COMPILER_SUPER_DIR}/include + DOC "The directory where Cg/cg.h resides" + ) + FIND_LIBRARY( CG_LIBRARY Cg + PATHS + /usr/lib64 + /usr/lib + /usr/local/lib64 + /usr/local/lib + ${CG_COMPILER_SUPER_DIR}/lib64 + ${CG_COMPILER_SUPER_DIR}/lib + DOC "The Cg runtime library" + ) + SET(CG_LIBRARY ${CG_LIBRARY} -lpthread) + FIND_LIBRARY( CG_GL_LIBRARY CgGL + PATHS + /usr/lib64 + /usr/lib + /usr/local/lib64 + /usr/local/lib + ${CG_COMPILER_SUPER_DIR}/lib64 + ${CG_COMPILER_SUPER_DIR}/lib + DOC "The Cg runtime library" + ) + ENDIF (WIN32) +ENDIF (APPLE) + +IF (CG_INCLUDE_PATH) + SET( CG_FOUND 1 CACHE STRING "Set to 1 if CG is found, 0 otherwise") +ELSE (CG_INCLUDE_PATH) + SET( CG_FOUND 0 CACHE STRING "Set to 1 if CG is found, 0 otherwise") +ENDIF (CG_INCLUDE_PATH) + +MARK_AS_ADVANCED( CG_FOUND ) diff --git a/cmake/FindDirectX.cmake b/cmake/FindDirectX.cmake new file mode 100644 index 0000000..f8663c3 --- /dev/null +++ b/cmake/FindDirectX.cmake @@ -0,0 +1,32 @@ + +IF (WIN32) + + FIND_PATH(DX10_INCLUDE_PATH D3D10.h + PATHS + "$ENV{DXSDK_DIR}/Include" + "$ENV{PROGRAMFILES}/Microsoft DirectX SDK/Include" + DOC "The directory where D3D10.h resides") + + FIND_LIBRARY(D3D10_LIBRARY d3d10.lib + PATHS + "$ENV{DXSDK_DIR}/Lib/x86" + "$ENV{PROGRAMFILES}/Microsoft DirectX SDK/Lib/x86" + DOC "The directory where d3d10.lib resides") + + FIND_LIBRARY(D3DX10_LIBRARY d3dx10.lib + PATHS + "$ENV{DXSDK_DIR}/Lib/x86" + "$ENV{PROGRAMFILES}/Microsoft DirectX SDK/Lib/x86" + DOC "The directory where d3dx10.lib resides") + + SET(DX10_LIBRARIES D3D10_LIBRARY D3DX10_LIBRARY) + +ENDIF (WIN32) + +IF (DX10_INCLUDE_PATH) + SET( DX10_FOUND 1 CACHE STRING "Set to 1 if CG is found, 0 otherwise") +ELSE (DX10_INCLUDE_PATH) + SET( DX10_FOUND 0 CACHE STRING "Set to 1 if CG is found, 0 otherwise") +ENDIF (DX10_INCLUDE_PATH) + +MARK_AS_ADVANCED( DX10_FOUND ) diff --git a/cmake/FindMaya.cmake b/cmake/FindMaya.cmake new file mode 100644 index 0000000..3599329 --- /dev/null +++ b/cmake/FindMaya.cmake @@ -0,0 +1,67 @@ + + + +IF (WIN32) + + # Maya plugins can only be compiled with msvc + IF (MSVC) + + FIND_PATH(MAYA_INCLUDE_PATH maya/MTypes.h + PATHS + "$ENV{PROGRAMFILES}/Autodesk/Maya8.5/include" + "$ENV{MAYA_LOCATION}/include" + DOC "The directory where MTypes.h resides") + + # Find maya version! + + FIND_LIBRARY(MAYA_FOUNDATION_LIBRARY Foundation + PATHS + "$ENV{PROGRAMFILES}/Autodesk/Maya8.5/lib" + "$ENV{MAYA_LOCATION}/lib" + DOC "The directory where Foundation.lib resides") + + FIND_LIBRARY(MAYA_OPENMAYA_LIBRARY OpenMaya + PATHS + "$ENV{PROGRAMFILES}/Autodesk/Maya8.5/lib" + "$ENV{MAYA_LOCATION}/lib" + DOC "The directory where OpenMaya.lib resides") + + FIND_LIBRARY(MAYA_OPENMAYAANIM_LIBRARY OpenMayaAnim + PATHS + "$ENV{PROGRAMFILES}/Autodesk/Maya8.5/lib" + "$ENV{MAYA_LOCATION}/lib" + DOC "The directory where OpenMayaAnim.lib resides") + + SET(MAYA_LIBRARIES + ${MAYA_FOUNDATION_LIBRARY} + ${MAYA_OPENMAYA_LIBRARY} + ${MAYA_OPENMAYAANIM_LIBRARY}) + + SET(MAYA_EXTENSION ".mll") + + ENDIF (MSVC) +ELSE (WIN32) + + # On linux, check gcc version. + + # OSX and Linux + + FIND_PATH(MAYA_INCLUDE_PATH maya/MTypes.h + PATHS + /usr/autodesk/maya/include + $ENV{MAYA_LOCATION}/include + DOC "The directory where MTypes.h resides") + +# TODO + +ENDIF (WIN32) + + + +IF (MAYA_INCLUDE_PATH) + SET( MAYA_FOUND 1 CACHE STRING "Set to 1 if Maya is found, 0 otherwise") +ELSE (MAYA_INCLUDE_PATH) + SET( MAYA_FOUND 0 CACHE STRING "Set to 1 if Maya is found, 0 otherwise") +ENDIF (MAYA_INCLUDE_PATH) + +MARK_AS_ADVANCED( MAYA_FOUND ) diff --git a/cmake/FindOpenEXR.cmake b/cmake/FindOpenEXR.cmake new file mode 100644 index 0000000..2ec1896 --- /dev/null +++ b/cmake/FindOpenEXR.cmake @@ -0,0 +1,55 @@ +# +# Try to find OpenEXR's libraries, and include path. +# Once done this will define: +# +# OPENEXR_FOUND = OpenEXR found. +# OPENEXR_INCLUDE_PATH = OpenEXR include directory. +# OPENEXR_LIBRARIES = libraries that are needed to use OpenEXR. +# + + +IF (WIN32) +ELSE (WIN32) + + FIND_PATH(OPENEXR_INCLUDE_PATH ImfRgbaFile.h + /usr/include + /usr/local/include) + + FIND_LIBRARY(OPENEXR_HALF_LIBRARY + NAMES Half + PATHS + /usr/lib + /usr/local/lib) + + FIND_LIBRARY(OPENEXR_IEX_LIBRARY + NAMES Iex + PATHS + /usr/lib + /usr/local/lib) + + FIND_LIBRARY(OPENEXR_IMATH_LIBRARY + NAMES Imath + PATHS + /usr/lib + /usr/local/lib) + + FIND_LIBRARY(OPENEXR_ILMIMF_LIBRARY + NAMES IlmImf + PATHS + /usr/lib + /usr/local/lib) + +ENDIF (WIN32) + +IF (OPENEXR_INCLUDE_DIR AND OPENEXR_IMATH_LIBRARY AND OPENEXR_ILMIMF_LIBRARY AND OPENEXR_IEX_LIBRARY AND OPENEXR_HALF_LIBRARY) + SET(OPENEXR_FOUND TRUE) + SET(OPENEXR_LIBRARIES ${OPENEXR_IMATH_LIBRARY} ${OPENEXR_ILMIMF_LIBRARY} ${OPENEXR_IEX_LIBRARY} ${OPENEXR_HALF_LIBRARY} CACHE STRING "The libraries needed to use OpenEXR") +ENDIF (OPENEXR_INCLUDE_DIR AND OPENEXR_IMATH_LIBRARY AND OPENEXR_ILMIMF_LIBRARY AND OPENEXR_IEX_LIBRARY AND OPENEXR_HALF_LIBRARY) + +MARK_AS_ADVANCED( + OPENEXR_INCLUDE_DIR + OPENEXR_LIBRARIES + OPENEXR_ILMIMF_LIBRARY + OPENEXR_IMATH_LIBRARY + OPENEXR_IEX_LIBRARY + OPENEXR_HALF_LIBRARY) diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 5663e7f..f8757c7 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -23,6 +23,14 @@ ELSE(GLUT_FOUND) MESSAGE(STATUS "Looking for GLUT - not found") ENDIF(GLUT_FOUND) +# DirectX +INCLUDE(${NV_CMAKE_DIR}/FindDirectX.cmake) +IF(DX10_FOUND) + MESSAGE(STATUS "Looking for DirectX - found") +ELSE(DX10_FOUND) + MESSAGE(STATUS "Looking for DirectX - not found") +ENDIF(DX10_FOUND) + # GLEW INCLUDE(${NV_CMAKE_DIR}/FindGLEW.cmake) IF(GLEW_FOUND) @@ -47,6 +55,15 @@ ELSE(CUDA_FOUND) MESSAGE(STATUS "Looking for CUDA - not found") ENDIF(CUDA_FOUND) +# Maya +INCLUDE(${NV_CMAKE_DIR}/FindMaya.cmake) +IF(MAYA_FOUND) + SET(HAVE_MAYA MAYA_FOUND) + MESSAGE(STATUS "Looking for Maya - found") +ELSE(MAYA_FOUND) + MESSAGE(STATUS "Looking for Maya - not found") +ENDIF(MAYA_FOUND) + # JPEG INCLUDE(FindJPEG) IF(JPEG_FOUND) @@ -74,6 +91,15 @@ ELSE(TIFF_FOUND) MESSAGE(STATUS "Looking for TIFF - not found") ENDIF(TIFF_FOUND) +# OpenEXR +INCLUDE(FindOpenEXR) +IF(OPENEXR_FOUND) + SET(HAVE_OPENEXR OPENEXR_FOUND) + MESSAGE(STATUS "Looking for OpenEXR - found") +ELSE(OPENEXR_FOUND) + MESSAGE(STATUS "Looking for OpenEXR - not found") +ENDIF(OPENEXR_FOUND) + # Qt FIND_PACKAGE(Qt4) diff --git a/src/nvconfig.h.in b/src/nvconfig.h.in index 9b15db3..ac9bd57 100644 --- a/src/nvconfig.h.in +++ b/src/nvconfig.h.in @@ -10,5 +10,8 @@ #cmakedefine HAVE_PNG #cmakedefine HAVE_JPEG #cmakedefine HAVE_TIFF +#cmakedefine HAVE_OPENEXR + +#cmakedefine HAVE_MAYA #endif // NV_CONFIG diff --git a/src/nvcore/CMakeLists.txt b/src/nvcore/CMakeLists.txt index 6c7e849..a437ed2 100644 --- a/src/nvcore/CMakeLists.txt +++ b/src/nvcore/CMakeLists.txt @@ -3,6 +3,7 @@ ADD_SUBDIRECTORY(poshlib) SET(CORE_SRCS nvcore.h + Ptr.h BitArray.h Memory.h Memory.cpp diff --git a/src/nvcore/Containers.h b/src/nvcore/Containers.h index 086e577..329b110 100644 --- a/src/nvcore/Containers.h +++ b/src/nvcore/Containers.h @@ -283,7 +283,7 @@ namespace nv else { m_size = new_size; - m_buffer[new_size-1] = val; + new(m_buffer+new_size-1) T(val); } } void pushBack( const T & val ) diff --git a/src/nvcore/Debug.cpp b/src/nvcore/Debug.cpp index e1b4ef0..51ffd5f 100644 --- a/src/nvcore/Debug.cpp +++ b/src/nvcore/Debug.cpp @@ -195,7 +195,7 @@ namespace // Solaris: // ucp->uc_mcontext.gregs[REG_PC] // Linux hppa: - // uc->uc_mcontext.sc_iaoq[0] & ~0×3UL + // uc->uc_mcontext.sc_iaoq[0] & ~0x3UL // Linux sparc: // ((struct sigcontext*) secret)->sigc_regs.tpc // Linux sparc64: @@ -204,7 +204,7 @@ namespace // potentially correct for other archs: // Linux alpha: ucp->m_context.sc_pc // Linux arm: ucp->m_context.ctx.arm_pc - // Linux ia64: ucp->m_context.sc_ip & ~0×3UL + // Linux ia64: ucp->m_context.sc_ip & ~0x3UL // Linux mips: ucp->m_context.sc_pc // Linux s390: ucp->m_context.sregs->regs.psw.addr } @@ -257,7 +257,7 @@ namespace { bool result = false; - HINSTANCE kern_lib = LoadLibraryEx( "kernel32.dll", NULL, 0 ); + HINSTANCE kern_lib = LoadLibraryExA( "kernel32.dll", NULL, 0 ); if( kern_lib ) { FARPROC lIsDebuggerPresent = GetProcAddress( kern_lib, "IsDebuggerPresent" ); if( lIsDebuggerPresent && lIsDebuggerPresent() ) { @@ -302,7 +302,7 @@ namespace } flushMessageQueue(); - int action = MessageBox(NULL, error_string, "Assertion failed", MB_ABORTRETRYIGNORE|MB_ICONERROR); + int action = MessageBoxA(NULL, error_string, "Assertion failed", MB_ABORTRETRYIGNORE|MB_ICONERROR); switch( action ) { case IDRETRY: ret = NV_ABORT_DEBUG; diff --git a/src/nvcore/StdStream.h b/src/nvcore/StdStream.h index be56b75..a2384c1 100644 --- a/src/nvcore/StdStream.h +++ b/src/nvcore/StdStream.h @@ -73,6 +73,12 @@ public: { return m_fp == NULL || ferror( m_fp ) != 0; } + + virtual void clearError() + { + nvDebugCheck(m_fp != NULL); + clearerr(m_fp); + } virtual bool isAtEnd() const { @@ -210,6 +216,11 @@ public: return m_mem == NULL || m_ptr > m_mem + m_size || m_ptr < m_mem; } + virtual void clearError() + { + // Nothing to do. + } + virtual bool isAtEnd() const { return m_ptr == m_mem + m_size; diff --git a/src/nvcore/Stream.h b/src/nvcore/Stream.h index 429dc4d..7d28607 100644 --- a/src/nvcore/Stream.h +++ b/src/nvcore/Stream.h @@ -9,7 +9,7 @@ namespace nv { -/** Base stream class. */ +/// Base stream class. class Stream { public: @@ -41,7 +41,7 @@ public: ByteOrder byteOrder() const { return m_byteOrder; } - /// Serialize the given data. + /// Serialize the given data. @@ Should return bytes serialized? virtual void serialize( void * data, int len ) = 0; /// Move to the given position in the archive. @@ -55,7 +55,10 @@ public: /// Determine if there has been any error. virtual bool isError() const = 0; - + + /// Clear errors. + virtual void clearError() = 0; + /// Return true if the stream is at the end. virtual bool isAtEnd() const = 0; diff --git a/src/nvcore/Tokenizer.h b/src/nvcore/Tokenizer.h index a2ab6d7..48579c8 100644 --- a/src/nvcore/Tokenizer.h +++ b/src/nvcore/Tokenizer.h @@ -49,6 +49,10 @@ namespace nv int m_column; }; + // @@ Use enums instead of bools for clarity! + //enum SkipEmptyLines { skipEmptyLines, noSkipEmptyLines }; + //enum SkipEndOfLine { skipEndOfLine, noSkipEndOfLine }; + /// A simple stream tokenizer. class NVCORE_CLASS Tokenizer { diff --git a/src/nvimage/FloatImage.h b/src/nvimage/FloatImage.h index c1a207e..a2f67c3 100644 --- a/src/nvimage/FloatImage.h +++ b/src/nvimage/FloatImage.h @@ -87,6 +87,7 @@ public: float * scanline(uint y, uint c); void setPixel(float f, uint x, uint y, uint c); + void addPixel(float f, uint x, uint y, uint c); float pixel(uint x, uint y, uint c) const; void setPixel(float f, uint idx); @@ -164,6 +165,16 @@ inline void FloatImage::setPixel(float f, uint x, uint y, uint c) m_mem[(c * m_height + y) * m_width + x] = f; } +/// Add to pixel component. +inline void FloatImage::addPixel(float f, uint x, uint y, uint c) +{ + nvDebugCheck(m_mem != NULL); + nvDebugCheck(x < m_width); + nvDebugCheck(y < m_height); + nvDebugCheck(c < m_componentNum); + m_mem[(c * m_height + y) * m_width + x] += f; +} + /// Get pixel component. inline float FloatImage::pixel(uint x, uint y, uint c) const { diff --git a/src/nvimage/ImageIO.cpp b/src/nvimage/ImageIO.cpp index a117282..91e98d2 100644 --- a/src/nvimage/ImageIO.cpp +++ b/src/nvimage/ImageIO.cpp @@ -29,6 +29,13 @@ extern "C" { # include #endif +#if defined(HAVE_EXR) +# include +# include // ??? +# include +using namespace Imf; +#endif + using namespace nv; namespace { @@ -80,6 +87,34 @@ Image * nv::ImageIO::load(const char * name, Stream & s) return loadPSD(s); } // @@ use image plugins? + return NULL; +} + +NVIMAGE_API FloatImage * nv::ImageIO::loadFloat(const char * name) +{ + StdInputStream stream(name); + + if (stream.isError()) { + return false; + } + + return loadFloat(name, stream); +} + +NVIMAGE_API FloatImage * nv::ImageIO::loadFloat(const char * name, Stream & s) +{ + const char * extension = Path::extension(name); + +#if defined(HAVE_TIFF) + if (strCaseCmp(extension, ".tif") == 0 || strCaseCmp(extension, ".tiff") == 0) { + return loadFloatTIFF(name, s); + } +#endif +#if defined(HAVE_EXR) + if (strCaseCmp(extension, ".exr") == 0) { + return loadFloatEXR(name, s); + } +#endif return NULL; } @@ -744,15 +779,73 @@ Image * nv::ImageIO::loadJPG(Stream & s) #if defined(HAVE_TIFF) -FloatImage * nv::ImageIO::loadFloatTIFF(Stream & s) +static tsize_t tiffReadWriteProc(thandle_t h, tdata_t ptr, tsize_t size) { - nvCheck(!s.isError()); - return NULL; + Stream * s = (Stream *)h; + nvDebugCheck(s != NULL); + + s->serialize(ptr, size); + + return size; } -FloatImage * nv::ImageIO::loadFloatTIFF(const char * fileName) +static toff_t tiffSeekProc(thandle_t h, toff_t offset, int whence) { + Stream * s = (Stream *)h; + nvDebugCheck(s != NULL); + + if (!s->isSeekable()) + { + return (toff_t)-1; + } + + if (whence == SEEK_SET) + { + s->seek(offset); + } + else if (whence == SEEK_CUR) + { + s->seek(s->tell() + offset); + } + else if (whence == SEEK_END) + { + s->seek(s->size() + offset); + } + + return s->tell(); +} + +static int tiffCloseProc(thandle_t) +{ + return 0; +} + +static toff_t tiffSizeProc(thandle_t h) +{ + Stream * s = (Stream *)h; + nvDebugCheck(s != NULL); + return s->size(); +} + +static int tiffMapFileProc(thandle_t, tdata_t*, toff_t*) +{ + // @@ TODO, Implement these functions. + return -1; +} + +static void tiffUnmapFileProc(thandle_t, tdata_t, toff_t) +{ + // @@ TODO, Implement these functions. +} + + +FloatImage * nv::ImageIO::loadFloatTIFF(const char * fileName, Stream & s) +{ + nvCheck(!s.isError()); + TIFF * tif = TIFFOpen(fileName, "r"); + //TIFF * tif = TIFFClientOpen(fileName, "r", &s, tiffReadWriteProc, tiffReadWriteProc, tiffSeekProc, tiffCloseProc, tiffSizeProc, tiffMapFileProc, tiffUnmapFileProc); + if (!tif) { nvDebug("Can't open '%s' for reading\n", fileName); @@ -821,12 +914,11 @@ FloatImage * nv::ImageIO::loadFloatTIFF(const char * fileName) return fimage.release(); } - -bool nv::ImageIO::saveFloatTIFF(const char * fileName, FloatImage *fimage) +bool nv::ImageIO::saveFloatTIFF(const char * fileName, FloatImage *fimage, uint base_component, uint num_components) { int iW=fimage->width(); int iH=fimage->height(); - int iC=fimage->componentNum(); + int iC=num_components; TIFF * image = TIFFOpen(fileName, "w"); @@ -848,7 +940,6 @@ bool nv::ImageIO::saveFloatTIFF(const char * fileName, FloatImage *fimage) TIFFSetField(image, TIFFTAG_ROWSPERSTRIP, rowsperstrip); TIFFSetField(image, TIFFTAG_COMPRESSION, COMPRESSION_PACKBITS); TIFFSetField(image, TIFFTAG_ORIENTATION, ORIENTATION_TOPLEFT); - TIFFSetField(image, TIFFTAG_PLANARCONFIG, PLANARCONFIG_CONTIG); float *scanline = new float[iW * iC]; @@ -856,7 +947,7 @@ bool nv::ImageIO::saveFloatTIFF(const char * fileName, FloatImage *fimage) { for (int c=0; cscanline(y, c); + float *src = fimage->scanline(y, base_component + c); for (int x=0; x pixels; + pixels.resizeErase (height, width); + + inputFile.setFrameBuffer (&pixels[0][0] - dw.min.x - dw.min.y * width, 1, width); + inputFile.readPixels (box.min.y, box.max.y); + + AutoPtr fimage(new FloatImage()); + fimage->allocate(spp, width, height); + + for (int y = 0; y < height; y++) + { + for (int x = 0; x < width; x++) + { + fimage->setPixel(imagePixel.r, x, y, 0); + fimage->setPixel(imagePixel.g, x, y, 1); + fimage->setPixel(imagePixel.b, x, y, 2); + fimage->setPixel(imagePixel.a, x, y, 3); + } + } + + return fimage.release(); +} + +FloatImage * nv::ImageIO::loadFloatEXR(const char * fileName) +{ + StdInputStream stream(name); + + if (stream.isError()) { + return false; + } + + return loadFloatExr(fileName, stream); +} + +#endif // defined(HAVE_EXR) -#endif #if 0 diff --git a/src/nvimage/ImageIO.h b/src/nvimage/ImageIO.h index 2b00991..cb0335f 100644 --- a/src/nvimage/ImageIO.h +++ b/src/nvimage/ImageIO.h @@ -13,8 +13,10 @@ namespace nv namespace ImageIO { - NVIMAGE_API Image * load(const char * name); - NVIMAGE_API Image * load(const char * name, Stream & s); + NVIMAGE_API Image * load(const char * fileName); + NVIMAGE_API Image * load(const char * fileName, Stream & s); + NVIMAGE_API FloatImage * loadFloat(const char * fileName); + NVIMAGE_API FloatImage * loadFloat(const char * fileName, Stream & s); NVIMAGE_API Image * loadTGA(Stream & s); NVIMAGE_API bool saveTGA(Stream & s, const Image * img); @@ -29,13 +31,15 @@ namespace nv #if defined(HAVE_JPEG) NVIMAGE_API Image * loadJPG(Stream & s); #endif - + #if defined(HAVE_TIFF) - // Hacks! - NVIMAGE_API FloatImage * loadFloatTIFF(const char * fileName); - NVIMAGE_API bool saveFloatTIFF(const char * fileName, FloatImage *fimage); + NVIMAGE_API FloatImage * loadFloatTIFF(const char * fileName, Stream & s); + + NVIMAGE_API bool saveFloatTIFF(const char * fileName, FloatImage *fimage, uint base_component, uint num_components); +#endif - NVIMAGE_API FloatImage * loadFloatTIFF(Stream & s); +#if defined(HAVE_EXR) + NVIMAGE_API FloatImage * loadFloatEXR(const char * fileName, Stream & s); #endif } // ImageIO namespace diff --git a/src/nvmath/Box.h b/src/nvmath/Box.h index c24f880..a8426a3 100644 --- a/src/nvmath/Box.h +++ b/src/nvmath/Box.h @@ -65,6 +65,17 @@ public: return (m_maxs - m_mins) * 0.5f; } + /// Return extents of the box. + scalar extents(uint axis) const + { + nvDebugCheck(axis < 3); + if (axis == 0) return (m_maxs.x() - m_mins.x()) * 0.5f; + if (axis == 1) return (m_maxs.y() - m_mins.y()) * 0.5f; + if (axis == 2) return (m_maxs.z() - m_mins.z()) * 0.5f; + nvAssume(false); + return 0.0f; + } + /// Add a point to this box. void addPointToBounds(Vector3::Arg p) { diff --git a/src/nvmath/CMakeLists.txt b/src/nvmath/CMakeLists.txt index d483958..c9c3eae 100644 --- a/src/nvmath/CMakeLists.txt +++ b/src/nvmath/CMakeLists.txt @@ -4,6 +4,7 @@ SET(MATH_SRCS nvmath.h Vector.h Matrix.h + Quaternion.h Box.h Color.h Eigen.h Eigen.cpp @@ -11,7 +12,8 @@ SET(MATH_SRCS Montecarlo.h Montecarlo.cpp Random.h Random.cpp SphericalHarmonic.h SphericalHarmonic.cpp - Basis.h Basis.cpp) + Basis.h Basis.cpp + Triangle.h Triangle.cpp TriBox.cpp) INCLUDE_DIRECTORIES(${CMAKE_CURRENT_SOURCE_DIR}) diff --git a/src/nvmath/Quaternion.h b/src/nvmath/Quaternion.h new file mode 100644 index 0000000..96ebf0e --- /dev/null +++ b/src/nvmath/Quaternion.h @@ -0,0 +1,128 @@ +// This code is in the public domain -- castanyo@yahoo.es + +#ifndef NV_MATH_QUATERNION_H +#define NV_MATH_QUATERNION_H + +#include +#include + +namespace nv +{ + + class NVMATH_CLASS Quaternion + { + public: + typedef Quaternion const & Arg; + + Quaternion(); + explicit Quaternion(zero_t); + Quaternion(float x, float y, float z, float w); + Quaternion(Vector4::Arg v); + + const Quaternion & operator=(Quaternion::Arg v); + + scalar x() const; + scalar y() const; + scalar z() const; + scalar w() const; + + const Vector4 & asVector() const; + Vector4 & asVector(); + + private: + Vector4 q; + }; + + inline Quaternion::Quaternion() {} + inline Quaternion::Quaternion(zero_t) : q(zero) {} + inline Quaternion::Quaternion(float x, float y, float z, float w) : q(x, y, z, w) {} + inline Quaternion::Quaternion(Vector4::Arg v) : q(v) {} + + inline const Quaternion & Quaternion::operator=(Quaternion::Arg v) { q = v.q; return *this; } + + inline scalar Quaternion::x() const { return q.x(); } + inline scalar Quaternion::y() const { return q.y(); } + inline scalar Quaternion::z() const { return q.z(); } + inline scalar Quaternion::w() const { return q.w(); } + + inline const Vector4 & Quaternion::asVector() const { return q; } + inline Vector4 & Quaternion::asVector() { return q; } + + + inline Quaternion mul(Quaternion::Arg a, Quaternion::Arg b) + { + // @@ Efficient SIMD implementation? + return Quaternion( + + a.x() * b.w() + a.y()*b.z() - a.z()*b.y() + a.w()*b.x(), + - a.x() * b.z() + a.y()*b.w() + a.z()*b.x() + a.w()*b.y(), + + a.x() * b.y() - a.y()*b.x() + a.z()*b.w() + a.w()*b.z(), + - a.x() * b.x() - a.y()*b.y() - a.z()*b.z() + a.w()*b.w()); + } + + inline Quaternion scale(Quaternion::Arg q, float s) + { + return scale(q.asVector(), s); + } + inline Quaternion operator *(Quaternion::Arg q, float s) + { + return scale(q, s); + } + inline Quaternion operator *(float s, Quaternion::Arg q) + { + return scale(q, s); + } + + inline Quaternion scale(Quaternion::Arg q, Vector4::Arg s) + { + return scale(q.asVector(), s); + } + inline Quaternion operator *(Quaternion::Arg q, Vector4::Arg s) + { + return scale(q, s); + } + inline Quaternion operator *(Vector4::Arg s, Quaternion::Arg q) + { + return scale(q, s); + } + + inline Quaternion conjugate(Quaternion::Arg q) + { + return q * Vector4(-1, -1, -1, 1); + } + + inline float length(Quaternion::Arg q) + { + return length(q.asVector()); + } + + inline bool isNormalized(Quaternion::Arg q, float epsilon = NV_NORMAL_EPSILON) + { + return equal(length(q), 1, epsilon); + } + + inline Quaternion normalize(Quaternion::Arg q, float epsilon = NV_EPSILON) + { + float l = length(q); + nvDebugCheck(!isZero(l, epsilon)); + Quaternion n = scale(q, 1.0f / l); + nvDebugCheck(isNormalized(n)); + return n; + } + + inline Quaternion inverse(Quaternion::Arg q) + { + return conjugate(normalize(q)); + } + + /// Create a rotation quaternion for @a angle alpha around normal vector @a v. + inline Quaternion axisAngle(Vector3::Arg v, float alpha) + { + float s = sinf(alpha * 0.5f); + float c = cosf(alpha * 0.5f); + return Quaternion(Vector4(v * s, c)); + } + + +} // nv namespace + +#endif // NV_MATH_QUATERNION_H diff --git a/src/nvmath/TriBox.cpp b/src/nvmath/TriBox.cpp new file mode 100644 index 0000000..6c53e8f --- /dev/null +++ b/src/nvmath/TriBox.cpp @@ -0,0 +1,226 @@ +/********************************************************/ +/* AABB-triangle overlap test code */ +/* by Tomas Akenine-Möller */ +/* Function: int triBoxOverlap(float boxcenter[3], */ +/* float boxhalfsize[3],float triverts[3][3]); */ +/* History: */ +/* 2001-03-05: released the code in its first version */ +/* 2001-06-18: changed the order of the tests, faster */ +/* */ +/* Acknowledgement: Many thanks to Pierre Terdiman for */ +/* suggestions and discussions on how to optimize code. */ +/* Thanks to David Hunt for finding a ">="-bug! */ +/********************************************************/ + +#include +//#include + +using namespace nv; + +#define X 0 +#define Y 1 +#define Z 2 + +#define FINDMINMAX(x0,x1,x2,min,max) \ + min = max = x0; \ + if(x1max) max=x1;\ + if(x2max) max=x2; + + +static bool planeBoxOverlap(Vector3::Arg normal, Vector3::Arg vert, Vector3::Arg maxbox) // -NJMP- +{ + Vector3 vmin, vmax; + + float signs[3] = {1, 1, 1}; + if (normal.x() <= 0.0f) signs[0] = -1; + if (normal.y() <= 0.0f) signs[1] = -1; + if (normal.z() <= 0.0f) signs[2] = -1; + + Vector3 sign(signs[0], signs[1], signs[2]); + vmin = -scale(sign, maxbox) - vert; + vmax = scale(sign, maxbox) - vert; + + if (dot(normal, vmin) > 0.0f) return false; + if (dot(normal, vmax) >= 0.0f) return true; + + return false; +} + + +/*======================== X-tests ========================*/ +#define AXISTEST_X01(a, b, fa, fb) \ + p0 = a*v0.y() - b*v0.z(); \ + p2 = a*v2.y() - b*v2.z(); \ + if(p0rad || max<-rad) return false; + +#define AXISTEST_X2(a, b, fa, fb) \ + p0 = a*v0.y() - b*v0.z(); \ + p1 = a*v1.y() - b*v1.z(); \ + if(p0rad || max<-rad) return false; + +/*======================== Y-tests ========================*/ +#define AXISTEST_Y02(a, b, fa, fb) \ + p0 = -a*v0.x() + b*v0.z(); \ + p2 = -a*v2.x() + b*v2.z(); \ + if(p0rad || max<-rad) return false; + +#define AXISTEST_Y1(a, b, fa, fb) \ + p0 = -a*v0.x() + b*v0.z(); \ + p1 = -a*v1.x() + b*v1.z(); \ + if(p0rad || max<-rad) return false; + +/*======================== Z-tests ========================*/ + +#define AXISTEST_Z12(a, b, fa, fb) \ + p1 = a*v1.x() - b*v1.y(); \ + p2 = a*v2.x() - b*v2.y(); \ + if(p2rad || max<-rad) return false; + +#define AXISTEST_Z0(a, b, fa, fb) \ + p0 = a*v0.x() - b*v0.y(); \ + p1 = a*v1.x() - b*v1.y(); \ + if(p0rad || max<-rad) return false; + + +bool triBoxOverlap(Vector3::Arg boxcenter, Vector3::Arg boxhalfsize, const Vector3 * triverts) +{ + // use separating axis theorem to test overlap between triangle and box + // need to test for overlap in these directions: + // 1) the {x,y,z}-directions (actually, since we use the AABB of the triangle + // we do not even need to test these) + // 2) normal of the triangle + // 3) crossproduct(edge from tri, {x,y,z}-directin) + // this gives 3x3=9 more tests + Vector3 v0, v1, v2; + float min, max, p0, p1, p2, rad, fex, fey, fez; + Vector3 normal, e0, e1, e2; + + // This is the fastest branch on Sun. + // move everything so that the boxcenter is in (0,0,0) + v0 = triverts[0] - boxcenter; + v1 = triverts[1] - boxcenter; + v2 = triverts[2] - boxcenter; + + // Compute triangle edges. + e0 = v1 - v0; // tri edge 0 + e1 = v2 - v1; // tri edge 1 + e2 = v0 - v2; // tri edge 2 + + // Bullet 3: + // test the 9 tests first (this was faster) + fex = fabsf(e0.x()); + fey = fabsf(e0.y()); + fez = fabsf(e0.z()); + AXISTEST_X01(e0.z(), e0.y(), fez, fey); + AXISTEST_Y02(e0.z(), e0.x(), fez, fex); + AXISTEST_Z12(e0.y(), e0.x(), fey, fex); + + fex = fabsf(e1.x()); + fey = fabsf(e1.y()); + fez = fabsf(e1.z()); + AXISTEST_X01(e1.z(), e1.y(), fez, fey); + AXISTEST_Y02(e1.z(), e1.x(), fez, fex); + AXISTEST_Z0(e1.y(), e1.x(), fey, fex); + + fex = fabsf(e2.x()); + fey = fabsf(e2.y()); + fez = fabsf(e2.z()); + AXISTEST_X2(e2.z(), e2.y(), fez, fey); + AXISTEST_Y1(e2.z(), e2.x(), fez, fex); + AXISTEST_Z12(e2.y(), e2.x(), fey, fex); + + // Bullet 1: + // first test overlap in the {x,y,z}-directions + // find min, max of the triangle each direction, and test for overlap in + // that direction -- this is equivalent to testing a minimal AABB around + // the triangle against the AABB + + // test in X-direction + FINDMINMAX(v0.x(), v1.x(), v2.x(), min, max); + if(min > boxhalfsize.x() || max < -boxhalfsize.x()) return false; + + // test in Y-direction + FINDMINMAX(v0.y(), v1.y(), v2.y(), min, max); + if(min > boxhalfsize.y() || max < -boxhalfsize.y()) return false; + + // test in Z-direction + FINDMINMAX(v0.z(), v1.z(), v2.z(), min, max); + if(min > boxhalfsize.z() || max < -boxhalfsize.z()) return false; + + // Bullet 2: + // test if the box intersects the plane of the triangle + // compute plane equation of triangle: normal*x+d=0 + normal = cross(e0, e1); + + return planeBoxOverlap(normal, v0, boxhalfsize); +} + + +bool triBoxOverlapNoBounds(Vector3::Arg boxcenter, Vector3::Arg boxhalfsize, const Vector3 * triverts) +{ + // use separating axis theorem to test overlap between triangle and box + // need to test for overlap in these directions: + // 1) the {x,y,z}-directions (actually, since we use the AABB of the triangle + // we do not even need to test these) + // 2) normal of the triangle + // 3) crossproduct(edge from tri, {x,y,z}-directin) + // this gives 3x3=9 more tests + Vector3 v0, v1, v2; + float min, max, p0, p1, p2, rad, fex, fey, fez; + Vector3 normal, e0, e1, e2; + + // This is the fastest branch on Sun. + // move everything so that the boxcenter is in (0,0,0) + v0 = triverts[0] - boxcenter; + v1 = triverts[1] - boxcenter; + v2 = triverts[2] - boxcenter; + + // Compute triangle edges. + e0 = v1 - v0; // tri edge 0 + e1 = v2 - v1; // tri edge 1 + e2 = v0 - v2; // tri edge 2 + + // Bullet 3: + // test the 9 tests first (this was faster) + fex = fabsf(e0.x()); + fey = fabsf(e0.y()); + fez = fabsf(e0.z()); + AXISTEST_X01(e0.z(), e0.y(), fez, fey); + AXISTEST_Y02(e0.z(), e0.x(), fez, fex); + AXISTEST_Z12(e0.y(), e0.x(), fey, fex); + + fex = fabsf(e1.x()); + fey = fabsf(e1.y()); + fez = fabsf(e1.z()); + AXISTEST_X01(e1.z(), e1.y(), fez, fey); + AXISTEST_Y02(e1.z(), e1.x(), fez, fex); + AXISTEST_Z0(e1.y(), e1.x(), fey, fex); + + fex = fabsf(e2.x()); + fey = fabsf(e2.y()); + fez = fabsf(e2.z()); + AXISTEST_X2(e2.z(), e2.y(), fez, fey); + AXISTEST_Y1(e2.z(), e2.x(), fez, fex); + AXISTEST_Z12(e2.y(), e2.x(), fey, fex); + + // Bullet 2: + // test if the box intersects the plane of the triangle + // compute plane equation of triangle: normal*x+d=0 + normal = cross(e0, e1); + + return planeBoxOverlap(normal, v0, boxhalfsize); +} diff --git a/src/nvmath/Triangle.cpp b/src/nvmath/Triangle.cpp new file mode 100644 index 0000000..84819c7 --- /dev/null +++ b/src/nvmath/Triangle.cpp @@ -0,0 +1,171 @@ +// This code is in the public domain -- Ignacio Castaño + +#include + +using namespace nv; + + +/// Tomas Möller, barycentric ray-triangle test. +bool Triangle::TestRay_Moller(Vector3::Arg orig, Vector3::Arg dir, float * out_t, float * out_u, float * out_v) +{ + Vector3 e1, e2, tvec, pvec, qvec; + float det, inv_det; + + // find vectors for two edges sharing vert0 + e1 = v[1] - v[0]; + e2 = v[2] - v[0]; + + // begin calculating determinant - also used to calculate U parameter + pvec = cross(dir, e2); + + // if determinant is near zero, ray lies in plane of triangle + det = dot(e1, pvec); + if (det < -NV_EPSILON) { + return false; + } + + // calculate distance from vert0 to ray origin + tvec = orig - v[0]; + + // calculate U parameter and test bounds + float u = dot(tvec, pvec); + if( u < 0.0f || u > det ) { + return false; + } + + // prepare to test V parameter + qvec = cross(tvec, e1); + + // calculate V parameter and test bounds + float v = dot(dir, qvec); + if (v < 0.0f || u + v > det) { + return false; + } + + // calculate t, scale parameters, ray intersects triangle + inv_det = 1.0f / det; + *out_t = dot(e2, qvec) * inv_det; + *out_u = u * inv_det; // v + *out_v = v * inv_det; // 1-(u+v) + + return true; +} + + + + + +#if 0 + + +// IC: This code is adapted from my Pi.MathLib code, based on Moller-Trumbore triangle test. +FXVector3 edge1, edge2, pvec, tvec, qvec; + +edge1 = tri.V1 - tri.V0; +edge2 = tri.V2 - tri.V0; + +pvec.Cross(ray.Direction, edge2); + +float det = FXVector3.Dot(edge1, pvec); + +// calculate distance from vert0 to ray origin. +FXVector3 tvec = ray.Origin - vert0; + +if( det < 0 ) +{ + // calculate U parameter and test bounds. + float u = FXVector3.Dot(tvec, pvec); + if (u > 0.0 || u < det) + { + return false; + } + + // prepare to test V parameter. + qvec.Cross(tvec, edge1); + + // calculate V parameter and test bounds. + float v = FXVector3.Dot(dir, qvec); + + return v <= 0.0 && u + v >= det; +} +else +{ + // calculate U parameter and test bounds. + float u = FXVector3.Dot(tvec, pvec); + if (u < 0.0 || u > det) + { + return false; + } + + // prepare to test V parameter. + qvec.Cross(tvec, edge1); + + // calculate V parameter and test bounds. + float v = FXVector3.Dot(dir, qvec); + + return v >= 0.0 && u + v <= det; +} + + + +/** + * Dan Sunday, parametric ray-triangle test. + */ +// Output: *I = intersection point (when it exists) +// Return: -1 = triangle is degenerate (a segment or point) +// 0 = disjoint (no intersect) +// 1 = intersect in unique point I1 +// 2 = are in the same plane +bool RayTriangleTest( const Vec3 &p0, const Vec3 &p1, + const Vec3 &v0, const Vec3 &v1, const Vec3 &v2, const Vec3 &n, + Vec3 &I ) { + Vec3 u, v; // triangle vectors + Vec3 dir, w0, w; // ray vectors + float r, a, b; // params to calc ray-plane intersect + + // get triangle edge vectors and plane normal + u.Sub( v1, v0 ); + v.Sub( v2, v0 ); + + dir.Sub( p1, p0 ); // ray direction vector + w0.Sub( p0, v0 ); + a = Vec3DotProduct( n, w0 ); + b = Vec3DotProduct( n, dir ); + + if( fabs(b) < TI_EPSILON ) // ray is parallel to triangle plane + return false; + + + // get intersect point of ray with triangle plane + r = -a / b; + if( r < 0.0f ) // ray goes away from triangle + return false; // => no intersect + + // for a segment, also test if (r > 1.0) => no intersect + + I.Mad( p0, dir, r ); // intersect point of ray and plane + + // is I inside T? + float uu, uv, vv, wu, wv, D; + uu = Vec3DotProduct( u, u ); + uv = Vec3DotProduct( u, v ); + vv = Vec3DotProduct( v, v ); + w = I - v0; + wu = Vec3DotProduct( w, u ); + wv = Vec3DotProduct( w, v ); + D = uv * uv - uu * vv; + + // get and test parametric coords + float s, t; + s = (uv * wv - vv * wu) / D; + if( s<0.0 || s > 1.0) // I is outside T + return false; + t = (uv * wu - uu * wv) / D; + if( t<0.0 || (s + t) > 1.0) // I is outside T + return false; + + return true; // I is in T +} + + +#endif // 0 diff --git a/src/nvmath/Triangle.h b/src/nvmath/Triangle.h new file mode 100644 index 0000000..e8d55e5 --- /dev/null +++ b/src/nvmath/Triangle.h @@ -0,0 +1,149 @@ +// This code is in the public domain -- Ignacio Castaño + +#ifndef NV_MATH_TRIANGLE_H +#define NV_MATH_TRIANGLE_H + + +#include +#include +#include +//#include + +namespace nv +{ + +// Tomas Akenine-Möller box-triangle test. +NVMATH_API bool triBoxOverlap(Vector3::Arg boxcenter, Vector3::Arg boxhalfsize, const Vector3 * restrict triverts); +NVMATH_API bool triBoxOverlapNoBounds(Vector3::Arg boxcenter, Vector3::Arg boxhalfsize, const Vector3 * restrict triverts); + + +/// Triangle class with three vertices. +class Triangle +{ +public: + Triangle() {}; + + Triangle(const Vector3 & v0, const Vector3 & v1, const Vector3 & v2) + { + v[0] = v0; + v[1] = v1; + v[2] = v2; + } + + /// Get the bounds of the triangle. + Box bounds() const { + Box bounds; + bounds.clearBounds(); + bounds.addPointToBounds(v[0]); + bounds.addPointToBounds(v[1]); + bounds.addPointToBounds(v[2]); + return bounds; + } + +/* + /// Get barycentric coordinates of the given point in this triangle. + Vector3 barycentricCoordinates(Vector3::Arg p) + { + Vector3 bar; + + // p must lie in the triangle plane. + Plane plane; + plane.set(v[0], v[1], v[2]); + nvCheck( equalf(plane.Distance(p), 0.0f) ); + + Vector3 n; + + // Compute signed area of triangle + n = cross(v[1] - v[0], p - v[0]); + bar.x = length(n); + if (dot(n, plane.vector) < 0) { + bar->x = -bar->x; + } + + // Compute signed area of triangle + n = cross(v[2] - v[1], p - v[1]); + bar->y = length(cross(e, d)); + if (dot(n, plane.vector) < 0) { + bar->y = -bar->y; + } + + // Compute signed area of triangle + n = cross(v[0] - v[2], p - v[2]); + bar->z = length(n); + if (dot(n, plane.vector) < 0) { + bar->z = -bar->z; + } + + // We cannot just do this because we need the signed areas. + // bar->x = Vector3Area(e0, d0); + // bar->y = Vector3Area(e1, d1); + // bar->z = Vector3Area(e2, d2); + + // bar->x = Vector3TripleProduct(v[1], v[2], p); + // bar->y = Vector3TripleProduct(v[2], v[0], p); + // bar->z = Vector3TripleProduct(v[0], v[1], p); + + } +*/ + + // Moller ray triangle test. + bool TestRay_Moller(const Vector3 & orig, const Vector3 & dir, float * out_t, float * out_u, float * out_v); + + Vector3 v[3]; +}; + + +#if 0 + +/** A planar triangle. */ +class Triangle2 { +public: + + Triangle2() {}; + Triangle2(const Vec2 & v0, const Vec2 & v1, const Vec2 & v2) { + v[0] = v0; + v[1] = v1; + v[2] = v2; + } + + /** Get the barycentric coordinates of the given point for this triangle. + * http://stevehollasch.com/cgindex/math/barycentric.html + */ + void GetBarycentricCoordinates(const Vec2 & p, Vector3 * bar) const { + float denom = 1.0f / (v[1].x - v[0].x) * (v[2].y - v[0].y) - (v[2].x - v[0].x) * (v[1].y - v[0].y); + bar->x = ((v[1].x - p.x) * (v[2].y - p.y) - (v[2].x - p.x) * (v[1].y - p.y)) * denom; + bar->y = ((v[2].x - p.x) * (v[0].y - p.y) - (v[0].x - p.x) * (v[2].y - p.y)) * denom; + //bar->z = ((v[0].x - p.x) * (v[1].y - p.y) - (v[1].x - p.x) * (v[0].y - p.y)) * denom; + bar->z = 1 - bar->x - bar->y; + } + + + Vec2 v[3]; +}; + +#endif // 0 + + +inline bool overlap(const Triangle & t, const Box & b) +{ + Vector3 center = b.center(); + Vector3 extents = b.extents(); + return triBoxOverlap(center, extents, t.v); +} + +inline bool Overlap(const Box & b, const Triangle & t) +{ + return overlap(t, b); +} + + +inline bool overlapNoBounds(const Triangle & t, const Box & b) +{ + Vector3 center = b.center(); + Vector3 extents = b.extents(); + return triBoxOverlapNoBounds(center, extents, t.v); +} + +} // nv namespace + +#endif // NV_MATH_TRIANGLE_H diff --git a/src/nvmath/Vector.h b/src/nvmath/Vector.h index 4db0e55..5e8fbec 100644 --- a/src/nvmath/Vector.h +++ b/src/nvmath/Vector.h @@ -22,6 +22,7 @@ public: Vector2(); explicit Vector2(zero_t); + explicit Vector2(scalar f); Vector2(scalar x, scalar y); Vector2(Vector2::Arg v); @@ -29,7 +30,9 @@ public: scalar x() const; scalar y() const; - + + scalar component(uint idx) const; + const scalar * ptr() const; void set(scalar x, scalar y); @@ -42,7 +45,7 @@ public: friend bool operator==(Vector2::Arg a, Vector2::Arg b); friend bool operator!=(Vector2::Arg a, Vector2::Arg b); - + private: scalar m_x, m_y; }; @@ -66,7 +69,9 @@ public: scalar z() const; const Vector2 & xy() const; - + + scalar component(uint idx) const; + // @@ temporary... should use an explicit method? const scalar * ptr() const; @@ -76,6 +81,7 @@ public: void operator+=(Vector3::Arg v); void operator-=(Vector3::Arg v); void operator*=(scalar s); + void operator/=(scalar s); void operator*=(Vector3::Arg v); friend bool operator==(Vector3::Arg a, Vector3::Arg b); @@ -108,7 +114,12 @@ public: const Vector2 & xy() const; const Vector3 & xyz() const; - + + scalar component(uint idx) const; + + // @@ temporary... should use an explicit method? + const scalar * ptr() const; + void set(scalar x, scalar y, scalar z, scalar w); Vector4 operator-() const; @@ -129,6 +140,7 @@ private: inline Vector2::Vector2() {} inline Vector2::Vector2(zero_t) : m_x(0.0f), m_y(0.0f) {} +inline Vector2::Vector2(scalar f) : m_x(f), m_y(f) {} inline Vector2::Vector2(scalar x, scalar y) : m_x(x), m_y(y) {} inline Vector2::Vector2(Vector2::Arg v) : m_x(v.x()), m_y(v.y()) {} @@ -142,6 +154,15 @@ inline const Vector2 & Vector2::operator=(Vector2::Arg v) inline scalar Vector2::x() const { return m_x; } inline scalar Vector2::y() const { return m_y; } +inline scalar Vector2::component(uint idx) const +{ + nvDebugCheck(idx < 2); + if (idx == 0) return x(); + if (idx == 1) return y(); + nvAssume(false); + return 0.0f; +} + inline const scalar * Vector2::ptr() const { return &m_x; @@ -216,12 +237,21 @@ inline const Vector2 & Vector3::xy() const { return *(Vector2 *)this; } - + +inline scalar Vector3::component(uint idx) const +{ + nvDebugCheck(idx < 3); + if (idx == 0) return x(); + if (idx == 1) return y(); + if (idx == 2) return z(); + nvAssume(false); + return 0.0f; +} + inline const scalar * Vector3::ptr() const { return &m_x; } - inline void Vector3::set(scalar x, scalar y, scalar z) { @@ -256,6 +286,14 @@ inline void Vector3::operator*=(scalar s) m_z *= s; } +inline void Vector3::operator/=(scalar s) +{ + float is = 1.0f / s; + m_x *= is; + m_y *= is; + m_z *= is; +} + inline void Vector3::operator*=(Vector3::Arg v) { m_x *= v.m_x; @@ -306,6 +344,17 @@ inline const Vector3 & Vector4::xyz() const return *(Vector3 *)this; } +inline scalar Vector4::component(uint idx) const +{ + nvDebugCheck(idx < 4); + if (idx == 0) return x(); + if (idx == 1) return y(); + if (idx == 2) return z(); + if (idx == 3) return w(); + nvAssume(false); + return 0.0f; +} + inline void Vector4::set(scalar x, scalar y, scalar z, scalar w) { m_x = x; @@ -385,7 +434,6 @@ inline Vector2 operator-(Vector2::Arg a, Vector2::Arg b) return sub(a, b); } - inline Vector2 scale(Vector2::Arg v, scalar s) { return Vector2(v.x() * s, v.y() * s); @@ -508,6 +556,11 @@ inline Vector3 operator*(scalar s, Vector3::Arg v) return scale(v, s); } +inline Vector3 operator*(Vector3::Arg v, Vector3::Arg s) +{ + return scale(v, s); +} + inline Vector3 operator/(Vector3::Arg v, scalar s) { return scale(v, 1.0f/s);