Merge changes from private tree.

Eliminate files that are not needed for NVTT.
pull/216/head
castano 15 years ago
parent 6fb29816a2
commit 88fc5ca18e

@ -5,11 +5,18 @@ SET(NV_CMAKE_DIR "${NV_SOURCE_DIR}/cmake")
SET(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${NV_CMAKE_DIR}")
IF(WIN32)
SET(GNUWIN32 "${NV_SOURCE_DIR}/extern/gnuwin32")
SET(CMAKE_INCLUDE_PATH "${GNUWIN32}/include")
SET(CMAKE_LIBRARY_PATH "${GNUWIN32}/lib")
# gnuwin32 paths:
SET(GNUWIN32_PATH "${NV_SOURCE_DIR}/extern/gnuwin")
SET(CMAKE_INCLUDE_PATH "${GNUWIN32_PATH}/include")
IF (NV_SYSTEM_PROCESSOR STREQUAL "AMD64")
SET(CMAKE_LIBRARY_PATH ${CMAKE_LIBRARY_PATH} "${GNUWIN32_PATH}/lib/win64")
ELSE(NV_SYSTEM_PROCESSOR STREQUAL "AMD64")
SET(CMAKE_LIBRARY_PATH ${CMAKE_LIBRARY_PATH} "${GNUWIN32_PATH}/lib/win32")
ENDIF(NV_SYSTEM_PROCESSOR STREQUAL "AMD64")
# Set GLUT path:
SET(GLUT_ROOT_PATH "${NV_SOURCE_DIR}/extern/glut")
ENDIF(WIN32)
INCLUDE(${NV_CMAKE_DIR}/OptimalOptions.cmake)
@ -23,9 +30,6 @@ IF(NVTT_SHARED)
SET(NVIMAGE_SHARED TRUE)
ENDIF(NVTT_SHARED)
ADD_SUBDIRECTORY(extern)
ADD_SUBDIRECTORY(src)
IF(WIN32)
ADD_SUBDIRECTORY(extern/gnuwin32)
ENDIF(WIN32)

@ -10,8 +10,9 @@
IF (WIN32)
FIND_PATH( GLEW_INCLUDE_PATH GL/glew.h
$ENV{PROGRAMFILES}/GLEW/include
${PROJECT_SOURCE_DIR}/src/nvgl/glew/include
${GLEW_ROOT_DIR}/include
DOC "The directory where GL/glew.h resides")
IF (NV_SYSTEM_PROCESSOR STREQUAL "AMD64")
FIND_LIBRARY( GLEW_LIBRARY
NAMES glew64 glew64s
@ -37,7 +38,9 @@ ELSE (WIN32)
/usr/local/include
/sw/include
/opt/local/include
${GLEW_ROOT_DIR}/include
DOC "The directory where GL/glew.h resides")
FIND_LIBRARY( GLEW_LIBRARY
NAMES GLEW glew
PATHS
@ -47,13 +50,13 @@ ELSE (WIN32)
/usr/local/lib
/sw/lib
/opt/local/lib
${GLEW_ROOT_DIR}/lib
DOC "The GLEW library")
ENDIF (WIN32)
IF (GLEW_INCLUDE_PATH)
SET( GLEW_FOUND 1 CACHE STRING "Set to 1 if GLEW is found, 0 otherwise")
ELSE (GLEW_INCLUDE_PATH)
SET( GLEW_FOUND 0 CACHE STRING "Set to 1 if GLEW is found, 0 otherwise")
ENDIF (GLEW_INCLUDE_PATH)
SET(GLEW_FOUND "NO")
IF (GLEW_INCLUDE_PATH AND GLEW_LIBRARY)
SET(GLEW_LIBRARIES ${GLEW_LIBRARY})
SET(GLEW_FOUND "YES")
ENDIF (GLEW_INCLUDE_PATH AND GLEW_LIBRARY)
MARK_AS_ADVANCED( GLEW_FOUND )

14
configure vendored

@ -51,9 +51,9 @@ fi
echo "-- Configuring nvidia-texture-tools "`cat VERSION`
mkdir -p ./build
cd ./build
$CMAKE .. -DNVTT_SHARED=1 -DCMAKE_BUILD_TYPE=$build -DCMAKE_INSTALL_PREFIX=$prefix -G "Unix Makefiles" || exit 1
mkdir -p ./build-$build
cd ./build-$build
$CMAKE .. -DCMAKE_BUILD_TYPE=$build -DCMAKE_INSTALL_PREFIX=$prefix -G "Unix Makefiles" || exit 1
cd ..
echo ""
@ -62,11 +62,11 @@ echo ""
cat > Makefile << EOF
all:
@make --no-print-directory -C build/
@make --no-print-directory -C build-$build/
install:
@make install --no-print-directory -C build/
@make install --no-print-directory -C build-$build/
clean:
@make clean --no-print-directory -C build/
@make clean --no-print-directory -C build-$build/
distclean:
@rm -Rf build/
@rm -Rf build-$build/
EOF

@ -0,0 +1,7 @@
INSTALL(PROGRAMS
bin/win32/jpeg62.dll
bin/win32/libpng12.dll
bin/win32/libtiff3.dll
bin/win32/zlib1.dll
DESTINATION bin)

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

@ -1,7 +0,0 @@
INSTALL(PROGRAMS
bin/jpeg62.dll
bin/libpng12.dll
bin/libtiff3.dll
bin/zlib1.dll
DESTINATION bin)

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

@ -1,5 +1,6 @@
INCLUDE_DIRECTORIES(${CMAKE_CURRENT_SOURCE_DIR} ${CMAKE_CURRENT_BINARY_DIR})
INCLUDE_DIRECTORIES(${NV_SOURCE_DIR}/extern/poshlib)
SUBDIRS(nvcore)
SUBDIRS(nvmath)
@ -134,9 +135,8 @@ CHECK_INCLUDE_FILES(execinfo.h HAVE_EXECINFO_H)
CHECK_INCLUDE_FILES(malloc.h HAVE_MALLOC_H)
CONFIGURE_FILE(${CMAKE_CURRENT_SOURCE_DIR}/nvconfig.h.in ${CMAKE_CURRENT_BINARY_DIR}/nvconfig.h)
IF(GCONFTOOL2)
CONFIGURE_FILE(${CMAKE_CURRENT_SOURCE_DIR}/nvtt/tools/nvtt-thumbnailer.schema.in ${CMAKE_CURRENT_BINARY_DIR}/nvtt/tools/nvtt-thumbnailer.schema)
ENDIF(GCONFTOOL2)
#INSTALL(FILES ${CMAKE_CURRENT_BINARY_DIR}/nvconfig.h DESTINATION include)

@ -1,5 +1,4 @@
PROJECT(nvcore)
ADD_SUBDIRECTORY(poshlib)
SET(CORE_SRCS
nvcore.h
@ -18,14 +17,6 @@ SET(CORE_SRCS
Containers.h
StrLib.h
StrLib.cpp
Stream.h
StdStream.h
TextReader.h
TextReader.cpp
TextWriter.h
TextWriter.cpp
Tokenizer.h
Tokenizer.cpp
Radix.h
Radix.cpp
CpuInfo.h
@ -34,6 +25,14 @@ SET(CORE_SRCS
Timer.h
Library.h
Library.cpp
Stream.h
StdStream.h
TextReader.h
TextReader.cpp
TextWriter.h
TextWriter.cpp
Tokenizer.h
Tokenizer.cpp
FileSystem.h
FileSystem.cpp)
@ -66,7 +65,7 @@ IF(MSVC AND NV_SYSTEM_PROCESSOR STREQUAL "AMD64")
ARGS /nologo /Fo ${VSSCANF_ASM_OBJ} /c /Cx ${VSSCANF_ASM_SRC}
)
ENDIF(MSVC AND NV_SYSTEM_PROCESSOR STREQUAL "AMD64")
# targets
ADD_DEFINITIONS(-DNVCORE_EXPORTS)

@ -179,20 +179,29 @@ namespace nv
}
/// Const and save vector access.
/// Const element access.
const T & operator[]( uint index ) const
{
nvDebugCheck(index < m_size);
return m_buffer[index];
}
/// Safe vector access.
const T & at( uint index ) const
{
nvDebugCheck(index < m_size);
return m_buffer[index];
}
/// Element access.
T & operator[] ( uint index )
{
nvDebugCheck(index < m_size);
return m_buffer[index];
}
T & at( uint index )
{
nvDebugCheck(index < m_size);
return m_buffer[index];
}
/// Get vector size.
uint size() const { return m_size; }
@ -285,15 +294,22 @@ namespace nv
return m_buffer[0];
}
/// Check if the given element is contained in the array.
bool contains(const T & e) const
/// Return index of the
bool find(const T & element, uint * index)
{
for (uint i = 0; i < m_size; i++) {
if (m_buffer[i] == e) return true;
if (index != NULL) *index = i;
return true;
}
return false;
}
/// Check if the given element is contained in the array.
bool contains(const T & e) const
{
return find(e, NULL);
}
/// Remove the element at the given index. This is an expensive operation!
void removeAt( uint index )
{
@ -479,9 +495,10 @@ namespace nv
}
/// Assignment operator.
void operator=( const Array<T> & a )
Array<T> & operator=( const Array<T> & a )
{
copy( a.m_buffer, a.m_size );
return *this;
}
/*

@ -405,7 +405,7 @@ namespace
{
void * trace[64];
int size = backtrace(trace, 64);
nvPrintStackTrace(trace, size, 3);
nvPrintStackTrace(trace, size, 2);
}
# endif

@ -3,17 +3,18 @@
#ifndef NV_CORE_FILESYSTEM_H
#define NV_CORE_FILESYSTEM_H
#include <nvcore/nvcore.h>
namespace nv
{
namespace FileSystem
{
namespace FileSystem
{
bool exists(const char * path);
bool createDirectory(const char * path);
NVCORE_API bool exists(const char * path);
NVCORE_API bool createDirectory(const char * path);
} // FileSystem namespace
} // FileSystem namespace
} // nv namespace

@ -8,10 +8,6 @@
#include <stdio.h> // NULL
#define NV_DECLARE_PTR(Class) \
typedef SmartPtr<class Class> Class ## Ptr; \
typedef SmartPtr<const class Class> ClassConst ## Ptr
namespace nv
{
@ -55,6 +51,15 @@ public:
}
}
template <class Q>
void operator=( Q * p ) {
if (p != m_ptr)
{
delete m_ptr;
m_ptr = static_cast<T *>(p);
}
}
/** Member access. */
T * operator -> () const {
nvDebugCheck(m_ptr != NULL);

@ -6,6 +6,11 @@
#include <nvcore/nvcore.h>
#include <nvcore/Debug.h>
#define NV_DECLARE_PTR(Class) \
template <class T> class SmartPtr; \
typedef SmartPtr<class Class> Class ## Ptr; \
typedef SmartPtr<const class Class> Class ## ConstPtr
namespace nv
{

@ -1,5 +1,7 @@
#ifndef NV_STDSTREAM_H
#define NV_STDSTREAM_H
// This code is in the public domain -- castano@gmail.com
#ifndef NV_CORE_STDSTREAM_H
#define NV_CORE_STDSTREAM_H
#include <nvcore/Stream.h>
@ -366,4 +368,4 @@ private:
} // nv namespace
#endif // NV_STDSTREAM_H
#endif // NV_CORE_STDSTREAM_H

@ -137,9 +137,9 @@ namespace nv
void stripExtension();
// statics
static char separator();
static const char * fileName(const char *);
static const char * extension(const char *);
NVCORE_API static char separator();
NVCORE_API static const char * fileName(const char *);
NVCORE_API static const char * extension(const char *);
};

@ -1,7 +1,7 @@
// This code is in the public domain -- castanyo@yahoo.es
// This code is in the public domain -- castano@gmail.com
#ifndef NVCORE_STREAM_H
#define NVCORE_STREAM_H
#ifndef NV_CORE_STREAM_H
#define NV_CORE_STREAM_H
#include <nvcore/nvcore.h>
#include <nvcore/Debug.h>
@ -9,152 +9,152 @@
namespace nv
{
/// Base stream class.
class NVCORE_CLASS Stream {
public:
/// Base stream class.
class NVCORE_CLASS Stream {
public:
enum ByteOrder {
LittleEndian = false,
BigEndian = true,
};
/// Get the byte order of the system.
static ByteOrder getSystemByteOrder() {
#if NV_LITTLE_ENDIAN
return LittleEndian;
#else
return BigEndian;
#endif
}
enum ByteOrder {
LittleEndian = false,
BigEndian = true,
};
/// Get the byte order of the system.
static ByteOrder getSystemByteOrder() {
# if NV_LITTLE_ENDIAN
return LittleEndian;
# else
return BigEndian;
# endif
}
/// Ctor.
Stream() : m_byteOrder(LittleEndian) { }
/// Virtual destructor.
virtual ~Stream() {}
/// Set byte order.
void setByteOrder(ByteOrder bo) { m_byteOrder = bo; }
/// Get byte order.
ByteOrder byteOrder() const { return m_byteOrder; }
/// Serialize the given data.
virtual uint serialize( void * data, uint len ) = 0;
/// Move to the given position in the archive.
virtual void seek( uint pos ) = 0;
/// Return the current position in the archive.
virtual uint tell() const = 0;
/// Return the current size of the archive.
virtual uint size() const = 0;
/// 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;
/// Return true if the stream is seekable.
virtual bool isSeekable() const = 0;
/// Return true if this is an input stream.
virtual bool isLoading() const = 0;
/// Return true if this is an output stream.
virtual bool isSaving() const = 0;
// friends
friend Stream & operator<<( Stream & s, bool & c ) {
# if NV_OS_DARWIN
nvStaticCheck(sizeof(bool) == 4);
uint8 b = c ? 1 : 0;
s.serialize( &b, 1 );
c = (b == 1);
# else
nvStaticCheck(sizeof(bool) == 1);
s.serialize( &c, 1 );
# endif
return s;
}
friend Stream & operator<<( Stream & s, char & c ) {
nvStaticCheck(sizeof(char) == 1);
s.serialize( &c, 1 );
return s;
}
friend Stream & operator<<( Stream & s, uint8 & c ) {
nvStaticCheck(sizeof(uint8) == 1);
s.serialize( &c, 1 );
return s;
}
friend Stream & operator<<( Stream & s, int8 & c ) {
nvStaticCheck(sizeof(int8) == 1);
s.serialize( &c, 1 );
return s;
}
friend Stream & operator<<( Stream & s, uint16 & c ) {
nvStaticCheck(sizeof(uint16) == 2);
return s.byteOrderSerialize( &c, 2 );
}
friend Stream & operator<<( Stream & s, int16 & c ) {
nvStaticCheck(sizeof(int16) == 2);
return s.byteOrderSerialize( &c, 2 );
}
friend Stream & operator<<( Stream & s, uint32 & c ) {
nvStaticCheck(sizeof(uint32) == 4);
return s.byteOrderSerialize( &c, 4 );
}
friend Stream & operator<<( Stream & s, int32 & c ) {
nvStaticCheck(sizeof(int32) == 4);
return s.byteOrderSerialize( &c, 4 );
}
friend Stream & operator<<( Stream & s, uint64 & c ) {
nvStaticCheck(sizeof(uint64) == 8);
return s.byteOrderSerialize( &c, 8 );
}
friend Stream & operator<<( Stream & s, int64 & c ) {
nvStaticCheck(sizeof(int64) == 8);
return s.byteOrderSerialize( &c, 8 );
}
friend Stream & operator<<( Stream & s, float & c ) {
nvStaticCheck(sizeof(float) == 4);
return s.byteOrderSerialize( &c, 4 );
}
friend Stream & operator<<( Stream & s, double & c ) {
nvStaticCheck(sizeof(double) == 8);
return s.byteOrderSerialize( &c, 8 );
}
protected:
/// Serialize in the stream byte order.
Stream & byteOrderSerialize( void * v, uint len ) {
if( m_byteOrder == getSystemByteOrder() ) {
serialize( v, len );
/// Ctor.
Stream() : m_byteOrder(LittleEndian) { }
/// Virtual destructor.
virtual ~Stream() {}
/// Set byte order.
void setByteOrder(ByteOrder bo) { m_byteOrder = bo; }
/// Get byte order.
ByteOrder byteOrder() const { return m_byteOrder; }
/// Serialize the given data.
virtual uint serialize( void * data, uint len ) = 0;
/// Move to the given position in the archive.
virtual void seek( uint pos ) = 0;
/// Return the current position in the archive.
virtual uint tell() const = 0;
/// Return the current size of the archive.
virtual uint size() const = 0;
/// 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;
/// Return true if the stream is seekable.
virtual bool isSeekable() const = 0;
/// Return true if this is an input stream.
virtual bool isLoading() const = 0;
/// Return true if this is an output stream.
virtual bool isSaving() const = 0;
// friends
friend Stream & operator<<( Stream & s, bool & c ) {
#if NV_OS_DARWIN
nvStaticCheck(sizeof(bool) == 4);
uint8 b = c ? 1 : 0;
s.serialize( &b, 1 );
c = (b == 1);
#else
nvStaticCheck(sizeof(bool) == 1);
s.serialize( &c, 1 );
#endif
return s;
}
friend Stream & operator<<( Stream & s, char & c ) {
nvStaticCheck(sizeof(char) == 1);
s.serialize( &c, 1 );
return s;
}
else {
for( uint i = len; i > 0; i-- ) {
serialize( (uint8 *)v + i - 1, 1 );
friend Stream & operator<<( Stream & s, uint8 & c ) {
nvStaticCheck(sizeof(uint8) == 1);
s.serialize( &c, 1 );
return s;
}
friend Stream & operator<<( Stream & s, int8 & c ) {
nvStaticCheck(sizeof(int8) == 1);
s.serialize( &c, 1 );
return s;
}
friend Stream & operator<<( Stream & s, uint16 & c ) {
nvStaticCheck(sizeof(uint16) == 2);
return s.byteOrderSerialize( &c, 2 );
}
friend Stream & operator<<( Stream & s, int16 & c ) {
nvStaticCheck(sizeof(int16) == 2);
return s.byteOrderSerialize( &c, 2 );
}
friend Stream & operator<<( Stream & s, uint32 & c ) {
nvStaticCheck(sizeof(uint32) == 4);
return s.byteOrderSerialize( &c, 4 );
}
friend Stream & operator<<( Stream & s, int32 & c ) {
nvStaticCheck(sizeof(int32) == 4);
return s.byteOrderSerialize( &c, 4 );
}
friend Stream & operator<<( Stream & s, uint64 & c ) {
nvStaticCheck(sizeof(uint64) == 8);
return s.byteOrderSerialize( &c, 8 );
}
friend Stream & operator<<( Stream & s, int64 & c ) {
nvStaticCheck(sizeof(int64) == 8);
return s.byteOrderSerialize( &c, 8 );
}
friend Stream & operator<<( Stream & s, float & c ) {
nvStaticCheck(sizeof(float) == 4);
return s.byteOrderSerialize( &c, 4 );
}
friend Stream & operator<<( Stream & s, double & c ) {
nvStaticCheck(sizeof(double) == 8);
return s.byteOrderSerialize( &c, 8 );
}
protected:
/// Serialize in the stream byte order.
Stream & byteOrderSerialize( void * v, uint len ) {
if( m_byteOrder == getSystemByteOrder() ) {
serialize( v, len );
}
else {
for( uint i = len; i > 0; i-- ) {
serialize( (uint8 *)v + i - 1, 1 );
}
}
return *this;
}
return *this;
}
private:
private:
ByteOrder m_byteOrder;
ByteOrder m_byteOrder;
};
};
} // nv namespace
#endif // NV_STREAM_H
#endif // NV_CORE_STREAM_H

@ -1,6 +1,6 @@
// This code is in the public domain -- castanyo@yahoo.es
// This code is in the public domain -- castano@gmail.com
#include <nvcore/TextReader.h>
#include "TextReader.h"
using namespace nv;

@ -1,11 +1,10 @@
// This code is in the public domain -- castanyo@yahoo.es
// This code is in the public domain -- castano@gmail.com
#ifndef NVCORE_TEXTREADER_H
#define NVCORE_TEXTREADER_H
#ifndef NV_CORE_TEXTREADER_H
#define NV_CORE_TEXTREADER_H
#include <nvcore/nvcore.h>
#include <nvcore/Stream.h>
#include <nvcore/Containers.h>
#include <nvcore/Stream.h>
namespace nv
{
@ -35,4 +34,4 @@ private:
} // nv namespace
#endif // NVCORE_TEXTREADER_H
#endif // NV_CORE_TEXTREADER_H

@ -1,6 +1,6 @@
// This code is in the public domain -- castanyo@yahoo.es
// This code is in the public domain -- castano@gmail.com
#include <nvcore/TextWriter.h>
#include "TextWriter.h"
using namespace nv;

@ -1,11 +1,10 @@
// This code is in the public domain -- castanyo@yahoo.es
// This code is in the public domain -- castano@gmail.com
#ifndef NVCORE_TEXTWRITER_H
#define NVCORE_TEXTWRITER_H
#ifndef NV_CORE_TEXTWRITER_H
#define NV_CORE_TEXTWRITER_H
#include <nvcore/nvcore.h>
#include <nvcore/Stream.h>
#include <nvcore/StrLib.h>
#include <nvcore/Stream.h>
namespace nv
{

@ -1,73 +0,0 @@
// This code is in the public domain -- castanyo@yahoo.es
#ifndef NV_CORE_THREADLOCALSTORAGE_H
#define NV_CORE_THREADLOCALSTORAGE_H
#include <nvcore/nvcore.h>
// ThreadLocal<Context> context;
//
// context.allocate();
//
// context = new Context();
// context->member();
// context = NULL;
//
// context.free();
#if NV_CC_GNUC
#elif NV_CC_MSVC
template <class T>
class ThreadLocal
{
public:
ThreadLocal() : index(0) {}
~ThreadLocal() { nvCheck(index == 0); }
void allocate()
{
index = TlsAlloc();
}
void free()
{
delete ptr();
TlsFree(index);
index = 0;
}
bool isValid()
{
return index != 0;
}
void operator=( T * p )
{
if (p != ptr())
{
delete ptr();
TlsSetValue(index, p);
}
}
T * operator -> () const
{
return ptr();
}
T & operator*() const
{
return *ptr();
}
T * ptr() const {
return static_cast<T *>(TlsGetValue(index));
}
DWORD index;
};
#endif // NV_CC_MSVC
#endif // NV_CORE_THREADLOCALSTORAGE_H

@ -1,6 +1,6 @@
// This code is in the public domain -- castanyo@yahoo.es
// This code is in the public domain -- castano@gmail.com
#include <nvcore/Tokenizer.h>
#include "Tokenizer.h"
#include <nvcore/StrLib.h>
#include <stdio.h> // vsscanf

@ -1,12 +1,11 @@
// This code is in the public domain -- castanyo@yahoo.es
// This code is in the public domain -- castano@gmail.com
#ifndef NV_CORE_TOKENIZER_H
#define NV_CORE_TOKENIZER_H
#include <nvcore/nvcore.h>
#include <nvcore/StrLib.h>
#include <nvcore/Stream.h>
#include <nvcore/TextReader.h>
#include <nvcore/StrLib.h>
namespace nv
{

@ -22,7 +22,7 @@
// Platform definitions
#include "poshlib/posh.h"
#include <posh.h>
// OS:
// NV_OS_WIN32
@ -126,6 +126,9 @@
#define NV_DO_STRING_JOIN2(arg1, arg2) arg1 ## arg2
#define NV_STRING_JOIN3(arg1, arg2, arg3) NV_DO_STRING_JOIN3(arg1, arg2, arg3)
#define NV_DO_STRING_JOIN3(arg1, arg2, arg3) arg1 ## arg2 ## arg3
#define NV_STRING2(x) #x
#define NV_STRING(x) NV_STRING2(x)
#define NV_FILE_LINE __FILE__ "(" NV_STRING(__LINE__) ") : "
// Startup initialization macro.
#define NV_AT_STARTUP(some_code) \

@ -1,7 +0,0 @@
SET(POSHLIB_SRCS
posh.c
posh.h)
ADD_LIBRARY(posh STATIC ${POSHLIB_SRCS})

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

@ -23,7 +23,6 @@ SET(IMAGE_SRCS
NormalMap.h
NormalMap.cpp
NormalMipmap.h
NormalMipmap.cpp
PsdFile.h
TgaFile.h
ColorSpace.h

@ -12,7 +12,7 @@
#include <nvcore/Containers.h>
#include <nvcore/StrLib.h>
#include <nvcore/StdStream.h>
//#include <nvcore/Tokenizer.h> // @@ Disable temporarily
#include <nvcore/Tokenizer.h>
#include <nvcore/TextWriter.h>
// Extern
@ -186,14 +186,12 @@ FloatImage * nv::ImageIO::loadFloat(const char * fileName, Stream & s)
}
#endif
/* // @@ Disable temporarily
if (strCaseCmp(extension, ".pfm") == 0) {
return loadFloatPFM(fileName, s);
}
if (strCaseCmp(extension, ".hdr") == 0) {
return loadGridFloat(fileName, s);
}
*/
return NULL;
}
@ -1534,7 +1532,6 @@ bool nv::ImageIO::saveFloatEXR(const char * fileName, const FloatImage * fimage,
#endif // defined(HAVE_OPENEXR)
#if 0 // @@ Disable temporarily.
FloatImage * nv::ImageIO::loadFloatPFM(const char * fileName, Stream & s)
{
@ -1723,7 +1720,6 @@ NVIMAGE_API FloatImage * nv::ImageIO::loadGridFloat(const char * fileName, Strea
return fimage.release();
}
#endif
#if 0

@ -52,7 +52,7 @@ namespace nv
NVIMAGE_API bool saveFloatEXR(const char * fileName, const FloatImage * fimage, uint base_component, uint num_components);
#endif
/*
NVIMAGE_API FloatImage * loadFloatPFM(const char * fileName, Stream & s);
NVIMAGE_API bool saveFloatPFM(const char * fileName, const FloatImage * fimage, uint base_component, uint num_components);
@ -60,7 +60,7 @@ namespace nv
// Expects: 1) fileName will be an ".hdr" header file, 2) there will also exist a corresponding float data
// blob in a ".flt" file. (This is what USGS gives you.)
NVIMAGE_API FloatImage * loadGridFloat(const char * fileName, Stream & s);
*/
} // ImageIO namespace
} // nv namespace

@ -1,99 +0,0 @@
// This code is in the public domain -- castanyo@yahoo.es
#include <nvimage/NormalMipmap.h>
#include <nvimage/FloatImage.h>
#include <nvmath/Montecarlo.h>
#include <nvmath/SphericalHarmonic.h>
#include <nvcore/Ptr.h>
using namespace nv;
FloatImage * nv::createNormalMipmapMap(const FloatImage * img)
{
nvDebugCheck(img != NULL);
uint w = img->width();
uint h = img->height();
uint hw = w / 2;
uint hh = h / 2;
FloatImage dotImg;
dotImg.allocate(1, w, h);
FloatImage shImg;
shImg.allocate(9, hw, hh);
SampleDistribution distribution(256);
const uint sampleCount = distribution.sampleCount();
for (uint d = 0; d < sampleCount; d++)
{
const float * xChannel = img->channel(0);
const float * yChannel = img->channel(1);
const float * zChannel = img->channel(2);
Vector3 dir = distribution.sampleDir(d);
Sh2 basis;
basis.eval(dir);
for(uint i = 0; i < w*h; i++)
{
Vector3 normal(xChannel[i], yChannel[i], zChannel[i]);
normal = normalizeSafe(normal, Vector3(zero), 0.0f);
dotImg.setPixel(dot(dir, normal), d);
}
// @@ It would be nice to have a fastDownSample that took an existing image as an argument, to avoid allocations.
AutoPtr<FloatImage> dotMip(dotImg.fastDownSample());
for(uint p = 0; p < hw*hh; p++)
{
float f = dotMip->pixel(p);
// Project irradiance to sh basis and accumulate.
for (uint i = 0; i < 9; i++)
{
float & sum = shImg.channel(i)[p];
sum += f * basis.elemAt(i);
}
}
}
FloatImage * normalMipmap = new FloatImage;
normalMipmap->allocate(4, hw, hh);
// Precompute the clamped cosine radiance transfer.
Sh2 prt;
prt.cosineTransfer();
// Allocate outside the loop.
Sh2 sh;
for(uint p = 0; p < hw*hh; p++)
{
for (uint i = 0; i < 9; i++)
{
sh.elemAt(i) = shImg.channel(i)[p];
}
// Convolve sh irradiance by radiance transfer.
sh *= prt;
// Now sh(0) is the ambient occlusion.
// and sh(1) is the normal direction.
// Should we use SVD to fit only the normals to the SH?
}
return normalMipmap;
}

@ -0,0 +1,102 @@
// This code is in the public domain -- castano@gmail.com
#include "TiledImage.h"
#include <nvcore/StdStream.h>
using namespace nv;
namespace
{
// MRU helpers:
// ...
}
bool Tile::load(const char * name)
{
StdInputStream stream(name);
if (stream.isError()) {
return false;
}
uint header;
stream << header;
if (header == 'NVTC') {
return false;
}
uint count;
stream << count;
if (count != w*h) {
return false;
}
const uint size = count * sizeof(float);
return stream.serialize(data, size) == size;
}
bool Tile::unload(const char * name)
{
StdOutputStream stream(name);
if (stream.isError()) {
return false;
}
uint header = 'NVTC';
uint count = w * h;
const uint size = w * h * sizeof(float);
stream << header << count;
return stream.serialize(data, size) == size;
}
TiledImage::TiledImage()
{
}
void TiledImage::allocate(uint c, uint w, uint h, uint pageCount)
{
// Allocate page map:
const uint pw = ((w + TILE_SIZE - 1) / TILE_SIZE);
const uint ph = ((h + TILE_SIZE - 1) / TILE_SIZE);
const uint size = c * pw * ph;
m_pageMap.resize(size);
m_residentArray.resize(pageCount, ~0);
}
void TiledImage::prefetch(uint c, uint x, uint y)
{
}
void TiledImage::prefetch(uint c, uint x, uint y, uint w, uint h)
{
}
void TiledImage::loadPage(uint x, uint y)
{
const uint pw = ((w + TILE_SIZE - 1) / TILE_SIZE);
const uint ph = ((h + TILE_SIZE - 1) / TILE_SIZE);
nvDebugCheck(x < pw);
nvDebugCheck(y < ph);
}

@ -0,0 +1,152 @@
// This code is in the public domain -- castano@gmail.com
#ifndef NV_IMAGE_TILEDIMAGE_H
#define NV_IMAGE_TILEDIMAGE_H
#include <nvcore/Debug.h>
#include <nvcore/StrLib.h>
#include <nvimage/nvimage.h>
// For simplicity the tile size is fixed at compile time.
#define TILE_SIZE 256
// 256 * 256 * 4 = 2^(8+8+2) = 2^18 = 256 KB
// 512 * 512 * 4 = 2^(9+9+2) = 2^20 = 1 MB
namespace nv
{
#if 0
struct ImageConcept
{
float pixel(uint x, uint y) const;
};
enum WrapMode {
WrapMode_Clamp,
WrapMode_Repeat,
WrapMode_Mirror
};
template <class T>
class Sampler
{
// ...
};
#endif
class Tile
{
Tile(uint x, uint y, uint w, uint h) : xoffset(x), yoffset(y), w(w), h(h)
{
data = new float[w*h];
}
~Tile()
{
delete [] data;
}
uint size() const
{
return w * h * sizeof(float);
}
float pixel(uint x, uint y) const
{
x -= xoffset;
y -= yoffset;
nvDebugCheck (x < w);
nvDebugCheck (y < h);
return data[y * w + x];
}
bool load(const char * name);
void unload(const char * name);
uint xoffset, yoffset;
uint w, h;
float * data;
};
class TiledImage
{
public:
TiledImage();
void allocate(uint c, uint w, uint h, uint pageCount);
uint componentCount() const { return m_componentCount; }
uint width() const { return m_width; }
uint height() const { return m_height; }
uint pageCount() const { return m_residentArray.count(); }
void prefetch(uint c, uint x, uint y);
void prefetch(uint c, uint x, uint y, uint w, uint h);
float pixel(uint c, uint x, uint y);
private:
Tile * tileAt(uint c, uint x, uint y);
Tile * tileAt(uint idx);
uint loadPage(uint x, uint y);
void unloadPage(Tile *);
uint addAndReplace(uint newPage);
private:
uint m_componentCount;
uint m_width;
uint m_height;
struct Page {
Page() : tile(NULL) {}
String tmpFileName;
Tile * tile;
};
mutable Array<Page> m_pageMap;
mutable Array<uint> m_residentArray; // MRU
};
inline float TiledImage::pixel(uint c, uint x, uint y)
{
nvDebugCheck (c < m_componentCount);
nvDebugCheck (x < m_width);
nvDebugCheck (y < m_height);
uint px = x / TILE_SIZE;
uint py = y / TILE_SIZE;
Tile * tile = tileAt(c, px, py);
if (tile == NULL) {
tile = loadPage(c, px, py);
}
return tile->pixel(x, y);
}
inline Tile * TiledImage::tileAt(uint c, uint x, uint y)
{
uint idx = (c * h + y) * w + x;
return tileAt(idx);
}
inline Tile * TiledImage::tileAt(uint idx)
{
return m_pageMap[idx].tile;
}
} // nv namespace
#endif // NV_IMAGE_TILEDIMAGE_H

@ -1,228 +0,0 @@
// This code is in the public domain -- castanyo@yahoo.es
#include <nvmath/Basis.h>
using namespace nv;
/// Normalize basis vectors.
void Basis::normalize(float epsilon /*= NV_EPSILON*/)
{
normal = ::normalize(normal, epsilon);
tangent = ::normalize(tangent, epsilon);
bitangent = ::normalize(bitangent, epsilon);
}
/// Gram-Schmidt orthogonalization.
/// @note Works only if the vectors are close to orthogonal.
void Basis::orthonormalize(float epsilon /*= NV_EPSILON*/)
{
// N' = |N|
// T' = |T - (N' dot T) N'|
// B' = |B - (N' dot B) N' - (T' dot B) T'|
normal = ::normalize(normal, epsilon);
tangent -= normal * dot(normal, tangent);
tangent = ::normalize(tangent, epsilon);
bitangent -= normal * dot(normal, bitangent);
bitangent -= tangent * dot(tangent, bitangent);
bitangent = ::normalize(bitangent, epsilon);
}
/// Robust orthonormalization.
/// Returns an orthonormal basis even when the original is degenerate.
void Basis::robustOrthonormalize(float epsilon /*= NV_EPSILON*/)
{
if (length(normal) < epsilon)
{
normal = cross(tangent, bitangent);
if (length(normal) < epsilon)
{
tangent = Vector3(1, 0, 0);
bitangent = Vector3(0, 1, 0);
normal = Vector3(0, 0, 1);
return;
}
}
normal = nv::normalize(normal, epsilon);
tangent -= normal * dot(normal, tangent);
bitangent -= normal * dot(normal, bitangent);
if (length(tangent) < epsilon)
{
if (length(bitangent) < epsilon)
{
buildFrameForDirection(normal);
}
else
{
tangent = cross(bitangent, normal);
nvCheck(isNormalized(tangent, epsilon));
}
}
else
{
#if 0
tangent = nv::normalize(tangent, epsilon);
bitangent -= tangent * dot(tangent, bitangent);
if (length(bitangent) < epsilon)
{
bitangent = cross(tangent, normal);
nvCheck(isNormalized(bitangent));
}
else
{
bitangent = nv::normalize(bitangent, epsilon);
}
#else
if (length(bitangent) < epsilon)
{
bitangent = cross(tangent, normal);
nvCheck(isNormalized(bitangent));
}
else
{
tangent = nv::normalize(tangent);
bitangent = nv::normalize(bitangent);
Vector3 bisector;
if (length(tangent + bitangent) < epsilon)
{
bisector = tangent;
}
else
{
bisector = nv::normalize(tangent + bitangent);
}
Vector3 axis = cross(bisector, normal);
nvDebugCheck(isNormalized(axis, epsilon));
nvDebugCheck(equal(dot(axis, tangent), -dot(axis, bitangent), epsilon));
if (dot(axis, tangent) > 0)
{
tangent = nv::normalize(bisector + axis);
bitangent = nv::normalize(bisector - axis);
}
else
{
tangent = nv::normalize(bisector - axis);
bitangent = nv::normalize(bisector + axis);
}
}
#endif
}
/*// Check vector lengths.
if (!isNormalized(normal, epsilon))
{
nvDebug("%f %f %f\n", normal.x(), normal.y(), normal.z());
nvDebug("%f %f %f\n", tangent.x(), tangent.y(), tangent.z());
nvDebug("%f %f %f\n", bitangent.x(), bitangent.y(), bitangent.z());
}*/
nvCheck(isNormalized(normal, epsilon));
nvCheck(isNormalized(tangent, epsilon));
nvCheck(isNormalized(bitangent, epsilon));
// Check vector angles.
nvCheck(equal(dot(normal, tangent), 0.0f, epsilon));
nvCheck(equal(dot(normal, bitangent), 0.0f, epsilon));
nvCheck(equal(dot(tangent, bitangent), 0.0f, epsilon));
// Check vector orientation.
const float det = dot(cross(normal, tangent), bitangent);
nvCheck(equal(det, 1.0f, epsilon) || equal(det, -1.0f, epsilon));
}
/// Build an arbitrary frame for the given direction.
void Basis::buildFrameForDirection(Vector3::Arg d)
{
nvCheck(isNormalized(d));
normal = d;
// Choose minimum axis.
if (fabsf(normal.x()) < fabsf(normal.y()) && fabsf(normal.x()) < fabsf(normal.z()))
{
tangent = Vector3(1, 0, 0);
}
else if (fabsf(normal.y()) < fabsf(normal.z()))
{
tangent = Vector3(0, 1, 0);
}
else
{
tangent = Vector3(0, 0, 1);
}
// Ortogonalize
tangent -= normal * dot(normal, tangent);
tangent = ::normalize(tangent);
bitangent = cross(normal, tangent);
}
bool Basis::isValid() const
{
if (equal(normal, Vector3(zero))) return false;
if (equal(tangent, Vector3(zero))) return false;
if (equal(bitangent, Vector3(zero))) return false;
if (equal(determinant(), 0.0f)) return false;
return true;
}
/// Transform by this basis. (From this basis to object space).
Vector3 Basis::transform(Vector3::Arg v) const
{
Vector3 o = tangent * v.x();
o += bitangent * v.y();
o += normal * v.z();
return o;
}
/// Transform by the transpose. (From object space to this basis).
Vector3 Basis::transformT(Vector3::Arg v)
{
return Vector3(dot(tangent, v), dot(bitangent, v), dot(normal, v));
}
/// Transform by the inverse. (From object space to this basis).
/// @note Uses Cramer's rule so the inverse is not accurate if the basis is ill-conditioned.
Vector3 Basis::transformI(Vector3::Arg v) const
{
const float det = determinant();
nvDebugCheck(!equal(det, 0.0f, 0.0f));
const float idet = 1.0f / det;
// Rows of the inverse matrix.
Vector3 r0(
(bitangent.y() * normal.z() - bitangent.z() * normal.y()),
-(bitangent.x() * normal.z() - bitangent.z() * normal.x()),
(bitangent.x() * normal.y() - bitangent.y() * normal.x()));
Vector3 r1(
-(tangent.y() * normal.z() - tangent.z() * normal.y()),
(tangent.x() * normal.z() - tangent.z() * normal.x()),
-(tangent.x() * normal.y() - tangent.y() * normal.x()));
Vector3 r2(
(tangent.y() * bitangent.z() - tangent.z() * bitangent.y()),
-(tangent.x() * bitangent.z() - tangent.z() * bitangent.x()),
(tangent.x() * bitangent.y() - tangent.y() * bitangent.x()));
return Vector3(dot(v, r0), dot(v, r1), dot(v, r2)) * idet;
}

@ -1,81 +0,0 @@
// This code is in the public domain -- castanyo@yahoo.es
#ifndef NV_MATH_BASIS_H
#define NV_MATH_BASIS_H
#include <nvmath/nvmath.h>
#include <nvmath/Vector.h>
#include <nvmath/Matrix.h>
namespace nv
{
/// Basis class to compute tangent space basis, ortogonalizations and to
/// transform vectors from one space to another.
class Basis
{
public:
/// Create a null basis.
Basis() : tangent(0, 0, 0), bitangent(0, 0, 0), normal(0, 0, 0) {}
/// Create a basis given three vectors.
Basis(Vector3::Arg n, Vector3::Arg t, Vector3::Arg b) : tangent(t), bitangent(b), normal(n) {}
/// Create a basis with the given tangent vectors and the handness.
Basis(Vector3::Arg n, Vector3::Arg t, float sign)
{
build(n, t, sign);
}
NVMATH_API void normalize(float epsilon = NV_EPSILON);
NVMATH_API void orthonormalize(float epsilon = NV_EPSILON);
NVMATH_API void robustOrthonormalize(float epsilon = NV_EPSILON);
NVMATH_API void buildFrameForDirection(Vector3::Arg d);
/// Calculate the determinant [ F G N ] to obtain the handness of the basis.
float handness() const
{
return determinant() > 0.0f ? 1.0f : -1.0f;
}
/// Build a basis from 2 vectors and a handness flag.
void build(Vector3::Arg n, Vector3::Arg t, float sign)
{
normal = n;
tangent = t;
bitangent = sign * cross(t, n);
}
/// Compute the determinant of this basis.
float determinant() const
{
return
tangent.x() * bitangent.y() * normal.z() - tangent.z() * bitangent.y() * normal.x() +
tangent.y() * bitangent.z() * normal.x() - tangent.y() * bitangent.x() * normal.z() +
tangent.z() * bitangent.x() * normal.y() - tangent.x() * bitangent.z() * normal.y();
}
bool isValid() const;
// Get transform matrix for this basis.
NVMATH_API Matrix matrix() const;
// Transform by this basis. (From this basis to object space).
NVMATH_API Vector3 transform(Vector3::Arg v) const;
// Transform by the transpose. (From object space to this basis).
NVMATH_API Vector3 transformT(Vector3::Arg v);
// Transform by the inverse. (From object space to this basis).
NVMATH_API Vector3 transformI(Vector3::Arg v) const;
Vector3 tangent;
Vector3 bitangent;
Vector3 normal;
};
} // nv namespace
#endif // NV_MATH_BASIS_H

@ -1,97 +0,0 @@
// This code is in the public domain -- castanyo@yahoo.es
#include "Bezier.h"
using namespace nv;
static void deCasteljau(float u, Vector3::Arg p0, Vector3::Arg p1, Vector3::Arg p2, Vector3::Arg p3, Vector3 * p)
{
Vector3 q0 = lerp(p0, p1, u);
Vector3 q1 = lerp(p1, p2, u);
Vector3 q2 = lerp(p2, p3, u);
Vector3 r0 = lerp(q0, q1, u);
Vector3 r1 = lerp(q1, q2, u);
*p = lerp(r0, r1, u);
}
static void deCasteljau(float u, Vector3::Arg p0, Vector3::Arg p1, Vector3::Arg p2, Vector3::Arg p3, Vector3 * p, Vector3 * dp)
{
Vector3 q0 = lerp(p0, p1, u);
Vector3 q1 = lerp(p1, p2, u);
Vector3 q2 = lerp(p2, p3, u);
Vector3 r0 = lerp(q0, q1, u);
Vector3 r1 = lerp(q1, q2, u);
*dp = r0 - r1;
*p = lerp(r0, r1, u);
}
void nv::evaluateCubicBezierPatch(float u, float v,
Vector3::Arg p0, Vector3::Arg p1, Vector3::Arg p2, Vector3::Arg p3,
Vector3::Arg p4, Vector3::Arg p5, Vector3::Arg p6, Vector3::Arg p7,
Vector3::Arg p8, Vector3::Arg p9, Vector3::Arg pA, Vector3::Arg pB,
Vector3::Arg pC, Vector3::Arg pD, Vector3::Arg pE, Vector3::Arg pF,
Vector3 * pos, Vector3 * du, Vector3 * dv)
{
#if 0
Vector2 L0(1-u,1-v);
Vector2 L1(u,v);
Vector2 Q0 = L0 * L0;
Vector2 Q1 = 2 * L0 * L1;
Vector2 Q2 = L1 * L1;
Vector2 B0 = L0 * L0 * L0;
Vector2 B1 = 3 * L0 * L0 * L1;
Vector2 B2 = 3 * L1 * L1 * L0;
Vector2 B3 = L1 * L1 * L1;
*pos =
(B0.x() * p0 + B1.x() * p1 + B2.x() * p2 + B3.x() * p3) * B0.y() +
(B0.x() * p4 + B1.x() * p5 + B2.x() * p6 + B3.x() * p7) * B1.y() +
(B0.x() * p8 + B1.x() * p9 + B2.x() * pA + B3.x() * pB) * B2.y() +
(B0.x() * pC + B1.x() * pD + B2.x() * pE + B3.x() * pF) * B3.y();
*du =
((p0-p1) * B0.y() + (p4-p5) * B1.y() + (p8-p9) * B2.y() + (pC-pD) * B3.y()) * Q0.x() +
((p1-p2) * B0.y() + (p5-p6) * B1.y() + (p9-pA) * B2.y() + (pD-pE) * B3.y()) * Q1.x() +
((p2-p3) * B0.y() + (p6-p7) * B1.y() + (pA-pB) * B2.y() + (pE-pF) * B3.y()) * Q2.x();
*dv =
((p0-p4) * B0.x() + (p1-p5) * B1.x() + (p2-p6) * B2.x() + (p3-p7) * B3.x()) * Q0.y() +
((p4-p8) * B0.x() + (p5-p9) * B1.x() + (p6-pA) * B2.x() + (p7-pB) * B3.x()) * Q1.y() +
((p8-pC) * B0.x() + (p9-pD) * B1.x() + (pA-pE) * B2.x() + (pB-pF) * B3.x()) * Q2.y();
#else
Vector3 t0, t1, t2, t3;
Vector3 q0, q1, q2, q3;
deCasteljau(u, p0, p1, p2, p3, &q0, &t0);
deCasteljau(u, p4, p5, p6, p7, &q1, &t1);
deCasteljau(u, p8, p9, pA, pB, &q2, &t2);
deCasteljau(u, pC, pD, pE, pF, &q3, &t3);
deCasteljau(v, q0, q1, q2, q3, pos, dv);
deCasteljau(v, t0, t1, t2, t3, du);
#endif
}
void nv::degreeElevate(Vector3::Arg p0, Vector3::Arg p1, Vector3::Arg p2, Vector3::Arg p3,
Vector3 * q0, Vector3 * q1, Vector3 * q2, Vector3 * q3, Vector3 * q4)
{
}
void nv::evaluateQuarticBezierTriangle(float u, float v,
Vector3::Arg p0, Vector3::Arg p1, Vector3::Arg p2, Vector3::Arg p3, Vector3::Arg p4,
Vector3::Arg p5, Vector3::Arg p6, Vector3::Arg p7, Vector3::Arg p8,
Vector3::Arg p9, Vector3::Arg pA, Vector3::Arg pB,
Vector3::Arg pC, Vector3::Arg pD,
Vector3::Arg pE,
Vector3 * pos, Vector3 * du, Vector3 * dv)
{
}

@ -1,33 +0,0 @@
// This code is in the public domain -- castanyo@yahoo.es
#ifndef NV_MATH_BEZIER_H
#define NV_MATH_BEZIER_H
#include <nvmath/nvmath.h>
#include <nvmath/Vector.h>
namespace nv
{
void evaluateCubicBezierPatch(float u, float v,
Vector3::Arg p0, Vector3::Arg p1, Vector3::Arg p2, Vector3::Arg p3,
Vector3::Arg p4, Vector3::Arg p5, Vector3::Arg p6, Vector3::Arg p7,
Vector3::Arg p8, Vector3::Arg p9, Vector3::Arg pA, Vector3::Arg pB,
Vector3::Arg pC, Vector3::Arg pD, Vector3::Arg pE, Vector3::Arg pF,
Vector3 * pos, Vector3 * du, Vector3 * dv);
void degreeElevate(Vector3::Arg p0, Vector3::Arg p1, Vector3::Arg p2, Vector3::Arg p3,
Vector3 * q0, Vector3 * q1, Vector3 * q2, Vector3 * q3, Vector3 * q4);
void evaluateQuarticBezierTriangle(float u, float v,
Vector3::Arg p0, Vector3::Arg p1, Vector3::Arg p2, Vector3::Arg p3, Vector3::Arg p4,
Vector3::Arg p5, Vector3::Arg p6, Vector3::Arg p7, Vector3::Arg p8,
Vector3::Arg p9, Vector3::Arg pA, Vector3::Arg pB,
Vector3::Arg pC, Vector3::Arg pD,
Vector3::Arg pE,
Vector3 * pos, Vector3 * du, Vector3 * dv);
} // nv namespace
#endif // NV_MATH_BEZIER_H

@ -4,24 +4,12 @@ SET(MATH_SRCS
nvmath.h
Vector.h
Matrix.h
Quaternion.h
Plane.h Plane.cpp
Box.h
Color.h
Frustum.h Frustum.cpp
Montecarlo.h Montecarlo.cpp
Random.h Random.cpp
SphericalHarmonic.h SphericalHarmonic.cpp
Basis.h Basis.cpp
Triangle.h Triangle.cpp TriBox.cpp
Polygon.h Polygon.cpp
TypeSerialization.h TypeSerialization.cpp
Sparse.h Sparse.cpp
Solver.h Solver.cpp
KahanSum.h
Half.h Half.cpp
Fitting.h Fitting.cpp
Bezier.h Bezier.cpp)
Fitting.h Fitting.cpp)
INCLUDE_DIRECTORIES(${CMAKE_CURRENT_SOURCE_DIR})

@ -4,12 +4,51 @@
#include <nvcore/Algorithms.h> // max
#include <nvcore/Containers.h> // swap
#include <float.h> // FLT_MAX
using namespace nv;
// @@ Move to EigenSolver.h
static inline Vector3 firstEigenVector_PowerMethod(const float *__restrict matrix)
{
if (matrix[0] == 0 || matrix[3] == 0 || matrix[5] == 0)
{
return Vector3(zero);
}
const int NUM = 8;
Vector3 v(1, 1, 1);
for (int i = 0; i < NUM; i++)
{
float x = v.x() * matrix[0] + v.y() * matrix[1] + v.z() * matrix[2];
float y = v.x() * matrix[1] + v.y() * matrix[3] + v.z() * matrix[4];
float z = v.x() * matrix[2] + v.y() * matrix[4] + v.z() * matrix[5];
float norm = max(max(x, y), z);
v = Vector3(x, y, z) / norm;
}
return v;
}
Vector3 nv::ComputeCentroid(int n, const Vector3 * points, const float * weights, Vector3::Arg metric)
Vector3 nv::Fit::computeCentroid(int n, const Vector3 *__restrict points)
{
Vector3 centroid(zero);
for (int i = 0; i < n; i++)
{
centroid += points[i];
}
centroid /= float(n);
return centroid;
}
Vector3 nv::Fit::computeCentroid(int n, const Vector3 *__restrict points, const float *__restrict weights, Vector3::Arg metric)
{
Vector3 centroid(zero);
float total = 0.0f;
@ -25,10 +64,36 @@ Vector3 nv::ComputeCentroid(int n, const Vector3 * points, const float * weights
}
void nv::ComputeCovariance(int n, const Vector3 * points, const float * weights, Vector3::Arg metric, float * covariance)
Vector3 nv::Fit::computeCovariance(int n, const Vector3 *__restrict points, float *__restrict covariance)
{
// compute the centroid
Vector3 centroid = computeCentroid(n, points);
// compute covariance matrix
for (int i = 0; i < 6; i++)
{
covariance[i] = 0.0f;
}
for (int i = 0; i < n; i++)
{
Vector3 v = points[i] - centroid;
covariance[0] += v.x() * v.x();
covariance[1] += v.x() * v.y();
covariance[2] += v.x() * v.z();
covariance[3] += v.y() * v.y();
covariance[4] += v.y() * v.z();
covariance[5] += v.z() * v.z();
}
return centroid;
}
Vector3 nv::Fit::computeCovariance(int n, const Vector3 *__restrict points, const float *__restrict weights, Vector3::Arg metric, float *__restrict covariance)
{
// compute the centroid
Vector3 centroid = ComputeCentroid(n, points, weights, metric);
Vector3 centroid = computeCentroid(n, points, weights, metric);
// compute covariance matrix
for (int i = 0; i < 6; i++)
@ -48,43 +113,57 @@ void nv::ComputeCovariance(int n, const Vector3 * points, const float * weights,
covariance[4] += a.y()*b.z();
covariance[5] += a.z()*b.z();
}
return centroid;
}
Vector3 nv::Fit::computePrincipalComponent(int n, const Vector3 *__restrict points)
{
float matrix[6];
computeCovariance(n, points, matrix);
return firstEigenVector_PowerMethod(matrix);
}
Vector3 nv::Fit::computePrincipalComponent(int n, const Vector3 *__restrict points, const float *__restrict weights, Vector3::Arg metric)
{
float matrix[6];
computeCovariance(n, points, weights, metric, matrix);
return firstEigenVector_PowerMethod(matrix);
}
Vector3 nv::ComputePrincipalComponent(int n, const Vector3 * points, const float * weights, Vector3::Arg metric)
Plane nv::Fit::bestPlane(int n, const Vector3 *__restrict points)
{
// compute the centroid and covariance
float matrix[6];
ComputeCovariance(n, points, weights, metric, matrix);
Vector3 centroid = computeCovariance(n, points, matrix);
if (matrix[0] == 0 || matrix[3] == 0 || matrix[5] == 0)
{
return Vector3(zero);
// If no plane defined, then return a horizontal plane.
return Plane(Vector3(0, 0, 1), centroid);
}
const int NUM = 8;
Vector3 v(1, 1, 1);
for (int i = 0; i < NUM; i++)
{
float x = v.x() * matrix[0] + v.y() * matrix[1] + v.z() * matrix[2];
float y = v.x() * matrix[1] + v.y() * matrix[3] + v.z() * matrix[4];
float z = v.x() * matrix[2] + v.y() * matrix[4] + v.z() * matrix[5];
float norm = max(max(x, y), z);
v = Vector3(x, y, z) / norm;
}
#pragma message(NV_FILE_LINE "TODO: need to write an eigensolver!")
return v;
}
// - Numerical Recipes in C is a good reference. Householder transforms followed by QL decomposition seems to be the best approach.
// - The one from magic-tools is now LGPL. For the 3D case it uses a cubic root solver, which is not very accurate.
// - Charles' Galaxy3 contains an implementation of the tridiagonalization method, but is under BPL.
//EigenSolver3 solver(matrix);
return Plane();
}
int nv::Compute4Means(int n, const Vector3 * points, const float * weights, Vector3::Arg metric, Vector3 * cluster)
int nv::Fit::compute4Means(int n, const Vector3 *__restrict points, const float *__restrict weights, Vector3::Arg metric, Vector3 *__restrict cluster)
{
Vector3 centroid = ComputeCentroid(n, points, weights, metric);
// Compute principal component.
Vector3 principal = ComputePrincipalComponent(n, points, weights, metric);
float matrix[6];
Vector3 centroid = computeCovariance(n, points, weights, metric, matrix);
Vector3 principal = firstEigenVector_PowerMethod(matrix);
// Pick initial solution.
int mini, maxi;

@ -5,16 +5,26 @@
#include <nvmath/nvmath.h>
#include <nvmath/Vector.h>
#include <nvmath/Plane.h>
namespace nv
{
namespace Fit
{
Vector3 computeCentroid(int n, const Vector3 * points);
Vector3 computeCentroid(int n, const Vector3 * points, const float * weights, Vector3::Arg metric);
Vector3 ComputeCentroid(int n, const Vector3 * points, const float * weights, Vector3::Arg metric);
void ComputeCovariance(int n, const Vector3 * points, const float * weights, Vector3::Arg metric, float * covariance);
Vector3 ComputePrincipalComponent(int n, const Vector3 * points, const float * weights, Vector3::Arg metric);
Vector3 computeCovariance(int n, const Vector3 * points, float * covariance);
Vector3 computeCovariance(int n, const Vector3 * points, const float * weights, Vector3::Arg metric, float * covariance);
// Returns number of clusters [1-4].
int Compute4Means(int n, const Vector3 * points, const float * weights, Vector3::Arg metric, Vector3 * cluster);
Vector3 computePrincipalComponent(int n, const Vector3 * points);
Vector3 computePrincipalComponent(int n, const Vector3 * points, const float * weights, Vector3::Arg metric);
Plane bestPlane(int n, const Vector3 * points);
// Returns number of clusters [1-4].
int compute4Means(int n, const Vector3 * points, const float * weights, Vector3::Arg metric, Vector3 * cluster);
}
} // nv namespace

@ -1,76 +0,0 @@
// This code is in the public domain -- castanyo@yahoo.es
#include "Frustum.h"
#include "Box.h"
#include "Matrix.h"
namespace nv
{
Frustum::Frustum(float fovy, float aspect, float near, float far)
{
// Define a frustum looking along the -ve z axis.
planes[NEAR] = Plane(Vector3(0,0,1), near);
planes[FAR] = Plane(Vector3(0,0,-1), far);
const Vector3 origin(zero);
const float tanfy = tan(fovy/2.0f);
planes[TOP] = Plane(Vector3( 1.0f, 0.0f, tanfy * aspect), origin);
planes[BOTTOM] = Plane(Vector3(-1.0f, 0.0f, tanfy * aspect), origin);
planes[RIGHT] = Plane(Vector3(0.0f, 1.0f, tanfy), origin);
planes[LEFT] = Plane(Vector3(0.0f, -1.0f, tanfy), origin);
for(int p = 0; p < Frustum::PLANE_COUNT; ++p)
planes[p] = normalize(planes[p]);
}
static void getAllCorners(const Box& boxy, Vector3 c[])
{
c[0] = boxy.minCorner();
c[1] = boxy.maxCorner();
c[2] = Vector3(c[0].x(), c[1].y(), c[0].z());
c[3] = Vector3(c[0].x(), c[1].y(), c[1].z());
c[4] = Vector3(c[0].x(), c[0].y(), c[1].z());
c[5] = Vector3(c[1].x(), c[1].y(), c[0].z());
c[6] = Vector3(c[1].x(), c[0].y(), c[0].z());
c[7] = Vector3(c[1].x(), c[0].y(), c[1].z());
}
bool Frustum::intersects(const Box& boxy) const
{
const int N_CORNERS = 8;
Vector3 boxCorners[N_CORNERS];
getAllCorners(boxy, boxCorners);
// test all 8 corners against the 6 sides
// if all points are behind 1 specific plane, we are out
// if we are in with all points, then we are fully in
for(int p = 0; p < Frustum::PLANE_COUNT; ++p)
{
int iInCount = N_CORNERS;
for(int i = 0; i < N_CORNERS; ++i)
{
// test point [i] against the planes
if (distance(planes[p], boxCorners[i]) > 0.0f)
--iInCount;
}
// were all the points outside of plane p?
if (iInCount == 0)
return false;
}
return true;
}
Frustum transformFrustum(const Matrix& m, const Frustum& f)
{
Frustum result;
for (int i=0; i!=Frustum::PLANE_COUNT; ++i)
result.planes[i] = transformPlane(m, f.planes[i]);
return result;
}
}

@ -1,34 +0,0 @@
// This code is in the public domain -- castanyo@yahoo.es
#ifndef NV_MATH_FRUSTUM_H
#define NV_MATH_FRUSTUM_H
#include <nvmath/Plane.h>
namespace nv
{
class Box;
class NVMATH_CLASS Frustum
{
public:
// Construct a frustum from typical view parameters. fovy has the same meaning as for glut_perspective_reshaper.
// The resulting frustum is centred at the origin, pointing along the z-axis.
Frustum() {}
Frustum(float fovy, float aspect, float near, float far);
// Unlike some intersection methods, we don't bother to distinguish intersects
// from contains. A true result could indicate either.
bool intersects(const Box&) const;
private:
friend Frustum transformFrustum(const Matrix&, const Frustum&);
enum PlaneIndices { NEAR, LEFT, RIGHT, TOP, BOTTOM, FAR, PLANE_COUNT };
Plane planes[PLANE_COUNT];
};
Frustum transformFrustum(const Matrix&, const Frustum&);
}
#endif

@ -1,38 +0,0 @@
// This code is in the public domain -- castanyo@yahoo.es
#ifndef NV_MATH_KAHANSUM_H
#define NV_MATH_KAHANSUM_H
#include <nvmath/nvmath.h>
namespace nv
{
class KahanSum
{
public:
KahanSum() : accum(0.0f), err(0) {};
void add(float f)
{
float compensated = f + err;
float tmp = accum + compensated;
err = accum - tmp;
err += compensated;
accum = tmp;
}
float sum() const
{
return accum;
}
private:
float accum;
float err;
};
} // nv namespace
#endif // NV_MATH_KAHANSUM_H

@ -1,168 +0,0 @@
// This code is in the public domain -- Ignacio Castaño <castanyo@yahoo.es>
#include <nvmath/Polygon.h>
#include <nvmath/Triangle.h>
#include <nvmath/Plane.h>
using namespace nv;
Polygon::Polygon()
{
}
Polygon::Polygon(const Triangle & t)
{
pointArray.resize(3);
pointArray[0] = t.v[0];
pointArray[1] = t.v[1];
pointArray[2] = t.v[2];
}
Polygon::Polygon(const Vector3 * points, uint vertexCount)
{
pointArray.resize(vertexCount);
for (uint i = 0; i < vertexCount; i++)
{
pointArray[i] = points[i];
}
}
/// Compute polygon area.
float Polygon::area() const
{
float total = 0;
const uint pointCount = pointArray.count();
for (uint i = 2; i < pointCount; i++)
{
Vector3 v1 = pointArray[i-1] - pointArray[0];
Vector3 v2 = pointArray[i] - pointArray[0];
total += 0.5f * length(cross(v1, v2));
}
return total;
}
/// Get the bounds of the polygon.
Box Polygon::bounds() const
{
Box bounds;
bounds.clearBounds();
foreach(p, pointArray)
{
bounds.addPointToBounds(pointArray[p]);
}
return bounds;
}
/// Get the plane of the polygon.
Plane Polygon::plane() const
{
// @@ Do something better than this?
Vector3 n = cross(pointArray[1] - pointArray[0], pointArray[2] - pointArray[0]);
return Vector4(n, dot(n, pointArray[0]));
}
/// Clip polygon to box.
uint Polygon::clipTo(const Box & box)
{
const Plane posX( 1, 0, 0, box.maxCorner().x());
const Plane negX(-1, 0, 0,-box.minCorner().x());
const Plane posY( 0, 1, 0, box.maxCorner().y());
const Plane negY( 0,-1, 0,-box.minCorner().y());
const Plane posZ( 0, 0, 1, box.maxCorner().z());
const Plane negZ( 0, 0,-1,-box.minCorner().z());
if (clipTo(posX) == 0) return 0;
if (clipTo(negX) == 0) return 0;
if (clipTo(posY) == 0) return 0;
if (clipTo(negY) == 0) return 0;
if (clipTo(posZ) == 0) return 0;
if (clipTo(negZ) == 0) return 0;
return pointArray.count();
}
/// Clip polygon to plane.
uint Polygon::clipTo(const Plane & plane)
{
int count = 0;
const uint pointCount = pointArray.count();
Array<Vector3> newPointArray(pointCount + 1); // @@ Do not create copy every time.
Vector3 prevPoint = pointArray[pointCount - 1];
float prevDist = dot(plane.vector(), prevPoint) - plane.offset();
for (uint i = 0; i < pointCount; i++)
{
const Vector3 point = pointArray[i];
float dist = dot(plane.vector(), point) - plane.offset();
// @@ Handle points on plane better.
if (dist <= 0) // interior.
{
if (prevDist > 0) // exterior
{
// Add segment intersection point.
Vector3 dp = point - prevPoint;
float t = dist / prevDist;
newPointArray.append(point - dp * t);
}
// Add interior point.
newPointArray.append(point);
}
else if (dist > 0 && prevDist < 0)
{
// Add segment intersection point.
Vector3 dp = point - prevPoint;
float t = dist / prevDist;
newPointArray.append(point - dp * t);
}
prevPoint = point;
prevDist = dist;
}
swap(pointArray, newPointArray);
return count;
}
void Polygon::removeColinearPoints()
{
const uint pointCount = pointArray.count();
Array<Vector3> newPointArray(pointCount);
for (uint i = 0 ; i < pointCount; i++)
{
int j = (i + 1) % pointCount;
int k = (i + pointCount - 1) % pointCount;
Vector3 v1 = normalize(pointArray[j] - pointArray[i]);
Vector3 v2 = normalize(pointArray[i] - pointArray[k]);
if (dot(v1, v2) < 0.999)
{
newPointArray.append(pointArray[i]);
}
}
swap(pointArray, newPointArray);
}

@ -1,45 +0,0 @@
// This code is in the public domain -- Ignacio Castaño <castanyo@yahoo.es>
#ifndef NV_MATH_POLYGON_H
#define NV_MATH_POLYGON_H
#include <nvcore/Containers.h>
#include <nvmath/nvmath.h>
#include <nvmath/Vector.h>
#include <nvmath/Box.h>
namespace nv
{
class Box;
class Plane;
class Triangle;
class Polygon
{
NV_FORBID_COPY(Polygon);
public:
Polygon();
Polygon(const Triangle & t);
Polygon(const Vector3 * points, uint vertexCount);
float area() const;
Box bounds() const;
Plane plane() const;
uint clipTo(const Box & box);
uint clipTo(const Plane & plane);
void removeColinearPoints();
private:
Array<Vector3> pointArray;
};
} // nv namespace
#endif // NV_MATH_POLYGON_H

@ -1,179 +0,0 @@
// This code is in the public domain -- castanyo@yahoo.es
#ifndef NV_MATH_QUATERNION_H
#define NV_MATH_QUATERNION_H
#include <nvmath/nvmath.h>
#include <nvmath/Vector.h>
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)
{
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 mul(Quaternion::Arg a, Vector3::Arg b)
{
return Quaternion(
+ a.y()*b.z() - a.z()*b.y() + a.w()*b.x(),
- a.x() * b.z() + a.z()*b.x() + a.w()*b.y(),
+ a.x() * b.y() - a.y()*b.x() + a.w()*b.z(),
- a.x() * b.x() - a.y()*b.y() - a.z()*b.z() );
}
inline Quaternion mul(Vector3::Arg a, Quaternion::Arg b)
{
return Quaternion(
+ a.x() * b.w() + a.y()*b.z() - a.z()*b.y(),
- a.x() * b.z() + a.y()*b.w() + a.z()*b.x(),
+ a.x() * b.y() - a.y()*b.x() + a.z()*b.w(),
- a.x() * b.x() - a.y()*b.y() - a.z()*b.z());
}
inline Quaternion operator *(Quaternion::Arg a, Quaternion::Arg b)
{
return mul(a, b);
}
inline Quaternion operator *(Quaternion::Arg a, Vector3::Arg b)
{
return mul(a, b);
}
inline Quaternion operator *(Vector3::Arg a, Quaternion::Arg b)
{
return mul(a, b);
}
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 scale(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));
}
inline Vector3 imag(Quaternion::Arg q)
{
return q.asVector().xyz();
}
inline float real(Quaternion::Arg q)
{
return q.w();
}
/// Transform vector.
inline Vector3 transform(Quaternion::Arg q, Vector3::Arg v)
{
Quaternion t = q * v * conjugate(q);
return imag(t);
}
} // nv namespace
#endif // NV_MATH_QUATERNION_H

@ -1,739 +0,0 @@
// This code is in the public domain -- castanyo@yahoo.es
#include <nvmath/Solver.h>
using namespace nv;
namespace
{
class Preconditioner
{
public:
// Virtual dtor.
virtual ~Preconditioner() { }
// Apply preconditioning step.
virtual void apply(const FullVector & x, FullVector & y) const = 0;
};
// Jacobi preconditioner.
class JacobiPreconditioner : public Preconditioner
{
public:
JacobiPreconditioner(const SparseMatrix & M, bool symmetric) : m_inverseDiagonal(M.width())
{
nvCheck(M.isSquare());
for(uint x = 0; x < M.width(); x++)
{
float elem = M.getCoefficient(x, x);
nvDebugCheck( elem != 0.0f );
if (symmetric)
{
m_inverseDiagonal[x] = 1.0f / sqrt(fabs(elem));
}
else
{
m_inverseDiagonal[x] = 1.0f / elem;
}
}
}
void apply(const FullVector & x, FullVector & y) const
{
nvDebugCheck(x.dimension() == m_inverseDiagonal.dimension());
nvDebugCheck(y.dimension() == m_inverseDiagonal.dimension());
// @@ Wrap vector component-wise product into a separate function.
const uint D = x.dimension();
for (uint i = 0; i < D; i++)
{
y[i] = m_inverseDiagonal[i] * x[i];
}
}
private:
FullVector m_inverseDiagonal;
};
} // namespace
static int ConjugateGradientSolver(const SparseMatrix & A, const FullVector & b, FullVector & x, float epsilon);
static int ConjugateGradientSolver(const Preconditioner & preconditioner, const SparseMatrix & A, const FullVector & b, FullVector & x, float epsilon);
// Solve the symmetric system: At·A·x = At·b
void nv::LeastSquaresSolver(const SparseMatrix & A, const FullVector & b, FullVector & x, float epsilon/*1e-5f*/)
{
nvDebugCheck(A.width() == x.dimension());
nvDebugCheck(A.height() == b.dimension());
nvDebugCheck(A.height() >= A.width()); // @@ If height == width we could solve it directly...
const uint D = A.width();
SparseMatrix At(A.height(), A.width());
transpose(A, At);
FullVector Atb(D);
//mult(Transposed, A, b, Atb);
mult(At, b, Atb);
SparseMatrix AtA(D);
//mult(Transposed, A, NoTransposed, A, AtA);
mult(At, A, AtA);
SymmetricSolver(AtA, Atb, x, epsilon);
}
// See section 10.4.3 in: Mesh Parameterization: Theory and Practice, Siggraph Course Notes, August 2007
void nv::LeastSquaresSolver(const SparseMatrix & A, const FullVector & b, FullVector & x, const uint * lockedParameters, uint lockedCount, float epsilon/*= 1e-5f*/)
{
nvDebugCheck(A.width() == x.dimension());
nvDebugCheck(A.height() == b.dimension());
nvDebugCheck(A.height() >= A.width() - lockedCount);
// @@ This is not the most efficient way of building a system with reduced degrees of freedom. It would be faster to do it on the fly.
const uint D = A.width() - lockedCount;
nvDebugCheck(D > 0);
// Compute: b - Al * xl
FullVector b_Alxl(b);
for (uint y = 0; y < A.height(); y++)
{
const uint count = A.getRow(y).count();
for (uint e = 0; e < count; e++)
{
uint column = A.getRow(y)[e].x;
bool isFree = true;
for (uint i = 0; i < lockedCount; i++)
{
isFree &= (lockedParameters[i] != column);
}
if (!isFree)
{
b_Alxl[y] -= x[column] * A.getRow(y)[e].v;
}
}
}
// Remove locked columns from A.
SparseMatrix Af(D, A.height());
for (uint y = 0; y < A.height(); y++)
{
const uint count = A.getRow(y).count();
for (uint e = 0; e < count; e++)
{
uint column = A.getRow(y)[e].x;
uint ix = column;
bool isFree = true;
for (uint i = 0; i < lockedCount; i++)
{
isFree &= (lockedParameters[i] != column);
if (column > lockedParameters[i]) ix--; // shift columns
}
if (isFree)
{
Af.setCoefficient(ix, y, A.getRow(y)[e].v);
}
}
}
// Remove elements from x
FullVector xf(D);
for (uint i = 0, j = 0; i < A.width(); i++)
{
bool isFree = true;
for (uint l = 0; l < lockedCount; l++)
{
isFree &= (lockedParameters[l] != i);
}
if (isFree)
{
xf[j++] = x[i];
}
}
// Solve reduced system.
LeastSquaresSolver(Af, b_Alxl, xf, epsilon);
// Copy results back to x.
for (uint i = 0, j = 0; i < A.width(); i++)
{
bool isFree = true;
for (uint l = 0; l < lockedCount; l++)
{
isFree &= (lockedParameters[l] != i);
}
if (isFree)
{
x[i] = xf[j++];
}
}
}
void nv::SymmetricSolver(const SparseMatrix & A, const FullVector & b, FullVector & x, float epsilon/*1e-5f*/)
{
nvDebugCheck(A.height() == A.width());
nvDebugCheck(A.height() == b.dimension());
nvDebugCheck(b.dimension() == x.dimension());
JacobiPreconditioner jacobi(A, true);
ConjugateGradientSolver(jacobi, A, b, x, epsilon);
// ConjugateGradientSolver(A, b, x, epsilon);
}
/**
* Compute the solution of the sparse linear system Ab=x using the Conjugate
* Gradient method.
*
* Solving sparse linear systems:
* (1) A·x = b
*
* The conjugate gradient algorithm solves (1) only in the case that A is
* symmetric and positive definite. It is based on the idea of minimizing the
* function
*
* (2) f(x) = 1/2·x·A·x - b·x
*
* This function is minimized when its gradient
*
* (3) df = A·x - b
*
* is zero, which is equivalent to (1). The minimization is carried out by
* generating a succession of search directions p.k and improved minimizers x.k.
* At each stage a quantity alfa.k is found that minimizes f(x.k + alfa.k·p.k),
* and x.k+1 is set equal to the new point x.k + alfa.k·p.k. The p.k and x.k are
* built up in such a way that x.k+1 is also the minimizer of f over the whole
* vector space of directions already taken, {p.1, p.2, . . . , p.k}. After N
* iterations you arrive at the minimizer over the entire vector space, i.e., the
* solution to (1).
*
* For a really good explanation of the method see:
*
* "An Introduction to the Conjugate Gradient Method Without the Agonizing Pain",
* Jonhathan Richard Shewchuk.
*
**/
/*static*/ int ConjugateGradientSolver(const SparseMatrix & A, const FullVector & b, FullVector & x, float epsilon)
{
nvDebugCheck( A.isSquare() );
nvDebugCheck( A.width() == b.dimension() );
nvDebugCheck( A.width() == x.dimension() );
int i = 0;
const int D = A.width();
const int i_max = 4 * D; // Convergence should be linear, but in some cases, it's not.
FullVector r(D); // residual
FullVector p(D); // search direction
FullVector q(D); //
float delta_0;
float delta_old;
float delta_new;
float alpha;
float beta;
// r = b - A·x;
copy(b, r);
sgemv(-1, A, x, 1, r);
// p = r;
copy(r, p);
delta_new = dot( r, r );
delta_0 = delta_new;
while (i < i_max && delta_new > epsilon*epsilon*delta_0)
{
i++;
// q = A·p
mult(A, p, q);
// alpha = delta_new / p·q
alpha = delta_new / dot( p, q );
// x = alfa·p + x
saxpy(alpha, p, x);
if ((i & 31) == 0) // recompute r after 32 steps
{
// r = b - A·x
copy(b, r);
sgemv(-1, A, x, 1, r);
}
else
{
// r = r - alpha·q
saxpy(-alpha, q, r);
}
delta_old = delta_new;
delta_new = dot( r, r );
beta = delta_new / delta_old;
// p = beta·p + r
scal(beta, p);
saxpy(1, r, p);
}
return i;
}
// Conjugate gradient with preconditioner.
/*static*/ int ConjugateGradientSolver(const Preconditioner & preconditioner, const SparseMatrix & A, const FullVector & b, FullVector & x, float epsilon)
{
nvDebugCheck( A.isSquare() );
nvDebugCheck( A.width() == b.dimension() );
nvDebugCheck( A.width() == x.dimension() );
int i = 0;
const int D = A.width();
const int i_max = 4 * D; // Convergence should be linear, but in some cases, it's not.
FullVector r(D); // residual
FullVector p(D); // search direction
FullVector q(D); //
FullVector s(D); // preconditioned
float delta_0;
float delta_old;
float delta_new;
float alpha;
float beta;
// r = b - A·x
copy(b, r);
sgemv(-1, A, x, 1, r);
// p = M^-1 · r
preconditioner.apply(r, p);
//copy(r, p);
delta_new = dot(r, p);
delta_0 = delta_new;
while (i < i_max && delta_new > epsilon*epsilon*delta_0)
{
i++;
// q = A·p
mult(A, p, q);
// alpha = delta_new / p·q
alpha = delta_new / dot(p, q);
// x = alfa·p + x
saxpy(alpha, p, x);
if ((i & 31) == 0) // recompute r after 32 steps
{
// r = b - A·x
copy(b, r);
sgemv(-1, A, x, 1, r);
}
else
{
// r = r - alfa·q
saxpy(-alpha, q, r);
}
// s = M^-1 · r
preconditioner.apply(r, s);
//copy(r, s);
delta_old = delta_new;
delta_new = dot( r, s );
beta = delta_new / delta_old;
// p = s + beta·p
scal(beta, p);
saxpy(1, s, p);
}
return i;
}
#if 0 // Nonsymmetric solvers
/** Bi-conjugate gradient method. */
MATHLIB_API int BiConjugateGradientSolve( const SparseMatrix &A, const DenseVector &b, DenseVector &x, float epsilon ) {
piDebugCheck( A.IsSquare() );
piDebugCheck( A.Width() == b.Dim() );
piDebugCheck( A.Width() == x.Dim() );
int i = 0;
const int D = A.Width();
const int i_max = 4 * D;
float resid;
float rho_1 = 0;
float rho_2 = 0;
float alpha;
float beta;
DenseVector r(D);
DenseVector rtilde(D);
DenseVector p(D);
DenseVector ptilde(D);
DenseVector q(D);
DenseVector qtilde(D);
DenseVector tmp(D); // temporal vector.
// r = b - A·x;
A.Product( x, tmp );
r.Sub( b, tmp );
// rtilde = r
rtilde.Set( r );
// p = r;
p.Set( r );
// ptilde = rtilde
ptilde.Set( rtilde );
float normb = b.Norm();
if( normb == 0.0 ) normb = 1;
// test convergence
resid = r.Norm() / normb;
if( resid < epsilon ) {
// method converges?
return 0;
}
while( i < i_max ) {
i++;
rho_1 = DenseVectorDotProduct( r, rtilde );
if( rho_1 == 0 ) {
// method fails.
return -i;
}
if (i == 1) {
p.Set( r );
ptilde.Set( rtilde );
}
else {
beta = rho_1 / rho_2;
// p = r + beta * p;
p.Mad( r, p, beta );
// ptilde = ztilde + beta * ptilde;
ptilde.Mad( rtilde, ptilde, beta );
}
// q = A * p;
A.Product( p, q );
// qtilde = A^t * ptilde;
A.TransProduct( ptilde, qtilde );
alpha = rho_1 / DenseVectorDotProduct( ptilde, q );
// x += alpha * p;
x.Mad( x, p, alpha );
// r -= alpha * q;
r.Mad( r, q, -alpha );
// rtilde -= alpha * qtilde;
rtilde.Mad( rtilde, qtilde, -alpha );
rho_2 = rho_1;
// test convergence
resid = r.Norm() / normb;
if( resid < epsilon ) {
// method converges
return i;
}
}
return i;
}
/** Bi-conjugate gradient stabilized method. */
int BiCGSTABSolve( const SparseMatrix &A, const DenseVector &b, DenseVector &x, float epsilon ) {
piDebugCheck( A.IsSquare() );
piDebugCheck( A.Width() == b.Dim() );
piDebugCheck( A.Width() == x.Dim() );
int i = 0;
const int D = A.Width();
const int i_max = 2 * D;
float resid;
float rho_1 = 0;
float rho_2 = 0;
float alpha = 0;
float beta = 0;
float omega = 0;
DenseVector p(D);
DenseVector phat(D);
DenseVector s(D);
DenseVector shat(D);
DenseVector t(D);
DenseVector v(D);
DenseVector r(D);
DenseVector rtilde(D);
DenseVector tmp(D);
// r = b - A·x;
A.Product( x, tmp );
r.Sub( b, tmp );
// rtilde = r
rtilde.Set( r );
float normb = b.Norm();
if( normb == 0.0 ) normb = 1;
// test convergence
resid = r.Norm() / normb;
if( resid < epsilon ) {
// method converges?
return 0;
}
while( i<i_max ) {
i++;
rho_1 = DenseVectorDotProduct( rtilde, r );
if( rho_1 == 0 ) {
// method fails
return -i;
}
if( i == 1 ) {
p.Set( r );
}
else {
beta = (rho_1 / rho_2) * (alpha / omega);
// p = r + beta * (p - omega * v);
p.Mad( p, v, -omega );
p.Mad( r, p, beta );
}
//phat = M.solve(p);
phat.Set( p );
//Precond( &phat, p );
//v = A * phat;
A.Product( phat, v );
alpha = rho_1 / DenseVectorDotProduct( rtilde, v );
// s = r - alpha * v;
s.Mad( r, v, -alpha );
resid = s.Norm() / normb;
if( resid < epsilon ) {
// x += alpha * phat;
x.Mad( x, phat, alpha );
return i;
}
//shat = M.solve(s);
shat.Set( s );
//Precond( &shat, s );
//t = A * shat;
A.Product( shat, t );
omega = DenseVectorDotProduct( t, s ) / DenseVectorDotProduct( t, t );
// x += alpha * phat + omega * shat;
x.Mad( x, shat, omega );
x.Mad( x, phat, alpha );
//r = s - omega * t;
r.Mad( s, t, -omega );
rho_2 = rho_1;
resid = r.Norm() / normb;
if( resid < epsilon ) {
return i;
}
if( omega == 0 ) {
return -i; // ???
}
}
return i;
}
/** Bi-conjugate gradient stabilized method. */
int BiCGSTABPrecondSolve( const SparseMatrix &A, const DenseVector &b, DenseVector &x, const IPreconditioner &M, float epsilon ) {
piDebugCheck( A.IsSquare() );
piDebugCheck( A.Width() == b.Dim() );
piDebugCheck( A.Width() == x.Dim() );
int i = 0;
const int D = A.Width();
const int i_max = D;
// const int i_max = 1000;
float resid;
float rho_1 = 0;
float rho_2 = 0;
float alpha = 0;
float beta = 0;
float omega = 0;
DenseVector p(D);
DenseVector phat(D);
DenseVector s(D);
DenseVector shat(D);
DenseVector t(D);
DenseVector v(D);
DenseVector r(D);
DenseVector rtilde(D);
DenseVector tmp(D);
// r = b - A·x;
A.Product( x, tmp );
r.Sub( b, tmp );
// rtilde = r
rtilde.Set( r );
float normb = b.Norm();
if( normb == 0.0 ) normb = 1;
// test convergence
resid = r.Norm() / normb;
if( resid < epsilon ) {
// method converges?
return 0;
}
while( i<i_max ) {
i++;
rho_1 = DenseVectorDotProduct( rtilde, r );
if( rho_1 == 0 ) {
// method fails
return -i;
}
if( i == 1 ) {
p.Set( r );
}
else {
beta = (rho_1 / rho_2) * (alpha / omega);
// p = r + beta * (p - omega * v);
p.Mad( p, v, -omega );
p.Mad( r, p, beta );
}
//phat = M.solve(p);
//phat.Set( p );
M.Precond( &phat, p );
//v = A * phat;
A.Product( phat, v );
alpha = rho_1 / DenseVectorDotProduct( rtilde, v );
// s = r - alpha * v;
s.Mad( r, v, -alpha );
resid = s.Norm() / normb;
//printf( "--- Iteration %d: residual = %f\n", i, resid );
if( resid < epsilon ) {
// x += alpha * phat;
x.Mad( x, phat, alpha );
return i;
}
//shat = M.solve(s);
//shat.Set( s );
M.Precond( &shat, s );
//t = A * shat;
A.Product( shat, t );
omega = DenseVectorDotProduct( t, s ) / DenseVectorDotProduct( t, t );
// x += alpha * phat + omega * shat;
x.Mad( x, shat, omega );
x.Mad( x, phat, alpha );
//r = s - omega * t;
r.Mad( s, t, -omega );
rho_2 = rho_1;
resid = r.Norm() / normb;
if( resid < epsilon ) {
return i;
}
if( omega == 0 ) {
return -i; // ???
}
}
return i;
}
#endif

@ -1,20 +0,0 @@
// This code is in the public domain -- castanyo@yahoo.es
#ifndef NV_MATH_SOLVER_H
#define NV_MATH_SOLVER_H
#include <nvmath/Sparse.h>
namespace nv
{
// Linear solvers.
NVMATH_API void LeastSquaresSolver(const SparseMatrix & A, const FullVector & b, FullVector & x, float epsilon = 1e-5f);
NVMATH_API void LeastSquaresSolver(const SparseMatrix & A, const FullVector & b, FullVector & x, const uint * lockedParameters, uint lockedCount, float epsilon = 1e-5f);
NVMATH_API void SymmetricSolver(const SparseMatrix & A, const FullVector & b, FullVector & x, float epsilon = 1e-5f);
// NVMATH_API void NonSymmetricSolver(const SparseMatrix & A, const FullVector & b, FullVector & x, float epsilon = 1e-5f);
} // nv namespace
#endif // NV_MATH_SOLVER_H

@ -1,862 +0,0 @@
// This code is in the public domain -- Ignacio Castaño <castanyo@yahoo.es>
#include <nvmath/Sparse.h>
#include <nvmath/KahanSum.h>
using namespace nv;
/// Ctor.
FullVector::FullVector(uint dim)
{
m_array.resize(dim);
}
/// Copy ctor.
FullVector::FullVector(const FullVector & v) : m_array(v.m_array)
{
}
/// Copy operator
const FullVector & FullVector::operator=(const FullVector & v)
{
nvCheck(dimension() == v.dimension());
m_array = v.m_array;
return *this;
}
void FullVector::fill(float f)
{
const uint dim = dimension();
for (uint i = 0; i < dim; i++)
{
m_array[i] = f;
}
}
void FullVector::operator+= (const FullVector & v)
{
nvDebugCheck(dimension() == v.dimension());
const uint dim = dimension();
for (uint i = 0; i < dim; i++)
{
m_array[i] += v.m_array[i];
}
}
void FullVector::operator-= (const FullVector & v)
{
nvDebugCheck(dimension() == v.dimension());
const uint dim = dimension();
for (uint i = 0; i < dim; i++)
{
m_array[i] -= v.m_array[i];
}
}
void FullVector::operator*= (const FullVector & v)
{
nvDebugCheck(dimension() == v.dimension());
const uint dim = dimension();
for (uint i = 0; i < dim; i++)
{
m_array[i] *= v.m_array[i];
}
}
void FullVector::operator+= (float f)
{
const uint dim = dimension();
for (uint i = 0; i < dim; i++)
{
m_array[i] += f;
}
}
void FullVector::operator-= (float f)
{
const uint dim = dimension();
for (uint i = 0; i < dim; i++)
{
m_array[i] -= f;
}
}
void FullVector::operator*= (float f)
{
const uint dim = dimension();
for (uint i = 0; i < dim; i++)
{
m_array[i] *= f;
}
}
void nv::saxpy(float a, const FullVector & x, FullVector & y)
{
nvDebugCheck(x.dimension() == y.dimension());
const uint dim = x.dimension();
for (uint i = 0; i < dim; i++)
{
y[i] += a * x[i];
}
}
void nv::copy(const FullVector & x, FullVector & y)
{
nvDebugCheck(x.dimension() == y.dimension());
const uint dim = x.dimension();
for (uint i = 0; i < dim; i++)
{
y[i] = x[i];
}
}
void nv::scal(float a, FullVector & x)
{
const uint dim = x.dimension();
for (uint i = 0; i < dim; i++)
{
x[i] *= a;
}
}
float nv::dot(const FullVector & x, const FullVector & y)
{
nvDebugCheck(x.dimension() == y.dimension());
const uint dim = x.dimension();
/*float sum = 0;
for (uint i = 0; i < dim; i++)
{
sum += x[i] * y[i];
}
return sum;*/
KahanSum kahan;
for (uint i = 0; i < dim; i++)
{
kahan.add(x[i] * y[i]);
}
return kahan.sum();
}
FullMatrix::FullMatrix(uint d) : m_width(d), m_height(d)
{
m_array.resize(d*d, 0.0f);
}
FullMatrix::FullMatrix(uint w, uint h) : m_width(w), m_height(h)
{
m_array.resize(w*h, 0.0f);
}
FullMatrix::FullMatrix(const FullMatrix & m) : m_width(m.m_width), m_height(m.m_height)
{
m_array = m.m_array;
}
const FullMatrix & FullMatrix::operator=(const FullMatrix & m)
{
nvCheck(width() == m.width());
nvCheck(height() == m.height());
m_array = m.m_array;
return *this;
}
float FullMatrix::getCoefficient(uint x, uint y) const
{
nvDebugCheck( x < width() );
nvDebugCheck( y < height() );
return m_array[y * width() + x];
}
void FullMatrix::setCoefficient(uint x, uint y, float f)
{
nvDebugCheck( x < width() );
nvDebugCheck( y < height() );
m_array[y * width() + x] = f;
}
void FullMatrix::addCoefficient(uint x, uint y, float f)
{
nvDebugCheck( x < width() );
nvDebugCheck( y < height() );
m_array[y * width() + x] += f;
}
void FullMatrix::mulCoefficient(uint x, uint y, float f)
{
nvDebugCheck( x < width() );
nvDebugCheck( y < height() );
m_array[y * width() + x] *= f;
}
float FullMatrix::dotRow(uint y, const FullVector & v) const
{
nvDebugCheck( v.dimension() == width() );
nvDebugCheck( y < height() );
float sum = 0;
const uint count = v.dimension();
for (uint i = 0; i < count; i++)
{
sum += m_array[y * count + i] * v[i];
}
return sum;
}
void FullMatrix::madRow(uint y, float alpha, FullVector & v) const
{
nvDebugCheck( v.dimension() == width() );
nvDebugCheck( y < height() );
const uint count = v.dimension();
for (uint i = 0; i < count; i++)
{
v[i] += m_array[y * count + i];
}
}
// y = M * x
void nv::mult(const FullMatrix & M, const FullVector & x, FullVector & y)
{
mult(NoTransposed, M, x, y);
}
void nv::mult(Transpose TM, const FullMatrix & M, const FullVector & x, FullVector & y)
{
const uint w = M.width();
const uint h = M.height();
if (TM == Transposed)
{
nvDebugCheck( h == x.dimension() );
nvDebugCheck( w == y.dimension() );
y.fill(0.0f);
for (uint i = 0; i < h; i++)
{
M.madRow(i, x[i], y);
}
}
else
{
nvDebugCheck( w == x.dimension() );
nvDebugCheck( h == y.dimension() );
for (uint i = 0; i < h; i++)
{
y[i] = M.dotRow(i, x);
}
}
}
// y = alpha*A*x + beta*y
void nv::sgemv(float alpha, const FullMatrix & A, const FullVector & x, float beta, FullVector & y)
{
sgemv(alpha, NoTransposed, A, x, beta, y);
}
void nv::sgemv(float alpha, Transpose TA, const FullMatrix & A, const FullVector & x, float beta, FullVector & y)
{
const uint w = A.width();
const uint h = A.height();
if (TA == Transposed)
{
nvDebugCheck( h == x.dimension() );
nvDebugCheck( w == y.dimension() );
for (uint i = 0; i < h; i++)
{
A.madRow(i, alpha * x[i], y);
}
}
else
{
nvDebugCheck( w == x.dimension() );
nvDebugCheck( h == y.dimension() );
for (uint i = 0; i < h; i++)
{
y[i] = alpha * A.dotRow(i, x) + beta * y[i];
}
}
}
// Multiply a row of A by a column of B.
static float dot(uint j, Transpose TA, const FullMatrix & A, uint i, Transpose TB, const FullMatrix & B)
{
const uint w = (TA == NoTransposed) ? A.width() : A.height();
nvDebugCheck(w == (TB == NoTransposed) ? B.height() : A.width());
float sum = 0.0f;
for (uint k = 0; k < w; k++)
{
const float a = (TA == NoTransposed) ? A.getCoefficient(k, j) : A.getCoefficient(j, k); // @@ Move branches out of the loop?
const float b = (TB == NoTransposed) ? B.getCoefficient(i, k) : A.getCoefficient(k, i);
sum += a * b;
}
return sum;
}
// C = A * B
void nv::mult(const FullMatrix & A, const FullMatrix & B, FullMatrix & C)
{
mult(NoTransposed, A, NoTransposed, B, C);
}
void nv::mult(Transpose TA, const FullMatrix & A, Transpose TB, const FullMatrix & B, FullMatrix & C)
{
sgemm(1.0f, TA, A, TB, B, 0.0f, C);
}
// C = alpha*A*B + beta*C
void nv::sgemm(float alpha, const FullMatrix & A, const FullMatrix & B, float beta, FullMatrix & C)
{
sgemm(alpha, NoTransposed, A, NoTransposed, B, beta, C);
}
void nv::sgemm(float alpha, Transpose TA, const FullMatrix & A, Transpose TB, const FullMatrix & B, float beta, FullMatrix & C)
{
const uint w = C.width();
const uint h = C.height();
uint aw = (TA == NoTransposed) ? A.width() : A.height();
uint ah = (TA == NoTransposed) ? A.height() : A.width();
uint bw = (TB == NoTransposed) ? B.width() : B.height();
uint bh = (TB == NoTransposed) ? B.height() : B.width();
nvDebugCheck(aw == bh);
nvDebugCheck(bw == ah);
nvDebugCheck(w == bw);
nvDebugCheck(h == ah);
for (uint y = 0; y < h; y++)
{
for (uint x = 0; x < w; x++)
{
float c = alpha * ::dot(x, TA, A, y, TB, B) + beta * C.getCoefficient(x, y);
C.setCoefficient(x, y, c);
}
}
}
/// Ctor. Init the size of the sparse matrix.
SparseMatrix::SparseMatrix(uint d) : m_width(d)
{
m_array.resize(d);
}
/// Ctor. Init the size of the sparse matrix.
SparseMatrix::SparseMatrix(uint w, uint h) : m_width(w)
{
m_array.resize(h);
}
SparseMatrix::SparseMatrix(const SparseMatrix & m) : m_width(m.m_width)
{
m_array = m.m_array;
}
const SparseMatrix & SparseMatrix::operator=(const SparseMatrix & m)
{
nvCheck(width() == m.width());
nvCheck(height() == m.height());
m_array = m.m_array;
return *this;
}
// x is column, y is row
float SparseMatrix::getCoefficient(uint x, uint y) const
{
nvDebugCheck( x < width() );
nvDebugCheck( y < height() );
const uint count = m_array[y].count();
for (uint i = 0; i < count; i++)
{
if (m_array[y][i].x == x) return m_array[y][i].v;
}
return 0.0f;
}
void SparseMatrix::setCoefficient(uint x, uint y, float f)
{
nvDebugCheck( x < width() );
nvDebugCheck( y < height() );
const uint count = m_array[y].count();
for (uint i = 0; i < count; i++)
{
if (m_array[y][i].x == x)
{
m_array[y][i].v = f;
return;
}
}
if (f != 0.0f)
{
Coefficient c = { x, f };
m_array[y].append( c );
}
}
void SparseMatrix::addCoefficient(uint x, uint y, float f)
{
nvDebugCheck( x < width() );
nvDebugCheck( y < height() );
if (f != 0.0f)
{
const uint count = m_array[y].count();
for (uint i = 0; i < count; i++)
{
if (m_array[y][i].x == x)
{
m_array[y][i].v += f;
return;
}
}
Coefficient c = { x, f };
m_array[y].append( c );
}
}
void SparseMatrix::mulCoefficient(uint x, uint y, float f)
{
nvDebugCheck( x < width() );
nvDebugCheck( y < height() );
const uint count = m_array[y].count();
for (uint i = 0; i < count; i++)
{
if (m_array[y][i].x == x)
{
m_array[y][i].v *= f;
return;
}
}
if (f != 0.0f)
{
Coefficient c = { x, f };
m_array[y].append( c );
}
}
float SparseMatrix::sumRow(uint y) const
{
nvDebugCheck( y < height() );
const uint count = m_array[y].count();
/*float sum = 0;
for (uint i = 0; i < count; i++)
{
sum += m_array[y][i].v;
}
return sum;*/
KahanSum kahan;
for (uint i = 0; i < count; i++)
{
kahan.add(m_array[y][i].v);
}
return kahan.sum();
}
float SparseMatrix::dotRow(uint y, const FullVector & v) const
{
nvDebugCheck( y < height() );
const uint count = m_array[y].count();
/*float sum = 0;
for (uint i = 0; i < count; i++)
{
sum += m_array[y][i].v * v[m_array[y][i].x];
}
return sum;*/
KahanSum kahan;
for (uint i = 0; i < count; i++)
{
kahan.add(m_array[y][i].v * v[m_array[y][i].x]);
}
return kahan.sum();
}
void SparseMatrix::madRow(uint y, float alpha, FullVector & v) const
{
nvDebugCheck(y < height());
const uint count = m_array[y].count();
for (uint i = 0; i < count; i++)
{
v[m_array[y][i].x] += alpha * m_array[y][i].v;
}
}
void SparseMatrix::clearRow(uint y)
{
nvDebugCheck( y < height() );
m_array[y].clear();
}
void SparseMatrix::scaleRow(uint y, float f)
{
nvDebugCheck( y < height() );
const uint count = m_array[y].count();
for (uint i = 0; i < count; i++)
{
m_array[y][i].v *= f;
}
}
void SparseMatrix::normalizeRow(uint y)
{
nvDebugCheck( y < height() );
float norm = 0.0f;
const uint count = m_array[y].count();
for (uint i = 0; i < count; i++)
{
float f = m_array[y][i].v;
norm += f * f;
}
scaleRow(y, 1.0f / sqrtf(norm));
}
void SparseMatrix::clearColumn(uint x)
{
nvDebugCheck(x < width());
for (uint y = 0; y < height(); y++)
{
const uint count = m_array[y].count();
for (uint e = 0; e < count; e++)
{
if (m_array[y][e].x == x)
{
m_array[y][e].v = 0.0f;
break;
}
}
}
}
void SparseMatrix::scaleColumn(uint x, float f)
{
nvDebugCheck(x < width());
for (uint y = 0; y < height(); y++)
{
const uint count = m_array[y].count();
for (uint e = 0; e < count; e++)
{
if (m_array[y][e].x == x)
{
m_array[y][e].v *= f;
break;
}
}
}
}
const Array<SparseMatrix::Coefficient> & SparseMatrix::getRow(uint y) const
{
return m_array[y];
}
// y = M * x
void nv::mult(const SparseMatrix & M, const FullVector & x, FullVector & y)
{
mult(NoTransposed, M, x, y);
}
void nv::mult(Transpose TM, const SparseMatrix & M, const FullVector & x, FullVector & y)
{
const uint w = M.width();
const uint h = M.height();
if (TM == Transposed)
{
nvDebugCheck( h == x.dimension() );
nvDebugCheck( w == y.dimension() );
y.fill(0.0f);
for (uint i = 0; i < h; i++)
{
M.madRow(i, x[i], y);
}
}
else
{
nvDebugCheck( w == x.dimension() );
nvDebugCheck( h == y.dimension() );
for (uint i = 0; i < h; i++)
{
y[i] = M.dotRow(i, x);
}
}
}
// y = alpha*A*x + beta*y
void nv::sgemv(float alpha, const SparseMatrix & A, const FullVector & x, float beta, FullVector & y)
{
sgemv(alpha, NoTransposed, A, x, beta, y);
}
void nv::sgemv(float alpha, Transpose TA, const SparseMatrix & A, const FullVector & x, float beta, FullVector & y)
{
const uint w = A.width();
const uint h = A.height();
if (TA == Transposed)
{
nvDebugCheck( h == x.dimension() );
nvDebugCheck( w == y.dimension() );
for (uint i = 0; i < h; i++)
{
A.madRow(i, alpha * x[i], y);
}
}
else
{
nvDebugCheck( w == x.dimension() );
nvDebugCheck( h == y.dimension() );
for (uint i = 0; i < h; i++)
{
y[i] = alpha * A.dotRow(i, x) + beta * y[i];
}
}
}
// dot y-row of A by x-column of B
static float dotRowColumn(int y, const SparseMatrix & A, int x, const SparseMatrix & B)
{
const Array<SparseMatrix::Coefficient> & row = A.getRow(y);
const uint count = row.count();
/*float sum = 0.0f;
for (uint i = 0; i < count; i++)
{
const SparseMatrix::Coefficient & c = row[i];
sum += c.v * B.getCoefficient(x, c.x);
}
return sum;*/
KahanSum kahan;
for (uint i = 0; i < count; i++)
{
const SparseMatrix::Coefficient & c = row[i];
kahan.add(c.v * B.getCoefficient(x, c.x));
}
return kahan.sum();
}
// dot y-row of A by x-row of B
static float dotRowRow(int y, const SparseMatrix & A, int x, const SparseMatrix & B)
{
const Array<SparseMatrix::Coefficient> & row = A.getRow(y);
const uint count = row.count();
/*float sum = 0.0f;
for (uint i = 0; i < count; i++)
{
const SparseMatrix::Coefficient & c = row[i];
sum += c.v * B.getCoefficient(c.x, x);
}
//return sum;*/
KahanSum kahan;
for (uint i = 0; i < count; i++)
{
const SparseMatrix::Coefficient & c = row[i];
kahan.add(c.v * B.getCoefficient(c.x, x));
}
return kahan.sum();
}
// dot y-column of A by x-column of B
static float dotColumnColumn(int y, const SparseMatrix & A, int x, const SparseMatrix & B)
{
nvDebugCheck(A.height() == B.height());
const uint h = A.height();
/*float sum = 0.0f;
for (uint i = 0; i < h; i++)
{
sum += A.getCoefficient(y, i) * B.getCoefficient(x, i);
}
//return sum;*/
KahanSum kahan;
for (uint i = 0; i < h; i++)
{
kahan.add(A.getCoefficient(y, i) * B.getCoefficient(x, i));
}
return kahan.sum();
}
void nv::transpose(const SparseMatrix & A, SparseMatrix & B)
{
nvDebugCheck(A.width() == B.height());
nvDebugCheck(B.width() == A.height());
const uint w = A.width();
for (uint x = 0; x < w; x++)
{
B.clearRow(x);
}
const uint h = A.height();
for (uint y = 0; y < h; y++)
{
const Array<SparseMatrix::Coefficient> & row = A.getRow(y);
const uint count = row.count();
for (uint i = 0; i < count; i++)
{
const SparseMatrix::Coefficient & c = row[i];
nvDebugCheck(c.x < w);
B.setCoefficient(y, c.x, c.v);
}
}
}
// C = A * B
void nv::mult(const SparseMatrix & A, const SparseMatrix & B, SparseMatrix & C)
{
mult(NoTransposed, A, NoTransposed, B, C);
}
void nv::mult(Transpose TA, const SparseMatrix & A, Transpose TB, const SparseMatrix & B, SparseMatrix & C)
{
sgemm(1.0f, TA, A, TB, B, 0.0f, C);
}
// C = alpha*A*B + beta*C
void nv::sgemm(float alpha, const SparseMatrix & A, const SparseMatrix & B, float beta, SparseMatrix & C)
{
sgemm(alpha, NoTransposed, A, NoTransposed, B, beta, C);
}
void nv::sgemm(float alpha, Transpose TA, const SparseMatrix & A, Transpose TB, const SparseMatrix & B, float beta, SparseMatrix & C)
{
const uint w = C.width();
const uint h = C.height();
uint aw = (TA == NoTransposed) ? A.width() : A.height();
uint ah = (TA == NoTransposed) ? A.height() : A.width();
uint bw = (TB == NoTransposed) ? B.width() : B.height();
uint bh = (TB == NoTransposed) ? B.height() : B.width();
nvDebugCheck(aw == bh);
nvDebugCheck(bw == ah);
nvDebugCheck(w == bw);
nvDebugCheck(h == ah);
for (uint y = 0; y < h; y++)
{
for (uint x = 0; x < w; x++)
{
float c = beta * C.getCoefficient(x, y);
if (TA == NoTransposed && TB == NoTransposed)
{
// dot y-row of A by x-column of B.
c += alpha * dotRowColumn(y, A, x, B);
}
else if (TA == Transposed && TB == Transposed)
{
// dot y-column of A by x-row of B.
c += alpha * dotRowColumn(x, B, y, A);
}
else if (TA == Transposed && TB == NoTransposed)
{
// dot y-column of A by x-column of B.
c += alpha * dotColumnColumn(y, A, x, B);
}
else if (TA == NoTransposed && TB == Transposed)
{
// dot y-row of A by x-row of B.
c += alpha * dotRowRow(y, A, x, B);
}
C.setCoefficient(x, y, c);
}
}
}
// C = At * A
void nv::sqm(const SparseMatrix & A, SparseMatrix & C)
{
// This is quite expensive...
mult(Transposed, A, NoTransposed, A, C);
}

@ -1,200 +0,0 @@
// This code is in the public domain -- castanyo@yahoo.es
#ifndef NV_MATH_SPARSE_H
#define NV_MATH_SPARSE_H
#include <nvcore/Containers.h>
#include <nvmath/nvmath.h>
// Full and sparse vector and matrix classes. BLAS subset.
namespace nv
{
class FullVector;
class FullMatrix;
class SparseMatrix;
/// Fixed size vector class.
class FullVector
{
public:
FullVector(uint dim);
FullVector(const FullVector & v);
const FullVector & operator=(const FullVector & v);
uint dimension() const { return m_array.count(); }
const float & operator[]( uint index ) const { return m_array[index]; }
float & operator[] ( uint index ) { return m_array[index]; }
void fill(float f);
void operator+= (const FullVector & v);
void operator-= (const FullVector & v);
void operator*= (const FullVector & v);
void operator+= (float f);
void operator-= (float f);
void operator*= (float f);
private:
Array<float> m_array;
};
// Pseudo-BLAS interface.
NVMATH_API void saxpy(float a, const FullVector & x, FullVector & y); // y = a * x + y
NVMATH_API void copy(const FullVector & x, FullVector & y);
NVMATH_API void scal(float a, FullVector & x);
NVMATH_API float dot(const FullVector & x, const FullVector & y);
enum Transpose
{
NoTransposed = 0,
Transposed = 1
};
/// Full matrix class.
class FullMatrix
{
public:
FullMatrix(uint d);
FullMatrix(uint w, uint h);
FullMatrix(const FullMatrix & m);
const FullMatrix & operator=(const FullMatrix & m);
uint width() const { return m_width; }
uint height() const { return m_height; }
bool isSquare() const { return m_width == m_height; }
float getCoefficient(uint x, uint y) const;
void setCoefficient(uint x, uint y, float f);
void addCoefficient(uint x, uint y, float f);
void mulCoefficient(uint x, uint y, float f);
float dotRow(uint y, const FullVector & v) const;
void madRow(uint y, float alpha, FullVector & v) const;
protected:
bool isValid() const {
return m_array.size() == (m_width * m_height);
}
private:
const uint m_width;
const uint m_height;
Array<float> m_array;
};
NVMATH_API void mult(const FullMatrix & M, const FullVector & x, FullVector & y);
NVMATH_API void mult(Transpose TM, const FullMatrix & M, const FullVector & x, FullVector & y);
// y = alpha*A*x + beta*y
NVMATH_API void sgemv(float alpha, const FullMatrix & A, const FullVector & x, float beta, FullVector & y);
NVMATH_API void sgemv(float alpha, Transpose TA, const FullMatrix & A, const FullVector & x, float beta, FullVector & y);
NVMATH_API void mult(const FullMatrix & A, const FullMatrix & B, FullMatrix & C);
NVMATH_API void mult(Transpose TA, const FullMatrix & A, Transpose TB, const FullMatrix & B, FullMatrix & C);
// C = alpha*A*B + beta*C
NVMATH_API void sgemm(float alpha, const FullMatrix & A, const FullMatrix & B, float beta, FullMatrix & C);
NVMATH_API void sgemm(float alpha, Transpose TA, const FullMatrix & A, Transpose TB, const FullMatrix & B, float beta, FullMatrix & C);
/**
* Sparse matrix class. The matrix is assumed to be sparse and to have
* very few non-zero elements, for this reason it's stored in indexed
* format. To multiply column vectors efficiently, the matrix stores
* the elements in indexed-column order, there is a list of indexed
* elements for each row of the matrix. As with the FullVector the
* dimension of the matrix is constant.
**/
class SparseMatrix
{
friend class FullMatrix;
public:
// An element of the sparse array.
struct Coefficient {
uint x; // column
float v; // value
};
public:
SparseMatrix(uint d);
SparseMatrix(uint w, uint h);
SparseMatrix(const SparseMatrix & m);
const SparseMatrix & operator=(const SparseMatrix & m);
uint width() const { return m_width; }
uint height() const { return m_array.count(); }
bool isSquare() const { return width() == height(); }
float getCoefficient(uint x, uint y) const; // x is column, y is row
void setCoefficient(uint x, uint y, float f);
void addCoefficient(uint x, uint y, float f);
void mulCoefficient(uint x, uint y, float f);
float sumRow(uint y) const;
float dotRow(uint y, const FullVector & v) const;
void madRow(uint y, float alpha, FullVector & v) const;
void clearRow(uint y);
void scaleRow(uint y, float f);
void normalizeRow(uint y);
void clearColumn(uint x);
void scaleColumn(uint x, float f);
const Array<Coefficient> & getRow(uint y) const;
private:
/// Number of columns.
const uint m_width;
/// Array of matrix elements.
Array< Array<Coefficient> > m_array;
};
NVMATH_API void transpose(const SparseMatrix & A, SparseMatrix & B);
NVMATH_API void mult(const SparseMatrix & M, const FullVector & x, FullVector & y);
NVMATH_API void mult(Transpose TM, const SparseMatrix & M, const FullVector & x, FullVector & y);
// y = alpha*A*x + beta*y
NVMATH_API void sgemv(float alpha, const SparseMatrix & A, const FullVector & x, float beta, FullVector & y);
NVMATH_API void sgemv(float alpha, Transpose TA, const SparseMatrix & A, const FullVector & x, float beta, FullVector & y);
NVMATH_API void mult(const SparseMatrix & A, const SparseMatrix & B, SparseMatrix & C);
NVMATH_API void mult(Transpose TA, const SparseMatrix & A, Transpose TB, const SparseMatrix & B, SparseMatrix & C);
// C = alpha*A*B + beta*C
NVMATH_API void sgemm(float alpha, const SparseMatrix & A, const SparseMatrix & B, float beta, SparseMatrix & C);
NVMATH_API void sgemm(float alpha, Transpose TA, const SparseMatrix & A, Transpose TB, const SparseMatrix & B, float beta, SparseMatrix & C);
// C = At * A
NVMATH_API void sqm(const SparseMatrix & A, SparseMatrix & C);
} // nv namespace
#endif // NV_MATH_SPARSE_H

@ -1,243 +0,0 @@
// This code is in the public domain -- castanyo@yahoo.es
#include <nvmath/SphericalHarmonic.h>
using namespace nv;
namespace
{
// Basic integer factorial.
inline static int factorial( int v )
{
const static int fac_table[] = { 1, 1, 2, 6, 24, 120, 720, 5040, 40320, 362880, 3628800, 39916800 };
if(v <= 11){
return fac_table[v];
}
int result = v;
while (--v > 0) {
result *= v;
}
return result;
}
// Double factorial.
// Defined as: n!! = n*(n - 2)*(n - 4)..., n!!(0,-1) = 1.
inline static int doubleFactorial( int x )
{
if (x == 0 || x == -1) {
return 1;
}
int result = x;
while ((x -= 2) > 0) {
result *= x;
}
return result;
}
/// Normalization constant for spherical harmonic.
/// @param l is the band.
/// @param m is the argument, in the range [0, m]
inline static float K( int l, int m )
{
nvDebugCheck( m >= 0 );
return sqrtf(((2 * l + 1) * factorial(l - m)) / (4 * PI * factorial(l + m)));
}
/// Normalization constant for hemispherical harmonic.
inline static float HK( int l, int m )
{
nvDebugCheck( m >= 0 );
return sqrtf(((2 * l + 1) * factorial(l - m)) / (2 * PI * factorial(l + m)));
}
/// Evaluate Legendre polynomial. */
static float legendre( int l, int m, float x )
{
// piDebugCheck( m >= 0 );
// piDebugCheck( m <= l );
// piDebugCheck( fabs(x) <= 1 );
// Rule 2 needs no previous results
if (l == m) {
return powf(-1.0f, float(m)) * doubleFactorial(2 * m - 1) * powf(1 - x*x, 0.5f * m);
}
// Rule 3 requires the result for the same argument of the previous band
if (l == m + 1) {
return x * (2 * m + 1) * legendrePolynomial(m, m, x);
}
// Main reccurence used by rule 1 that uses result of the same argument from
// the previous two bands
return (x * (2 * l - 1) * legendrePolynomial(l - 1, m, x) - (l + m - 1) * legendrePolynomial(l - 2, m, x)) / (l - m);
}
template <int l, int m> float legendre(float x);
template <> float legendre<0, 0>(float ) {
return 1;
}
template <> float legendre<1, 0>(float x) {
return x;
}
template <> float legendre<1, 1>(float x) {
return -sqrtf(1 - x * x);
}
template <> float legendre<2, 0>(float x) {
return -0.5f + (3 * x * x) / 2;
}
template <> float legendre<2, 1>(float x) {
return -3 * x * sqrtf(1 - x * x);
}
template <> float legendre<2, 2>(float x) {
return -3 * (-1 + x * x);
}
template <> float legendre<3, 0>(float x) {
return -(3 * x) / 2 + (5 * x * x * x) / 2;
}
template <> float legendre<3, 1>(float x) {
return -3 * sqrtf(1 - x * x) / 2 * (-1 + 5 * x * x);
}
template <> float legendre<3, 2>(float x) {
return -15 * (-x + x * x * x);
}
template <> float legendre<3, 3>(float x) {
return -15 * powf(1 - x * x, 1.5f);
}
template <> float legendre<4, 0>(float x) {
return 0.125f * (3.0f - 30.0f * x * x + 35.0f * x * x * x * x);
}
template <> float legendre<4, 1>(float x) {
return -2.5f * x * sqrtf(1.0f - x * x) * (7.0f * x * x - 3.0f);
}
template <> float legendre<4, 2>(float x) {
return -7.5f * (1.0f - 8.0f * x * x + 7.0f * x * x * x * x);
}
template <> float legendre<4, 3>(float x) {
return -105.0f * x * powf(1 - x * x, 1.5f);
}
template <> float legendre<4, 4>(float x) {
return 105.0f * (x * x - 1.0f) * (x * x - 1.0f);
}
} // namespace
float nv::legendrePolynomial(int l, int m, float x)
{
switch(l)
{
case 0:
return legendre<0, 0>(x);
case 1:
if(m == 0) return legendre<1, 0>(x);
return legendre<1, 1>(x);
case 2:
if(m == 0) return legendre<2, 0>(x);
else if(m == 1) return legendre<2, 1>(x);
return legendre<2, 2>(x);
case 3:
if(m == 0) return legendre<3, 0>(x);
else if(m == 1) return legendre<3, 1>(x);
else if(m == 2) return legendre<3, 2>(x);
return legendre<3, 3>(x);
case 4:
if(m == 0) return legendre<4, 0>(x);
else if(m == 1) return legendre<4, 1>(x);
else if(m == 2) return legendre<4, 2>(x);
else if(m == 3) return legendre<4, 3>(x);
else return legendre<4, 4>(x);
}
// Fallback to the expensive version.
return legendre(l, m, x);
}
/**
* Evaluate the spherical harmonic function for the given angles.
* @param l is the band.
* @param m is the argument, in the range [-l,l]
* @param theta is the altitude, in the range [0, PI]
* @param phi is the azimuth, in the range [0, 2*PI]
*/
float nv::y( int l, int m, float theta, float phi )
{
if( m == 0 ) {
// K(l, 0) = sqrt((2*l+1)/(4*PI))
return sqrtf((2 * l + 1) / (4 * PI)) * legendrePolynomial(l, 0, cosf(theta));
}
else if( m > 0 ) {
return sqrtf(2.0f) * K(l, m) * cosf(m * phi) * legendrePolynomial(l, m, cosf(theta));
}
else {
return sqrtf(2.0f) * K(l, -m) * sinf(-m * phi) * legendrePolynomial(l, -m, cosf(theta));
}
}
/**
* Real spherical harmonic function of an unit vector. Uses the following
* equalities to call the angular function:
* x = sin(theta)*cos(phi)
* y = sin(theta)*sin(phi)
* z = cos(theta)
*/
float nv::y( int l, int m, Vector3::Arg v )
{
float theta = acosf(v.z());
float phi = atan2f(v.y(), v.x());
return y( l, m, theta, phi );
}
/**
* Evaluate the hemispherical harmonic function for the given angles.
* @param l is the band.
* @param m is the argument, in the range [-l,l]
* @param theta is the altitude, in the range [0, PI/2]
* @param phi is the azimuth, in the range [0, 2*PI]
*/
float nv::hy( int l, int m, float theta, float phi )
{
if( m == 0 ) {
// HK(l, 0) = sqrt((2*l+1)/(2*PI))
return sqrtf((2 * l + 1) / (2 * PI)) * legendrePolynomial(l, 0, 2*cosf(theta)-1);
}
else if( m > 0 ) {
return sqrtf(2.0f) * HK(l, m) * cosf(m * phi) * legendrePolynomial(l, m, 2*cosf(theta)-1);
}
else {
return sqrtf(2.0f) * HK(l, -m) * sinf(-m * phi) * legendrePolynomial(l, -m, 2*cosf(theta)-1);
}
}
/**
* Real hemispherical harmonic function of an unit vector. Uses the following
* equalities to call the angular function:
* x = sin(theta)*cos(phi)
* y = sin(theta)*sin(phi)
* z = cos(theta)
*/
float nv::hy( int l, int m, Vector3::Arg v )
{
float theta = acosf(v.z());
float phi = atan2f(v.y(), v.x());
return y( l, m, theta, phi );
}

@ -1,420 +0,0 @@
// This code is in the public domain -- castanyo@yahoo.es
#ifndef NV_MATH_SPHERICALHARMONIC_H
#define NV_MATH_SPHERICALHARMONIC_H
#include <string.h> // memcpy
#include <nvmath/Vector.h>
namespace nv
{
NVMATH_API float legendrePolynomial( int l, int m, float x ) NV_CONST;
NVMATH_API float y( int l, int m, float theta, float phi ) NV_CONST;
NVMATH_API float y( int l, int m, Vector3::Arg v ) NV_CONST;
NVMATH_API float hy( int l, int m, float theta, float phi ) NV_CONST;
NVMATH_API float hy( int l, int m, Vector3::Arg v ) NV_CONST;
class Sh;
float dot(const Sh & a, const Sh & b) NV_CONST;
/// Spherical harmonic class.
class Sh
{
friend class Sh2;
friend class ShMatrix;
public:
/// Construct a spherical harmonic of the given order.
Sh(int o) : m_order(o)
{
m_elemArray = new float[basisNum()];
}
/// Copy constructor.
Sh(const Sh & sh) : m_order(sh.order())
{
m_elemArray = new float[basisNum()];
memcpy(m_elemArray, sh.m_elemArray, sizeof(float) * basisNum());
}
/// Destructor.
~Sh()
{
delete [] m_elemArray;
m_elemArray = NULL;
}
/// Get number of bands.
static int bandNum(int order) {
return order + 1;
}
/// Get number of sh basis.
static int basisNum(int order) {
return (order + 1) * (order + 1);
}
/// Get the index for the given coefficients.
static int index( int l, int m ) {
return l * l + l + m;
}
/// Get sh order.
int order() const
{
return m_order;
}
/// Get sh order.
int bandNum() const
{
return bandNum(m_order);
}
/// Get sh order.
int basisNum() const
{
return basisNum(m_order);
}
/// Get sh coefficient indexed by l,m.
float elem( int l, int m ) const
{
return m_elemArray[index(l, m)];
}
/// Get sh coefficient indexed by l,m.
float & elem( int l, int m )
{
return m_elemArray[index(l, m)];
}
/// Get sh coefficient indexed by i.
float elemAt( int i ) const {
return m_elemArray[i];
}
/// Get sh coefficient indexed by i.
float & elemAt( int i )
{
return m_elemArray[i];
}
/// Reset the sh coefficients.
void reset()
{
for( int i = 0; i < basisNum(); i++ ) {
m_elemArray[i] = 0.0f;
}
}
/// Copy spherical harmonic.
void operator= ( const Sh & sh )
{
nvDebugCheck(order() <= sh.order());
for(int i = 0; i < basisNum(); i++) {
m_elemArray[i] = sh.m_elemArray[i];
}
}
/// Add spherical harmonics.
void operator+= ( const Sh & sh )
{
nvDebugCheck(order() == sh.order());
for(int i = 0; i < basisNum(); i++) {
m_elemArray[i] += sh.m_elemArray[i];
}
}
/// Substract spherical harmonics.
void operator-= ( const Sh & sh )
{
nvDebugCheck(order() == sh.order());
for(int i = 0; i < basisNum(); i++) {
m_elemArray[i] -= sh.m_elemArray[i];
}
}
// Not exactly convolution, nor product.
void operator*= ( const Sh & sh )
{
nvDebugCheck(order() == sh.order());
for(int i = 0; i < basisNum(); i++) {
m_elemArray[i] *= sh.m_elemArray[i];
}
}
/// Scale spherical harmonics.
void operator*= ( float f )
{
for(int i = 0; i < basisNum(); i++) {
m_elemArray[i] *= f;
}
}
/// Add scaled spherical harmonics.
void addScaled( const Sh & sh, float f )
{
nvDebugCheck(order() == sh.order());
for(int i = 0; i < basisNum(); i++) {
m_elemArray[i] += sh.m_elemArray[i] * f;
}
}
/*/// Add a weighted sample to the sh coefficients.
void AddSample( const Vec3 & dir, const Color3f & color, float w=1.0f ) {
for(int l = 0; l <= order; l++) {
for(int m = -l; m <= l; m++) {
Color3f & elem = GetElem(l, m);
elem.Mad( elem, color, w * y(l, m, dir) );
}
}
}*/
/// Evaluate
void eval(Vector3::Arg dir)
{
for(int l = 0; l <= m_order; l++) {
for(int m = -l; m <= l; m++) {
elem(l, m) = y(l, m, dir);
}
}
}
/// Evaluate the spherical harmonic function.
float sample(Vector3::Arg dir) const
{
Sh sh(order());
sh.eval(dir);
return dot(sh, *this);
}
protected:
const int m_order;
float * m_elemArray;
};
/// Compute dot product of the spherical harmonics.
inline float dot(const Sh & a, const Sh & b)
{
nvDebugCheck(a.order() == b.order());
float sum = 0;
for( int i = 0; i < Sh::basisNum(a.order()); i++ ) {
sum += a.elemAt(i) * b.elemAt(i);
}
return sum;
}
/// Second order spherical harmonic.
class Sh2 : public Sh
{
public:
/// Constructor.
Sh2() : Sh(2) {}
/// Copy constructor.
Sh2(const Sh2 & sh) : Sh(sh) {}
/// Spherical harmonic resulting from projecting the clamped cosine transfer function to the SH basis.
void cosineTransfer()
{
const float c1 = 0.282095f; // K(0, 0)
const float c2 = 0.488603f; // K(1, 0)
const float c3 = 1.092548f; // sqrt(15.0f / PI) / 2.0f = K(2, -2)
const float c4 = 0.315392f; // sqrt(5.0f / PI) / 4.0f) = K(2, 0)
const float c5 = 0.546274f; // sqrt(15.0f / PI) / 4.0f) = K(2, 2)
const float normalization = PI * 16.0f / 17.0f;
const float const1 = c1 * normalization * 1.0f;
const float const2 = c2 * normalization * (2.0f / 3.0f);
const float const3 = c3 * normalization * (1.0f / 4.0f);
const float const4 = c4 * normalization * (1.0f / 4.0f);
const float const5 = c5 * normalization * (1.0f / 4.0f);
m_elemArray[0] = const1;
m_elemArray[1] = -const2;
m_elemArray[2] = const2;
m_elemArray[3] = -const2;
m_elemArray[4] = const3;
m_elemArray[5] = -const3;
m_elemArray[6] = const4;
m_elemArray[7] = -const3;
m_elemArray[8] = const5;
}
};
#if 0
/// Spherical harmonic matrix.
class ShMatrix
{
public:
/// Create an identity matrix of the given order.
ShMatrix(int o = 2) : order(o), identity(true)
{
nvCheck(order > 0);
e = new float[Size()];
band = new float *[GetBandNum()];
setupBands();
}
/// Destroy and free matrix elements.
~ShMatrix()
{
delete e;
delete band;
}
/// Set identity matrix.
void setIdentity()
{
identity = true;
}
/// Return true if this is an identity matrix, false in other case.
bool isIdentity() const {
return identity;
}
/// Get number of bands of this matrix.
int bandNum() const
{
return order+1;
}
/// Get total number of elements in the matrix.
int size() const
{
int size = 0;
for( int i = 0; i < bandNum(); i++ ) {
size += SQ(i * 2 + 1);
}
return size;
}
/// Get element at the given raw index.
float elem(const int idx) const
{
return e[idx];
}
/// Get element at the given with the given indices.
float & elem( const int b, const int x, const int y )
{
nvDebugCheck(b >= 0);
nvDebugCheck(b < bandNum());
return band[b][(b + y) * (b * 2 + 1) + (b + x)];
}
/// Get element at the given with the given indices.
float elem( const int b, const int x, const int y ) const
{
nvDebugCheck(b >= 0);
nvDebugCheck(b < bandNum());
return band[b][(b + y) * (b * 2 + 1) + (b + x)];
}
/** Copy matrix. */
void Copy( const ShMatrix & m )
{
nvDebugCheck(order == m.order);
memcpy(e, m.e, Size() * sizeof(float));
}
/** Rotate the given coefficients. */
void transform( const Sh & restrict source, Sh * restrict dest ) const {
piCheck( &source != dest ); // Make sure there's no aliasing.
piCheck( dest->order <= order );
piCheck( order <= source.order );
if( identity ) {
*dest = source;
return;
}
// Loop through each band.
for( int l = 0; l <= dest->order; l++ ) {
for( int mo = -l; mo <= l; mo++ ) {
Color3f rgb = Color3f::Black;
for( int mi = -l; mi <= l; mi++ ) {
rgb.Mad( rgb, source.elem(l, mi), elem(l, mo, mi) );
}
dest->elem(l, mo) = rgb;
}
}
}
MATHLIB_API void multiply( const ShMatrix &A, const ShMatrix &B );
MATHLIB_API void rotation( const Matrix & m );
MATHLIB_API void rotation( int axis, float angles );
MATHLIB_API void print();
private:
// @@ These could be static indices precomputed only once.
/// Setup the band pointers.
void setupBands()
{
int size = 0;
for( int i = 0; i < bandNum(); i++ ) {
band[i] = &e[size];
size += SQ(i * 2 + 1);
}
}
private:
// Matrix order.
const int m_order;
// Identity flag for quick transform.
bool m_identity;
// Array of elements.
float * m_e;
// Band pointers.
float ** m_band;
};
#endif // 0
} // nv namespace
#endif // NV_MATH_SPHERICALHARMONIC_H

@ -1,226 +0,0 @@
/********************************************************/
/* 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 <nvmath/Vector.h>
#include <nvmath/Triangle.h>
using namespace nv;
#define X 0
#define Y 1
#define Z 2
#define FINDMINMAX(x0,x1,x2,min,max) \
min = max = x0; \
if(x1<min) min=x1;\
if(x1>max) max=x1;\
if(x2<min) min=x2;\
if(x2>max) 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(p0<p2) {min=p0; max=p2;} else {min=p2; max=p0;} \
rad = fa * boxhalfsize.y() + fb * boxhalfsize.z(); \
if(min>rad || 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(p0<p1) {min=p0; max=p1;} else {min=p1; max=p0;} \
rad = fa * boxhalfsize.y() + fb * boxhalfsize.z(); \
if(min>rad || 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(p0<p2) {min=p0; max=p2;} else {min=p2; max=p0;} \
rad = fa * boxhalfsize.x() + fb * boxhalfsize.z(); \
if(min>rad || 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(p0<p1) {min=p0; max=p1;} else {min=p1; max=p0;} \
rad = fa * boxhalfsize.x() + fb * boxhalfsize.z(); \
if(min>rad || 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(p2<p1) {min=p2; max=p1;} else {min=p1; max=p2;} \
rad = fa * boxhalfsize.x() + fb * boxhalfsize.y(); \
if(min>rad || 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(p0<p1) {min=p0; max=p1;} else {min=p1; max=p0;} \
rad = fa * boxhalfsize.x() + fb * boxhalfsize.y(); \
if(min>rad || max<-rad) return false;
bool nv::triBoxOverlap(Vector3::Arg boxcenter, Vector3::Arg boxhalfsize, const Triangle & tri)
{
// 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 = tri.v[0] - boxcenter;
v1 = tri.v[1] - boxcenter;
v2 = tri.v[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 nv::triBoxOverlapNoBounds(Vector3::Arg boxcenter, Vector3::Arg boxhalfsize, const Triangle & tri)
{
// 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 = tri.v[0] - boxcenter;
v1 = tri.v[1] - boxcenter;
v2 = tri.v[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);
}

@ -1,168 +0,0 @@
// This code is in the public domain -- Ignacio Castaño <castanyo@yahoo.es>
#include <nvmath/Triangle.h>
using namespace nv;
/// Tomas Möller, barycentric ray-triangle test.
bool rayTest_Moller(const Triangle & t, Vector3::Arg orig, Vector3::Arg dir, float * out_t, float * out_u, float * out_v)
{
// find vectors for two edges sharing vert0
Vector3 e1 = t.v[1] - t.v[0];
Vector3 e2 = t.v[2] - t.v[0];
// begin calculating determinant - also used to calculate U parameter
Vector3 pvec = cross(dir, e2);
// if determinant is near zero, ray lies in plane of triangle
float det = dot(e1, pvec);
if (det < -NV_EPSILON) {
return false;
}
// calculate distance from vert0 to ray origin
Vector3 tvec = orig - t.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
Vector3 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
float 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

@ -1,81 +0,0 @@
// This code is in the public domain -- Ignacio Castaño <castanyo@yahoo.es>
#ifndef NV_MATH_TRIANGLE_H
#define NV_MATH_TRIANGLE_H
#include <nvmath/nvmath.h>
#include <nvmath/Vector.h>
#include <nvmath/Box.h>
namespace nv
{
/// Triangle class with three vertices.
class Triangle
{
public:
Triangle() {};
Triangle(Vector3::Arg v0, Vector3::Arg v1, Vector3::Arg 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;
}
Vector4 plane() const
{
Vector3 n = cross(v[1]-v[0], v[2]-v[0]);
return Vector4(n, dot(n, v[0]));
}
Vector3 v[3];
};
// Tomas Akenine-Möller box-triangle test.
NVMATH_API bool triBoxOverlap(Vector3::Arg boxcenter, Vector3::Arg boxhalfsize, const Triangle & triangle);
NVMATH_API bool triBoxOverlapNoBounds(Vector3::Arg boxcenter, Vector3::Arg boxhalfsize, const Triangle & triangle);
// Moller ray triangle test.
NVMATH_API bool rayTest_Moller(const Triangle & t, Vector3::Arg orig, Vector3::Arg dir, float * out_t, float * out_u, float * out_v);
inline bool rayTest(const Triangle & t, Vector3::Arg orig, Vector3::Arg dir, float * out_t, float * out_u, float * out_v)
{
return rayTest_Moller(t, orig, dir, out_t, out_u, out_v);
}
inline bool overlap(const Triangle & t, const Box & b)
{
Vector3 center = b.center();
Vector3 extents = b.extents();
return triBoxOverlap(center, extents, t);
}
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);
}
} // nv namespace
#endif // NV_MATH_TRIANGLE_H

@ -1,87 +0,0 @@
// This code is in the public domain -- castanyo@yahoo.es
#include <nvcore/Stream.h>
#include <nvmath/Vector.h>
#include <nvmath/Matrix.h>
#include <nvmath/Quaternion.h>
#include <nvmath/Basis.h>
#include <nvmath/Box.h>
#include <nvmath/Plane.h>
#include <nvmath/TypeSerialization.h>
using namespace nv;
Stream & nv::operator<< (Stream & s, Vector2 & v)
{
float x = v.x();
float y = v.y();
s << x << y;
if (s.isLoading())
{
v.set(x, y);
}
return s;
}
Stream & nv::operator<< (Stream & s, Vector3 & v)
{
float x = v.x();
float y = v.y();
float z = v.z();
s << x << y << z;
if (s.isLoading())
{
v.set(x, y, z);
}
return s;
}
Stream & nv::operator<< (Stream & s, Vector4 & v)
{
float x = v.x();
float y = v.y();
float z = v.z();
float w = v.w();
s << x << y << z << w;
if (s.isLoading())
{
v.set(x, y, z, w);
}
return s;
}
Stream & nv::operator<< (Stream & s, Matrix & m)
{
return s;
}
Stream & nv::operator<< (Stream & s, Quaternion & q)
{
return s << q.asVector();
}
Stream & nv::operator<< (Stream & s, Basis & basis)
{
return s << basis.tangent << basis.bitangent << basis.normal;
}
Stream & nv::operator<< (Stream & s, Box & box)
{
return s << box.m_mins << box.m_maxs;
}
Stream & nv::operator<< (Stream & s, Plane & plane)
{
return s << plane.asVector();
}

@ -1,34 +0,0 @@
// This code is in the public domain -- castanyo@yahoo.es
#ifndef NV_MATH_TYPESERIALIZATION_H
#define NV_MATH_TYPESERIALIZATION_H
#include <nvmath/nvmath.h>
namespace nv
{
class Stream;
class Vector2;
class Vector3;
class Vector4;
class Matrix;
class Quaternion;
class Basis;
class Box;
class Plane;
NVMATH_API Stream & operator<< (Stream & s, Vector2 & obj);
NVMATH_API Stream & operator<< (Stream & s, Vector3 & obj);
NVMATH_API Stream & operator<< (Stream & s, Vector4 & obj);
NVMATH_API Stream & operator<< (Stream & s, Matrix & obj);
NVMATH_API Stream & operator<< (Stream & s, Quaternion & obj);
NVMATH_API Stream & operator<< (Stream & s, Basis & obj);
NVMATH_API Stream & operator<< (Stream & s, Box & obj);
NVMATH_API Stream & operator<< (Stream & s, Plane & obj);
} // nv namespace
#endif // NV_MATH_TYPESERIALIZATION_H

@ -48,19 +48,37 @@
#define IS_NEGATIVE_FLOAT(x) (IR(x)&SIGN_BITMASK)
*/
inline float sqrt_assert(const float f)
inline double sqrt_assert(const double f)
{
nvDebugCheck(f >= 0.0f);
return sqrt(f);
}
inline float sqrtf_assert(const float f)
{
nvDebugCheck(f >= 0.0f);
return sqrtf(f);
}
inline float acos_assert(const float f)
inline double acos_assert(const double f)
{
nvDebugCheck(f >= -1.0f && f <= 1.0f);
return acos(f);
}
inline float acosf_assert(const float f)
{
nvDebugCheck(f >= -1.0f && f <= 1.0f);
return acosf(f);
}
inline float asin_assert(const float f)
inline double asin_assert(const double f)
{
nvDebugCheck(f >= -1.0f && f <= 1.0f);
return asin(f);
}
inline float asinf_assert(const float f)
{
nvDebugCheck(f >= -1.0f && f <= 1.0f);
return asinf(f);
@ -68,11 +86,11 @@ inline float asin_assert(const float f)
// Replace default functions with asserting ones.
#define sqrt sqrt_assert
#define sqrtf sqrt_assert
#define sqrtf sqrtf_assert
#define acos acos_assert
#define acosf acos_assert
#define acosf acosf_assert
#define asin asin_assert
#define asinf asin_assert
#define asinf asinf_assert
#if NV_OS_WIN32
#include <float.h>

@ -86,7 +86,10 @@ TARGET_LINK_LIBRARIES(nvtestsuite nvcore nvmath nvimage nvtt)
ADD_EXECUTABLE(nvzoom tools/resize.cpp tools/cmdline.h)
TARGET_LINK_LIBRARIES(nvzoom nvcore nvmath nvimage)
INSTALL(TARGETS nvcompress nvdecompress nvddsinfo nvimgdiff nvassemble nvzoom nvtestsuite DESTINATION bin)
ADD_EXECUTABLE(driverapitest tests/driverapi.cpp)
TARGET_LINK_LIBRARIES(driverapitest nvcore nvmath nvimage)
INSTALL(TARGETS nvcompress nvdecompress nvddsinfo nvimgdiff nvassemble nvzoom nvtestsuite driverapitest DESTINATION bin)
ADD_EXECUTABLE(nv-gnome-thumbnailer tools/thumbnailer.cpp tools/cmdline.h)
TARGET_LINK_LIBRARIES(nv-gnome-thumbnailer nvcore nvmath nvimage)

@ -0,0 +1,144 @@
#include <nvcore/Library.h>
#include <cuda.h>
#include <stdio.h>
// Typedefs
typedef CUresult CUDAAPI (*cuInitPtr)( unsigned int Flags );
typedef CUresult CUDAAPI (*cuDeviceGetPtr)(CUdevice *device, int ordinal);
typedef CUresult CUDAAPI (*cuDeviceGetCountPtr)(int *count);
typedef CUresult CUDAAPI (*cuDeviceGetNamePtr)(char *name, int len, CUdevice dev);
typedef CUresult CUDAAPI (*cuDeviceComputeCapabilityPtr)(int *major, int *minor, CUdevice dev);
typedef CUresult CUDAAPI (*cuDeviceTotalMemPtr)(unsigned int *bytes, CUdevice dev);
typedef CUresult CUDAAPI (*cuDeviceGetPropertiesPtr)(CUdevprop *prop, CUdevice dev);
typedef CUresult CUDAAPI (*cuDeviceGetAttributePtr)(int *pi, CUdevice_attribute attrib, CUdevice dev);
typedef CUresult CUDAAPI (*cuCtxCreatePtr)(CUcontext *pctx, unsigned int flags, CUdevice dev );
typedef CUresult CUDAAPI (*cuCtxDestroyPtr)( CUcontext ctx );
typedef CUresult CUDAAPI (*cuCtxAttachPtr)(CUcontext *pctx, unsigned int flags);
typedef CUresult CUDAAPI (*cuCtxDetachPtr)(CUcontext ctx);
typedef CUresult CUDAAPI (*cuCtxPushCurrentPtr)( CUcontext ctx );
typedef CUresult CUDAAPI (*cuCtxPopCurrentPtr)( CUcontext *pctx );
typedef CUresult CUDAAPI (*cuCtxGetDevicePtr)(CUdevice *device);
typedef CUresult CUDAAPI (*cuCtxSynchronizePtr)(void);
// A compressor inits CUDA and creates a context for each device.
//
struct CudaDevice
{
CUdevice device;
CUcontext context;
};
struct CudaContext
{
CudaContext()
{
printf("CudaContext()\n");
#if NV_OS_WIN32
Library nvcuda("nvcuda.dll");
#else
Library nvcuda(NV_LIBRARY_NAME(cuda));
#endif
cuInit = (cuInitPtr)nvcuda.bindSymbol("cuInit");
cuDeviceGet = (cuDeviceGetPtr)nvcuda.bindSymbol("cuDeviceGet");
cuDeviceGetCount = (cuDeviceGetCountPtr)nvcuda.bindSymbol("cuDeviceGetCount");
cuDeviceGetName = (cuDeviceGetNamePtr)nvcuda.bindSymbol("cuDeviceGetName");
cuDeviceComputeCapability = (cuDeviceComputeCapabilityPtr)nvcuda.bindSymbol("cuDeviceComputeCapability");
cuDeviceTotalMem = (cuDeviceTotalMemPtr)nvcuda.bindSymbol("cuDeviceTotalMem");
cuDeviceGetProperties = (cuDeviceGetPropertiesPtr)nvcuda.bindSymbol("cuDeviceGetProperties");
cuDeviceGetAttribute = (cuDeviceGetAttributePtr)nvcuda.bindSymbol("cuDeviceGetAttribute");
cuCtxCreate = (cuCtxCreatePtr)nvcuda.bindSymbol("cuCtxCreate");
cuCtxDestroy = (cuCtxDestroyPtr)nvcuda.bindSymbol("cuCtxDestroy");
cuCtxAttach = (cuCtxAttachPtr)nvcuda.bindSymbol("cuCtxAttach");
cuCtxDetach = (cuCtxDetachPtr)nvcuda.bindSymbol("cuCtxDetach");
cuCtxPushCurrent = (cuCtxPushCurrentPtr)nvcuda.bindSymbol("cuCtxPushCurrent");
cuCtxPopCurrent = (cuCtxPopCurrentPtr)nvcuda.bindSymbol("cuCtxPopCurrent");
cuCtxGetDevice = (cuCtxGetDevicePtr)nvcuda.bindSymbol("cuCtxGetDevice");
cuCtxSynchronize = (cuCtxSynchronizePtr)nvcuda.bindSymbol("cuCtxSynchronize");
CUresult status = cuInit(0);
if (status == CUDA_SUCCESS)
{
printf("cuInit succeeded.\n");
}
m_deviceCount = 0;
cuDeviceGetCount(&m_deviceCount);
printf("%d devices found.\n", m_deviceCount);
if (m_deviceCount > 0)
{
m_devices = new CudaDevice[m_deviceCount];
uint flags = CU_CTX_SCHED_AUTO;
if (m_deviceCount > 1) flags = CU_CTX_SCHED_YIELD;
for (int i = 0; i < m_deviceCount; i++)
{
cuDeviceGet(&m_devices[i].device, i);
cuCtxCreate(&m_devices[i].context, flags, m_devices[i].device);
cuCtxDestroy(m_devices[i].context);
}
}
}
~CudaContext()
{
printf("~CudaContext()\n");
if (m_deviceCount > 0)
{
for (int i = 0; i < m_deviceCount; i++)
{
cuCtxDestroy(m_devices[i].context);
}
delete [] m_devices;
}
}
public:
cuInitPtr cuInit;
cuDeviceGetPtr cuDeviceGet;
cuDeviceGetCountPtr cuDeviceGetCount;
cuDeviceGetNamePtr cuDeviceGetName;
cuDeviceComputeCapabilityPtr cuDeviceComputeCapability;
cuDeviceTotalMemPtr cuDeviceTotalMem;
cuDeviceGetPropertiesPtr cuDeviceGetProperties;
cuDeviceGetAttributePtr cuDeviceGetAttribute;
cuCtxCreatePtr cuCtxCreate;
cuCtxDestroyPtr cuCtxDestroy;
cuCtxAttachPtr cuCtxAttach;
cuCtxDetachPtr cuCtxDetach;
cuCtxPushCurrentPtr cuCtxPushCurrent;
cuCtxPopCurrentPtr cuCtxPopCurrent;
cuCtxGetDevicePtr cuCtxGetDevice;
cuCtxSynchronizePtr cuCtxSynchronize;
int m_deviceCount;
CudaDevice * m_devices;
};
int main(void)
{
CudaContext ctx;
// cuInit(0);
return 0;
}
Loading…
Cancel
Save