- weighted cuda compressor.

- faster and better BC3n compressor
- add normal map flag to DDS files that store normal maps.
- stop using RXGB fourcc code.
- move tools to tools/
- add temptative config dialog for UI based tool. 
- add experimental normal map mipmap generation.
- start adding support for input dds files in nvcompress.
- many other small fixes and cleanup.
This commit is contained in:
castano
2007-05-17 00:11:38 +00:00
parent d729ea51f6
commit babb7e8df7
53 changed files with 9935 additions and 6137 deletions

View File

@ -40,6 +40,11 @@ IF(MSVC)
ENDIF(MSVC) ENDIF(MSVC)
#SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -march=pentium4") #SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -march=pentium4")
#SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -mcpu=powerpc")
# ibook G4:
#SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -mcpu=7450 -mtune=7450 -maltivec -mabi=altivec")
ADD_SUBDIRECTORY(src) ADD_SUBDIRECTORY(src)

View File

@ -1,13 +1,13 @@
Short term: Short term:
- support for DXT1a format. - Improve quality of fast compressors.
- More accellerated compressors. - More accellerated compressors.
- Accellerate mipmap generation. - Accellerate mipmap generation.
- Improve quality of fast compressors.
- Generic RGB pixel format conversion. - Generic RGB pixel format conversion.
- Do not assume that alpha is used for transparency. - Do not assume that alpha is used for transparency.
Longer term: Longer term:
- support for DXT1a format.
- support for correct cubemap filtering. - support for correct cubemap filtering.
- support for correct cubemap borders and atlas borders. (Crytek request) - support for correct cubemap borders and atlas borders. (Crytek request)
- support for 3d textures & 3d compression. - support for 3d textures & 3d compression.

File diff suppressed because it is too large Load Diff

View File

@ -336,6 +336,14 @@ namespace nv
return m_buffer[0]; return m_buffer[0];
} }
/// Check if the given element is contained in the array.
bool contains(const T & e) const
{
for (uint i = 0; i < m_size; i++) {
if (m_buffer[i] == e) return true;
}
return false;
}
/// Remove the element at the given index. This is an expensive operation! /// Remove the element at the given index. This is an expensive operation!
void removeAt( uint index ) void removeAt( uint index )
@ -422,7 +430,7 @@ namespace nv
if( m_size == 0 ) { if( m_size == 0 ) {
//Allocate(0); // Don't shrink automatically. //Allocate(0); // Don't shrink automatically.
} }
else if( m_size <= m_buffer_size && m_size > m_buffer_size >> 1) { else if( m_size <= m_buffer_size/* && m_size > m_buffer_size >> 1*/) {
// don't compact yet. // don't compact yet.
nvDebugCheck(m_buffer != NULL); nvDebugCheck(m_buffer != NULL);
} }

View File

@ -13,28 +13,26 @@
#define NV_ABORT_IGNORE 2 #define NV_ABORT_IGNORE 2
#define NV_ABORT_EXIT 3 #define NV_ABORT_EXIT 3
#if NV_CC_MSVC #define nvNoAssert(exp) \
#define nvNoAssert __noop do { \
#else (void)sizeof(exp); \
#define nvNoAssert(exp) } while(0)
#endif
#if NV_NO_ASSERT #if NV_NO_ASSERT
# define nvAssert(exp) nvNoAssert() # define nvAssert(exp) nvNoAssert(exp)
# define nvCheck(exp) nvNoAssert() # define nvCheck(exp) nvNoAssert(exp)
# define nvDebugAssert(exp) nvNoAssert() # define nvDebugAssert(exp) nvNoAssert(exp)
# define nvDebugCheck(exp) nvNoAssert() # define nvDebugCheck(exp) nvNoAssert(exp)
# define nvDebugBreak() # define nvDebugBreak() nvNoAssert(0)
#else // NV_NO_ASSERT #else // NV_NO_ASSERT
# if NV_CC_MSVC && NV_CPU_X86 && 0 # if NV_CC_MSVC
# define nvDebugBreak() __asm int 3 // @@ Does this work in msvc-6 and earlier?
# elif NV_CC_MSVC // this is only on recent versions... // @@ Do I have to include <intrin.h> ?
// Do I have to include <intrin.h> ?
# define nvDebugBreak() __debugbreak() # define nvDebugBreak() __debugbreak()
// define nvDebugBreak() __asm int 3
# elif NV_CC_GNUC && NV_CPU_PPC && NV_OS_DARWIN # elif NV_CC_GNUC && NV_CPU_PPC && NV_OS_DARWIN
# define nvDebugBreak() __asm__ volatile ("trap"); # define nvDebugBreak() __asm__ volatile ("trap");
# elif NV_CC_GNUC && NV_CPU_X86 && NV_OS_DARWIN # elif NV_CC_GNUC && NV_CPU_X86 && NV_OS_DARWIN
@ -43,7 +41,8 @@
# define nvDebugBreak() __asm__ ( "int %0" : :"I"(3) ) # define nvDebugBreak() __asm__ ( "int %0" : :"I"(3) )
# else # else
# include <signal.h> # include <signal.h>
# define nvDebugBreak() raise(SIGTRAP); //*((int *)(0)) = 0 # define nvDebugBreak() raise(SIGTRAP);
// define nvDebugBreak() *((int *)(0)) = 0
# endif # endif
# define nvAssertMacro(exp) \ # define nvAssertMacro(exp) \
@ -85,11 +84,11 @@
#if PI_CC_MSVC #if PI_CC_MSVC
// I'm not sure it's a good idea to use the default static assert. // @@ I'm not sure it's a good idea to use the default static assert.
#define nvStaticCheck(x) _STATIC_ASSERT(x) # define nvStaticCheck(x) _STATIC_ASSERT(x)
#else #else
#define nvStaticCheck(x) typedef char NV_DO_STRING_JOIN2(__static_assert_,__LINE__)[(x)] # define nvStaticCheck(x) typedef char NV_DO_STRING_JOIN2(__static_assert_,__LINE__)[(x)]
//#define nvStaticCheck(x) switch(0) { case 0: case x:; } // define nvStaticCheck(x) switch(0) { case 0: case x:; }
#endif #endif
NVCORE_API int nvAbort(const char *exp, const char *file, int line, const char * func = 0); NVCORE_API int nvAbort(const char *exp, const char *file, int line, const char * func = 0);

View File

@ -1,3 +1,9 @@
// This code is in the public domain -- castanyo@yahoo.es
#ifndef NV_CORE_PREFETCH_H
#define NV_CORE_PREFETCH_H
#include <nvcore/nvcore.h>
// nvPrefetch // nvPrefetch
#if NV_CC_GNUC #if NV_CC_GNUC
@ -22,3 +28,4 @@ __forceinline void nvPrefetch(const void * mem)
#endif // NV_CC_MSVC #endif // NV_CC_MSVC
#endif // NV_CORE_PREFETCH_H

File diff suppressed because it is too large Load Diff

View File

@ -1,176 +1,175 @@
// Copyright NVIDIA Corporation 2007 -- Ignacio Castano <icastano@nvidia.com> // Copyright NVIDIA Corporation 2007 -- Ignacio Castano <icastano@nvidia.com>
// //
// Permission is hereby granted, free of charge, to any person // Permission is hereby granted, free of charge, to any person
// obtaining a copy of this software and associated documentation // obtaining a copy of this software and associated documentation
// files (the "Software"), to deal in the Software without // files (the "Software"), to deal in the Software without
// restriction, including without limitation the rights to use, // restriction, including without limitation the rights to use,
// copy, modify, merge, publish, distribute, sublicense, and/or sell // copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the // copies of the Software, and to permit persons to whom the
// Software is furnished to do so, subject to the following // Software is furnished to do so, subject to the following
// conditions: // conditions:
// //
// The above copyright notice and this permission notice shall be // The above copyright notice and this permission notice shall be
// included in all copies or substantial portions of the Software. // included in all copies or substantial portions of the Software.
// //
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
// OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND // OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, // HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
// WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING // WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
// OTHER DEALINGS IN THE SOFTWARE. // OTHER DEALINGS IN THE SOFTWARE.
#ifndef NV_TT_BLOCKDXT_H #ifndef NV_IMAGE_BLOCKDXT_H
#define NV_TT_BLOCKDXT_H #define NV_IMAGE_BLOCKDXT_H
#include <nvmath/Color.h> #include <nvmath/Color.h>
#include "nvtt.h"
namespace nv
namespace nv {
{ struct ColorBlock;
struct ColorBlock;
/// DXT1 block.
/// DXT1 block. struct BlockDXT1
struct BlockDXT1 {
{ Color16 col0;
Color16 col0; Color16 col1;
Color16 col1; union {
union { uint8 row[4];
uint8 row[4]; uint indices;
uint indices; };
};
bool isFourColorMode() const;
bool isFourColorMode() const;
uint evaluatePalette(Color32 color_array[4]) const;
uint evaluatePalette(Color32 color_array[4]) const; uint evaluatePaletteFast(Color32 color_array[4]) const;
uint evaluatePaletteFast(Color32 color_array[4]) const; void evaluatePalette3(Color32 color_array[4]) const;
void evaluatePalette3(Color32 color_array[4]) const; void evaluatePalette4(Color32 color_array[4]) const;
void evaluatePalette4(Color32 color_array[4]) const;
void decodeBlock(ColorBlock * block) const;
void decodeBlock(ColorBlock * block) const;
void setIndices(int * idx);
void setIndices(int * idx);
void flip4();
void flip4(); void flip2();
void flip2(); };
};
/// Return true if the block uses four color mode, false otherwise.
/// Return true if the block uses four color mode, false otherwise. inline bool BlockDXT1::isFourColorMode() const
inline bool BlockDXT1::isFourColorMode() const {
{ return col0.u >= col1.u; // @@ > or >= ?
return col0.u >= col1.u; // @@ > or >= ? }
}
/// DXT3 alpha block with explicit alpha.
/// DXT3 alpha block with explicit alpha. struct AlphaBlockDXT3
struct AlphaBlockDXT3 {
{ union {
union { struct {
struct { uint alpha0 : 4;
uint alpha0 : 4; uint alpha1 : 4;
uint alpha1 : 4; uint alpha2 : 4;
uint alpha2 : 4; uint alpha3 : 4;
uint alpha3 : 4; uint alpha4 : 4;
uint alpha4 : 4; uint alpha5 : 4;
uint alpha5 : 4; uint alpha6 : 4;
uint alpha6 : 4; uint alpha7 : 4;
uint alpha7 : 4; uint alpha8 : 4;
uint alpha8 : 4; uint alpha9 : 4;
uint alpha9 : 4; uint alphaA : 4;
uint alphaA : 4; uint alphaB : 4;
uint alphaB : 4; uint alphaC : 4;
uint alphaC : 4; uint alphaD : 4;
uint alphaD : 4; uint alphaE : 4;
uint alphaE : 4; uint alphaF : 4;
uint alphaF : 4; };
}; uint16 row[4];
uint16 row[4]; };
};
void flip4();
void flip4(); void flip2();
void flip2(); };
};
/// DXT3 block.
/// DXT3 block. struct BlockDXT3
struct BlockDXT3 {
{ AlphaBlockDXT3 alpha;
AlphaBlockDXT3 alpha; BlockDXT1 color;
BlockDXT1 color;
void decodeBlock(ColorBlock * block) const;
void decodeBlock(ColorBlock * block) const;
void flip4();
void flip4(); void flip2();
void flip2(); };
};
/// DXT5 alpha block.
/// DXT5 alpha block. struct AlphaBlockDXT5
struct AlphaBlockDXT5 {
{ union {
union { struct {
struct { uint64 alpha0 : 8; // 8
uint64 alpha0 : 8; // 8 uint64 alpha1 : 8; // 16
uint64 alpha1 : 8; // 16 uint64 bits0 : 3; // 3 - 19
uint64 bits0 : 3; // 3 - 19 uint64 bits1 : 3; // 6 - 22
uint64 bits1 : 3; // 6 - 22 uint64 bits2 : 3; // 9 - 25
uint64 bits2 : 3; // 9 - 25 uint64 bits3 : 3; // 12 - 28
uint64 bits3 : 3; // 12 - 28 uint64 bits4 : 3; // 15 - 31
uint64 bits4 : 3; // 15 - 31 uint64 bits5 : 3; // 18 - 34
uint64 bits5 : 3; // 18 - 34 uint64 bits6 : 3; // 21 - 37
uint64 bits6 : 3; // 21 - 37 uint64 bits7 : 3; // 24 - 40
uint64 bits7 : 3; // 24 - 40 uint64 bits8 : 3; // 27 - 43
uint64 bits8 : 3; // 27 - 43 uint64 bits9 : 3; // 30 - 46
uint64 bits9 : 3; // 30 - 46 uint64 bitsA : 3; // 33 - 49
uint64 bitsA : 3; // 33 - 49 uint64 bitsB : 3; // 36 - 52
uint64 bitsB : 3; // 36 - 52 uint64 bitsC : 3; // 39 - 55
uint64 bitsC : 3; // 39 - 55 uint64 bitsD : 3; // 42 - 58
uint64 bitsD : 3; // 42 - 58 uint64 bitsE : 3; // 45 - 61
uint64 bitsE : 3; // 45 - 61 uint64 bitsF : 3; // 48 - 64
uint64 bitsF : 3; // 48 - 64 };
}; uint64 u;
uint64 u; };
};
void evaluatePalette(uint8 alpha[8]) const;
void evaluatePalette(uint8 alpha[8]) const; void evaluatePalette8(uint8 alpha[8]) const;
void evaluatePalette8(uint8 alpha[8]) const; void evaluatePalette6(uint8 alpha[8]) const;
void evaluatePalette6(uint8 alpha[8]) const; void indices(uint8 index_array[16]) const;
void indices(uint8 index_array[16]) const;
uint index(uint index) const;
uint index(uint index) const; void setIndex(uint index, uint value);
void setIndex(uint index, uint value);
void flip4();
void flip4(); void flip2();
void flip2(); };
};
/// DXT5 block.
/// DXT5 block. struct BlockDXT5
struct BlockDXT5 {
{ AlphaBlockDXT5 alpha;
AlphaBlockDXT5 alpha; BlockDXT1 color;
BlockDXT1 color;
void decodeBlock(ColorBlock * block) const;
void decodeBlock(ColorBlock * block) const;
void flip4();
void flip4(); void flip2();
void flip2(); };
};
/// 3DC block.
/// 3DC block. struct Block3DC
struct Block3DC {
{ AlphaBlockDXT5 y;
AlphaBlockDXT5 y; AlphaBlockDXT5 x;
AlphaBlockDXT5 x;
void decodeBlock(ColorBlock * block) const;
void decodeBlock(ColorBlock * block) const;
void flip4();
void flip4(); void flip2();
void flip2(); };
};
} // nv namespace
} // nv namespace
#endif // NV_IMAGE_BLOCKDXT_H
#endif // NV_TT_BLOCKDXT_H

View File

@ -14,6 +14,8 @@ SET(IMAGE_SRCS
ImageIO.cpp ImageIO.cpp
ColorBlock.h ColorBlock.h
ColorBlock.cpp ColorBlock.cpp
BlockDXT.h
BlockDXT.cpp
HoleFilling.h HoleFilling.h
HoleFilling.cpp HoleFilling.cpp
DirectDrawSurface.h DirectDrawSurface.h
@ -21,7 +23,9 @@ SET(IMAGE_SRCS
Quantize.h Quantize.h
Quantize.cpp Quantize.cpp
NormalMap.h NormalMap.h
NormalMap.cpp) NormalMap.cpp
NormalMipmap.h
NormalMipmap.cpp)
INCLUDE_DIRECTORIES(${CMAKE_CURRENT_SOURCE_DIR}) INCLUDE_DIRECTORIES(${CMAKE_CURRENT_SOURCE_DIR})

View File

@ -53,7 +53,7 @@ void ColorBlock::init(const Image * img, uint x, uint y)
nvDebugCheck(bw != 0); nvDebugCheck(bw != 0);
nvDebugCheck(bh != 0); nvDebugCheck(bh != 0);
int remainder[] = { static int remainder[] = {
0, 0, 0, 0, 0, 0, 0, 0,
0, 1, 0, 1, 0, 1, 0, 1,
0, 1, 2, 0, 0, 1, 2, 0,
@ -61,7 +61,7 @@ void ColorBlock::init(const Image * img, uint x, uint y)
}; };
// Blocks that are smaller than 4x4 are handled by repeating the pixels. // Blocks that are smaller than 4x4 are handled by repeating the pixels.
// @@ Thats only correct when block size is 1, 2 or 4, but not with 3. // @@ Thats only correct when block size is 1, 2 or 4, but not with 3. :(
for(uint i = 0; i < 4; i++) { for(uint i = 0; i < 4; i++) {
//const int by = i % bh; //const int by = i % bh;
@ -80,7 +80,7 @@ void ColorBlock::swizzleDXT5n()
for(int i = 0; i < 16; i++) for(int i = 0; i < 16; i++)
{ {
Color32 c = m_color[i]; Color32 c = m_color[i];
m_color[i] = Color32(0, c.r, 0, c.g); m_color[i] = Color32(0, c.g, 0, c.r);
} }
} }

View File

@ -1,258 +1,652 @@
// Copyright NVIDIA Corporation 2007 -- Ignacio Castano <icastano@nvidia.com> // Copyright NVIDIA Corporation 2007 -- Ignacio Castano <icastano@nvidia.com>
// //
// Permission is hereby granted, free of charge, to any person // Permission is hereby granted, free of charge, to any person
// obtaining a copy of this software and associated documentation // obtaining a copy of this software and associated documentation
// files (the "Software"), to deal in the Software without // files (the "Software"), to deal in the Software without
// restriction, including without limitation the rights to use, // restriction, including without limitation the rights to use,
// copy, modify, merge, publish, distribute, sublicense, and/or sell // copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the // copies of the Software, and to permit persons to whom the
// Software is furnished to do so, subject to the following // Software is furnished to do so, subject to the following
// conditions: // conditions:
// //
// The above copyright notice and this permission notice shall be // The above copyright notice and this permission notice shall be
// included in all copies or substantial portions of the Software. // included in all copies or substantial portions of the Software.
// //
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
// OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND // OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, // HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
// WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING // WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
// OTHER DEALINGS IN THE SOFTWARE. // OTHER DEALINGS IN THE SOFTWARE.
#include <nvcore/Debug.h> #include <nvcore/Debug.h>
#include <nvcore/Containers.h> // max
#include <nvimage/DirectDrawSurface.h> #include <nvcore/StdStream.h>
#include <string.h> // memset #include <nvimage/DirectDrawSurface.h>
#include <nvimage/ColorBlock.h>
#include <nvimage/Image.h>
using namespace nv; #include <nvimage/BlockDXT.h>
#if !defined(MAKEFOURCC) #include <string.h> // memset
# define MAKEFOURCC(ch0, ch1, ch2, ch3) \
(uint(uint8(ch0)) | (uint(uint8(ch1)) << 8) | \
(uint(uint8(ch2)) << 16) | (uint(uint8(ch3)) << 24 )) using namespace nv;
#endif
#if !defined(MAKEFOURCC)
namespace # define MAKEFOURCC(ch0, ch1, ch2, ch3) \
{ (uint(uint8(ch0)) | (uint(uint8(ch1)) << 8) | \
static const uint FOURCC_DDS = MAKEFOURCC('D', 'D', 'S', ' '); (uint(uint8(ch2)) << 16) | (uint(uint8(ch3)) << 24 ))
static const uint FOURCC_DXT1 = MAKEFOURCC('D', 'X', 'T', '1'); #endif
static const uint FOURCC_DXT2 = MAKEFOURCC('D', 'X', 'T', '2');
static const uint FOURCC_DXT3 = MAKEFOURCC('D', 'X', 'T', '3'); namespace
static const uint FOURCC_DXT4 = MAKEFOURCC('D', 'X', 'T', '4'); {
static const uint FOURCC_DXT5 = MAKEFOURCC('D', 'X', 'T', '5'); static const uint FOURCC_DDS = MAKEFOURCC('D', 'D', 'S', ' ');
static const uint FOURCC_RXGB = MAKEFOURCC('R', 'X', 'G', 'B'); static const uint FOURCC_DXT1 = MAKEFOURCC('D', 'X', 'T', '1');
static const uint FOURCC_ATI1 = MAKEFOURCC('A', 'T', 'I', '1'); static const uint FOURCC_DXT2 = MAKEFOURCC('D', 'X', 'T', '2');
static const uint FOURCC_ATI2 = MAKEFOURCC('A', 'T', 'I', '2'); static const uint FOURCC_DXT3 = MAKEFOURCC('D', 'X', 'T', '3');
static const uint FOURCC_DXT4 = MAKEFOURCC('D', 'X', 'T', '4');
static const uint DDSD_CAPS = 0x00000001U; static const uint FOURCC_DXT5 = MAKEFOURCC('D', 'X', 'T', '5');
static const uint DDSD_PIXELFORMAT = 0x00001000U; static const uint FOURCC_RXGB = MAKEFOURCC('R', 'X', 'G', 'B');
static const uint DDSD_WIDTH = 0x00000004U; static const uint FOURCC_ATI1 = MAKEFOURCC('A', 'T', 'I', '1');
static const uint DDSD_HEIGHT = 0x00000002U; static const uint FOURCC_ATI2 = MAKEFOURCC('A', 'T', 'I', '2');
static const uint DDSD_PITCH = 0x00000008U; static const uint FOURCC_BC3N = MAKEFOURCC('B', 'C', '3', 'N');
static const uint DDSD_MIPMAPCOUNT = 0x00020000U;
static const uint DDSD_LINEARSIZE = 0x00080000U; static const uint DDSD_CAPS = 0x00000001U;
static const uint DDSD_DEPTH = 0x00800000U; static const uint DDSD_PIXELFORMAT = 0x00001000U;
static const uint DDSD_WIDTH = 0x00000004U;
static const uint DDSCAPS_COMPLEX = 0x00000008U; static const uint DDSD_HEIGHT = 0x00000002U;
static const uint DDSCAPS_TEXTURE = 0x00001000U; static const uint DDSD_PITCH = 0x00000008U;
static const uint DDSCAPS_MIPMAP = 0x00400000U; static const uint DDSD_MIPMAPCOUNT = 0x00020000U;
static const uint DDSCAPS2_VOLUME = 0x00200000U; static const uint DDSD_LINEARSIZE = 0x00080000U;
static const uint DDSCAPS2_CUBEMAP = 0x00000200U; static const uint DDSD_DEPTH = 0x00800000U;
static const uint DDSCAPS2_CUBEMAP_POSITIVEX = 0x00000400U; static const uint DDSCAPS_COMPLEX = 0x00000008U;
static const uint DDSCAPS2_CUBEMAP_NEGATIVEX = 0x00000800U; static const uint DDSCAPS_TEXTURE = 0x00001000U;
static const uint DDSCAPS2_CUBEMAP_POSITIVEY = 0x00001000U; static const uint DDSCAPS_MIPMAP = 0x00400000U;
static const uint DDSCAPS2_CUBEMAP_NEGATIVEY = 0x00002000U; static const uint DDSCAPS2_VOLUME = 0x00200000U;
static const uint DDSCAPS2_CUBEMAP_POSITIVEZ = 0x00004000U; static const uint DDSCAPS2_CUBEMAP = 0x00000200U;
static const uint DDSCAPS2_CUBEMAP_NEGATIVEZ = 0x00008000U;
static const uint DDSCAPS2_CUBEMAP_ALL_FACES = 0x0000F000U; static const uint DDSCAPS2_CUBEMAP_POSITIVEX = 0x00000400U;
static const uint DDSCAPS2_CUBEMAP_NEGATIVEX = 0x00000800U;
static const uint DDPF_RGB = 0x00000040U; static const uint DDSCAPS2_CUBEMAP_POSITIVEY = 0x00001000U;
static const uint DDPF_FOURCC = 0x00000004U; static const uint DDSCAPS2_CUBEMAP_NEGATIVEY = 0x00002000U;
static const uint DDPF_ALPHAPIXELS = 0x00000001U; static const uint DDSCAPS2_CUBEMAP_POSITIVEZ = 0x00004000U;
} static const uint DDSCAPS2_CUBEMAP_NEGATIVEZ = 0x00008000U;
static const uint DDSCAPS2_CUBEMAP_ALL_FACES = 0x0000FC00U;
DDSHeader::DDSHeader()
{ static const uint DDPF_RGB = 0x00000040U;
this->fourcc = FOURCC_DDS; static const uint DDPF_FOURCC = 0x00000004U;
this->size = 124; static const uint DDPF_ALPHAPIXELS = 0x00000001U;
this->flags = (DDSD_CAPS|DDSD_PIXELFORMAT); static const uint DDPF_NORMAL = 0x80000000U; // @@ Custom flag.
this->height = 0;
this->width = 0; } // namespace
this->pitch = 0;
this->depth = 0; namespace nv
this->mipmapcount = 0; {
memset(this->reserved, 0, sizeof(this->reserved)); static Stream & operator<< (Stream & s, DDSPixelFormat & pf)
{
// Store version information on the reserved header attributes. s << pf.size;
this->reserved[9] = MAKEFOURCC('N', 'V', 'T', 'T'); s << pf.flags;
this->reserved[10] = (0 << 16) | (1 << 8) | (0); // major.minor.revision s << pf.fourcc;
s << pf.bitcount;
this->pf.size = 32; s << pf.rmask;
this->pf.flags = 0; s << pf.gmask;
this->pf.fourcc = 0; s << pf.bmask;
this->pf.bitcount = 0; s << pf.amask;
this->pf.rmask = 0; return s;
this->pf.gmask = 0; }
this->pf.bmask = 0;
this->pf.amask = 0; static Stream & operator<< (Stream & s, DDSCaps & caps)
this->caps.caps1 = DDSCAPS_TEXTURE; {
this->caps.caps2 = 0; s << caps.caps1;
this->caps.caps3 = 0; s << caps.caps2;
this->caps.caps4 = 0; s << caps.caps3;
this->notused = 0; s << caps.caps4;
} return s;
}
void DDSHeader::setWidth(uint w)
{ static Stream & operator<< (Stream & s, DDSHeader & header)
this->flags |= DDSD_WIDTH; {
this->width = w; nvStaticCheck(sizeof(DDSHeader) == 128);
} s << header.fourcc;
s << header.size;
void DDSHeader::setHeight(uint h) s << header.flags;
{ s << header.height;
this->flags |= DDSD_HEIGHT; s << header.width;
this->height = h; s << header.pitch;
} s << header.depth;
s << header.mipmapcount;
void DDSHeader::setDepth(uint d) s.serialize(header.reserved, 11 * sizeof(uint));
{ s << header.pf;
this->flags |= DDSD_DEPTH; s << header.caps;
this->height = d; s << header.notused;
} return s;
}
void DDSHeader::setMipmapCount(uint count) }
{
if (count == 0) DDSHeader::DDSHeader()
{ {
this->flags &= ~DDSD_MIPMAPCOUNT; this->fourcc = FOURCC_DDS;
this->mipmapcount = 0; this->size = 124;
this->flags = (DDSD_CAPS|DDSD_PIXELFORMAT);
if (this->caps.caps2 == 0) { this->height = 0;
this->caps.caps1 = DDSCAPS_TEXTURE; this->width = 0;
} this->pitch = 0;
else { this->depth = 0;
this->caps.caps1 = DDSCAPS_TEXTURE | DDSCAPS_COMPLEX; this->mipmapcount = 0;
} memset(this->reserved, 0, sizeof(this->reserved));
}
else // Store version information on the reserved header attributes.
{ this->reserved[9] = MAKEFOURCC('N', 'V', 'T', 'T');
this->flags |= DDSD_MIPMAPCOUNT; this->reserved[10] = (0 << 16) | (1 << 8) | (0); // major.minor.revision
this->mipmapcount = count;
this->pf.size = 32;
this->caps.caps1 |= DDSCAPS_COMPLEX | DDSCAPS_MIPMAP; this->pf.flags = 0;
} this->pf.fourcc = 0;
} this->pf.bitcount = 0;
this->pf.rmask = 0;
void DDSHeader::setTexture2D() this->pf.gmask = 0;
{ this->pf.bmask = 0;
// nothing to do here. this->pf.amask = 0;
} this->caps.caps1 = DDSCAPS_TEXTURE;
this->caps.caps2 = 0;
void DDSHeader::setTexture3D() this->caps.caps3 = 0;
{ this->caps.caps4 = 0;
this->caps.caps2 = DDSCAPS2_VOLUME; this->notused = 0;
} }
void DDSHeader::setTextureCube() void DDSHeader::setWidth(uint w)
{ {
this->caps.caps1 |= DDSCAPS_COMPLEX; this->flags |= DDSD_WIDTH;
this->caps.caps2 = DDSCAPS2_CUBEMAP | DDSCAPS2_CUBEMAP_ALL_FACES; this->width = w;
} }
void DDSHeader::setLinearSize(uint size) void DDSHeader::setHeight(uint h)
{ {
this->flags &= ~DDSD_PITCH; this->flags |= DDSD_HEIGHT;
this->flags |= DDSD_LINEARSIZE; this->height = h;
this->pitch = size; }
}
void DDSHeader::setDepth(uint d)
void DDSHeader::setPitch(uint pitch) {
{ this->flags |= DDSD_DEPTH;
this->flags &= ~DDSD_LINEARSIZE; this->height = d;
this->flags |= DDSD_PITCH; }
this->pitch = pitch;
} void DDSHeader::setMipmapCount(uint count)
{
void DDSHeader::setFourCC(uint8 c0, uint8 c1, uint8 c2, uint8 c3) if (count == 0)
{ {
// set fourcc pixel format. this->flags &= ~DDSD_MIPMAPCOUNT;
this->pf.flags = DDPF_FOURCC; this->mipmapcount = 0;
this->pf.fourcc = MAKEFOURCC(c0, c1, c2, c3);
this->pf.bitcount = 0; if (this->caps.caps2 == 0) {
this->pf.rmask = 0; this->caps.caps1 = DDSCAPS_TEXTURE;
this->pf.gmask = 0; }
this->pf.bmask = 0; else {
this->pf.amask = 0; this->caps.caps1 = DDSCAPS_TEXTURE | DDSCAPS_COMPLEX;
} }
}
void DDSHeader::setPixelFormat(uint bitcount, uint rmask, uint gmask, uint bmask, uint amask) else
{ {
// Make sure the masks are correct. this->flags |= DDSD_MIPMAPCOUNT;
nvCheck((rmask & gmask) == 0); this->mipmapcount = count;
nvCheck((rmask & bmask) == 0);
nvCheck((rmask & amask) == 0); this->caps.caps1 |= DDSCAPS_COMPLEX | DDSCAPS_MIPMAP;
nvCheck((gmask & bmask) == 0); }
nvCheck((gmask & amask) == 0); }
nvCheck((bmask & amask) == 0);
void DDSHeader::setTexture2D()
this->pf.flags = DDPF_RGB; {
// nothing to do here.
if (amask != 0) { }
this->pf.flags |= DDPF_ALPHAPIXELS;
} void DDSHeader::setTexture3D()
{
if (bitcount == 0) this->caps.caps2 = DDSCAPS2_VOLUME;
{ }
// Compute bit count from the masks.
uint total = rmask | gmask | bmask | amask; void DDSHeader::setTextureCube()
while(total != 0) { {
bitcount++; this->caps.caps1 |= DDSCAPS_COMPLEX;
total >>= 1; this->caps.caps2 = DDSCAPS2_CUBEMAP | DDSCAPS2_CUBEMAP_ALL_FACES;
} }
// @@ Align to 8?
} void DDSHeader::setLinearSize(uint size)
{
this->pf.fourcc = 0; this->flags &= ~DDSD_PITCH;
this->pf.bitcount = bitcount; this->flags |= DDSD_LINEARSIZE;
this->pf.rmask = rmask; this->pitch = size;
this->pf.gmask = gmask; }
this->pf.bmask = bmask;
this->pf.amask = amask; void DDSHeader::setPitch(uint pitch)
} {
this->flags &= ~DDSD_LINEARSIZE;
this->flags |= DDSD_PITCH;
void DDSHeader::swapBytes() this->pitch = pitch;
{ }
this->fourcc = POSH_LittleU32(this->fourcc);
this->size = POSH_LittleU32(this->size); void DDSHeader::setFourCC(uint8 c0, uint8 c1, uint8 c2, uint8 c3)
this->flags = POSH_LittleU32(this->flags); {
this->height = POSH_LittleU32(this->height); // set fourcc pixel format.
this->width = POSH_LittleU32(this->width); this->pf.flags = DDPF_FOURCC;
this->pitch = POSH_LittleU32(this->pitch); this->pf.fourcc = MAKEFOURCC(c0, c1, c2, c3);
this->depth = POSH_LittleU32(this->depth); this->pf.bitcount = 0;
this->mipmapcount = POSH_LittleU32(this->mipmapcount); this->pf.rmask = 0;
this->pf.gmask = 0;
for(int i = 0; i < 11; i++) { this->pf.bmask = 0;
this->reserved[i] = POSH_LittleU32(this->reserved[i]); this->pf.amask = 0;
} }
this->pf.size = POSH_LittleU32(this->pf.size); void DDSHeader::setPixelFormat(uint bitcount, uint rmask, uint gmask, uint bmask, uint amask)
this->pf.flags = POSH_LittleU32(this->pf.flags); {
this->pf.fourcc = POSH_LittleU32(this->pf.fourcc); // Make sure the masks are correct.
this->pf.bitcount = POSH_LittleU32(this->pf.bitcount); nvCheck((rmask & gmask) == 0);
this->pf.rmask = POSH_LittleU32(this->pf.rmask); nvCheck((rmask & bmask) == 0);
this->pf.gmask = POSH_LittleU32(this->pf.gmask); nvCheck((rmask & amask) == 0);
this->pf.bmask = POSH_LittleU32(this->pf.bmask); nvCheck((gmask & bmask) == 0);
this->pf.amask = POSH_LittleU32(this->pf.amask); nvCheck((gmask & amask) == 0);
this->caps.caps1 = POSH_LittleU32(this->caps.caps1); nvCheck((bmask & amask) == 0);
this->caps.caps2 = POSH_LittleU32(this->caps.caps2);
this->caps.caps3 = POSH_LittleU32(this->caps.caps3); this->pf.flags = DDPF_RGB;
this->caps.caps4 = POSH_LittleU32(this->caps.caps4);
this->notused = POSH_LittleU32(this->notused); if (amask != 0) {
} this->pf.flags |= DDPF_ALPHAPIXELS;
}
if (bitcount == 0)
{
// Compute bit count from the masks.
uint total = rmask | gmask | bmask | amask;
while(total != 0) {
bitcount++;
total >>= 1;
}
// @@ Align to 8?
}
this->pf.fourcc = 0;
this->pf.bitcount = bitcount;
this->pf.rmask = rmask;
this->pf.gmask = gmask;
this->pf.bmask = bmask;
this->pf.amask = amask;
}
void DDSHeader::setNormalFlag(bool b)
{
if (b) this->pf.flags |= DDPF_NORMAL;
else this->pf.flags &= ~DDPF_NORMAL;
}
void DDSHeader::swapBytes()
{
this->fourcc = POSH_LittleU32(this->fourcc);
this->size = POSH_LittleU32(this->size);
this->flags = POSH_LittleU32(this->flags);
this->height = POSH_LittleU32(this->height);
this->width = POSH_LittleU32(this->width);
this->pitch = POSH_LittleU32(this->pitch);
this->depth = POSH_LittleU32(this->depth);
this->mipmapcount = POSH_LittleU32(this->mipmapcount);
for(int i = 0; i < 11; i++) {
this->reserved[i] = POSH_LittleU32(this->reserved[i]);
}
this->pf.size = POSH_LittleU32(this->pf.size);
this->pf.flags = POSH_LittleU32(this->pf.flags);
this->pf.fourcc = POSH_LittleU32(this->pf.fourcc);
this->pf.bitcount = POSH_LittleU32(this->pf.bitcount);
this->pf.rmask = POSH_LittleU32(this->pf.rmask);
this->pf.gmask = POSH_LittleU32(this->pf.gmask);
this->pf.bmask = POSH_LittleU32(this->pf.bmask);
this->pf.amask = POSH_LittleU32(this->pf.amask);
this->caps.caps1 = POSH_LittleU32(this->caps.caps1);
this->caps.caps2 = POSH_LittleU32(this->caps.caps2);
this->caps.caps3 = POSH_LittleU32(this->caps.caps3);
this->caps.caps4 = POSH_LittleU32(this->caps.caps4);
this->notused = POSH_LittleU32(this->notused);
}
DirectDrawSurface::DirectDrawSurface(const char * name) : stream(new StdInputStream(name))
{
if (!stream->isError())
{
(*stream) << header;
}
}
DirectDrawSurface::~DirectDrawSurface()
{
delete stream;
}
bool DirectDrawSurface::isValid() const
{
if (stream->isError())
{
return false;
}
if (header.fourcc != FOURCC_DDS || header.size != 124)
{
return false;
}
const uint required = (DDSD_WIDTH|DDSD_HEIGHT|DDSD_CAPS|DDSD_PIXELFORMAT);
if( (header.flags & required) != required ) {
return false;
}
if (header.pf.size != 32) {
return false;
}
if( !(header.caps.caps1 & DDSCAPS_TEXTURE) ) {
return false;
}
return true;
}
bool DirectDrawSurface::isSupported() const
{
nvDebugCheck(isValid());
if (header.pf.flags & DDPF_FOURCC)
{
if (header.pf.fourcc != FOURCC_DXT1 &&
header.pf.fourcc != FOURCC_DXT2 &&
header.pf.fourcc != FOURCC_DXT3 &&
header.pf.fourcc != FOURCC_DXT4 &&
header.pf.fourcc != FOURCC_DXT5 &&
header.pf.fourcc != FOURCC_RXGB &&
header.pf.fourcc != FOURCC_ATI1 &&
header.pf.fourcc != FOURCC_ATI2 &&
header.pf.fourcc != FOURCC_BC3N)
{
// Unknown fourcc code.
return false;
}
}
else if (header.pf.flags & DDPF_RGB)
{
if (header.pf.bitcount == 24)
{
}
else if (header.pf.bitcount == 24)
{
}
else
{
// Unsupported pixel format.
return false;
}
}
else
{
return false;
}
if (isTextureCube() && (header.caps.caps2 & DDSCAPS2_CUBEMAP_ALL_FACES) != DDSCAPS2_CUBEMAP_ALL_FACES)
{
// Cubemaps must contain all faces.
return false;
}
if (isTexture3D())
{
// @@ 3D textures not supported yet.
return false;
}
return false;
}
uint DirectDrawSurface::mipmapCount() const
{
nvDebugCheck(isValid());
if (header.flags & DDSD_MIPMAPCOUNT) return header.mipmapcount;
else return 0;
}
uint DirectDrawSurface::width() const
{
nvDebugCheck(isValid());
if (header.flags & DDSD_WIDTH) return header.width;
else return 1;
}
uint DirectDrawSurface::height() const
{
nvDebugCheck(isValid());
if (header.flags & DDSD_HEIGHT) return header.height;
else return 1;
}
uint DirectDrawSurface::depth() const
{
nvDebugCheck(isValid());
if (header.flags & DDSD_DEPTH) return header.depth;
else return 1;
}
bool DirectDrawSurface::isTexture2D() const
{
nvDebugCheck(isValid());
return !isTexture3D() && !isTextureCube();
}
bool DirectDrawSurface::isTexture3D() const
{
nvDebugCheck(isValid());
return (header.caps.caps2 & DDSCAPS2_VOLUME) != 0;
}
bool DirectDrawSurface::isTextureCube() const
{
nvDebugCheck(isValid());
return (header.caps.caps2 & DDSCAPS2_CUBEMAP) != 0;
}
void DirectDrawSurface::mipmap(Image * img, uint face, uint mipmap)
{
nvDebugCheck(isValid());
stream->seek(offset(face, mipmap));
uint w = width();
uint h = height();
// Compute width and height.
for (uint m = 0; m < mipmap; m++)
{
w = max(1U, w / 2);
h = max(1U, h / 2);
}
img->allocate(w, h);
// readLinearImage(stream, img);
// readBlockImage(stream, img);
}
void DirectDrawSurface::readLinearImage(Stream * stream, Image * img)
{
nvDebugCheck(stream != NULL);
nvDebugCheck(img != NULL);
}
void DirectDrawSurface::readBlockImage(Stream * stream, Image * img)
{
nvDebugCheck(stream != NULL);
nvDebugCheck(img != NULL);
const uint bw = (img->width() + 3) / 4;
const uint bh = (img->height() + 3) / 4;
for (uint by = 0; by < bh; by++)
{
for (uint bx = 0; bx < bw; bx++)
{
ColorBlock block;
// Read color block.
readBlock(stream, &block);
// Write color block.
}
}
}
void DirectDrawSurface::readBlock(Stream * stream, ColorBlock * rgba)
{
nvDebugCheck(stream != NULL);
nvDebugCheck(rgba != NULL);
if (header.pf.fourcc == FOURCC_DXT1 ||
header.pf.fourcc == FOURCC_DXT2 ||
header.pf.fourcc == FOURCC_DXT3 ||
header.pf.fourcc == FOURCC_DXT4 ||
header.pf.fourcc == FOURCC_DXT5 ||
header.pf.fourcc == FOURCC_RXGB ||
header.pf.fourcc != FOURCC_BC3N)
{
// Read DXT1 block.
BlockDXT1 block;
if (header.pf.fourcc == FOURCC_BC3N)
{
// Write G only
}
else
{
// Write RGB.
}
}
if (header.pf.fourcc == FOURCC_ATI2)
{
// Read DXT5 alpha block.
// Write R.
}
if (header.pf.fourcc == FOURCC_DXT2 ||
header.pf.fourcc == FOURCC_DXT3)
{
// Read DXT3 alpha block.
}
if (header.pf.fourcc == FOURCC_DXT4 ||
header.pf.fourcc == FOURCC_DXT5 ||
header.pf.fourcc == FOURCC_RXGB)
{
// Read DXT5 alpha block.
}
if (header.pf.fourcc == FOURCC_RXGB)
{
// swap G & A
}
}
uint DirectDrawSurface::blockSize() const
{
switch(header.pf.fourcc)
{
case FOURCC_DXT1:
case FOURCC_ATI1:
return 8;
case FOURCC_DXT2:
case FOURCC_DXT3:
case FOURCC_DXT4:
case FOURCC_DXT5:
case FOURCC_RXGB:
case FOURCC_ATI2:
case FOURCC_BC3N:
return 16;
};
// This should never happen.
nvDebugCheck(false);
return 0;
}
uint DirectDrawSurface::mipmapSize(uint mipmap) const
{
uint w = width();
uint h = height();
uint d = depth();
for (uint m = 0; m < mipmap; m++)
{
w = max(1U, w / 2);
h = max(1U, h / 2);
d = max(1U, d / 2);
}
if (header.pf.flags & DDPF_FOURCC)
{
// @@ How are 3D textures aligned?
w = (w + 3) / 4;
h = (h + 3) / 4;
return blockSize() * w * h;
}
else
{
nvDebugCheck(header.pf.flags & DDPF_RGB);
// Align pixels to bytes.
uint byteCount = (header.pf.bitcount + 7) / 8;
// Align pitch to 4 bytes.
uint pitch = 4 * ((w * byteCount + 3) / 4);
return pitch * h * d;
}
}
uint DirectDrawSurface::faceSize() const
{
const uint count = mipmapCount();
uint size = 0;
for (uint m = 0; m < count; m++)
{
size += mipmapSize(m);
}
return size;
}
uint DirectDrawSurface::offset(const uint face, const uint mipmap)
{
uint size = sizeof(DDSHeader);
if (face != 0)
{
size += face * faceSize();
}
for (uint m = 0; m < mipmap; m++)
{
size += mipmapSize(m);
}
return size;
}

View File

@ -1,85 +1,127 @@
// Copyright NVIDIA Corporation 2007 -- Ignacio Castano <icastano@nvidia.com> // Copyright NVIDIA Corporation 2007 -- Ignacio Castano <icastano@nvidia.com>
// //
// Permission is hereby granted, free of charge, to any person // Permission is hereby granted, free of charge, to any person
// obtaining a copy of this software and associated documentation // obtaining a copy of this software and associated documentation
// files (the "Software"), to deal in the Software without // files (the "Software"), to deal in the Software without
// restriction, including without limitation the rights to use, // restriction, including without limitation the rights to use,
// copy, modify, merge, publish, distribute, sublicense, and/or sell // copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the // copies of the Software, and to permit persons to whom the
// Software is furnished to do so, subject to the following // Software is furnished to do so, subject to the following
// conditions: // conditions:
// //
// The above copyright notice and this permission notice shall be // The above copyright notice and this permission notice shall be
// included in all copies or substantial portions of the Software. // included in all copies or substantial portions of the Software.
// //
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
// OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND // OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, // HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
// WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING // WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
// OTHER DEALINGS IN THE SOFTWARE. // OTHER DEALINGS IN THE SOFTWARE.
#ifndef NV_IMAGE_DIRECTDRAWSURFACE_H #ifndef NV_IMAGE_DIRECTDRAWSURFACE_H
#define NV_IMAGE_DIRECTDRAWSURFACE_H #define NV_IMAGE_DIRECTDRAWSURFACE_H
#include <nvcore/nvcore.h> #include <nvcore/nvcore.h>
namespace nv namespace nv
{ {
class Image;
struct DDSPixelFormat { class Stream;
uint size; struct ColorBlock;
uint flags;
uint fourcc; struct DDSPixelFormat {
uint bitcount; uint size;
uint rmask; uint flags;
uint gmask; uint fourcc;
uint bmask; uint bitcount;
uint amask; uint rmask;
}; uint gmask;
uint bmask;
struct DDSCaps { uint amask;
uint caps1; };
uint caps2;
uint caps3; struct DDSCaps {
uint caps4; uint caps1;
}; uint caps2;
uint caps3;
/// DDS file header. uint caps4;
struct DDSHeader { };
uint fourcc;
uint size; /// DDS file header.
uint flags; struct DDSHeader {
uint height; uint fourcc;
uint width; uint size;
uint pitch; uint flags;
uint depth; uint height;
uint mipmapcount; uint width;
uint reserved[11]; uint pitch;
DDSPixelFormat pf; uint depth;
DDSCaps caps; uint mipmapcount;
uint notused; uint reserved[11];
DDSPixelFormat pf;
// Helper methods. DDSCaps caps;
DDSHeader(); uint notused;
void setWidth(uint w);
void setHeight(uint h); // Helper methods.
void setDepth(uint d); DDSHeader();
void setMipmapCount(uint count);
void setLinearSize(uint size); void setWidth(uint w);
void setPitch(uint pitch); void setHeight(uint h);
void setFourCC(uint8 c0, uint8 c1, uint8 c2, uint8 c3); void setDepth(uint d);
void setPixelFormat(uint bitcount, uint rmask, uint gmask, uint bmask, uint amask); void setMipmapCount(uint count);
void setTexture2D(); void setTexture2D();
void setTexture3D(); void setTexture3D();
void setTextureCube(); void setTextureCube();
void setLinearSize(uint size);
void swapBytes(); void setPitch(uint pitch);
}; void setFourCC(uint8 c0, uint8 c1, uint8 c2, uint8 c3);
void setPixelFormat(uint bitcount, uint rmask, uint gmask, uint bmask, uint amask);
void setNormalFlag(bool b);
} // nv namespace
void swapBytes();
#endif // NV_IMAGE_DIRECTDRAWSURFACE_H };
/// DirectDraw Surface. (DDS)
class DirectDrawSurface
{
public:
DirectDrawSurface(const char * file);
~DirectDrawSurface();
bool isValid() const;
bool isSupported() const;
uint mipmapCount() const;
uint width() const;
uint height() const;
uint depth() const;
bool isTexture2D() const;
bool isTexture3D() const;
bool isTextureCube() const;
void mipmap(Image * img, uint f, uint m);
private:
uint blockSize() const;
uint faceSize() const;
uint mipmapSize(uint m) const;
uint offset(uint f, uint m);
void readLinearImage(Stream * stream, Image * img);
void readBlockImage(Stream * stream, Image * img);
void readBlock(Stream * stream, ColorBlock * rgba);
private:
Stream * const stream;
DDSHeader header;
};
} // nv namespace
#endif // NV_IMAGE_DIRECTDRAWSURFACE_H

View File

@ -22,7 +22,7 @@ namespace nv
Spline, Spline,
Lanczos, Lanczos,
Mitchell, Mitchell,
Kaiser, Kaiser, // Kaiser-windowed sinc filter
Num Num
}; };

View File

@ -1,125 +1,124 @@
// This code is in the public domain -- castanyo@yahoo.es // This code is in the public domain -- castanyo@yahoo.es
#include <nvcore/Debug.h> #include <nvcore/Debug.h>
#include <nvcore/Ptr.h> #include <nvcore/Ptr.h>
#include <nvmath/Color.h> #include <nvmath/Color.h>
#include <nvimage/Image.h> #include <nvimage/Image.h>
#include <nvimage/ImageIO.h> #include <nvimage/ImageIO.h>
using namespace nv; using namespace nv;
Image::Image() : m_width(0), m_height(0), m_format(Format_RGB), m_data(NULL) Image::Image() : m_width(0), m_height(0), m_format(Format_RGB), m_data(NULL)
{ {
} }
Image::~Image() Image::~Image()
{ {
free(); free();
} }
void Image::allocate(uint w, uint h) void Image::allocate(uint w, uint h)
{ {
free(); m_width = w;
m_width = w; m_height = h;
m_height = h; m_data = (Color32 *)realloc(m_data, w * h * sizeof(Color32));
m_data = new Color32[w*h]; }
}
bool Image::load(const char * name)
bool Image::load(const char * name) {
{ free();
free();
AutoPtr<Image> img(ImageIO::load(name));
AutoPtr<Image> img(ImageIO::load(name)); if (img == NULL) {
if (img == NULL) { return false;
return false; }
}
swap(m_width, img->m_width);
swap(m_width, img->m_width); swap(m_height, img->m_height);
swap(m_height, img->m_height); swap(m_format, img->m_format);
swap(m_format, img->m_format); swap(m_data, img->m_data);
swap(m_data, img->m_data);
return true;
return true; }
}
void Image::wrap(void * data, uint w, uint h)
void Image::wrap(void * data, uint w, uint h) {
{ free();
free(); m_data = (Color32 *)data;
m_data = (Color32 *)data; m_width = w;
m_width = w; m_height = h;
m_height = h; }
}
void Image::unwrap()
void Image::unwrap() {
{ m_data = NULL;
m_data = NULL; m_width = 0;
m_width = 0; m_height = 0;
m_height = 0; }
}
void Image::free()
void Image::free() {
{ ::free(m_data);
delete m_data; m_data = NULL;
m_data = NULL; }
}
uint Image::width() const
uint Image::width() const {
{ return m_width;
return m_width; }
}
uint Image::height() const
uint Image::height() const {
{ return m_height;
return m_height; }
}
const Color32 * Image::scanline(uint h) const
const Color32 * Image::scanline(uint h) const {
{ nvDebugCheck(h < m_height);
nvDebugCheck(h < m_height); return m_data + h * m_width;
return m_data + h * m_width; }
}
Color32 * Image::scanline(uint h)
Color32 * Image::scanline(uint h) {
{ nvDebugCheck(h < m_height);
nvDebugCheck(h < m_height); return m_data + h * m_width;
return m_data + h * m_width; }
}
const Color32 * Image::pixels() const
const Color32 * Image::pixels() const {
{ return m_data;
return m_data; }
}
Color32 * Image::pixels()
Color32 * Image::pixels() {
{ return m_data;
return m_data; }
}
const Color32 & Image::pixel(uint idx) const
const Color32 & Image::pixel(uint idx) const {
{ nvDebugCheck(idx < m_width * m_height);
nvDebugCheck(idx < m_width * m_height); return m_data[idx];
return m_data[idx]; }
}
Color32 & Image::pixel(uint idx)
Color32 & Image::pixel(uint idx) {
{ nvDebugCheck(idx < m_width * m_height);
nvDebugCheck(idx < m_width * m_height); return m_data[idx];
return m_data[idx]; }
}
Image::Format Image::format() const
Image::Format Image::format() const {
{ return m_format;
return m_format; }
}
void Image::setFormat(Image::Format f)
void Image::setFormat(Image::Format f) {
{ m_format = f;
m_format = f; }
}

View File

@ -1,138 +1,138 @@
// Copyright NVIDIA Corporation 2007 -- Ignacio Castano <icastano@nvidia.com> // Copyright NVIDIA Corporation 2007 -- Ignacio Castano <icastano@nvidia.com>
// //
// Permission is hereby granted, free of charge, to any person // Permission is hereby granted, free of charge, to any person
// obtaining a copy of this software and associated documentation // obtaining a copy of this software and associated documentation
// files (the "Software"), to deal in the Software without // files (the "Software"), to deal in the Software without
// restriction, including without limitation the rights to use, // restriction, including without limitation the rights to use,
// copy, modify, merge, publish, distribute, sublicense, and/or sell // copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the // copies of the Software, and to permit persons to whom the
// Software is furnished to do so, subject to the following // Software is furnished to do so, subject to the following
// conditions: // conditions:
// //
// The above copyright notice and this permission notice shall be // The above copyright notice and this permission notice shall be
// included in all copies or substantial portions of the Software. // included in all copies or substantial portions of the Software.
// //
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
// OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND // OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, // HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
// WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING // WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
// OTHER DEALINGS IN THE SOFTWARE. // OTHER DEALINGS IN THE SOFTWARE.
#include <nvcore/Ptr.h> #include <nvcore/Ptr.h>
#include <nvmath/Color.h> #include <nvmath/Color.h>
#include <nvimage/NormalMap.h> #include <nvimage/NormalMap.h>
#include <nvimage/Filter.h> #include <nvimage/Filter.h>
#include <nvimage/FloatImage.h> #include <nvimage/FloatImage.h>
#include <nvimage/Image.h> #include <nvimage/Image.h>
using namespace nv; using namespace nv;
// Create normal map using the given kernels. // Create normal map using the given kernels.
static FloatImage * createNormalMap(const Image * img, FloatImage::WrapMode wm, Vector4::Arg heightWeights, const Kernel2 * kdu, const Kernel2 * kdv) static FloatImage * createNormalMap(const Image * img, FloatImage::WrapMode wm, Vector4::Arg heightWeights, const Kernel2 * kdu, const Kernel2 * kdv)
{ {
nvCheck(kdu != NULL); nvCheck(kdu != NULL);
nvCheck(kdv != NULL); nvCheck(kdv != NULL);
nvCheck(img != NULL); nvCheck(img != NULL);
const uint w = img->width(); const uint w = img->width();
const uint h = img->height(); const uint h = img->height();
AutoPtr<FloatImage> fimage(new FloatImage()); AutoPtr<FloatImage> fimage(new FloatImage());
fimage->allocate(4, w, h); fimage->allocate(4, w, h);
// Compute height and store in alpha channel: // Compute height and store in alpha channel:
float * alphaChannel = fimage->channel(3); float * alphaChannel = fimage->channel(3);
for(uint i = 0; i < w*h; i++) for(uint i = 0; i < w*h; i++)
{ {
Vector4 color = toVector4(img->pixel(i)); Vector4 color = toVector4(img->pixel(i));
alphaChannel[i] = dot(color, heightWeights); alphaChannel[i] = dot(color, heightWeights);
} }
float heightScale = 1.0f / 16.0f; // @@ Use a user defined factor. float heightScale = 1.0f / 16.0f; // @@ Use a user defined factor.
for(uint y = 0; y < h; y++) for(uint y = 0; y < h; y++)
{ {
for(uint x = 0; x < w; x++) for(uint x = 0; x < w; x++)
{ {
const float du = fimage->applyKernel(kdu, x, y, 3, wm); const float du = fimage->applyKernel(kdu, x, y, 3, wm);
const float dv = fimage->applyKernel(kdv, x, y, 3, wm); const float dv = fimage->applyKernel(kdv, x, y, 3, wm);
Vector3 n = normalize(Vector3(du, dv, heightScale)); Vector3 n = normalize(Vector3(du, dv, heightScale));
fimage->setPixel(0.5f * n.x() + 0.5f, x, y, 0); fimage->setPixel(0.5f * n.x() + 0.5f, x, y, 0);
fimage->setPixel(0.5f * n.y() + 0.5f, x, y, 1); fimage->setPixel(0.5f * n.y() + 0.5f, x, y, 1);
fimage->setPixel(0.5f * n.z() + 0.5f, x, y, 2); fimage->setPixel(0.5f * n.z() + 0.5f, x, y, 2);
} }
} }
return fimage.release(); return fimage.release();
} }
/// Create normal map using the given filter. /// Create normal map using the given filter.
FloatImage * nv::createNormalMap(const Image * img, FloatImage::WrapMode wm, Vector4::Arg heightWeights, NormalMapFilter filter /*= Sobel3x3*/) FloatImage * nv::createNormalMap(const Image * img, FloatImage::WrapMode wm, Vector4::Arg heightWeights, NormalMapFilter filter /*= Sobel3x3*/)
{ {
nvCheck(img != NULL); nvCheck(img != NULL);
// Init the kernels. // Init the kernels.
Kernel2 * kdu = NULL; Kernel2 * kdu = NULL;
Kernel2 * kdv = NULL; Kernel2 * kdv = NULL;
switch(filter) switch(filter)
{ {
case NormalMapFilter_Sobel3x3: case NormalMapFilter_Sobel3x3:
kdu = new Kernel2(3); kdu = new Kernel2(3);
break; break;
case NormalMapFilter_Sobel5x5: case NormalMapFilter_Sobel5x5:
kdu = new Kernel2(5); kdu = new Kernel2(5);
break; break;
case NormalMapFilter_Sobel7x7: case NormalMapFilter_Sobel7x7:
kdu = new Kernel2(7); kdu = new Kernel2(7);
break; break;
case NormalMapFilter_Sobel9x9: case NormalMapFilter_Sobel9x9:
kdu = new Kernel2(9); kdu = new Kernel2(9);
break; break;
default: default:
nvDebugCheck(false); nvDebugCheck(false);
}; };
kdu->initSobel(); kdu->initSobel();
kdu->normalize(); kdu->normalize();
kdv = new Kernel2(*kdu); kdv = new Kernel2(*kdu);
kdv->transpose(); kdv->transpose();
return ::createNormalMap(img, wm, heightWeights, kdu, kdv); return ::createNormalMap(img, wm, heightWeights, kdu, kdv);
} }
/// Create normal map combining multiple sobel filters. /// Create normal map combining multiple sobel filters.
FloatImage * nv::createNormalMap(const Image * img, FloatImage::WrapMode wm, Vector4::Arg heightWeights, Vector4::Arg filterWeights) FloatImage * nv::createNormalMap(const Image * img, FloatImage::WrapMode wm, Vector4::Arg heightWeights, Vector4::Arg filterWeights)
{ {
nvCheck(img != NULL); nvCheck(img != NULL);
Kernel2 * kdu = NULL; Kernel2 * kdu = NULL;
Kernel2 * kdv = NULL; Kernel2 * kdv = NULL;
kdu = new Kernel2(9); kdu = new Kernel2(9);
kdu->initBlendedSobel(filterWeights); kdu->initBlendedSobel(filterWeights);
kdu->normalize(); kdu->normalize();
kdv = new Kernel2(*kdu); kdv = new Kernel2(*kdu);
kdv->transpose(); kdv->transpose();
return ::createNormalMap(img, wm, heightWeights, kdu, kdv); return ::createNormalMap(img, wm, heightWeights, kdu, kdv);
} }
/// Normalize the given image in place. /// Normalize the given image in place.
void nv::normalize(FloatImage * img) void nv::normalize(FloatImage * img)
{ {
nvCheck(img != NULL); nvCheck(img != NULL);
img->normalize(0); img->normalize(0);
} }

View File

@ -1,24 +1,24 @@
// Copyright NVIDIA Corporation 2007 -- Ignacio Castano <icastano@nvidia.com> // Copyright NVIDIA Corporation 2007 -- Ignacio Castano <icastano@nvidia.com>
// //
// Permission is hereby granted, free of charge, to any person // Permission is hereby granted, free of charge, to any person
// obtaining a copy of this software and associated documentation // obtaining a copy of this software and associated documentation
// files (the "Software"), to deal in the Software without // files (the "Software"), to deal in the Software without
// restriction, including without limitation the rights to use, // restriction, including without limitation the rights to use,
// copy, modify, merge, publish, distribute, sublicense, and/or sell // copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the // copies of the Software, and to permit persons to whom the
// Software is furnished to do so, subject to the following // Software is furnished to do so, subject to the following
// conditions: // conditions:
// //
// The above copyright notice and this permission notice shall be // The above copyright notice and this permission notice shall be
// included in all copies or substantial portions of the Software. // included in all copies or substantial portions of the Software.
// //
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
// OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND // OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, // HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
// WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING // WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
// OTHER DEALINGS IN THE SOFTWARE. // OTHER DEALINGS IN THE SOFTWARE.
#ifndef NV_IMAGE_NORMALMAP_H #ifndef NV_IMAGE_NORMALMAP_H

View File

@ -0,0 +1,98 @@
// This code is in the public domain -- castanyo@yahoo.es
#include <nvcore/Ptr.h>
#include <nvmath/Montecarlo.h>
#include <nvmath/SphericalHarmonic.h>
#include <nvimage/NormalMipmap.h>
#include <nvimage/FloatImage.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;
}

View File

@ -0,0 +1,17 @@
// This code is in the public domain -- castanyo@yahoo.es
#ifndef NV_IMAGE_NORMALMIPMAP_H
#define NV_IMAGE_NORMALMIPMAP_H
#include <nvimage/nvimage.h>
namespace nv
{
class FloatImage;
FloatImage * createNormalMipmapMap(const FloatImage * img);
} // nv namespace
#endif // NV_IMAGE_NORMALMIPMAP_H

View File

@ -10,8 +10,6 @@ SET(NVTT_SRCS
CompressRGB.cpp CompressRGB.cpp
FastCompressDXT.h FastCompressDXT.h
FastCompressDXT.cpp FastCompressDXT.cpp
BlockDXT.h
BlockDXT.cpp
dxtlib.cpp dxtlib.cpp
dxtlib_compat.h dxtlib_compat.h
CompressionOptions.h CompressionOptions.h
@ -28,7 +26,7 @@ IF(CUDA_FOUND)
ADD_DEFINITIONS(-DHAVE_CUDA) ADD_DEFINITIONS(-DHAVE_CUDA)
WRAP_CUDA(CUDA_SRCS cuda/CompressKernel.cu) WRAP_CUDA(CUDA_SRCS cuda/CompressKernel.cu)
SET(NVTT_SRCS ${NVTT_SRCS} ${CUDA_SRCS}) SET(NVTT_SRCS ${NVTT_SRCS} ${CUDA_SRCS})
SET(LIBS ${LIBS} ${CUDA_LIBRARY}) SET(LIBS ${LIBS} ${CUDA_LIBRARIES})
INCLUDE_DIRECTORIES(${CUDA_INCLUDE_PATH}) INCLUDE_DIRECTORIES(${CUDA_INCLUDE_PATH})
ENDIF(CUDA_FOUND) ENDIF(CUDA_FOUND)
@ -46,7 +44,7 @@ TARGET_LINK_LIBRARIES(nvtt ${LIBS} nvcore nvmath nvimage squish)
# test executables # test executables
ADD_EXECUTABLE(nvcompress compress.cpp) ADD_EXECUTABLE(nvcompress tools/compress.cpp)
TARGET_LINK_LIBRARIES(nvcompress nvcore nvmath nvimage nvtt) TARGET_LINK_LIBRARIES(nvcompress nvcore nvmath nvimage nvtt)
INSTALL(TARGETS nvcompress DESTINATION bin) INSTALL(TARGETS nvcompress DESTINATION bin)

File diff suppressed because it is too large Load Diff

View File

@ -1,65 +1,65 @@
// Copyright NVIDIA Corporation 2007 -- Ignacio Castano <icastano@nvidia.com> // Copyright NVIDIA Corporation 2007 -- Ignacio Castano <icastano@nvidia.com>
// //
// Permission is hereby granted, free of charge, to any person // Permission is hereby granted, free of charge, to any person
// obtaining a copy of this software and associated documentation // obtaining a copy of this software and associated documentation
// files (the "Software"), to deal in the Software without // files (the "Software"), to deal in the Software without
// restriction, including without limitation the rights to use, // restriction, including without limitation the rights to use,
// copy, modify, merge, publish, distribute, sublicense, and/or sell // copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the // copies of the Software, and to permit persons to whom the
// Software is furnished to do so, subject to the following // Software is furnished to do so, subject to the following
// conditions: // conditions:
// //
// The above copyright notice and this permission notice shall be // The above copyright notice and this permission notice shall be
// included in all copies or substantial portions of the Software. // included in all copies or substantial portions of the Software.
// //
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
// OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND // OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, // HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
// WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING // WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
// OTHER DEALINGS IN THE SOFTWARE. // OTHER DEALINGS IN THE SOFTWARE.
#ifndef NV_TT_COMPRESSDXT_H #ifndef NV_TT_COMPRESSDXT_H
#define NV_TT_COMPRESSDXT_H #define NV_TT_COMPRESSDXT_H
#include <nvimage/nvimage.h> #include <nvimage/nvimage.h>
#include "nvtt.h" #include "nvtt.h"
namespace nv namespace nv
{ {
class Image; class Image;
class FloatImage; class FloatImage;
void doPrecomputation(); void doPrecomputation();
// Fast compressors. // Fast compressors.
void fastCompressDXT1(const Image * image, const nvtt::OutputOptions & outputOptions); void fastCompressDXT1(const Image * image, const nvtt::OutputOptions & outputOptions);
void fastCompressDXT3(const Image * image, const nvtt::OutputOptions & outputOptions); void fastCompressDXT3(const Image * image, const nvtt::OutputOptions & outputOptions);
void fastCompressDXT5(const Image * image, const nvtt::OutputOptions & outputOptions); void fastCompressDXT5(const Image * image, const nvtt::OutputOptions & outputOptions);
void fastCompressDXT5n(const Image * image, const nvtt::OutputOptions & outputOptions); void fastCompressDXT5n(const Image * image, const nvtt::OutputOptions & outputOptions);
void fastCompressBC4(const Image * image, const nvtt::OutputOptions & outputOptions); void fastCompressBC4(const Image * image, const nvtt::OutputOptions & outputOptions);
void fastCompressBC5(const Image * image, const nvtt::OutputOptions & outputOptions); void fastCompressBC5(const Image * image, const nvtt::OutputOptions & outputOptions);
// Normal compressors. // Normal compressors.
void compressDXT1(const Image * image, const nvtt::OutputOptions & outputOptions, const nvtt::CompressionOptions::Private & compressionOptions); void compressDXT1(const Image * image, const nvtt::OutputOptions & outputOptions, const nvtt::CompressionOptions::Private & compressionOptions);
void compressDXT3(const Image * image, const nvtt::OutputOptions & outputOptions, const nvtt::CompressionOptions::Private & compressionOptions); void compressDXT3(const Image * image, const nvtt::OutputOptions & outputOptions, const nvtt::CompressionOptions::Private & compressionOptions);
void compressDXT5(const Image * image, const nvtt::OutputOptions & outputOptions, const nvtt::CompressionOptions::Private & compressionOptions); void compressDXT5(const Image * image, const nvtt::OutputOptions & outputOptions, const nvtt::CompressionOptions::Private & compressionOptions);
void compressDXT5n(const Image * image, const nvtt::OutputOptions & outputOptions, const nvtt::CompressionOptions::Private & compressionOptions); void compressDXT5n(const Image * image, const nvtt::OutputOptions & outputOptions, const nvtt::CompressionOptions::Private & compressionOptions);
void compressBC4(const Image * image, const nvtt::OutputOptions & outputOptions, const nvtt::CompressionOptions::Private & compressionOptions); void compressBC4(const Image * image, const nvtt::OutputOptions & outputOptions, const nvtt::CompressionOptions::Private & compressionOptions);
void compressBC5(const Image * image, const nvtt::OutputOptions & outputOptions, const nvtt::CompressionOptions::Private & compressionOptions); void compressBC5(const Image * image, const nvtt::OutputOptions & outputOptions, const nvtt::CompressionOptions::Private & compressionOptions);
// External compressors. // External compressors.
#if defined(HAVE_S3QUANT) #if defined(HAVE_S3QUANT)
void s3CompressDXT1(const Image * image, const nvtt::OutputOptions & outputOptions); void s3CompressDXT1(const Image * image, const nvtt::OutputOptions & outputOptions);
#endif #endif
#if defined(HAVE_ATITC) #if defined(HAVE_ATITC)
void atiCompressDXT1(const Image * image, const nvtt::OutputOptions & outputOptions); void atiCompressDXT1(const Image * image, const nvtt::OutputOptions & outputOptions);
#endif #endif
} // nv namespace } // nv namespace
#endif // NV_TT_COMPRESSDXT_H #endif // NV_TT_COMPRESSDXT_H

View File

@ -1,153 +1,153 @@
// Copyright NVIDIA Corporation 2007 -- Ignacio Castano <icastano@nvidia.com> // Copyright NVIDIA Corporation 2007 -- Ignacio Castano <icastano@nvidia.com>
// //
// Permission is hereby granted, free of charge, to any person // Permission is hereby granted, free of charge, to any person
// obtaining a copy of this software and associated documentation // obtaining a copy of this software and associated documentation
// files (the "Software"), to deal in the Software without // files (the "Software"), to deal in the Software without
// restriction, including without limitation the rights to use, // restriction, including without limitation the rights to use,
// copy, modify, merge, publish, distribute, sublicense, and/or sell // copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the // copies of the Software, and to permit persons to whom the
// Software is furnished to do so, subject to the following // Software is furnished to do so, subject to the following
// conditions: // conditions:
// //
// The above copyright notice and this permission notice shall be // The above copyright notice and this permission notice shall be
// included in all copies or substantial portions of the Software. // included in all copies or substantial portions of the Software.
// //
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
// OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND // OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, // HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
// WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING // WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
// OTHER DEALINGS IN THE SOFTWARE. // OTHER DEALINGS IN THE SOFTWARE.
#include <string.h> #include <string.h>
#include <nvcore/Debug.h> #include <nvcore/Debug.h>
#include <nvimage/Image.h> #include <nvimage/Image.h>
#include "CompressRGB.h" #include "CompressRGB.h"
#include "CompressionOptions.h" #include "CompressionOptions.h"
using namespace nv; using namespace nv;
using namespace nvtt; using namespace nvtt;
namespace namespace
{ {
inline uint computePitch(uint w, uint bitsize) inline uint computePitch(uint w, uint bitsize)
{ {
uint p = w * ((bitsize + 7) / 8); uint p = w * ((bitsize + 7) / 8);
// Align to 32 bits. // Align to 32 bits.
return ((p + 3) / 4) * 4; return ((p + 3) / 4) * 4;
} }
static void convert_to_rgba8888(void * src, void * dst, uint w) static void convert_to_rgba8888(void * src, void * dst, uint w)
{ {
// @@ TODO // @@ TODO
} }
static void convert_to_bgra8888(const void * src, void * dst, uint w) static void convert_to_bgra8888(const void * src, void * dst, uint w)
{ {
memcpy(dst, src, 4 * w); memcpy(dst, src, 4 * w);
} }
static void convert_to_rgb888(const void * src, void * dst, uint w) static void convert_to_rgb888(const void * src, void * dst, uint w)
{ {
// @@ TODO // @@ TODO
} }
static uint truncate(uint c, uint inbits, uint outbits) static uint truncate(uint c, uint inbits, uint outbits)
{ {
nvDebugCheck(inbits > outbits); nvDebugCheck(inbits > outbits);
c >>= inbits - outbits; c >>= inbits - outbits;
} }
static uint bitexpand(uint c, uint inbits, uint outbits) static uint bitexpand(uint c, uint inbits, uint outbits)
{ {
// @@ TODO // @@ TODO
} }
static void maskShiftAndSize(uint mask, uint & shift, uint & size) static void maskShiftAndSize(uint mask, uint & shift, uint & size)
{ {
shift = 0; shift = 0;
while((mask & 1) == 0) { while((mask & 1) == 0) {
shift++; shift++;
mask >>= 1; mask >>= 1;
} }
while((mask & 1) == 1) { while((mask & 1) == 1) {
size++; size++;
mask >>= 1; mask >>= 1;
} }
} }
} // namespace } // namespace
// Pixel format converter. // Pixel format converter.
void nv::compressRGB(const Image * image, const OutputOptions & outputOptions, const CompressionOptions::Private & compressionOptions) void nv::compressRGB(const Image * image, const OutputOptions & outputOptions, const CompressionOptions::Private & compressionOptions)
{ {
nvCheck(image != NULL); nvCheck(image != NULL);
const uint w = image->width(); const uint w = image->width();
const uint h = image->height(); const uint h = image->height();
uint rshift, rsize; uint rshift, rsize;
maskShiftAndSize(compressionOptions.rmask, rshift, rsize); maskShiftAndSize(compressionOptions.rmask, rshift, rsize);
uint gshift, gsize; uint gshift, gsize;
maskShiftAndSize(compressionOptions.gmask, gshift, gsize); maskShiftAndSize(compressionOptions.gmask, gshift, gsize);
uint bshift, bsize; uint bshift, bsize;
maskShiftAndSize(compressionOptions.bmask, bshift, bsize); maskShiftAndSize(compressionOptions.bmask, bshift, bsize);
uint ashift, asize; uint ashift, asize;
maskShiftAndSize(compressionOptions.amask, ashift, asize); maskShiftAndSize(compressionOptions.amask, ashift, asize);
// Determine pitch. // Determine pitch.
uint pitch = computePitch(w, compressionOptions.bitcount); uint pitch = computePitch(w, compressionOptions.bitcount);
void * dst = malloc(pitch); void * dst = malloc(pitch);
for (uint y = 0; y < h; y++) for (uint y = 0; y < h; y++)
{ {
const Color32 * src = image->scanline(y); const Color32 * src = image->scanline(y);
convert_to_bgra8888(src, dst, w); convert_to_bgra8888(src, dst, w);
if (false) if (false)
{ {
// uint c = 0; // uint c = 0;
// c |= (src[i].r >> (8 - rsize)) << rshift; // c |= (src[i].r >> (8 - rsize)) << rshift;
// c |= (src[i].g >> (8 - gsize)) << gshift; // c |= (src[i].g >> (8 - gsize)) << gshift;
// c |= (src[i].b >> (8 - bsize)) << bshift; // c |= (src[i].b >> (8 - bsize)) << bshift;
} }
/* /*
if (rmask == 0xFF000000 && gmask == 0xFF0000 && bmask == 0xFF00 && amask == 0xFF) if (rmask == 0xFF000000 && gmask == 0xFF0000 && bmask == 0xFF00 && amask == 0xFF)
{ {
convert_to_rgba8888(src, dst, w); convert_to_rgba8888(src, dst, w);
} }
else if (rmask == 0xFF0000 && gmask == 0xFF00 && bmask == 0xFF && amask == 0) else if (rmask == 0xFF0000 && gmask == 0xFF00 && bmask == 0xFF && amask == 0)
{ {
convert_to_rgb888(src, dst, w); convert_to_rgb888(src, dst, w);
} }
else else
{ {
// @@ Not supported. // @@ Not supported.
} }
*/ */
if (outputOptions.outputHandler != NULL) if (outputOptions.outputHandler != NULL)
{ {
outputOptions.outputHandler->writeData(dst, pitch); outputOptions.outputHandler->writeData(dst, pitch);
} }
} }
free(dst); free(dst);
} }

View File

@ -1,24 +1,24 @@
// Copyright NVIDIA Corporation 2007 -- Ignacio Castano <icastano@nvidia.com> // Copyright NVIDIA Corporation 2007 -- Ignacio Castano <icastano@nvidia.com>
// //
// Permission is hereby granted, free of charge, to any person // Permission is hereby granted, free of charge, to any person
// obtaining a copy of this software and associated documentation // obtaining a copy of this software and associated documentation
// files (the "Software"), to deal in the Software without // files (the "Software"), to deal in the Software without
// restriction, including without limitation the rights to use, // restriction, including without limitation the rights to use,
// copy, modify, merge, publish, distribute, sublicense, and/or sell // copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the // copies of the Software, and to permit persons to whom the
// Software is furnished to do so, subject to the following // Software is furnished to do so, subject to the following
// conditions: // conditions:
// //
// The above copyright notice and this permission notice shall be // The above copyright notice and this permission notice shall be
// included in all copies or substantial portions of the Software. // included in all copies or substantial portions of the Software.
// //
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
// OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND // OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, // HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
// WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING // WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
// OTHER DEALINGS IN THE SOFTWARE. // OTHER DEALINGS IN THE SOFTWARE.
#ifndef NV_TT_COMPRESSRGB_H #ifndef NV_TT_COMPRESSRGB_H

View File

@ -1,113 +1,114 @@
// Copyright NVIDIA Corporation 2007 -- Ignacio Castano <icastano@nvidia.com> // Copyright NVIDIA Corporation 2007 -- Ignacio Castano <icastano@nvidia.com>
// //
// Permission is hereby granted, free of charge, to any person // Permission is hereby granted, free of charge, to any person
// obtaining a copy of this software and associated documentation // obtaining a copy of this software and associated documentation
// files (the "Software"), to deal in the Software without // files (the "Software"), to deal in the Software without
// restriction, including without limitation the rights to use, // restriction, including without limitation the rights to use,
// copy, modify, merge, publish, distribute, sublicense, and/or sell // copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the // copies of the Software, and to permit persons to whom the
// Software is furnished to do so, subject to the following // Software is furnished to do so, subject to the following
// conditions: // conditions:
// //
// The above copyright notice and this permission notice shall be // The above copyright notice and this permission notice shall be
// included in all copies or substantial portions of the Software. // included in all copies or substantial portions of the Software.
// //
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
// OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND // OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, // HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
// WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING // WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
// OTHER DEALINGS IN THE SOFTWARE. // OTHER DEALINGS IN THE SOFTWARE.
#include "nvtt.h" #include "nvtt.h"
#include "CompressionOptions.h" #include "CompressionOptions.h"
using namespace nv; using namespace nv;
using namespace nvtt; using namespace nvtt;
/// Constructor. Sets compression options to the default values. /// Constructor. Sets compression options to the default values.
CompressionOptions::CompressionOptions() : m(*new CompressionOptions::Private()) CompressionOptions::CompressionOptions() : m(*new CompressionOptions::Private())
{ {
reset(); reset();
} }
/// Destructor. /// Destructor.
CompressionOptions::~CompressionOptions() CompressionOptions::~CompressionOptions()
{ {
delete &m; delete &m;
} }
/// Set default compression options. /// Set default compression options.
void CompressionOptions::reset() void CompressionOptions::reset()
{ {
m.format = Format_DXT1; m.format = Format_DXT1;
m.quality = Quality_Normal; m.quality = Quality_Normal;
m.colorWeight.set(1.0f, 1.0f, 1.0f); m.colorWeight.set(1.0f, 1.0f, 1.0f);
m.useCuda = true; m.useCuda = true;
m.bitcount = 32; m.bitcount = 32;
m.bmask = 0x000000FF; m.bmask = 0x000000FF;
m.gmask = 0x0000FF00; m.gmask = 0x0000FF00;
m.rmask = 0x00FF0000; m.rmask = 0x00FF0000;
m.amask = 0xFF000000; m.amask = 0xFF000000;
} }
/// Set desired compression format. /// Set desired compression format.
void CompressionOptions::setFormat(Format format) void CompressionOptions::setFormat(Format format)
{ {
m.format = format; m.format = format;
} }
/// Set compression quality settings. /// Set compression quality settings.
void CompressionOptions::setQuality(Quality quality, float errorThreshold /*= 0.5f*/) void CompressionOptions::setQuality(Quality quality, float errorThreshold /*= 0.5f*/)
{ {
m.quality = quality; m.quality = quality;
m.errorThreshold = errorThreshold; m.errorThreshold = errorThreshold;
} }
/// Set the weights of each color channel. /// Set the weights of each color channel.
/// The choice for these values is subjective. In many case uniform color weights /// The choice for these values is subjective. In many case uniform color weights
/// (1.0, 1.0, 1.0) work very well. A popular choice is to use the NTSC luma encoding /// (1.0, 1.0, 1.0) work very well. A popular choice is to use the NTSC luma encoding
/// weights (0.2126, 0.7152, 0.0722), but I think that blue contributes to our /// weights (0.2126, 0.7152, 0.0722), but I think that blue contributes to our
/// perception more than a 7%. A better choice in my opinion is (3, 4, 2). Ideally /// perception more than a 7%. A better choice in my opinion is (3, 4, 2). Ideally
/// the compressor should use a non linear colour metric as described here: /// the compressor should use a non linear colour metric as described here:
/// http://www.compuphase.com/cmetric.htm /// http://www.compuphase.com/cmetric.htm
void CompressionOptions::setColorWeights(float red, float green, float blue) void CompressionOptions::setColorWeights(float red, float green, float blue)
{ {
float total = red + green + blue; float total = red + green + blue;
float x = blue / total; float x = blue / total;
float y = green / total; float y = green / total;
m.colorWeight.set(x, y, 1.0f - x - y); m.colorWeight.set(x, y, 1.0f - x - y);
} }
/// Enable or disable hardware compression. /// Enable or disable hardware compression.
void CompressionOptions::enableHardwareCompression(bool enable) void CompressionOptions::enableHardwareCompression(bool enable)
{ {
m.useCuda = enable; m.useCuda = enable;
} }
/// Set color mask to describe the RGB/RGBA format. /// Set color mask to describe the RGB/RGBA format.
void CompressionOptions::setPixelFormat(uint bitcount, uint rmask, uint gmask, uint bmask, uint amask) void CompressionOptions::setPixelFormat(uint bitcount, uint rmask, uint gmask, uint bmask, uint amask)
{ {
m.bitcount = bitcount; m.bitcount = bitcount;
m.rmask = rmask; m.rmask = rmask;
m.gmask = gmask; m.gmask = gmask;
m.bmask = bmask; m.bmask = bmask;
m.amask = amask; m.amask = amask;
} }
/// Use external compressor. /// Use external compressor.
void CompressionOptions::setExternalCompressor(const char * name) void CompressionOptions::setExternalCompressor(const char * name)
{ {
m.externalCompressor = name; m.externalCompressor = name;
} }

View File

@ -1,57 +1,57 @@
// Copyright NVIDIA Corporation 2007 -- Ignacio Castano <icastano@nvidia.com> // Copyright NVIDIA Corporation 2007 -- Ignacio Castano <icastano@nvidia.com>
// //
// Permission is hereby granted, free of charge, to any person // Permission is hereby granted, free of charge, to any person
// obtaining a copy of this software and associated documentation // obtaining a copy of this software and associated documentation
// files (the "Software"), to deal in the Software without // files (the "Software"), to deal in the Software without
// restriction, including without limitation the rights to use, // restriction, including without limitation the rights to use,
// copy, modify, merge, publish, distribute, sublicense, and/or sell // copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the // copies of the Software, and to permit persons to whom the
// Software is furnished to do so, subject to the following // Software is furnished to do so, subject to the following
// conditions: // conditions:
// //
// The above copyright notice and this permission notice shall be // The above copyright notice and this permission notice shall be
// included in all copies or substantial portions of the Software. // included in all copies or substantial portions of the Software.
// //
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
// OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND // OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, // HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
// WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING // WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
// OTHER DEALINGS IN THE SOFTWARE. // OTHER DEALINGS IN THE SOFTWARE.
#ifndef NV_TT_COMPRESSIONOPTIONS_H #ifndef NV_TT_COMPRESSIONOPTIONS_H
#define NV_TT_COMPRESSIONOPTIONS_H #define NV_TT_COMPRESSIONOPTIONS_H
#include <nvcore/StrLib.h> #include <nvcore/StrLib.h>
#include <nvmath/Vector.h> #include <nvmath/Vector.h>
#include "nvtt.h" #include "nvtt.h"
namespace nvtt namespace nvtt
{ {
struct CompressionOptions::Private struct CompressionOptions::Private
{ {
Format format; Format format;
Quality quality; Quality quality;
float errorThreshold; float errorThreshold;
nv::Vector3 colorWeight; nv::Vector3 colorWeight;
uint bitcount; uint bitcount;
uint rmask; uint rmask;
uint gmask; uint gmask;
uint bmask; uint bmask;
uint amask; uint amask;
bool useCuda; bool useCuda;
nv::String externalCompressor; nv::String externalCompressor;
}; };
} // nvtt namespace } // nvtt namespace
#endif // NV_TT_COMPRESSIONOPTIONS_H #endif // NV_TT_COMPRESSIONOPTIONS_H

File diff suppressed because it is too large Load Diff

View File

@ -1,81 +1,84 @@
// Copyright NVIDIA Corporation 2007 -- Ignacio Castano <icastano@nvidia.com> // Copyright NVIDIA Corporation 2007 -- Ignacio Castano <icastano@nvidia.com>
// //
// Permission is hereby granted, free of charge, to any person // Permission is hereby granted, free of charge, to any person
// obtaining a copy of this software and associated documentation // obtaining a copy of this software and associated documentation
// files (the "Software"), to deal in the Software without // files (the "Software"), to deal in the Software without
// restriction, including without limitation the rights to use, // restriction, including without limitation the rights to use,
// copy, modify, merge, publish, distribute, sublicense, and/or sell // copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the // copies of the Software, and to permit persons to whom the
// Software is furnished to do so, subject to the following // Software is furnished to do so, subject to the following
// conditions: // conditions:
// //
// The above copyright notice and this permission notice shall be // The above copyright notice and this permission notice shall be
// included in all copies or substantial portions of the Software. // included in all copies or substantial portions of the Software.
// //
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
// OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND // OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, // HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
// WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING // WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
// OTHER DEALINGS IN THE SOFTWARE. // OTHER DEALINGS IN THE SOFTWARE.
#ifndef NV_TT_FASTCOMPRESSDXT_H #ifndef NV_TT_FASTCOMPRESSDXT_H
#define NV_TT_FASTCOMPRESSDXT_H #define NV_TT_FASTCOMPRESSDXT_H
#include <nvimage/nvimage.h> #include <nvimage/nvimage.h>
namespace nv namespace nv
{ {
struct ColorBlock; struct ColorBlock;
struct BlockDXT1; struct BlockDXT1;
struct BlockDXT3; struct BlockDXT3;
struct BlockDXT5; struct BlockDXT5;
struct AlphaBlockDXT3; struct AlphaBlockDXT3;
struct AlphaBlockDXT5; struct AlphaBlockDXT5;
// Color compression: // Color compression:
// Compressor that uses the extremes of the luminance axis. // Compressor that uses the extremes of the luminance axis.
void compressBlock_DiameterAxis(const ColorBlock & rgba, BlockDXT1 * block); void compressBlock_DiameterAxis(const ColorBlock & rgba, BlockDXT1 * block);
// Compressor that uses the extremes of the luminance axis. // Compressor that uses the extremes of the luminance axis.
void compressBlock_LuminanceAxis(const ColorBlock & rgba, BlockDXT1 * block); void compressBlock_LuminanceAxis(const ColorBlock & rgba, BlockDXT1 * block);
// Compressor that uses bounding box. // Compressor that uses bounding box.
void compressBlock_BoundsRange(const ColorBlock & rgba, BlockDXT1 * block); void compressBlock_BoundsRange(const ColorBlock & rgba, BlockDXT1 * block);
// Compressor that uses the best fit axis. // Compressor that uses the best fit axis.
void compressBlock_BestFitAxis(const ColorBlock & rgba, BlockDXT1 * block); void compressBlock_BestFitAxis(const ColorBlock & rgba, BlockDXT1 * block);
// Simple, but slow compressor that tests all color pairs. // Simple, but slow compressor that tests all color pairs.
void compressBlock_TestAllPairs(const ColorBlock & rgba, BlockDXT1 * block); void compressBlock_TestAllPairs(const ColorBlock & rgba, BlockDXT1 * block);
// Brute force 6d search along the best fit axis. // Brute force 6d search along the best fit axis.
void compressBlock_AnalyzeBestFitAxis(const ColorBlock & rgba, BlockDXT1 * block); void compressBlock_AnalyzeBestFitAxis(const ColorBlock & rgba, BlockDXT1 * block);
// Spatial greedy search. // Spatial greedy search.
void refineSolution_1dSearch(const ColorBlock & rgba, BlockDXT1 * block); void refineSolution_1dSearch(const ColorBlock & rgba, BlockDXT1 * block);
void refineSolution_3dSearch(const ColorBlock & rgba, BlockDXT1 * block); void refineSolution_3dSearch(const ColorBlock & rgba, BlockDXT1 * block);
void refineSolution_6dSearch(const ColorBlock & rgba, BlockDXT1 * block); void refineSolution_6dSearch(const ColorBlock & rgba, BlockDXT1 * block);
// Minimize error of the endpoints. // Brute force compressor for DXT5n
void optimizeEndPoints(const ColorBlock & rgba, BlockDXT1 * block); void compressGreenBlock_BruteForce(const ColorBlock & rgba, BlockDXT1 * block);
uint blockError(const ColorBlock & rgba, const BlockDXT1 & block); // Minimize error of the endpoints.
uint blockError(const ColorBlock & rgba, const AlphaBlockDXT5 & block); void optimizeEndPoints(const ColorBlock & rgba, BlockDXT1 * block);
// Alpha compression: uint blockError(const ColorBlock & rgba, const BlockDXT1 & block);
void compressBlock(const ColorBlock & rgba, AlphaBlockDXT3 * block); uint blockError(const ColorBlock & rgba, const AlphaBlockDXT5 & block);
void compressBlock_BoundsRange(const ColorBlock & rgba, BlockDXT3 * block);
void compressBlock_BoundsRange(const ColorBlock & rgba, BlockDXT5 * block); // Alpha compression:
void compressBlock(const ColorBlock & rgba, AlphaBlockDXT3 * block);
uint compressBlock_BoundsRange(const ColorBlock & rgba, AlphaBlockDXT5 * block); void compressBlock_BoundsRange(const ColorBlock & rgba, BlockDXT3 * block);
uint compressBlock_BruteForce(const ColorBlock & rgba, AlphaBlockDXT5 * block); void compressBlock_BoundsRange(const ColorBlock & rgba, BlockDXT5 * block);
uint compressBlock_Iterative(const ColorBlock & rgba, AlphaBlockDXT5 * block);
uint compressBlock_BoundsRange(const ColorBlock & rgba, AlphaBlockDXT5 * block);
} // nv namespace uint compressBlock_BruteForce(const ColorBlock & rgba, AlphaBlockDXT5 * block);
uint compressBlock_Iterative(const ColorBlock & rgba, AlphaBlockDXT5 * block);
#endif // NV_TT_FASTCOMPRESSDXT_H
} // nv namespace
#endif // NV_TT_FASTCOMPRESSDXT_H

View File

@ -1,250 +1,254 @@
// Copyright NVIDIA Corporation 2007 -- Ignacio Castano <icastano@nvidia.com> // Copyright NVIDIA Corporation 2007 -- Ignacio Castano <icastano@nvidia.com>
// //
// Permission is hereby granted, free of charge, to any person // Permission is hereby granted, free of charge, to any person
// obtaining a copy of this software and associated documentation // obtaining a copy of this software and associated documentation
// files (the "Software"), to deal in the Software without // files (the "Software"), to deal in the Software without
// restriction, including without limitation the rights to use, // restriction, including without limitation the rights to use,
// copy, modify, merge, publish, distribute, sublicense, and/or sell // copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the // copies of the Software, and to permit persons to whom the
// Software is furnished to do so, subject to the following // Software is furnished to do so, subject to the following
// conditions: // conditions:
// //
// The above copyright notice and this permission notice shall be // The above copyright notice and this permission notice shall be
// included in all copies or substantial portions of the Software. // included in all copies or substantial portions of the Software.
// //
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
// OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND // OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, // HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
// WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING // WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
// OTHER DEALINGS IN THE SOFTWARE. // OTHER DEALINGS IN THE SOFTWARE.
#include <string.h> // memcpy #include <string.h> // memcpy
#include <nvcore/Memory.h> #include <nvcore/Memory.h>
#include "nvtt.h" #include "nvtt.h"
#include "InputOptions.h" #include "InputOptions.h"
using namespace nv; using namespace nv;
using namespace nvtt; using namespace nvtt;
namespace namespace
{ {
static int countMipmaps(int w, int h, int d) static int countMipmaps(int w, int h, int d)
{ {
int mipmap = 0; int mipmap = 0;
while (w != 1 && h != 1) { while (w != 1 && h != 1) {
w = max(1, w / 2); w = max(1, w / 2);
h = max(1, h / 2); h = max(1, h / 2);
d = max(1, d / 2); d = max(1, d / 2);
mipmap++; mipmap++;
} }
return mipmap + 1; return mipmap + 1;
} }
} // namespace } // namespace
/// Constructor. /// Constructor.
InputOptions::InputOptions() : m(*new InputOptions::Private()) InputOptions::InputOptions() : m(*new InputOptions::Private())
{ {
reset(); reset();
} }
// Delete images. // Delete images.
InputOptions::~InputOptions() InputOptions::~InputOptions()
{ {
resetTextureLayout(); resetTextureLayout();
delete &m; delete &m;
} }
// Reset input options. // Reset input options.
void InputOptions::reset() void InputOptions::reset()
{ {
m.wrapMode = WrapMode_Repeat; m.wrapMode = WrapMode_Repeat;
m.textureType = TextureType_2D; m.textureType = TextureType_2D;
m.inputFormat = InputFormat_BGRA_8UB; m.inputFormat = InputFormat_BGRA_8UB;
m.enableColorDithering = false; m.enableColorDithering = false;
m.enableAlphaDithering = false; m.enableAlphaDithering = false;
m.binaryAlpha = false; m.binaryAlpha = false;
m.alphaThreshold = 127; m.alphaThreshold = 127;
m.alphaTransparency = true; m.alphaTransparency = true;
m.inputGamma = 2.2f; m.inputGamma = 2.2f;
m.outputGamma = 2.2f; m.outputGamma = 2.2f;
m.generateMipmaps = false; m.generateMipmaps = false;
m.maxLevel = -1; m.maxLevel = -1;
m.mipmapFilter = MipmapFilter_Box; m.mipmapFilter = MipmapFilter_Box;
m.normalizeMipmaps = false; m.normalizeMipmaps = false;
m.convertToNormalMap = false; m.convertToNormalMap = false;
m.heightFactors.set(0.0f, 0.0f, 0.0f, 1.0f); m.heightFactors.set(0.0f, 0.0f, 0.0f, 1.0f);
m.bumpFrequencyScale = Vector4(1.0f, 0.5f, 0.25f, 0.125f) / (1.0f + 0.5f + 0.25f + 0.125f); m.bumpFrequencyScale = Vector4(1.0f, 0.5f, 0.25f, 0.125f) / (1.0f + 0.5f + 0.25f + 0.125f);
} }
// Setup the input image. // Setup the input image.
void InputOptions::setTextureLayout(TextureType type, int w, int h, int d /*= 1*/) void InputOptions::setTextureLayout(TextureType type, int width, int height, int depth /*= 1*/)
{ {
// Validate arguments. // Validate arguments.
nvCheck(w >= 0); nvCheck(width >= 0);
nvCheck(h >= 0); nvCheck(height >= 0);
nvCheck(d >= 0); nvCheck(depth >= 0);
// Correct arguments. // Correct arguments.
if (w == 0) w = 1; if (width == 0) width = 1;
if (h == 0) h = 1; if (height == 0) height = 1;
if (d == 0) d = 1; if (depth == 0) depth = 1;
// Delete previous images. // Delete previous images.
resetTextureLayout(); resetTextureLayout();
m.textureType = type; m.textureType = type;
// Allocate images. // Allocate images.
m.mipmapCount = countMipmaps(w, h, d); m.mipmapCount = countMipmaps(width, height, depth);
m.faceCount = (type == TextureType_Cube) ? 6 : 1; m.faceCount = (type == TextureType_Cube) ? 6 : 1;
m.imageCount = m.mipmapCount * m.faceCount; m.imageCount = m.mipmapCount * m.faceCount;
m.images = new Private::Image[m.imageCount]; m.images = new Private::Image[m.imageCount];
for(int f = 0; f < m.faceCount; f++) for(int f = 0; f < m.faceCount; f++)
{ {
for (int mipLevel = 0; mipLevel < m.mipmapCount; mipLevel++) int w = width;
{ int h = height;
Private::Image & img = m.images[f * m.mipmapCount + mipLevel]; int d = depth;
img.width = w;
img.height = h; for (int mipLevel = 0; mipLevel < m.mipmapCount; mipLevel++)
img.depth = d; {
img.mipLevel = mipLevel; Private::Image & img = m.images[f * m.mipmapCount + mipLevel];
img.face = f; img.width = w;
img.height = h;
img.data = NULL; img.depth = d;
img.mipLevel = mipLevel;
w = max(1, w / 2); img.face = f;
h = max(1, h / 2);
d = max(1, d / 2); img.data = NULL;
}
} w = max(1, w / 2);
} h = max(1, h / 2);
d = max(1, d / 2);
}
void InputOptions::resetTextureLayout() }
{ }
if (m.images != NULL)
{
// Delete image array. void InputOptions::resetTextureLayout()
delete [] m.images; {
m.images = NULL; if (m.images != NULL)
{
m.faceCount = 0; // Delete image array.
m.mipmapCount = 0; delete [] m.images;
m.imageCount = 0; m.images = NULL;
}
} m.faceCount = 0;
m.mipmapCount = 0;
m.imageCount = 0;
// Copies the data to our internal structures. }
bool InputOptions::setMipmapData(const void * data, int width, int height, int depth /*= 1*/, int face /*= 0*/, int mipLevel /*= 0*/) }
{
nvCheck(depth == 1);
// Copies the data to our internal structures.
const int idx = face * m.mipmapCount + mipLevel; bool InputOptions::setMipmapData(const void * data, int width, int height, int depth /*= 1*/, int face /*= 0*/, int mipLevel /*= 0*/)
{
if (m.images[idx].width != width || m.images[idx].height != height || m.images[idx].depth != depth || m.images[idx].mipLevel != mipLevel || m.images[idx].face != face) nvCheck(depth == 1);
{
// Invalid dimension or index. const int idx = face * m.mipmapCount + mipLevel;
return false;
} if (m.images[idx].width != width || m.images[idx].height != height || m.images[idx].depth != depth || m.images[idx].mipLevel != mipLevel || m.images[idx].face != face)
{
m.images[idx].data = new nv::Image(); // Invalid dimension or index.
m.images[idx].data->allocate(width, height); return false;
memcpy(m.images[idx].data->pixels(), data, width * height * 4); }
return true; m.images[idx].data = new nv::Image();
} m.images[idx].data->allocate(width, height);
memcpy(m.images[idx].data->pixels(), data, width * height * 4);
/// Describe the format of the input. return true;
void InputOptions::setFormat(InputFormat format, bool alphaTransparency) }
{
m.inputFormat = format;
m.alphaTransparency = alphaTransparency; /// Describe the format of the input.
} void InputOptions::setFormat(InputFormat format, bool alphaTransparency)
{
m.inputFormat = format;
/// Set gamma settings. m.alphaTransparency = alphaTransparency;
void InputOptions::setGamma(float inputGamma, float outputGamma) }
{
m.inputGamma = inputGamma;
m.outputGamma = outputGamma; /// Set gamma settings.
} void InputOptions::setGamma(float inputGamma, float outputGamma)
{
m.inputGamma = inputGamma;
/// Set texture wrappign mode. m.outputGamma = outputGamma;
void InputOptions::setWrapMode(WrapMode mode) }
{
m.wrapMode = mode;
} /// Set texture wrappign mode.
void InputOptions::setWrapMode(WrapMode mode)
{
/// Set mipmapping options. m.wrapMode = mode;
void InputOptions::setMipmapping(bool generateMipmaps, MipmapFilter filter/*= MipmapFilter_Kaiser*/, int maxLevel/*= -1*/) }
{
m.generateMipmaps = generateMipmaps;
m.mipmapFilter = filter; /// Set mipmapping options.
m.maxLevel = maxLevel; void InputOptions::setMipmapping(bool generateMipmaps, MipmapFilter filter/*= MipmapFilter_Kaiser*/, int maxLevel/*= -1*/)
} {
m.generateMipmaps = generateMipmaps;
m.mipmapFilter = filter;
/// Set quantization options. m.maxLevel = maxLevel;
/// @warning Do not enable dithering unless you know what you are doing. Quantization }
/// introduces errors. It's better to let the compressor quantize the result to
/// minimize the error, instead of quantizing the data before handling it to
/// the compressor. /// Set quantization options.
void InputOptions::setQuantization(bool colorDithering, bool alphaDithering, bool binaryAlpha, int alphaThreshold/*= 127*/) /// @warning Do not enable dithering unless you know what you are doing. Quantization
{ /// introduces errors. It's better to let the compressor quantize the result to
m.enableColorDithering = colorDithering; /// minimize the error, instead of quantizing the data before handling it to
m.enableAlphaDithering = alphaDithering; /// the compressor.
m.binaryAlpha = binaryAlpha; void InputOptions::setQuantization(bool colorDithering, bool alphaDithering, bool binaryAlpha, int alphaThreshold/*= 127*/)
m.alphaThreshold = alphaThreshold; {
} m.enableColorDithering = colorDithering;
m.enableAlphaDithering = alphaDithering;
m.binaryAlpha = binaryAlpha;
/// Enable normal map conversion. m.alphaThreshold = alphaThreshold;
void InputOptions::setConvertToNormalMap(bool convert) }
{
m.convertToNormalMap = convert;
} /// Enable normal map conversion.
void InputOptions::setConvertToNormalMap(bool convert)
/// Set height evaluation factors. {
void InputOptions::setHeightEvaluation(float redScale, float greenScale, float blueScale, float alphaScale) m.convertToNormalMap = convert;
{ }
// Do not normalize height factors.
// float total = redScale + greenScale + blueScale + alphaScale; /// Set height evaluation factors.
m.heightFactors = Vector4(redScale, greenScale, blueScale, alphaScale); void InputOptions::setHeightEvaluation(float redScale, float greenScale, float blueScale, float alphaScale)
} {
// Do not normalize height factors.
/// Set normal map conversion filter. // float total = redScale + greenScale + blueScale + alphaScale;
void InputOptions::setNormalFilter(float small, float medium, float big, float large) m.heightFactors = Vector4(redScale, greenScale, blueScale, alphaScale);
{ }
float total = small + medium + big + large;
m.bumpFrequencyScale = Vector4(small, medium, big, large) / total; /// Set normal map conversion filter.
} void InputOptions::setNormalFilter(float small, float medium, float big, float large)
{
/// Enable mipmap normalization. float total = small + medium + big + large;
void InputOptions::setNormalizeMipmaps(bool normalize) m.bumpFrequencyScale = Vector4(small, medium, big, large) / total;
{ }
m.normalizeMipmaps = normalize;
} /// Enable mipmap normalization.
void InputOptions::setNormalizeMipmaps(bool normalize)
{
m.normalizeMipmaps = normalize;
}

View File

@ -1,24 +1,24 @@
// Copyright NVIDIA Corporation 2007 -- Ignacio Castano <icastano@nvidia.com> // Copyright NVIDIA Corporation 2007 -- Ignacio Castano <icastano@nvidia.com>
// //
// Permission is hereby granted, free of charge, to any person // Permission is hereby granted, free of charge, to any person
// obtaining a copy of this software and associated documentation // obtaining a copy of this software and associated documentation
// files (the "Software"), to deal in the Software without // files (the "Software"), to deal in the Software without
// restriction, including without limitation the rights to use, // restriction, including without limitation the rights to use,
// copy, modify, merge, publish, distribute, sublicense, and/or sell // copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the // copies of the Software, and to permit persons to whom the
// Software is furnished to do so, subject to the following // Software is furnished to do so, subject to the following
// conditions: // conditions:
// //
// The above copyright notice and this permission notice shall be // The above copyright notice and this permission notice shall be
// included in all copies or substantial portions of the Software. // included in all copies or substantial portions of the Software.
// //
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
// OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND // OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, // HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
// WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING // WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
// OTHER DEALINGS IN THE SOFTWARE. // OTHER DEALINGS IN THE SOFTWARE.
#ifndef NV_TT_INPUTOPTIONS_H #ifndef NV_TT_INPUTOPTIONS_H

View File

@ -1,32 +1,32 @@
// Copyright NVIDIA Corporation 2007 -- Ignacio Castano <icastano@nvidia.com> // Copyright NVIDIA Corporation 2007 -- Ignacio Castano <icastano@nvidia.com>
// //
// Permission is hereby granted, free of charge, to any person // Permission is hereby granted, free of charge, to any person
// obtaining a copy of this software and associated documentation // obtaining a copy of this software and associated documentation
// files (the "Software"), to deal in the Software without // files (the "Software"), to deal in the Software without
// restriction, including without limitation the rights to use, // restriction, including without limitation the rights to use,
// copy, modify, merge, publish, distribute, sublicense, and/or sell // copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the // copies of the Software, and to permit persons to whom the
// Software is furnished to do so, subject to the following // Software is furnished to do so, subject to the following
// conditions: // conditions:
// //
// The above copyright notice and this permission notice shall be // The above copyright notice and this permission notice shall be
// included in all copies or substantial portions of the Software. // included in all copies or substantial portions of the Software.
// //
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
// OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND // OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, // HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
// WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING // WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
// OTHER DEALINGS IN THE SOFTWARE. // OTHER DEALINGS IN THE SOFTWARE.
#include "nvtt.h" #include "nvtt.h"
using namespace nvtt; using namespace nvtt;
/// Set default output options. /// Set default output options.
void OutputOptions::reset() void OutputOptions::reset()
{ {
// endiannes = native... // endiannes = native...
} }

View File

@ -1,44 +0,0 @@
// Copyright NVIDIA Corporation 2007 -- Ignacio Castano <icastano@nvidia.com>
#ifndef CMDLINE_H
#define CMDLINE_H
#include <nvcore/Debug.h>
#include <stdarg.h>
struct MyMessageHandler : public nv::MessageHandler {
MyMessageHandler() {
nv::debug::setMessageHandler( this );
}
~MyMessageHandler() {
nv::debug::resetMessageHandler();
}
virtual void log( const char * str, va_list arg ) {
va_list val;
va_copy(val, arg);
vfprintf(stderr, str, arg);
va_end(val);
}
};
struct MyAssertHandler : public nv::AssertHandler {
MyAssertHandler() {
nv::debug::setAssertHandler( this );
}
~MyAssertHandler() {
nv::debug::resetAssertHandler();
}
// Handler method, note that func might be NULL!
virtual int assert( const char *exp, const char *file, int line, const char *func ) {
fprintf(stderr, "Assertion failed: %s\nIn %s:%d\n", exp, file, line);
nv::debug::dumpInfo();
exit(1);
}
};
#endif // CMDLINE_H

View File

@ -28,7 +28,7 @@
#include "CudaMath.h" #include "CudaMath.h"
#define THREAD_NUM 64 // Number of threads per block. #define NUM_THREADS 64 // Number of threads per block.
#if __DEVICE_EMULATION__ #if __DEVICE_EMULATION__
#define __debugsync() __syncthreads() #define __debugsync() __syncthreads()
@ -94,7 +94,6 @@ static __device__ float evalPermutation4(const float3 * colors, uint permutation
betax_sum += beta * colors[i]; betax_sum += beta * colors[i];
} }
// alpha2, beta2, alphabeta and factor could be precomputed for each permutation, but it's faster to recompute them.
const float factor = 1.0f / (alpha2_sum * beta2_sum - alphabeta_sum * alphabeta_sum); const float factor = 1.0f / (alpha2_sum * beta2_sum - alphabeta_sum * alphabeta_sum);
float3 a = (alphax_sum * beta2_sum - betax_sum * alphabeta_sum) * factor; float3 a = (alphax_sum * beta2_sum - betax_sum * alphabeta_sum) * factor;
@ -151,89 +150,92 @@ static __device__ float evalPermutation3(const float3 * colors, uint permutation
return dot(e, kColorMetric); return dot(e, kColorMetric);
} }
static __device__ float evalPermutation4(const float3 * colors, const float * weights, uint permutation, ushort * start, ushort * end)
{
// Compute endpoints using least squares.
float alpha2_sum = 0.0f;
float beta2_sum = 0.0f;
float alphabeta_sum = 0.0f;
float3 alphax_sum = make_float3(0.0f, 0.0f, 0.0f);
float3 betax_sum = make_float3(0.0f, 0.0f, 0.0f);
// Compute alpha & beta for this permutation.
for (int i = 0; i < 16; i++)
{
const uint bits = permutation >> (2*i);
float beta = (bits & 1);
if (bits & 2) beta = (1 + beta) / 3.0f;
float alpha = 1.0f - beta;
alpha2_sum += alpha * alpha * weights[i];
beta2_sum += beta * beta * weights[i];
alphabeta_sum += alpha * beta * weights[i];
alphax_sum += alpha * colors[i] * weights[i];
betax_sum += beta * colors[i] * weights[i];
}
const float factor = 1.0f / (alpha2_sum * beta2_sum - alphabeta_sum * alphabeta_sum);
float3 a = (alphax_sum * beta2_sum - betax_sum * alphabeta_sum) * factor;
float3 b = (betax_sum * alpha2_sum - alphax_sum * alphabeta_sum) * factor;
// Round a, b to the closest 5-6-5 color and expand...
a = roundAndExpand(a, start);
b = roundAndExpand(b, end);
// compute the error
float3 e = a * a * alpha2_sum + b * b * beta2_sum + 2.0f * (a * b * alphabeta_sum - a * alphax_sum - b * betax_sum);
return dot(e, kColorMetric);
}
static __device__ float evalPermutation3(const float3 * colors, const float * weights, uint permutation, ushort * start, ushort * end)
{
// Compute endpoints using least squares.
float alpha2_sum = 0.0f;
float beta2_sum = 0.0f;
float alphabeta_sum = 0.0f;
float3 alphax_sum = make_float3(0.0f, 0.0f, 0.0f);
float3 betax_sum = make_float3(0.0f, 0.0f, 0.0f);
// Compute alpha & beta for this permutation.
for (int i = 0; i < 16; i++)
{
const uint bits = permutation >> (2*i);
float beta = (bits & 1);
if (bits & 2) beta = 0.5f;
float alpha = 1.0f - beta;
alpha2_sum += alpha * alpha * weights[i];
beta2_sum += beta * beta * weights[i];
alphabeta_sum += alpha * beta * weights[i];
alphax_sum += alpha * colors[i] * weights[i];
betax_sum += beta * colors[i] * weights[i];
}
const float factor = 1.0f / (alpha2_sum * beta2_sum - alphabeta_sum * alphabeta_sum);
float3 a = (alphax_sum * beta2_sum - betax_sum * alphabeta_sum) * factor;
float3 b = (betax_sum * alpha2_sum - alphax_sum * alphabeta_sum) * factor;
// Round a, b to the closest 5-6-5 color and expand...
a = roundAndExpand(a, start);
b = roundAndExpand(b, end);
// compute the error
float3 e = a * a * alpha2_sum + b * b * beta2_sum + 2.0f * (a * b * alphabeta_sum - a * alphax_sum - b * betax_sum);
return dot(e, kColorMetric);
}
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
// Sort colors // Sort colors
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
__device__ void sortColors(float * values, float3 * colors, int * xrefs) __device__ void sortColors(float * values, float3 * colors, int * cmp)
{
#if __DEVICE_EMULATION__
if (threadIdx.x == 0)
{
for( int i = 0; i < 16; ++i )
{
xrefs[i] = i;
}
// Use a sequential sort on emulation.
for( int i = 0; i < 16; ++i )
{
for( int j = i; j > 0 && values[j] < values[j - 1]; --j )
{
swap( values[j], values[j - 1] );
swap( xrefs[j], xrefs[j - 1] );
// swap( colors[j], colors[j - 1] );
}
}
float3 tmp[16];
for( int i = 0; i < 16; ++i )
{
tmp[i] = colors[i];
}
for( int i = 0; i < 16; ++i )
{
int xid = xrefs[i];
colors[i] = tmp[xid];
}
}
#else
int tid = threadIdx.x;
xrefs[tid] = tid;
// Parallel bitonic sort.
for (int k = 2; k <= 16; k *= 2)
{
// bitonic merge:
for (int j = k / 2; j>0; j /= 2)
{
int ixj = tid ^ j;
if (ixj > tid) {
// @@ Optimize these branches.
if ((tid & k) == 0) {
if (values[xrefs[tid]] > values[xrefs[ixj]]) {
// swap(values[tid], values[ixj]);
swap(colors[tid], colors[ixj]);
swap(xrefs[tid], xrefs[ixj]);
}
}
else {
if (values[xrefs[tid]] < values[xrefs[ixj]]) {
// swap(values[tid], values[ixj]);
swap(colors[tid], colors[ixj]);
swap(xrefs[tid], xrefs[ixj]);
}
}
}
}
}
#endif
// It would be faster to avoid color swaps during the sort, but there
// are compiler bugs preventing that.
#if 0
float3 tmp = colors[xrefs[tid]];
colors[tid] = tmp;
#endif
}
// This sort is faster, but does not sort correctly elements with the same value.
__device__ void sortColors2(float * values, float3 * colors, int * cmp)
{ {
int tid = threadIdx.x; int tid = threadIdx.x;
@ -254,10 +256,70 @@ __device__ void sortColors2(float * values, float3 * colors, int * cmp)
cmp[tid] += (values[14] < values[tid]); cmp[tid] += (values[14] < values[tid]);
cmp[tid] += (values[15] < values[tid]); cmp[tid] += (values[15] < values[tid]);
// Resolve elements with the same index.
if (tid > 0 && cmp[tid] == cmp[0]) ++cmp[tid];
if (tid > 1 && cmp[tid] == cmp[1]) ++cmp[tid];
if (tid > 2 && cmp[tid] == cmp[2]) ++cmp[tid];
if (tid > 3 && cmp[tid] == cmp[3]) ++cmp[tid];
if (tid > 4 && cmp[tid] == cmp[4]) ++cmp[tid];
if (tid > 5 && cmp[tid] == cmp[5]) ++cmp[tid];
if (tid > 6 && cmp[tid] == cmp[6]) ++cmp[tid];
if (tid > 7 && cmp[tid] == cmp[7]) ++cmp[tid];
if (tid > 8 && cmp[tid] == cmp[8]) ++cmp[tid];
if (tid > 9 && cmp[tid] == cmp[9]) ++cmp[tid];
if (tid > 10 && cmp[tid] == cmp[10]) ++cmp[tid];
if (tid > 11 && cmp[tid] == cmp[11]) ++cmp[tid];
if (tid > 12 && cmp[tid] == cmp[12]) ++cmp[tid];
if (tid > 13 && cmp[tid] == cmp[13]) ++cmp[tid];
if (tid > 14 && cmp[tid] == cmp[14]) ++cmp[tid];
float3 tmp = colors[tid]; float3 tmp = colors[tid];
colors[cmp[tid]] = tmp; colors[cmp[tid]] = tmp;
} }
__device__ void sortColors(float * values, float3 * colors, float * weights, int * cmp)
{
int tid = threadIdx.x;
cmp[tid] = (values[0] < values[tid]);
cmp[tid] += (values[1] < values[tid]);
cmp[tid] += (values[2] < values[tid]);
cmp[tid] += (values[3] < values[tid]);
cmp[tid] += (values[4] < values[tid]);
cmp[tid] += (values[5] < values[tid]);
cmp[tid] += (values[6] < values[tid]);
cmp[tid] += (values[7] < values[tid]);
cmp[tid] += (values[8] < values[tid]);
cmp[tid] += (values[9] < values[tid]);
cmp[tid] += (values[10] < values[tid]);
cmp[tid] += (values[11] < values[tid]);
cmp[tid] += (values[12] < values[tid]);
cmp[tid] += (values[13] < values[tid]);
cmp[tid] += (values[14] < values[tid]);
cmp[tid] += (values[15] < values[tid]);
// Resolve elements with the same index.
if (tid > 0 && cmp[tid] == cmp[0]) ++cmp[tid];
if (tid > 1 && cmp[tid] == cmp[1]) ++cmp[tid];
if (tid > 2 && cmp[tid] == cmp[2]) ++cmp[tid];
if (tid > 3 && cmp[tid] == cmp[3]) ++cmp[tid];
if (tid > 4 && cmp[tid] == cmp[4]) ++cmp[tid];
if (tid > 5 && cmp[tid] == cmp[5]) ++cmp[tid];
if (tid > 6 && cmp[tid] == cmp[6]) ++cmp[tid];
if (tid > 7 && cmp[tid] == cmp[7]) ++cmp[tid];
if (tid > 8 && cmp[tid] == cmp[8]) ++cmp[tid];
if (tid > 9 && cmp[tid] == cmp[9]) ++cmp[tid];
if (tid > 10 && cmp[tid] == cmp[10]) ++cmp[tid];
if (tid > 11 && cmp[tid] == cmp[11]) ++cmp[tid];
if (tid > 12 && cmp[tid] == cmp[12]) ++cmp[tid];
if (tid > 13 && cmp[tid] == cmp[13]) ++cmp[tid];
if (tid > 14 && cmp[tid] == cmp[14]) ++cmp[tid];
float3 tmp = colors[tid];
colors[cmp[tid]] = tmp;
weights[cmp[tid]] = weights[tid];
}
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
@ -269,7 +331,7 @@ __device__ void minimizeError(float * errors, int * indices)
#if __DEVICE_EMULATION__ #if __DEVICE_EMULATION__
for(int d = THREAD_NUM/2; d > 0; d >>= 1) for(int d = NUM_THREADS/2; d > 0; d >>= 1)
{ {
__syncthreads(); __syncthreads();
@ -287,7 +349,7 @@ __device__ void minimizeError(float * errors, int * indices)
#else #else
for(int d = THREAD_NUM/2; d > 32; d >>= 1) for(int d = NUM_THREADS/2; d > 32; d >>= 1)
{ {
__syncthreads(); __syncthreads();
@ -295,7 +357,7 @@ __device__ void minimizeError(float * errors, int * indices)
{ {
float err0 = errors[idx]; float err0 = errors[idx];
float err1 = errors[idx + d]; float err1 = errors[idx + d];
if (err1 < err0) { if (err1 < err0) {
errors[idx] = err1; errors[idx] = err1;
indices[idx] = indices[idx + d]; indices[idx] = indices[idx + d];
@ -338,7 +400,7 @@ __device__ void minimizeError(float * errors, int * indices)
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
// Compress color block // Compress color block
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
__global__ void compress(const uint * permutations, const uint * image, uint * result) __global__ void compress(const uint * permutations, const uint * image, uint2 * result)
{ {
const int bid = blockIdx.x; const int bid = blockIdx.x;
const int idx = threadIdx.x; const int idx = threadIdx.x;
@ -349,19 +411,14 @@ __global__ void compress(const uint * permutations, const uint * image, uint * r
if (idx < 16) if (idx < 16)
{ {
// Read color. // Read color and copy to shared mem.
uint c = image[(bid) * 16 + idx]; uint c = image[(bid) * 16 + idx];
// No need to synchronize, 16 < warp size.
#if __DEVICE_EMULATION__
} __debugsync(); if (idx < 16) {
#endif
// Copy color to shared mem.
colors[idx].z = ((c >> 0) & 0xFF) * (1.0f / 255.0f); colors[idx].z = ((c >> 0) & 0xFF) * (1.0f / 255.0f);
colors[idx].y = ((c >> 8) & 0xFF) * (1.0f / 255.0f); colors[idx].y = ((c >> 8) & 0xFF) * (1.0f / 255.0f);
colors[idx].x = ((c >> 16) & 0xFF) * (1.0f / 255.0f); colors[idx].x = ((c >> 16) & 0xFF) * (1.0f / 255.0f);
// No need to synchronize, 16 < warp size.
#if __DEVICE_EMULATION__ #if __DEVICE_EMULATION__
} __debugsync(); if (idx < 16) { } __debugsync(); if (idx < 16) {
#endif #endif
@ -383,15 +440,66 @@ __global__ void compress(const uint * permutations, const uint * image, uint * r
float bestError = FLT_MAX; float bestError = FLT_MAX;
__syncthreads(); __syncthreads();
for(int i = 0; i < 16; i++) #if 0
// This version is more clear, but slightly slower.
for(int i = 0; i < 16; i++)
{
if (i == 15 && idx >= 32) break;
ushort start, end;
uint permutation = permutations[idx + NUM_THREADS * i];
float error = evalPermutation4(colors, permutation, &start, &end);
if (error < bestError)
{
bestError = error;
bestPermutation = permutation;
bestStart = start;
bestEnd = end;
}
}
if (bestStart < bestEnd)
{
swap(bestEnd, bestStart);
bestPermutation ^= 0x55555555; // Flip indices.
}
for(int i = 0; i < 3; i++)
{
if (i == 2 && idx >= 32) break;
ushort start, end;
uint permutation = permutations[idx + NUM_THREADS * i];
float error = evalPermutation3(colors, permutation, &start, &end);
if (error < bestError)
{
bestError = error;
bestPermutation = permutation;
bestStart = start;
bestEnd = end;
if (bestStart > bestEnd)
{
swap(bestEnd, bestStart);
bestPermutation ^= (~bestPermutation >> 1) & 0x55555555; // Flip indices.
}
}
}
#else
{ {
if (i == 15 && idx >= 32) break; int pidx = idx + NUM_THREADS * 15;
if (idx >= 32)
{
pidx = idx + NUM_THREADS * 2;
}
ushort start, end; ushort start, end;
uint permutation = permutations[idx + THREAD_NUM * i]; uint permutation = permutations[pidx];
float error = evalPermutation4(colors, permutation, &start, &end); float error = evalPermutation4(colors, permutation, &start, &end);
if (error < bestError) if (error < bestError)
{ {
bestError = error; bestError = error;
@ -401,45 +509,73 @@ __global__ void compress(const uint * permutations, const uint * image, uint * r
} }
} }
for(int i = 3; i < 15; i++)
{
ushort start, end;
uint permutation = permutations[idx + NUM_THREADS * i];
float error = evalPermutation4(colors, permutation, &start, &end);
if (error < bestError)
{
bestError = error;
bestPermutation = permutation;
bestStart = start;
bestEnd = end;
}
}
if (bestStart < bestEnd) if (bestStart < bestEnd)
{ {
swap(bestEnd, bestStart); swap(bestEnd, bestStart);
bestPermutation ^= 0x55555555; // Flip indices. bestPermutation ^= 0x55555555; // Flip indices.
} }
for(int i = 0; i < 3; i++)
{ for(int i = 0; i < 3; i++)
if (i == 2 && idx >= 32) break; {
if (i == 2 && idx >= 32) break;
ushort start, end;
uint permutation = permutations[idx + THREAD_NUM * i]; ushort start, end;
float error = evalPermutation3(colors, permutation, &start, &end); uint permutation = permutations[idx + NUM_THREADS * i];
float error = evalPermutation3(colors, permutation, &start, &end);
if (error < bestError)
{ if (error < bestError)
bestError = error; {
bestPermutation = permutation; bestError = error;
bestStart = start; bestPermutation = permutation;
bestEnd = end; bestStart = start;
bestEnd = end;
if (bestStart > bestEnd)
if (bestStart > bestEnd)
{
swap(bestEnd, bestStart);
bestPermutation ^= (~bestPermutation >> 1) & 0x55555555; // Flip indices.
}
}
error = evalPermutation4(colors, permutation, &start, &end);
if (error < bestError)
{
bestError = error;
bestPermutation = permutation;
bestStart = start;
bestEnd = end;
if (bestStart < bestEnd)
{ {
swap(bestEnd, bestStart); swap(bestEnd, bestStart);
bestPermutation ^= (~bestPermutation >> 1) & 0x55555555; // Flip indices. bestPermutation ^= 0x55555555; // Flip indices.
} }
} }
} }
#endif
if (bestStart == bestEnd)
{
bestPermutation = 0;
}
__syncthreads(); __syncthreads();
// Use a parallel reduction to find minimum error. // Use a parallel reduction to find minimum error.
__shared__ float errors[THREAD_NUM]; __shared__ float errors[NUM_THREADS];
__shared__ int indices[THREAD_NUM]; __shared__ int indices[NUM_THREADS];
errors[idx] = bestError; errors[idx] = bestError;
indices[idx] = idx; indices[idx] = idx;
@ -451,31 +587,261 @@ __global__ void compress(const uint * permutations, const uint * image, uint * r
// Only write the result of the winner thread. // Only write the result of the winner thread.
if (idx == indices[0]) if (idx == indices[0])
{ {
if (bestStart == bestEnd)
{
bestPermutation = 0;
}
// Reorder permutation. // Reorder permutation.
uint perm = 0; uint perm = 0;
for(int i = 0; i < 16; i++) for(int i = 0; i < 16; i++)
{ {
int ref = xrefs[i]; int ref = xrefs[i];
perm |= ((bestPermutation >> (2 * i)) & 3) << (2 * ref); perm |= ((bestPermutation >> (2 * ref)) & 3) << (2 * i);
} }
// Write endpoints. (bestStart, bestEnd) // Write endpoints. (bestStart, bestEnd)
result[2 * bid + 0] = (bestEnd << 16) | bestStart; result[bid].x = (bestEnd << 16) | bestStart;
// Write palette indices (permutation). // Write palette indices (permutation).
result[2 * bid + 1] = perm; result[bid].y = perm;
} }
} }
__global__ void compressWeighted(const uint * permutations, const uint * image, uint2 * result)
{
const int bid = blockIdx.x;
const int idx = threadIdx.x;
__shared__ float3 colors[16];
__shared__ float weights[16];
__shared__ float dps[16];
__shared__ int xrefs[16];
if (idx < 16)
{
// Read color and copy to shared mem.
uint c = image[(bid) * 16 + idx];
colors[idx].z = ((c >> 0) & 0xFF) * (1.0f / 255.0f);
colors[idx].y = ((c >> 8) & 0xFF) * (1.0f / 255.0f);
colors[idx].x = ((c >> 16) & 0xFF) * (1.0f / 255.0f);
weights[idx] = ((c >> 24) & 0xFF) * (1.0f / 255.0f);
// No need to synchronize, 16 < warp size.
#if __DEVICE_EMULATION__
} __debugsync(); if (idx < 16) {
#endif
// Sort colors along the best fit line.
float3 axis = bestFitLine(colors);
dps[idx] = dot(colors[idx], axis);
#if __DEVICE_EMULATION__
} __debugsync(); if (idx < 16) {
#endif
sortColors(dps, colors, weights, xrefs);
}
ushort bestStart, bestEnd;
uint bestPermutation;
float bestError = FLT_MAX;
__syncthreads();
#if 0
// This version is more clear, but slightly slower.
for(int i = 0; i < 16; i++)
{
if (i == 15 && idx >= 32) break;
ushort start, end;
uint permutation = permutations[idx + NUM_THREADS * i];
float error = evalPermutation4(colors, weights, permutation, &start, &end);
if (error < bestError)
{
bestError = error;
bestPermutation = permutation;
bestStart = start;
bestEnd = end;
}
}
if (bestStart < bestEnd)
{
swap(bestEnd, bestStart);
bestPermutation ^= 0x55555555; // Flip indices.
}
for(int i = 0; i < 3; i++)
{
if (i == 2 && idx >= 32) break;
ushort start, end;
uint permutation = permutations[idx + NUM_THREADS * i];
float error = evalPermutation3(colors, weights, permutation, &start, &end);
if (error < bestError)
{
bestError = error;
bestPermutation = permutation;
bestStart = start;
bestEnd = end;
if (bestStart > bestEnd)
{
swap(bestEnd, bestStart);
bestPermutation ^= (~bestPermutation >> 1) & 0x55555555; // Flip indices.
}
}
}
#else
{
int pidx = idx + NUM_THREADS * 15;
if (idx >= 32)
{
pidx = idx + NUM_THREADS * 2;
}
ushort start, end;
uint permutation = permutations[pidx];
float error = evalPermutation4(colors, weights, permutation, &start, &end);
if (error < bestError)
{
bestError = error;
bestPermutation = permutation;
bestStart = start;
bestEnd = end;
}
}
for(int i = 3; i < 15; i++)
{
ushort start, end;
uint permutation = permutations[idx + NUM_THREADS * i];
float error = evalPermutation4(colors, weights, permutation, &start, &end);
if (error < bestError)
{
bestError = error;
bestPermutation = permutation;
bestStart = start;
bestEnd = end;
}
}
if (bestStart < bestEnd)
{
swap(bestEnd, bestStart);
bestPermutation ^= 0x55555555; // Flip indices.
}
for(int i = 0; i < 3; i++)
{
if (i == 2 && idx >= 32) break;
ushort start, end;
uint permutation = permutations[idx + NUM_THREADS * i];
float error = evalPermutation3(colors, weights, permutation, &start, &end);
if (error < bestError)
{
bestError = error;
bestPermutation = permutation;
bestStart = start;
bestEnd = end;
if (bestStart > bestEnd)
{
swap(bestEnd, bestStart);
bestPermutation ^= (~bestPermutation >> 1) & 0x55555555; // Flip indices.
}
}
error = evalPermutation4(colors, weights, permutation, &start, &end);
if (error < bestError)
{
bestError = error;
bestPermutation = permutation;
bestStart = start;
bestEnd = end;
if (bestStart < bestEnd)
{
swap(bestEnd, bestStart);
bestPermutation ^= 0x55555555; // Flip indices.
}
}
}
#endif
__syncthreads();
// Use a parallel reduction to find minimum error.
__shared__ float errors[NUM_THREADS];
__shared__ int indices[NUM_THREADS];
errors[idx] = bestError;
indices[idx] = idx;
minimizeError(errors, indices);
__syncthreads();
// Only write the result of the winner thread.
if (idx == indices[0])
{
if (bestStart == bestEnd)
{
bestPermutation = 0;
}
// Reorder permutation.
uint perm = 0;
for(int i = 0; i < 16; i++)
{
int ref = xrefs[i];
perm |= ((bestPermutation >> (2 * ref)) & 3) << (2 * i);
}
// Write endpoints. (bestStart, bestEnd)
result[bid].x = (bestEnd << 16) | bestStart;
// Write palette indices (permutation).
result[bid].y = perm;
}
}
////////////////////////////////////////////////////////////////////////////////
// Setup kernel
////////////////////////////////////////////////////////////////////////////////
extern "C" void setupCompressKernel(const float weights[3])
{
// Set constants.
cudaMemcpyToSymbol(kColorMetric, weights, sizeof(float) * 3, 0);
}
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
// Launch kernel // Launch kernel
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
extern "C" void compressKernel(uint blockNum, uint * d_data, uint * d_result, uint * d_bitmaps, float weights[3])
{
// Set constants.
cudaMemcpyToSymbol(kColorMetric, weights, sizeof(float) * 3, 0);
compress<<<blockNum, THREAD_NUM>>>(d_bitmaps, d_data, d_result); extern "C" void compressKernel(uint blockNum, uint * d_data, uint * d_result, uint * d_bitmaps)
{
compress<<<blockNum, NUM_THREADS>>>(d_bitmaps, d_data, (uint2 *)d_result);
} }
extern "C" void compressWeightedKernel(uint blockNum, uint * d_data, uint * d_result, uint * d_bitmaps)
{
compressWeighted<<<blockNum, NUM_THREADS>>>(d_bitmaps, d_data, (uint2 *)d_result);
}

View File

@ -0,0 +1,74 @@
// Copyright NVIDIA Corporation 2007 -- Ignacio Castano <icastano@nvidia.com>
//
// Permission is hereby granted, free of charge, to any person
// obtaining a copy of this software and associated documentation
// files (the "Software"), to deal in the Software without
// restriction, including without limitation the rights to use,
// copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the
// Software is furnished to do so, subject to the following
// conditions:
//
// The above copyright notice and this permission notice shall be
// included in all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
// OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
// WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
// OTHER DEALINGS IN THE SOFTWARE.
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <math.h>
#include "CudaMath.h"
#define THREAD_COUNT 256
#define MAX_KERNEL_WIDTH 32
#if __DEVICE_EMULATION__
#define __debugsync() __syncthreads()
#else
#define __debugsync()
#endif
__constant__ float kernel[MAX_KERNEL_WIDTH];
////////////////////////////////////////////////////////////////////////////////
// Monophase X convolution filter
////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////
// Monophase Y convolution filter
////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////
// Setup kernel
////////////////////////////////////////////////////////////////////////////////
extern "C" void setupConvolveKernel(const float * k, int w)
{
w = min(w, MAX_KERNEL_WIDTH);
cudaMemcpyToSymbol(kernel, k, sizeof(float) * w, 0);
}
////////////////////////////////////////////////////////////////////////////////
// Launch kernel
////////////////////////////////////////////////////////////////////////////////

View File

@ -24,7 +24,10 @@
#include <nvcore/Debug.h> #include <nvcore/Debug.h>
#include <nvcore/Containers.h> #include <nvcore/Containers.h>
#include <nvmath/Color.h> #include <nvmath/Color.h>
#include <nvmath/Fitting.h>
#include <nvimage/Image.h> #include <nvimage/Image.h>
#include <nvimage/ColorBlock.h>
#include <nvimage/BlockDXT.h>
#include <nvimage/nvtt/CompressionOptions.h> #include <nvimage/nvtt/CompressionOptions.h>
#include "CudaCompressDXT.h" #include "CudaCompressDXT.h"
@ -34,13 +37,17 @@
#include <cuda_runtime.h> #include <cuda_runtime.h>
#endif #endif
#include <time.h>
#include <stdio.h>
using namespace nv; using namespace nv;
using namespace nvtt; using namespace nvtt;
#if defined HAVE_CUDA #if defined HAVE_CUDA
extern "C" void compressKernel(uint blockNum, uint * d_data, uint * d_result, uint * d_bitmaps, float weights[3]); extern "C" void setupCompressKernel(const float weights[3]);
extern "C" void compressKernel(uint blockNum, uint * d_data, uint * d_result, uint * d_bitmaps);
extern "C" void compressWeightedKernel(uint blockNum, uint * d_data, uint * d_result, uint * d_bitmaps);
static uint * d_bitmaps = NULL; static uint * d_bitmaps = NULL;
@ -86,7 +93,7 @@ static void doPrecomputation()
} }
bitmaps[num] = bitmap; bitmaps[num] = bitmap;
num++; num++;
} }
} }
@ -95,7 +102,7 @@ static void doPrecomputation()
// Align to 160. // Align to 160.
for(int i = 0; i < 9; i++) for(int i = 0; i < 9; i++)
{ {
bitmaps[num] = 0x000AA555; bitmaps[num] = 0x555AA000;
num++; num++;
} }
nvDebugCheck(num == 160); nvDebugCheck(num == 160);
@ -153,25 +160,35 @@ static void doPrecomputation()
// Align to 1024. // Align to 1024.
for(int i = 0; i < 49; i++) for(int i = 0; i < 49; i++)
{ {
bitmaps[num] = 0x00AAFF55; bitmaps[num] = 0x555AA000;
num++; num++;
} }
nvDebugCheck(num == 1024); nvDebugCheck(num == 1024);
/*
printf("uint bitmaps[1024] = {\n");
for (int i = 0; i < 1024; i++)
{
printf("\t0x%.8X,\n", bitmaps[i]);
}
printf("};\n");
*/
// Upload bitmaps. // Upload bitmaps.
cudaMalloc((void**) &d_bitmaps, 1024 * sizeof(uint)); cudaMalloc((void**) &d_bitmaps, 1024 * sizeof(uint));
cudaMemcpy(d_bitmaps, bitmaps, 1024 * sizeof(uint), cudaMemcpyHostToDevice); cudaMemcpy(d_bitmaps, bitmaps, 1024 * sizeof(uint), cudaMemcpyHostToDevice);
// @@ Check for errors. // @@ Check for errors.
// @@ Free allocated memory.
} }
#endif #endif
/// Compress image using CUDA. /// Compress image using CUDA.
void nv::cudaCompressDXT1(const Image * image, const OutputOptions & outputOptions, const nvtt::CompressionOptions::Private & compressionOptions) void nv::cudaCompressDXT1(const Image * image, const OutputOptions & outputOptions, const CompressionOptions::Private & compressionOptions)
{ {
nvDebugCheck(cuda::isHardwarePresent()); nvDebugCheck(cuda::isHardwarePresent());
#if defined HAVE_CUDA #if defined HAVE_CUDA
@ -192,7 +209,7 @@ void nv::cudaCompressDXT1(const Image * image, const OutputOptions & outputOptio
const uint bh = min(image->height() - by * 4, 4U); const uint bh = min(image->height() - by * 4, 4U);
for (uint i = 0; i < 16; i++) { for (uint i = 0; i < 16; i++) {
const int x = (i & 3) % bw; const int x = (i % 4) % bw;
const int y = (i / 4) % bh; const int y = (i / 4) % bh;
blockLinearImage[(by * w + bx) * 16 + i] = image->pixel(bx * 4 + x, by * 4 + y).u; blockLinearImage[(by * w + bx) * 16 + i] = image->pixel(bx * 4 + x, by * 4 + y).u;
} }
@ -211,6 +228,10 @@ void nv::cudaCompressDXT1(const Image * image, const OutputOptions & outputOptio
uint * d_result = NULL; uint * d_result = NULL;
cudaMalloc((void**) &d_result, min(compressedSize, blockMax * 8U)); cudaMalloc((void**) &d_result, min(compressedSize, blockMax * 8U));
setupCompressKernel(compressionOptions.colorWeight.ptr());
clock_t start = clock();
// TODO: Add support for multiple GPUs. // TODO: Add support for multiple GPUs.
uint bn = 0; uint bn = 0;
while(bn != blockNum) while(bn != blockNum)
@ -220,11 +241,7 @@ void nv::cudaCompressDXT1(const Image * image, const OutputOptions & outputOptio
cudaMemcpy(d_data, blockLinearImage + bn * 16, count * 64, cudaMemcpyHostToDevice); cudaMemcpy(d_data, blockLinearImage + bn * 16, count * 64, cudaMemcpyHostToDevice);
// Launch kernel. // Launch kernel.
float weights[3]; compressKernel(count, d_data, d_result, d_bitmaps);
weights[0] = compressionOptions.colorWeight.x();
weights[1] = compressionOptions.colorWeight.y();
weights[2] = compressionOptions.colorWeight.z();
compressKernel(count, d_data, d_result, d_bitmaps, weights);
// Check for errors. // Check for errors.
cudaError_t err = cudaGetLastError(); cudaError_t err = cudaGetLastError();
@ -234,7 +251,7 @@ void nv::cudaCompressDXT1(const Image * image, const OutputOptions & outputOptio
if (outputOptions.errorHandler != NULL) if (outputOptions.errorHandler != NULL)
{ {
outputOptions.errorHandler->error(nvtt::Error_CudaError); outputOptions.errorHandler->error(Error_CudaError);
} }
} }
@ -250,6 +267,9 @@ void nv::cudaCompressDXT1(const Image * image, const OutputOptions & outputOptio
bn += count; bn += count;
} }
clock_t end = clock();
printf("\rCUDA time taken: %.3f seconds\n", float(end-start) / CLOCKS_PER_SEC);
free(blockLinearImage); free(blockLinearImage);
cudaFree(d_data); cudaFree(d_data);
cudaFree(d_result); cudaFree(d_result);
@ -262,3 +282,189 @@ void nv::cudaCompressDXT1(const Image * image, const OutputOptions & outputOptio
#endif #endif
} }
#if defined HAVE_CUDA
class Task
{
public:
explicit Task(uint numBlocks) : blockMaxCount(numBlocks), blockCount(0)
{
// System memory allocations.
blockLinearImage = new uint[blockMaxCount * 16];
xrefs = new uint[blockMaxCount * 16];
// Device memory allocations.
cudaMalloc((void**) &d_blockLinearImage, blockMaxCount * 16 * sizeof(uint));
cudaMalloc((void**) &d_compressedImage, blockMaxCount * 8U);
// @@ Check for allocation errors.
}
~Task()
{
delete [] blockLinearImage;
delete [] xrefs;
cudaFree(d_blockLinearImage);
cudaFree(d_compressedImage);
}
void addColorBlock(const ColorBlock & rgba)
{
nvDebugCheck(!isFull());
// @@ Count unique colors?
/*
// Convert colors to vectors.
Array<Vector3> pointArray(16);
for(int i = 0; i < 16; i++) {
const Color32 color = rgba.color(i);
pointArray.append(Vector3(color.r, color.g, color.b));
}
// Find best fit line.
const Vector3 axis = Fit::bestLine(pointArray).direction();
// Project points to axis.
float dps[16];
uint * order = &xrefs[blockCount * 16];
for (uint i = 0; i < 16; ++i)
{
dps[i] = dot(pointArray[i], axis);
order[i] = i;
}
// Sort them.
for (uint i = 0; i < 16; ++i)
{
for (uint j = i; j > 0 && dps[j] < dps[j - 1]; --j)
{
swap(dps[j], dps[j - 1]);
swap(order[j], order[j - 1]);
}
}
*/
// Write sorted colors to blockLinearImage.
for(uint i = 0; i < 16; ++i)
{
// blockLinearImage[blockCount * 16 + i] = rgba.color(order[i]);
blockLinearImage[blockCount * 16 + i] = rgba.color(i);
}
++blockCount;
}
bool isFull()
{
nvDebugCheck(blockCount <= blockMaxCount);
return blockCount == blockMaxCount;
}
void flush(const OutputOptions & outputOptions)
{
if (blockCount == 0)
{
// Nothing to do.
return;
}
// Copy input color blocks.
cudaMemcpy(d_blockLinearImage, blockLinearImage, blockCount * 64, cudaMemcpyHostToDevice);
// Launch kernel.
compressKernel(blockCount, d_blockLinearImage, d_compressedImage, d_bitmaps);
// Check for errors.
cudaError_t err = cudaGetLastError();
if (err != cudaSuccess)
{
nvDebug("CUDA Error: %s\n", cudaGetErrorString(err));
if (outputOptions.errorHandler != NULL)
{
outputOptions.errorHandler->error(Error_CudaError);
}
}
// Copy result to host, overwrite swizzled image.
uint * compressedImage = blockLinearImage;
cudaMemcpy(compressedImage, d_compressedImage, blockCount * 8, cudaMemcpyDeviceToHost);
// @@ Sort block indices.
// Output result.
if (outputOptions.outputHandler != NULL)
{
// outputOptions.outputHandler->writeData(compressedImage, blockCount * 8);
}
blockCount = 0;
}
private:
const uint blockMaxCount;
uint blockCount;
uint * blockLinearImage;
uint * xrefs;
uint * d_blockLinearImage;
uint * d_compressedImage;
};
#endif // defined HAVE_CUDA
void nv::cudaCompressDXT1_2(const Image * image, const OutputOptions & outputOptions, const CompressionOptions::Private & compressionOptions)
{
#if defined HAVE_CUDA
const uint w = image->width();
const uint h = image->height();
const uint blockNum = ((w + 3) / 4) * ((h + 3) / 4);
const uint blockMax = 32768; // 65535
doPrecomputation();
setupCompressKernel(compressionOptions.colorWeight.ptr());
ColorBlock rgba;
Task task(min(blockNum, blockMax));
clock_t start = clock();
for (uint y = 0; y < h; y += 4) {
for (uint x = 0; x < w; x += 4) {
rgba.init(image, x, y);
task.addColorBlock(rgba);
if (task.isFull())
{
task.flush(outputOptions);
}
}
}
task.flush(outputOptions);
clock_t end = clock();
printf("\rCUDA time taken: %.3f seconds\n", float(end-start) / CLOCKS_PER_SEC);
#else
if (outputOptions.errorHandler != NULL)
{
outputOptions.errorHandler->error(Error_CudaError);
}
#endif
}

View File

@ -32,7 +32,8 @@ namespace nv
class Image; class Image;
void cudaCompressDXT1(const Image * image, const nvtt::OutputOptions & outputOptions, const nvtt::CompressionOptions::Private & compressionOptions); void cudaCompressDXT1(const Image * image, const nvtt::OutputOptions & outputOptions, const nvtt::CompressionOptions::Private & compressionOptions);
void cudaCompressDXT1_2(const Image * image, const nvtt::OutputOptions & outputOptions, const nvtt::CompressionOptions::Private & compressionOptions);
} // nv namespace } // nv namespace

View File

@ -111,7 +111,7 @@ inline __device__ __host__ float3 clamp(float3 v, float3 a, float3 b)
inline __device__ __host__ float3 normalize(float3 v) inline __device__ __host__ float3 normalize(float3 v)
{ {
float len = 1.0f / dot(v, v); float len = 1.0f / sqrtf(dot(v, v));
return make_float3(v.x * len, v.y * len, v.z * len); return make_float3(v.x * len, v.y * len, v.z * len);
} }

View File

@ -73,8 +73,12 @@ static bool isWow32()
bool nv::cuda::isHardwarePresent() bool nv::cuda::isHardwarePresent()
{ {
#if defined HAVE_CUDA #if defined HAVE_CUDA
#if NV_OS_WIN32
return !isWindowsVista() && deviceCount() > 0; return !isWindowsVista() && deviceCount() > 0;
//return !isWindowsVista() && isWow32() && deviceCount() > 0; //return !isWindowsVista() && isWow32() && deviceCount() > 0;
#else
return deviceCount() > 0;
#endif
#else #else
return false; return false;
#endif #endif

View File

@ -1,486 +1,485 @@
// Copyright NVIDIA Corporation 2007 -- Ignacio Castano <icastano@nvidia.com> // Copyright NVIDIA Corporation 2007 -- Ignacio Castano <icastano@nvidia.com>
// //
// Permission is hereby granted, free of charge, to any person // Permission is hereby granted, free of charge, to any person
// obtaining a copy of this software and associated documentation // obtaining a copy of this software and associated documentation
// files (the "Software"), to deal in the Software without // files (the "Software"), to deal in the Software without
// restriction, including without limitation the rights to use, // restriction, including without limitation the rights to use,
// copy, modify, merge, publish, distribute, sublicense, and/or sell // copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the // copies of the Software, and to permit persons to whom the
// Software is furnished to do so, subject to the following // Software is furnished to do so, subject to the following
// conditions: // conditions:
// //
// The above copyright notice and this permission notice shall be // The above copyright notice and this permission notice shall be
// included in all copies or substantial portions of the Software. // included in all copies or substantial portions of the Software.
// //
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
// OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND // OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, // HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
// WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING // WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
// OTHER DEALINGS IN THE SOFTWARE. // OTHER DEALINGS IN THE SOFTWARE.
#include <nvcore/Memory.h> #include <nvcore/Memory.h>
#include <nvcore/Ptr.h> #include <nvcore/Ptr.h>
#include <nvimage/DirectDrawSurface.h> #include <nvimage/DirectDrawSurface.h>
#include <nvimage/ColorBlock.h> #include <nvimage/ColorBlock.h>
#include <nvimage/Image.h> #include <nvimage/BlockDXT.h>
#include <nvimage/FloatImage.h> #include <nvimage/Image.h>
#include <nvimage/Filter.h> #include <nvimage/FloatImage.h>
#include <nvimage/Quantize.h> #include <nvimage/Filter.h>
#include <nvimage/NormalMap.h> #include <nvimage/Quantize.h>
#include <nvimage/NormalMap.h>
#include "CompressDXT.h"
#include "FastCompressDXT.h" #include "CompressDXT.h"
#include "CompressRGB.h" #include "FastCompressDXT.h"
#include "BlockDXT.h" #include "CompressRGB.h"
#include "InputOptions.h" #include "InputOptions.h"
#include "CompressionOptions.h" #include "CompressionOptions.h"
#include "cuda/CudaUtils.h" #include "cuda/CudaUtils.h"
#include "cuda/CudaCompressDXT.h" #include "cuda/CudaCompressDXT.h"
using namespace nv; using namespace nv;
using namespace nvtt; using namespace nvtt;
namespace namespace
{ {
static int blockSize(Format format) static int blockSize(Format format)
{ {
if (format == Format_DXT1 /*|| format == Format_DXT1a*/) { if (format == Format_DXT1 /*|| format == Format_DXT1a*/) {
return 8; return 8;
} }
else if (format == Format_DXT3) { else if (format == Format_DXT3) {
return 16; return 16;
} }
else if (format == Format_DXT5 || format == Format_DXT5n) { else if (format == Format_DXT5 || format == Format_DXT5n) {
return 16; return 16;
} }
else if (format == Format_BC4) { else if (format == Format_BC4) {
return 8; return 8;
} }
else if (format == Format_BC5) { else if (format == Format_BC5) {
return 16; return 16;
} }
return 0; return 0;
} }
static int computeImageSize(int w, int h, Format format) static int computeImageSize(int w, int h, Format format)
{ {
if (format == Format_RGBA) { if (format == Format_RGBA) {
return w * h * sizeof(Color32); return w * h * sizeof(Color32);
} }
else { else {
return ((w + 3) / 4) * ((h + 3) / 4) * blockSize(format); return ((w + 3) / 4) * ((h + 3) / 4) * blockSize(format);
} }
} }
} // namespace } // namespace
// //
// compress // compress
// //
static void outputHeader(const InputOptions::Private & inputOptions, const OutputOptions & outputOptions, const CompressionOptions::Private & compressionOptions) static void outputHeader(const InputOptions::Private & inputOptions, const OutputOptions & outputOptions, const CompressionOptions::Private & compressionOptions)
{ {
// Output DDS header. // Output DDS header.
if (outputOptions.outputHandler != NULL && outputOptions.outputHeader) if (outputOptions.outputHandler != NULL && outputOptions.outputHeader)
{ {
DDSHeader header; DDSHeader header;
// Only 1 face and 2d textures supported. InputOptions::Private::Image * img = inputOptions.images;
nvCheck(inputOptions.faceCount == 1); nvCheck(img != NULL);
InputOptions::Private::Image * img = inputOptions.images; header.setWidth(img->width);
nvCheck(img != NULL); header.setHeight(img->height);
header.setWidth(img->width); int mipmapCount = inputOptions.mipmapCount;
header.setHeight(img->height); if (!inputOptions.generateMipmaps) mipmapCount = 0;
else if (inputOptions.maxLevel != -1 && inputOptions.maxLevel < mipmapCount) mipmapCount = inputOptions.maxLevel;
int mipmapCount = inputOptions.mipmapCount; header.setMipmapCount(mipmapCount);
if (!inputOptions.generateMipmaps) mipmapCount = 0;
else if (inputOptions.maxLevel != -1 && inputOptions.maxLevel < mipmapCount) mipmapCount = inputOptions.maxLevel; if (inputOptions.textureType == TextureType_2D) {
header.setMipmapCount(mipmapCount); header.setTexture2D();
}
if (inputOptions.textureType == TextureType_2D) { else if (inputOptions.textureType == TextureType_Cube) {
header.setTexture2D(); header.setTextureCube();
} }
else if (inputOptions.textureType == TextureType_Cube) { /*else if (inputOptions.textureType == TextureType_3D) {
header.setTextureCube(); header.setTexture3D();
} header.setDepth(img->depth);
/*else if (inputOptions.textureType == TextureType_3D) { }*/
header.setTexture3D();
header.setDepth(img->depth); if (compressionOptions.format == Format_RGBA)
}*/ {
header.setPitch(4 * img->width);
if (compressionOptions.format == Format_RGBA) header.setPixelFormat(compressionOptions.bitcount, compressionOptions.rmask, compressionOptions.gmask, compressionOptions.bmask, compressionOptions.amask);
{ }
header.setPitch(4 * img->width); else
header.setPixelFormat(compressionOptions.bitcount, compressionOptions.rmask, compressionOptions.gmask, compressionOptions.bmask, compressionOptions.amask); {
} header.setLinearSize(computeImageSize(img->width, img->height, compressionOptions.format));
else
{ if (compressionOptions.format == Format_DXT1 /*|| compressionOptions.format == Format_DXT1a*/) {
header.setLinearSize(computeImageSize(img->width, img->height, compressionOptions.format)); header.setFourCC('D', 'X', 'T', '1');
}
if (compressionOptions.format == Format_DXT1 /*|| compressionOptions.format == Format_DXT1a*/) { else if (compressionOptions.format == Format_DXT3) {
header.setFourCC('D', 'X', 'T', '1'); header.setFourCC('D', 'X', 'T', '3');
} }
else if (compressionOptions.format == Format_DXT3) { else if (compressionOptions.format == Format_DXT5) {
header.setFourCC('D', 'X', 'T', '3'); header.setFourCC('D', 'X', 'T', '5');
} }
else if (compressionOptions.format == Format_DXT5) { else if (compressionOptions.format == Format_DXT5n) {
header.setFourCC('D', 'X', 'T', '5'); header.setFourCC('D', 'X', 'T', '5');
} header.setNormalFlag(true);
else if (compressionOptions.format == Format_DXT5n) { }
header.setFourCC('R', 'X', 'G', 'B'); else if (compressionOptions.format == Format_BC4) {
} header.setFourCC('A', 'T', 'I', '1');
else if (compressionOptions.format == Format_BC4) { }
header.setFourCC('A', 'T', 'I', '1'); else if (compressionOptions.format == Format_BC5) {
} header.setFourCC('A', 'T', 'I', '2');
else if (compressionOptions.format == Format_BC5) { header.setNormalFlag(true);
header.setFourCC('A', 'T', 'I', '2'); }
} }
}
// Swap bytes if necessary.
// Swap bytes if necessary. header.swapBytes();
header.swapBytes();
nvStaticCheck(sizeof(DDSHeader) == 128);
nvStaticCheck(sizeof(DDSHeader) == 128); outputOptions.outputHandler->writeData(&header, 128);
outputOptions.outputHandler->writeData(&header, 128);
// Revert swap.
// Revert swap. header.swapBytes();
header.swapBytes(); }
} }
}
static bool compressMipmap(const Image * image, const OutputOptions & outputOptions, const CompressionOptions::Private & compressionOptions)
static bool compressMipmap(const Image * image, const OutputOptions & outputOptions, const CompressionOptions::Private & compressionOptions) {
{ nvDebugCheck(image != NULL);
nvDebugCheck(image != NULL);
if (compressionOptions.format == Format_RGBA || compressionOptions.format == Format_RGB)
if (compressionOptions.format == Format_RGBA || compressionOptions.format == Format_RGB) {
{ compressRGB(image, outputOptions, compressionOptions);
compressRGB(image, outputOptions, compressionOptions); }
} else if (compressionOptions.format == Format_DXT1)
else if (compressionOptions.format == Format_DXT1) {
{ #if defined(HAVE_S3QUANT)
#if defined(HAVE_S3QUANT) if (compressionOptions.externalCompressor == "s3")
if (compressionOptions.externalCompressor == "s3") {
{ s3CompressDXT1(image, outputOptions);
s3CompressDXT1(image, outputOptions); }
} else
else #endif
#endif
#if defined(HAVE_ATITC)
#if defined(HAVE_ATITC) if (compressionOptions.externalCompressor == "ati")
if (compressionOptions.externalCompressor == "ati") {
{ printf("ATI\n");
printf("ATI\n"); atiCompressDXT1(image, outputOptions);
atiCompressDXT1(image, outputOptions); }
} else
else #endif
#endif if (compressionOptions.useCuda && nv::cuda::isHardwarePresent())
if (compressionOptions.useCuda && nv::cuda::isHardwarePresent()) {
{ cudaCompressDXT1(image, outputOptions, compressionOptions);
cudaCompressDXT1(image, outputOptions, compressionOptions); }
} else
else {
{ if (compressionOptions.quality == Quality_Fastest)
if (compressionOptions.quality == Quality_Fastest) {
{ fastCompressDXT1(image, outputOptions);
fastCompressDXT1(image, outputOptions); }
} else
else {
{ compressDXT1(image, outputOptions, compressionOptions);
compressDXT1(image, outputOptions, compressionOptions); }
} }
} }
} else if (compressionOptions.format == Format_DXT3)
else if (compressionOptions.format == Format_DXT3) {
{ if (compressionOptions.quality == Quality_Fastest)
if (compressionOptions.quality == Quality_Fastest) {
{ fastCompressDXT3(image, outputOptions);
fastCompressDXT3(image, outputOptions); }
} else
else {
{ compressDXT3(image, outputOptions, compressionOptions);
compressDXT3(image, outputOptions, compressionOptions); }
} }
} else if (compressionOptions.format == Format_DXT5)
else if (compressionOptions.format == Format_DXT5) {
{ if (compressionOptions.quality == Quality_Fastest)
if (compressionOptions.quality == Quality_Fastest) {
{ fastCompressDXT5(image, outputOptions);
fastCompressDXT5(image, outputOptions); }
} else
else {
{ compressDXT5(image, outputOptions, compressionOptions);
compressDXT5(image, outputOptions, compressionOptions); }
} }
} else if (compressionOptions.format == Format_DXT5n)
else if (compressionOptions.format == Format_DXT5n) {
{ if (compressionOptions.quality == Quality_Fastest)
if (compressionOptions.quality == Quality_Fastest) {
{ fastCompressDXT5n(image, outputOptions);
fastCompressDXT5n(image, outputOptions); }
} else
else {
{ compressDXT5n(image, outputOptions, compressionOptions);
compressDXT5n(image, outputOptions, compressionOptions); }
} }
} else if (compressionOptions.format == Format_BC4)
else if (compressionOptions.format == Format_BC4) {
{ compressBC4(image, outputOptions, compressionOptions);
compressBC4(image, outputOptions, compressionOptions); }
} else if (compressionOptions.format == Format_BC5)
else if (compressionOptions.format == Format_BC5) {
{ compressBC5(image, outputOptions, compressionOptions);
compressBC5(image, outputOptions, compressionOptions); }
}
return true;
return true; }
}
// Convert input image to linear float image.
// Convert input image to linear float image. static FloatImage * toFloatImage(const Image * image, const InputOptions::Private & inputOptions)
static FloatImage * toFloatImage(const Image * image, const InputOptions::Private & inputOptions) {
{ nvDebugCheck(image != NULL);
nvDebugCheck(image != NULL);
FloatImage * floatImage = new FloatImage(image);
FloatImage * floatImage = new FloatImage(image);
// Convert to linear space.
// Convert to linear space. if (inputOptions.inputGamma != 1.0f) {
if (inputOptions.inputGamma != 1.0f) { floatImage->toLinear(0, 3, inputOptions.inputGamma);
floatImage->toLinear(0, 3, inputOptions.inputGamma); }
}
return floatImage;
return floatImage; }
}
// Convert linear float image to output image.
// Convert linear float image to output image. static Image * toFixedImage(const FloatImage * floatImage, const InputOptions::Private & inputOptions)
static Image * toFixedImage(const FloatImage * floatImage, const InputOptions::Private & inputOptions) {
{ nvDebugCheck(floatImage != NULL);
nvDebugCheck(floatImage != NULL);
return floatImage->createImageGammaCorrect(inputOptions.outputGamma);
return floatImage->createImageGammaCorrect(inputOptions.outputGamma); }
}
// Create mipmap from the given image.
// Create mipmap from the given image. static FloatImage * createMipmap(const FloatImage * floatImage, const InputOptions::Private & inputOptions)
static FloatImage * createMipmap(const FloatImage * floatImage, const InputOptions::Private & inputOptions) {
{ FloatImage * result = NULL;
FloatImage * result = NULL;
if (inputOptions.mipmapFilter == MipmapFilter_Box)
if (inputOptions.mipmapFilter == MipmapFilter_Box) {
{ // Use fast downsample.
// Use fast downsample. result = floatImage->fastDownSample();
result = floatImage->fastDownSample(); }
} else if (inputOptions.mipmapFilter == MipmapFilter_Triangle)
else if (inputOptions.mipmapFilter == MipmapFilter_Triangle) {
{ Kernel1 kernel(4);
Kernel1 kernel(4); kernel.initFilter(Filter::Triangle);
kernel.initFilter(Filter::Triangle); result = floatImage->downSample(kernel, (FloatImage::WrapMode)inputOptions.wrapMode);
result = floatImage->downSample(kernel, (FloatImage::WrapMode)inputOptions.wrapMode); }
} else /*if (inputOptions.mipmapFilter == MipmapFilter_Kaiser)*/
else /*if (inputOptions.mipmapFilter == MipmapFilter_Kaiser)*/ {
{ Kernel1 kernel(10);
Kernel1 kernel(10); kernel.initKaiser(8.0, 0.75f);
kernel.initKaiser(8.0, 0.75f); result = floatImage->downSample(kernel, (FloatImage::WrapMode)inputOptions.wrapMode);
result = floatImage->downSample(kernel, (FloatImage::WrapMode)inputOptions.wrapMode); }
}
// Normalize mipmap.
// Normalize mipmap. if (inputOptions.normalizeMipmaps)
if (inputOptions.normalizeMipmaps) {
{ normalize(result);
normalize(result); }
}
return result;
return result; }
}
// Quantize the input image to the precision of the output format.
// Quantize the input image to the precision of the output format. static void quantize(Image * img, const InputOptions::Private & inputOptions, Format format)
static void quantize(Image * img, const InputOptions::Private & inputOptions, Format format) {
{ if (inputOptions.enableColorDithering)
if (inputOptions.enableColorDithering) {
{ if (format >= Format_DXT1 && format <= Format_DXT5)
if (format >= Format_DXT1 && format <= Format_DXT5) {
{ Quantize::FloydSteinberg_RGB16(img);
Quantize::FloydSteinberg_RGB16(img); }
} }
} if (inputOptions.binaryAlpha)
if (inputOptions.binaryAlpha) {
{ if (inputOptions.enableAlphaDithering)
if (inputOptions.enableAlphaDithering) {
{ Quantize::FloydSteinberg_BinaryAlpha(img, inputOptions.alphaThreshold);
Quantize::FloydSteinberg_BinaryAlpha(img, inputOptions.alphaThreshold); }
} else
else {
{ Quantize::BinaryAlpha(img, inputOptions.alphaThreshold);
Quantize::BinaryAlpha(img, inputOptions.alphaThreshold); }
} }
} else
else {
{ if (inputOptions.enableAlphaDithering)
if (inputOptions.enableAlphaDithering) {
{ if (format == Format_DXT3)
if (format == Format_DXT3) {
{ Quantize::Alpha4(img);
Quantize::Alpha4(img); }
} /*else if (format == Format_DXT1a)
/*else if (format == Format_DXT1a) {
{ Quantize::BinaryAlpha(img, inputOptions.alphaThreshold);
Quantize::BinaryAlpha(img, inputOptions.alphaThreshold); }*/
}*/ }
} }
} }
}
/// Compress the input texture with the given compression options.
/// Compress the input texture with the given compression options. bool nvtt::compress(const InputOptions & inputOptions, const OutputOptions & outputOptions, const CompressionOptions & compressionOptions)
bool nvtt::compress(const InputOptions & inputOptions, const OutputOptions & outputOptions, const CompressionOptions & compressionOptions) {
{ // Make sure enums match.
// Make sure enums match. nvStaticCheck(FloatImage::WrapMode_Clamp == (FloatImage::WrapMode)WrapMode_Clamp);
nvStaticCheck(FloatImage::WrapMode_Clamp == (FloatImage::WrapMode)WrapMode_Clamp); nvStaticCheck(FloatImage::WrapMode_Mirror == (FloatImage::WrapMode)WrapMode_Mirror);
nvStaticCheck(FloatImage::WrapMode_Mirror == (FloatImage::WrapMode)WrapMode_Mirror); nvStaticCheck(FloatImage::WrapMode_Repeat == (FloatImage::WrapMode)WrapMode_Repeat);
nvStaticCheck(FloatImage::WrapMode_Repeat == (FloatImage::WrapMode)WrapMode_Repeat);
// Output DDS header.
// Output DDS header. outputHeader(inputOptions.m, outputOptions, compressionOptions.m);
outputHeader(inputOptions.m, outputOptions, compressionOptions.m);
Format format = compressionOptions.m.format;
Format format = compressionOptions.m.format;
for (int f = 0; f < inputOptions.m.faceCount; f++)
for (int f = 0; f < inputOptions.m.faceCount; f++) {
{ Image * lastImage = NULL;
Image * lastImage = NULL; AutoPtr<FloatImage> floatImage(NULL);
AutoPtr<FloatImage> floatImage(NULL);
for (int m = 0; m < inputOptions.m.mipmapCount; m++)
for (int m = 0; m < inputOptions.m.mipmapCount; m++) {
{ int idx = f * inputOptions.m.mipmapCount + m;
int idx = f * inputOptions.m.mipmapCount + m; InputOptions::Private::Image & mipmap = inputOptions.m.images[idx];
InputOptions::Private::Image & mipmap = inputOptions.m.images[idx];
if (outputOptions.outputHandler)
if (outputOptions.outputHandler) {
{ int size = computeImageSize(mipmap.width, mipmap.height, format);
int size = computeImageSize(mipmap.width, mipmap.height, format); outputOptions.outputHandler->mipmap(size, mipmap.width, mipmap.height, mipmap.depth, mipmap.face, mipmap.mipLevel);
outputOptions.outputHandler->mipmap(size, mipmap.width, mipmap.height, mipmap.depth, mipmap.face, mipmap.mipLevel); }
}
Image * img; // Image to compress.
Image * img; // Image to compress.
if (mipmap.data != NULL) // Mipmap provided.
if (mipmap.data != NULL) // Mipmap provided. {
{ // Convert to normal map.
// Convert to normal map. if (inputOptions.m.convertToNormalMap)
if (inputOptions.m.convertToNormalMap) {
{ floatImage = createNormalMap(mipmap.data, (FloatImage::WrapMode)inputOptions.m.wrapMode, inputOptions.m.heightFactors, inputOptions.m.bumpFrequencyScale);
floatImage = createNormalMap(mipmap.data, (FloatImage::WrapMode)inputOptions.m.wrapMode, inputOptions.m.heightFactors, inputOptions.m.bumpFrequencyScale); }
} else
else {
{ lastImage = img = mipmap.data;
lastImage = img = mipmap.data;
// Delete float image.
// Delete float image. floatImage = NULL;
floatImage = NULL; }
} }
} else // Create mipmap from last.
else // Create mipmap from last. {
{ if (m == 0) {
if (m == 0) { // First mipmap missing.
// First mipmap missing. if (outputOptions.errorHandler != NULL) outputOptions.errorHandler->error(Error_InvalidInput);
if (outputOptions.errorHandler != NULL) outputOptions.errorHandler->error(Error_InvalidInput); return false;
return false; }
}
if (floatImage == NULL)
if (floatImage == NULL) {
{ nvDebugCheck(lastImage != NULL);
nvDebugCheck(lastImage != NULL); floatImage = toFloatImage(lastImage, inputOptions.m);
floatImage = toFloatImage(lastImage, inputOptions.m); }
}
// Create mipmap.
// Create mipmap. floatImage = createMipmap(floatImage.ptr(), inputOptions.m);
floatImage = createMipmap(floatImage.ptr(), inputOptions.m); }
}
if (floatImage != NULL)
if (floatImage != NULL) {
{ // Convert to fixed.
// Convert to fixed. img = toFixedImage(floatImage.ptr(), inputOptions.m);
img = toFixedImage(floatImage.ptr(), inputOptions.m); }
}
quantize(img, inputOptions.m, format);
quantize(img, inputOptions.m, format);
compressMipmap(img, outputOptions, compressionOptions.m);
compressMipmap(img, outputOptions, compressionOptions.m);
if (img != mipmap.data)
if (img != mipmap.data) {
{ delete img;
delete img; }
}
if (!inputOptions.m.generateMipmaps || (inputOptions.m.maxLevel >= 0 && m >= inputOptions.m.maxLevel)) {
if (!inputOptions.m.generateMipmaps || (inputOptions.m.maxLevel >= 0 && m >= inputOptions.m.maxLevel)) { // continue with next face.
// continue with next face. break;
break; }
} }
} }
}
return true;
return true; }
}
/// Estimate the size of compressing the input with the given options.
/// Estimate the size of compressing the input with the given options. int nvtt::estimateSize(const InputOptions & inputOptions, const CompressionOptions & compressionOptions)
int nvtt::estimateSize(const InputOptions & inputOptions, const CompressionOptions & compressionOptions) {
{ Format format = compressionOptions.m.format;
Format format = compressionOptions.m.format;
int size = 0;
int size = 0;
for (int f = 0; f < inputOptions.m.faceCount; f++)
for (int f = 0; f < inputOptions.m.faceCount; f++) {
{ for (int m = 0; m < inputOptions.m.mipmapCount; m++)
for (int m = 0; m < inputOptions.m.mipmapCount; m++) {
{ int idx = f * inputOptions.m.mipmapCount + m;
int idx = f * inputOptions.m.mipmapCount + m; const InputOptions::Private::Image & img = inputOptions.m.images[idx];
const InputOptions::Private::Image & img = inputOptions.m.images[idx];
size += computeImageSize(img.width, img.height, format);
size += computeImageSize(img.width, img.height, format);
if (!inputOptions.m.generateMipmaps || (inputOptions.m.maxLevel >= 0 && m >= inputOptions.m.maxLevel)) {
if (!inputOptions.m.generateMipmaps || (inputOptions.m.maxLevel >= 0 && m >= inputOptions.m.maxLevel)) { // continue with next face.
// continue with next face. break;
break; }
} }
} }
}
return size;
return size; }
}
/// Return a string for the given error.
/// Return a string for the given error. const char * nvtt::errorString(Error e)
const char * nvtt::errorString(Error e) {
{ switch(e)
switch(e) {
{ case Error_InvalidInput:
case Error_InvalidInput: return "Invalid input";
return "Invalid input"; case Error_UserInterruption:
case Error_UserInterruption: return "User interruption";
return "User interruption"; case Error_UnsupportedFeature:
case Error_UnsupportedFeature: return "Unsupported feature";
return "Unsupported feature"; case Error_CudaError:
case Error_CudaError: return "CUDA error";
return "CUDA error"; case Error_Unknown:
case Error_Unknown: return "Unknown error";
return "Unknown error"; }
}
return NULL;
return NULL; }
}

View File

@ -1,242 +1,245 @@
// Copyright NVIDIA Corporation 2007 -- Ignacio Castano <icastano@nvidia.com> // Copyright NVIDIA Corporation 2007 -- Ignacio Castano <icastano@nvidia.com>
// //
// Permission is hereby granted, free of charge, to any person // Permission is hereby granted, free of charge, to any person
// obtaining a copy of this software and associated documentation // obtaining a copy of this software and associated documentation
// files (the "Software"), to deal in the Software without // files (the "Software"), to deal in the Software without
// restriction, including without limitation the rights to use, // restriction, including without limitation the rights to use,
// copy, modify, merge, publish, distribute, sublicense, and/or sell // copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the // copies of the Software, and to permit persons to whom the
// Software is furnished to do so, subject to the following // Software is furnished to do so, subject to the following
// conditions: // conditions:
// //
// The above copyright notice and this permission notice shall be // The above copyright notice and this permission notice shall be
// included in all copies or substantial portions of the Software. // included in all copies or substantial portions of the Software.
// //
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
// OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND // OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, // HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
// WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING // WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
// OTHER DEALINGS IN THE SOFTWARE. // OTHER DEALINGS IN THE SOFTWARE.
#ifndef NV_TT_H #ifndef NV_TT_H
#define NV_TT_H #define NV_TT_H
#include <nvcore/nvcore.h> #include <nvcore/nvcore.h>
// Function linkage //#define HAVE_S3QUANT
#if NVTT_SHARED //#define HAVE_ATITC
#ifdef NVTT_EXPORTS
#define NVTT_API DLL_EXPORT // Function linkage
#define NVTT_CLASS DLL_EXPORT_CLASS #if NVTT_SHARED
#else #ifdef NVTT_EXPORTS
#define NVTT_API DLL_IMPORT #define NVTT_API DLL_EXPORT
#define NVTT_CLASS DLL_IMPORT #define NVTT_CLASS DLL_EXPORT_CLASS
#endif #else
#else #define NVTT_API DLL_IMPORT
#define NVTT_API #define NVTT_CLASS DLL_IMPORT
#define NVTT_CLASS #endif
#endif #else
#define NVTT_API
// Public interface. #define NVTT_CLASS
namespace nvtt #endif
{
/// Supported compression formats. // Public interface.
enum Format namespace nvtt
{ {
// No compression. /// Supported compression formats.
Format_RGB, enum Format
Format_RGBA = Format_RGB, {
// No compression.
// DX9 formats. Format_RGB,
Format_DXT1, Format_RGBA = Format_RGB,
// Format_DXT1a, // DXT1 with binary alpha.
Format_DXT3, // DX9 formats.
Format_DXT5, Format_DXT1,
Format_DXT5n, // Compressed HILO: R=0, G=x, B=0, A=y // Format_DXT1a, // DXT1 with binary alpha.
Format_DXT3,
// DX10 formats. Format_DXT5,
Format_BC1 = Format_DXT1, Format_DXT5n, // Compressed HILO: R=0, G=x, B=0, A=y
Format_BC2 = Format_DXT3,
Format_BC3 = Format_DXT5, // DX10 formats.
Format_BC3n = Format_DXT5n, Format_BC1 = Format_DXT1,
Format_BC4, // ATI1 Format_BC2 = Format_DXT3,
Format_BC5, // 3DC, ATI2 Format_BC3 = Format_DXT5,
Format_BC3n = Format_DXT5n,
// OpenGL formats. Format_BC4, // ATI1
Format_LATC = Format_BC5, Format_BC5, // 3DC, ATI2
};
// OpenGL formats.
/// Quality modes. Format_LATC = Format_BC5,
enum Quality };
{
Quality_Fastest, /// Quality modes.
Quality_Normal, enum Quality
Quality_Production, {
Quality_Highest, Quality_Fastest,
}; Quality_Normal,
Quality_Production,
/// Compression options. This class describes the desired compression format and other compression settings. Quality_Highest,
class CompressionOptions };
{
public: /// Compression options. This class describes the desired compression format and other compression settings.
NVTT_API CompressionOptions(); class CompressionOptions
NVTT_API ~CompressionOptions(); {
public:
NVTT_API void reset(); NVTT_API CompressionOptions();
NVTT_API ~CompressionOptions();
NVTT_API void setFormat(Format format);
NVTT_API void setQuality(Quality quality, float errorThreshold = 0.5f); NVTT_API void reset();
NVTT_API void setColorWeights(float red, float green, float blue);
NVTT_API void enableHardwareCompression(bool enable); NVTT_API void setFormat(Format format);
NVTT_API void setQuality(Quality quality, float errorThreshold = 0.5f);
NVTT_API void setExternalCompressor(const char * name); NVTT_API void setColorWeights(float red, float green, float blue);
NVTT_API void enableHardwareCompression(bool enable);
// Set color mask to describe the RGB/RGBA format.
NVTT_API void setPixelFormat(uint bitcount, uint rmask, uint gmask, uint bmask, uint amask); NVTT_API void setExternalCompressor(const char * name);
//private: // Set color mask to describe the RGB/RGBA format.
struct Private; NVTT_API void setPixelFormat(uint bitcount, uint rmask, uint gmask, uint bmask, uint amask);
Private & m;
}; //private:
struct Private;
Private & m;
/// Wrap modes. // This matches FloatImage::WrapMode. };
enum WrapMode
{
WrapMode_Clamp, /// Wrap modes. // This matches FloatImage::WrapMode.
WrapMode_Repeat, enum WrapMode
WrapMode_Mirror, {
}; WrapMode_Clamp,
WrapMode_Repeat,
/// Texture types. WrapMode_Mirror,
enum TextureType };
{
TextureType_2D, /// Texture types.
TextureType_Cube, enum TextureType
// TextureType_3D, {
}; TextureType_2D,
TextureType_Cube,
/// Input formats. // TextureType_3D,
enum InputFormat };
{
InputFormat_BGRA_8UB, /// Input formats.
// InputFormat_RGBE_8UB, enum InputFormat
// InputFormat_BGRA_32F, {
}; InputFormat_BGRA_8UB,
// InputFormat_RGBE_8UB,
/// Mipmap downsampling filters. // InputFormat_BGRA_32F,
enum MipmapFilter };
{
MipmapFilter_Box, ///< Box filter is quite good and very fast. /// Mipmap downsampling filters.
MipmapFilter_Triangle, ///< Triangle filter blurs the results too much, but that might be what you want. enum MipmapFilter
MipmapFilter_Kaiser, ///< Kaiser-windowed Sinc filter is the best downsampling filter. {
}; MipmapFilter_Box, ///< Box filter is quite good and very fast.
MipmapFilter_Triangle, ///< Triangle filter blurs the results too much, but that might be what you want.
MipmapFilter_Kaiser, ///< Kaiser-windowed Sinc filter is the best downsampling filter.
};
/// Input options. Specify format and layout of the input texture.
struct InputOptions
{
NVTT_API InputOptions(); /// Input options. Specify format and layout of the input texture.
NVTT_API ~InputOptions(); struct InputOptions
{
// Set default options. NVTT_API InputOptions();
NVTT_API void reset(); NVTT_API ~InputOptions();
// Setup input layout. // Set default options.
NVTT_API void setTextureLayout(TextureType type, int w, int h, int d = 1); NVTT_API void reset();
NVTT_API void resetTextureLayout();
// Setup input layout.
// Set mipmap data. Copies the data. NVTT_API void setTextureLayout(TextureType type, int w, int h, int d = 1);
NVTT_API bool setMipmapData(const void * data, int w, int h, int d = 1, int face = 0, int mipmap = 0); NVTT_API void resetTextureLayout();
// Describe the format of the input. // Set mipmap data. Copies the data.
NVTT_API void setFormat(InputFormat fmt, bool alphaTransparency); NVTT_API bool setMipmapData(const void * data, int w, int h, int d = 1, int face = 0, int mipmap = 0);
// Set gamma settings. // Describe the format of the input.
NVTT_API void setGamma(float inputGamma, float outputGamma); NVTT_API void setFormat(InputFormat fmt, bool alphaTransparency);
// Set texture wrappign mode. // Set gamma settings.
NVTT_API void setWrapMode(WrapMode mode); NVTT_API void setGamma(float inputGamma, float outputGamma);
// Set mipmapping options. // Set texture wrappign mode.
NVTT_API void setMipmapping(bool generateMipmaps, MipmapFilter filter = MipmapFilter_Kaiser, int maxLevel = -1); NVTT_API void setWrapMode(WrapMode mode);
// Set quantization options. // Set mipmapping options.
NVTT_API void setQuantization(bool colorDithering, bool alphaDithering, bool binaryAlpha, int alphaThreshold = 127); NVTT_API void setMipmapping(bool generateMipmaps, MipmapFilter filter = MipmapFilter_Kaiser, int maxLevel = -1);
// Set normal map options. // Set quantization options.
NVTT_API void setConvertToNormalMap(bool convert); NVTT_API void setQuantization(bool colorDithering, bool alphaDithering, bool binaryAlpha, int alphaThreshold = 127);
NVTT_API void setHeightEvaluation(float redScale, float greenScale, float blueScale, float alphaScale);
NVTT_API void setNormalFilter(float small, float medium, float big, float large); // Set normal map options.
NVTT_API void setNormalizeMipmaps(bool b); NVTT_API void setConvertToNormalMap(bool convert);
NVTT_API void setHeightEvaluation(float redScale, float greenScale, float blueScale, float alphaScale);
//private: NVTT_API void setNormalFilter(float small, float medium, float big, float large);
struct Private; NVTT_API void setNormalizeMipmaps(bool b);
Private & m;
}; //private:
struct Private;
Private & m;
/// Output handler. };
struct OutputHandler
{
virtual ~OutputHandler() {} /// Output handler.
struct OutputHandler
/// Indicate the start of a new compressed image that's part of the final texture. {
virtual void mipmap(int size, int width, int height, int depth, int face, int miplevel) = 0; virtual ~OutputHandler() {}
/// Output data. Compressed data is output as soon as it's generated to minimize memory allocations. /// Indicate the start of a new compressed image that's part of the final texture.
virtual void writeData(const void * data, int size) = 0; virtual void mipmap(int size, int width, int height, int depth, int face, int miplevel) = 0;
};
/// Output data. Compressed data is output as soon as it's generated to minimize memory allocations.
/// Error codes. virtual void writeData(const void * data, int size) = 0;
enum Error };
{
Error_InvalidInput, /// Error codes.
Error_UserInterruption, enum Error
Error_UnsupportedFeature, {
Error_CudaError, Error_InvalidInput,
Error_Unknown, Error_UserInterruption,
}; Error_UnsupportedFeature,
Error_CudaError,
/// Error handler. Error_Unknown,
struct ErrorHandler };
{
virtual ~ErrorHandler() {} /// Error handler.
struct ErrorHandler
// Signal error. {
virtual void error(Error e) = 0; virtual ~ErrorHandler() {}
};
// Signal error.
virtual void error(Error e) = 0;
/// Output Options. This class holds pointers to the interfaces that are used to report the output of };
/// the compressor to the user.
struct OutputOptions
{ /// Output Options. This class holds pointers to the interfaces that are used to report the output of
OutputOptions() : outputHandler(NULL), outputHeader(true) { reset(); } /// the compressor to the user.
OutputOptions(OutputHandler * oh, ErrorHandler * eh) : outputHandler(oh), errorHandler(eh), outputHeader(true) { reset(); } struct OutputOptions
{
// Set default options. OutputOptions() : outputHandler(NULL), outputHeader(true) { reset(); }
NVTT_API void reset(); OutputOptions(OutputHandler * oh, ErrorHandler * eh) : outputHandler(oh), errorHandler(eh), outputHeader(true) { reset(); }
OutputHandler * outputHandler; // Set default options.
ErrorHandler * errorHandler; NVTT_API void reset();
bool outputHeader;
}; OutputHandler * outputHandler;
ErrorHandler * errorHandler;
bool outputHeader;
// Main entrypoint of the compression library. };
NVTT_API bool compress(const InputOptions & inputOptions, const OutputOptions & outputOptions, const CompressionOptions & compressionOptions);
// Estimate the size of compressing the input with the given options. // Main entrypoint of the compression library.
NVTT_API int estimateSize(const InputOptions & inputOptions, const CompressionOptions & compressionOptions); NVTT_API bool compress(const InputOptions & inputOptions, const OutputOptions & outputOptions, const CompressionOptions & compressionOptions);
// Return string for the given error. // Estimate the size of compressing the input with the given options.
NVTT_API const char * errorString(Error e); NVTT_API int estimateSize(const InputOptions & inputOptions, const CompressionOptions & compressionOptions);
} // nvtt namespace // Return string for the given error.
NVTT_API const char * errorString(Error e);
#endif // NV_TT_H
} // nvtt namespace
#endif // NV_TT_H

View File

@ -0,0 +1,65 @@
// Copyright NVIDIA Corporation 2007 -- Ignacio Castano <icastano@nvidia.com>
//
// Permission is hereby granted, free of charge, to any person
// obtaining a copy of this software and associated documentation
// files (the "Software"), to deal in the Software without
// restriction, including without limitation the rights to use,
// copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the
// Software is furnished to do so, subject to the following
// conditions:
//
// The above copyright notice and this permission notice shall be
// included in all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
// OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
// WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
// OTHER DEALINGS IN THE SOFTWARE.
#ifndef CMDLINE_H
#define CMDLINE_H
#include <nvcore/Debug.h>
#include <stdarg.h>
struct MyMessageHandler : public nv::MessageHandler {
MyMessageHandler() {
nv::debug::setMessageHandler( this );
}
~MyMessageHandler() {
nv::debug::resetMessageHandler();
}
virtual void log( const char * str, va_list arg ) {
va_list val;
va_copy(val, arg);
vfprintf(stderr, str, arg);
va_end(val);
}
};
struct MyAssertHandler : public nv::AssertHandler {
MyAssertHandler() {
nv::debug::setAssertHandler( this );
}
~MyAssertHandler() {
nv::debug::resetAssertHandler();
}
// Handler method, note that func might be NULL!
virtual int assert( const char *exp, const char *file, int line, const char *func ) {
fprintf(stderr, "Assertion failed: %s\nIn %s:%d\n", exp, file, line);
nv::debug::dumpInfo();
exit(1);
}
};
#endif // CMDLINE_H

View File

@ -1,354 +1,427 @@
// Copyright NVIDIA Corporation 2007 -- Ignacio Castano <icastano@nvidia.com> // Copyright NVIDIA Corporation 2007 -- Ignacio Castano <icastano@nvidia.com>
// //
// Permission is hereby granted, free of charge, to any person // Permission is hereby granted, free of charge, to any person
// obtaining a copy of this software and associated documentation // obtaining a copy of this software and associated documentation
// files (the "Software"), to deal in the Software without // files (the "Software"), to deal in the Software without
// restriction, including without limitation the rights to use, // restriction, including without limitation the rights to use,
// copy, modify, merge, publish, distribute, sublicense, and/or sell // copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the // copies of the Software, and to permit persons to whom the
// Software is furnished to do so, subject to the following // Software is furnished to do so, subject to the following
// conditions: // conditions:
// //
// The above copyright notice and this permission notice shall be // The above copyright notice and this permission notice shall be
// included in all copies or substantial portions of the Software. // included in all copies or substantial portions of the Software.
// //
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
// OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND // OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, // HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
// WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING // WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
// OTHER DEALINGS IN THE SOFTWARE. // OTHER DEALINGS IN THE SOFTWARE.
#include <nvcore/StrLib.h> #include <nvcore/StrLib.h>
#include <nvcore/StdStream.h> #include <nvcore/StdStream.h>
#include <nvimage/Image.h> #include <nvimage/Image.h>
#include <nvimage/nvtt/nvtt.h> #include <nvimage/DirectDrawSurface.h>
#include <nvimage/nvtt/nvtt.h>
#include "cmdline.h"
#include "cmdline.h"
#include <time.h> // clock
#include <time.h> // clock
struct MyOutputHandler : public nvtt::OutputHandler
{ //#define WINDOWS_LEAN_AND_MEAN
MyOutputHandler() : total(0), progress(0), percentage(0), stream(NULL) {} //#include <windows.h> // TIMER
MyOutputHandler(const char * name) : total(0), progress(0), percentage(0), stream(new nv::StdOutputStream(name)) {}
virtual ~MyOutputHandler() { delete stream; } struct MyOutputHandler : public nvtt::OutputHandler
{
bool open(const char * name) MyOutputHandler() : total(0), progress(0), percentage(0), stream(NULL) {}
{ MyOutputHandler(const char * name) : total(0), progress(0), percentage(0), stream(new nv::StdOutputStream(name)) {}
stream = new nv::StdOutputStream(name); virtual ~MyOutputHandler() { delete stream; }
percentage = progress = 0;
if (stream->isError()) { bool open(const char * name)
printf("Error opening '%s' for writting\n", name); {
return false; stream = new nv::StdOutputStream(name);
} percentage = progress = 0;
return true; if (stream->isError()) {
} printf("Error opening '%s' for writting\n", name);
return false;
virtual void setTotal(int t) }
{ return true;
total = t; }
}
virtual void setTotal(int t)
virtual void mipmap(int size, int width, int height, int depth, int face, int miplevel) {
{ total = t;
// ignore. }
}
virtual void mipmap(int size, int width, int height, int depth, int face, int miplevel)
// Output data. {
virtual void writeData(const void * data, int size) // ignore.
{ }
nvDebugCheck(stream != NULL);
stream->serialize(const_cast<void *>(data), size); // Output data.
virtual void writeData(const void * data, int size)
progress += size; {
int p = (100 * progress) / total; nvDebugCheck(stream != NULL);
if (p != percentage) stream->serialize(const_cast<void *>(data), size);
{
percentage = p; progress += size;
printf("\r%d%%", percentage); int p = (100 * progress) / total;
fflush(stdout); if (p != percentage)
} {
} percentage = p;
printf("\r%d%%", percentage);
int total; fflush(stdout);
int progress; }
int percentage; }
nv::StdOutputStream * stream;
}; int total;
int progress;
struct MyErrorHandler : public nvtt::ErrorHandler int percentage;
{ nv::StdOutputStream * stream;
virtual void error(nvtt::Error e) };
{
nvDebugBreak(); struct MyErrorHandler : public nvtt::ErrorHandler
} {
}; virtual void error(nvtt::Error e)
{
nvDebugBreak();
}
};
// Set color to normal map conversion options.
void setColorToNormalMap(nvtt::InputOptions & inputOptions)
{
inputOptions.setConvertToNormalMap(true);
inputOptions.setHeightEvaluation(1.0f/3.0f, 1.0f/3.0f, 1.0f/3.0f, 0.0f); // Set color to normal map conversion options.
//inputOptions.setNormalFilter(1.0f, 0, 0, 0); void setColorToNormalMap(nvtt::InputOptions & inputOptions)
//inputOptions.setNormalFilter(0.0f, 0, 0, 1); {
inputOptions.setGamma(1.0f, 1.0f); inputOptions.setConvertToNormalMap(true);
inputOptions.setNormalizeMipmaps(true); inputOptions.setHeightEvaluation(1.0f/3.0f, 1.0f/3.0f, 1.0f/3.0f, 0.0f);
} //inputOptions.setNormalFilter(1.0f, 0, 0, 0);
//inputOptions.setNormalFilter(0.0f, 0, 0, 1);
// Set options for normal maps. inputOptions.setGamma(1.0f, 1.0f);
void setNormalMap(nvtt::InputOptions & inputOptions) inputOptions.setNormalizeMipmaps(true);
{ }
inputOptions.setConvertToNormalMap(false);
inputOptions.setGamma(1.0f, 1.0f); // Set options for normal maps.
inputOptions.setNormalizeMipmaps(true); void setNormalMap(nvtt::InputOptions & inputOptions)
} {
inputOptions.setConvertToNormalMap(false);
// Set options for color maps. inputOptions.setGamma(1.0f, 1.0f);
void setColorMap(nvtt::InputOptions & inputOptions) inputOptions.setNormalizeMipmaps(true);
{ }
inputOptions.setConvertToNormalMap(false);
inputOptions.setGamma(2.2f, 2.2f); // Set options for color maps.
inputOptions.setNormalizeMipmaps(false); void setColorMap(nvtt::InputOptions & inputOptions)
} {
inputOptions.setConvertToNormalMap(false);
inputOptions.setGamma(2.2f, 2.2f);
inputOptions.setNormalizeMipmaps(false);
int main(int argc, char *argv[]) }
{
MyAssertHandler assertHandler;
MyMessageHandler messageHandler;
int main(int argc, char *argv[])
bool normal = false; {
bool color2normal = false; MyAssertHandler assertHandler;
bool wrapRepeat = false; MyMessageHandler messageHandler;
bool noMipmaps = false;
bool fast = false; bool normal = false;
bool nocuda = false; bool color2normal = false;
nvtt::Format format = nvtt::Format_BC1; bool wrapRepeat = false;
bool noMipmaps = false;
const char * externalCompressor = NULL; bool fast = false;
bool nocuda = false;
nv::Path input; nvtt::Format format = nvtt::Format_BC1;
nv::Path output;
const char * externalCompressor = NULL;
// Parse arguments. nv::Path input;
for (int i = 1; i < argc; i++) nv::Path output;
{
// Input options.
if (strcmp("-color", argv[i]) == 0) // Parse arguments.
{ for (int i = 1; i < argc; i++)
} {
else if (strcmp("-normal", argv[i]) == 0) // Input options.
{ if (strcmp("-color", argv[i]) == 0)
normal = true; {
} }
else if (strcmp("-tonormal", argv[i]) == 0) else if (strcmp("-normal", argv[i]) == 0)
{ {
color2normal = true; normal = true;
} }
else if (strcmp("-clamp", argv[i]) == 0) else if (strcmp("-tonormal", argv[i]) == 0)
{ {
} color2normal = true;
else if (strcmp("-repeat", argv[i]) == 0) }
{ else if (strcmp("-clamp", argv[i]) == 0)
wrapRepeat = true; {
} }
else if (strcmp("-nomips", argv[i]) == 0) else if (strcmp("-repeat", argv[i]) == 0)
{ {
noMipmaps = true; wrapRepeat = true;
} }
else if (strcmp("-nomips", argv[i]) == 0)
// Compression options. {
else if (strcmp("-fast", argv[i]) == 0) noMipmaps = true;
{ }
fast = true;
} // Compression options.
else if (strcmp("-nocuda", argv[i]) == 0) else if (strcmp("-fast", argv[i]) == 0)
{ {
nocuda = true; fast = true;
} }
else if (strcmp("-rgb", argv[i]) == 0) else if (strcmp("-nocuda", argv[i]) == 0)
{ {
format = nvtt::Format_RGB; nocuda = true;
} }
else if (strcmp("-bc1", argv[i]) == 0) else if (strcmp("-rgb", argv[i]) == 0)
{ {
format = nvtt::Format_BC1; format = nvtt::Format_RGB;
} }
else if (strcmp("-bc2", argv[i]) == 0) else if (strcmp("-bc1", argv[i]) == 0)
{ {
format = nvtt::Format_BC2; format = nvtt::Format_BC1;
} }
else if (strcmp("-bc3", argv[i]) == 0) else if (strcmp("-bc2", argv[i]) == 0)
{ {
format = nvtt::Format_BC3; format = nvtt::Format_BC2;
} }
else if (strcmp("-bc3n", argv[i]) == 0) else if (strcmp("-bc3", argv[i]) == 0)
{ {
format = nvtt::Format_BC3n; format = nvtt::Format_BC3;
} }
else if (strcmp("-bc4", argv[i]) == 0) else if (strcmp("-bc3n", argv[i]) == 0)
{ {
format = nvtt::Format_BC4; format = nvtt::Format_BC3n;
} }
else if (strcmp("-bc5", argv[i]) == 0) else if (strcmp("-bc4", argv[i]) == 0)
{ {
format = nvtt::Format_BC5; format = nvtt::Format_BC4;
} }
else if (strcmp("-bc5", argv[i]) == 0)
// Undocumented option. Mainly used for testing. {
else if (strcmp("-ext", argv[i]) == 0) format = nvtt::Format_BC5;
{ }
if (i+1 < argc && argv[i+1][0] != '-') {
externalCompressor = argv[i+1]; // Undocumented option. Mainly used for testing.
printf("using %s\n", argv[i+1]); else if (strcmp("-ext", argv[i]) == 0)
i++; {
} if (i+1 < argc && argv[i+1][0] != '-') {
} externalCompressor = argv[i+1];
i++;
else if (argv[i][0] != '-') }
{ }
input = argv[i];
else if (argv[i][0] != '-')
if (i+1 < argc && argv[i+1][0] != '-') { {
output = argv[i+1]; input = argv[i];
}
else if (i+1 < argc && argv[i+1][0] != '-') {
{ output = argv[i+1];
output.copy(input.str()); }
output.stripExtension(); else
output.append(".dds"); {
} output.copy(input.str());
output.stripExtension();
break; output.append(".dds");
} }
}
break;
if (input.empty()) }
{ }
printf("NVIDIA Texture Tools - Copyright NVIDIA Corporation 2007\n\n");
if (input.empty())
printf("usage: nvcompress [options] infile [outfile]\n\n"); {
printf("NVIDIA Texture Tools - Copyright NVIDIA Corporation 2007\n\n");
printf("Input options:\n");
printf(" -color \tThe input image is a color map (default).\n"); printf("usage: nvcompress [options] infile [outfile]\n\n");
printf(" -normal \tThe input image is a normal map.\n");
printf(" -tonormal\tConvert input to normal map.\n"); printf("Input options:\n");
printf(" -clamp \tClamp wrapping mode (default).\n"); printf(" -color \tThe input image is a color map (default).\n");
printf(" -repeat \tRepeat wrapping mode.\n"); printf(" -normal \tThe input image is a normal map.\n");
printf(" -nomips \tDisable mipmap generation.\n\n"); printf(" -tonormal\tConvert input to normal map.\n");
printf(" -clamp \tClamp wrapping mode (default).\n");
printf("Compression options:\n"); printf(" -repeat \tRepeat wrapping mode.\n");
printf(" -fast \tFast compression.\n"); printf(" -nomips \tDisable mipmap generation.\n\n");
printf(" -nocuda \tDo not use cuda compressor.\n");
printf(" -rgb \tRGBA format\n"); printf("Compression options:\n");
printf(" -bc1 \tBC1 format (DXT1)\n"); printf(" -fast \tFast compression.\n");
printf(" -bc2 \tBC2 format (DXT3)\n"); printf(" -nocuda \tDo not use cuda compressor.\n");
printf(" -bc3 \tBC3 format (DXT5)\n"); printf(" -rgb \tRGBA format\n");
printf(" -bc3n \tBC3 normal map format (DXT5n/RXGB)\n"); printf(" -bc1 \tBC1 format (DXT1)\n");
printf(" -bc4 \tBC4 format (ATI1)\n"); printf(" -bc2 \tBC2 format (DXT3)\n");
printf(" -bc5 \tBC5 format (3Dc/ATI2)\n\n"); printf(" -bc3 \tBC3 format (DXT5)\n");
printf(" -bc3n \tBC3 normal map format (DXT5nm)\n");
return 1; printf(" -bc4 \tBC4 format (ATI1)\n");
} printf(" -bc5 \tBC5 format (3Dc/ATI2)\n\n");
nv::Image image; return 1;
if (!image.load(input)) }
{
printf("The file '%s' is not a supported image type.\n", input.str()); // @@ Make sure input file exists.
return 1;
} // Set input options.
nvtt::InputOptions inputOptions;
MyErrorHandler errorHandler; if (nv::strCaseCmp(input.extension(), ".dds") == 0)
MyOutputHandler outputHandler(output); {
if (outputHandler.stream->isError()) // Load surface.
{ printf("The file '%s' is not a supported image type.\n", input.str());
printf("Error opening '%s' for writting\n", output.str());
return 1; nv::DirectDrawSurface dds(input);
} if (!dds.isValid())
{
// Set input options. printf("The file '%s' is not a valid DDS file.\n", input.str());
nvtt::InputOptions inputOptions; return 1;
inputOptions.setTextureLayout(nvtt::TextureType_2D, image.width(), image.height()); }
inputOptions.setMipmapData(image.pixels(), image.width(), image.height());
if (!dds.isSupported() || dds.isTexture3D())
if (fast) {
{ printf("The file '%s' is not a supported DDS file.\n", input.str());
inputOptions.setMipmapping(true, nvtt::MipmapFilter_Box); return 1;
} }
else
{ uint faceCount;
inputOptions.setMipmapping(true, nvtt::MipmapFilter_Kaiser); if (dds.isTexture2D())
} {
inputOptions.setTextureLayout(nvtt::TextureType_2D, dds.width(), dds.height());
if (wrapRepeat) faceCount = 1;
{ }
inputOptions.setWrapMode(nvtt::WrapMode_Repeat); else
} {
else nvDebugCheck(dds.isTextureCube());
{ inputOptions.setTextureLayout(nvtt::TextureType_Cube, dds.width(), dds.height());
inputOptions.setWrapMode(nvtt::WrapMode_Clamp); faceCount = 6;
} }
if (normal) uint mipmapCount = dds.mipmapCount();
{
setNormalMap(inputOptions); nv::Image mipmap;
}
else if (color2normal) for (uint f = 0; f < faceCount; f++)
{ {
setColorToNormalMap(inputOptions); for (uint m = 0; m <= mipmapCount; m++)
} {
else dds.mipmap(&mipmap, f, m);
{
setColorMap(inputOptions); inputOptions.setMipmapData(mipmap.pixels(), mipmap.width(), mipmap.height(), 1, f, m);
} }
}
if (noMipmaps) }
{ else
inputOptions.setMipmapping(false); {
} // Regular image.
nv::Image image;
if (!image.load(input))
nvtt::CompressionOptions compressionOptions; {
compressionOptions.setFormat(format); printf("The file '%s' is not a supported image type.\n", input.str());
if (fast) return 1;
{ }
compressionOptions.setQuality(nvtt::Quality_Fastest);
} inputOptions.setTextureLayout(nvtt::TextureType_2D, image.width(), image.height());
else inputOptions.setMipmapData(image.pixels(), image.width(), image.height());
{ }
compressionOptions.setQuality(nvtt::Quality_Normal);
//compressionOptions.setQuality(nvtt::Quality_Production, 0.5f); if (fast)
//compressionOptions.setQuality(nvtt::Quality_Highest); {
} inputOptions.setMipmapping(true, nvtt::MipmapFilter_Box);
compressionOptions.enableHardwareCompression(!nocuda); }
compressionOptions.setColorWeights(1, 1, 1); else
{
if (externalCompressor != NULL) inputOptions.setMipmapping(true, nvtt::MipmapFilter_Kaiser);
{ }
compressionOptions.setExternalCompressor(externalCompressor);
} if (wrapRepeat)
{
outputHandler.setTotal(nvtt::estimateSize(inputOptions, compressionOptions)); inputOptions.setWrapMode(nvtt::WrapMode_Repeat);
}
nvtt::OutputOptions outputOptions(&outputHandler, &errorHandler); else
{
clock_t start = clock(); inputOptions.setWrapMode(nvtt::WrapMode_Clamp);
}
nvtt::compress(inputOptions, outputOptions, compressionOptions);
if (normal)
clock_t end = clock(); {
printf("\rtime taken: %.3f seconds\n", float(end-start) / CLOCKS_PER_SEC); setNormalMap(inputOptions);
}
return 0; else if (color2normal)
} {
setColorToNormalMap(inputOptions);
}
else
{
setColorMap(inputOptions);
}
if (noMipmaps)
{
inputOptions.setMipmapping(false);
}
nvtt::CompressionOptions compressionOptions;
compressionOptions.setFormat(format);
if (fast)
{
compressionOptions.setQuality(nvtt::Quality_Fastest);
}
else
{
compressionOptions.setQuality(nvtt::Quality_Normal);
//compressionOptions.setQuality(nvtt::Quality_Production, 0.5f);
//compressionOptions.setQuality(nvtt::Quality_Highest);
}
compressionOptions.enableHardwareCompression(!nocuda);
compressionOptions.setColorWeights(1, 1, 1);
if (externalCompressor != NULL)
{
compressionOptions.setExternalCompressor(externalCompressor);
}
MyErrorHandler errorHandler;
MyOutputHandler outputHandler(output);
if (outputHandler.stream->isError())
{
printf("Error opening '%s' for writting\n", output.str());
return 1;
}
outputHandler.setTotal(nvtt::estimateSize(inputOptions, compressionOptions));
nvtt::OutputOptions outputOptions(&outputHandler, &errorHandler);
//nvtt::OutputOptions outputOptions(NULL, &errorHandler);
// printf("Press ENTER.\n");
// fflush(stdout);
// getchar();
/* LARGE_INTEGER temp;
QueryPerformanceFrequency((LARGE_INTEGER*) &temp);
double freq = ((double) temp.QuadPart) / 1000.0;
LARGE_INTEGER start_time;
QueryPerformanceCounter((LARGE_INTEGER*) &start_time);
*/
clock_t start = clock();
nvtt::compress(inputOptions, outputOptions, compressionOptions);
/*
LARGE_INTEGER end_time;
QueryPerformanceCounter((LARGE_INTEGER*) &end_time);
float diff_time = (float) (((double) end_time.QuadPart - (double) start_time.QuadPart) / freq);
printf("\rtime taken: %.3f seconds\n", diff_time/1000);
*/
clock_t end = clock();
printf("\rtime taken: %.3f seconds\n", float(end-start) / CLOCKS_PER_SEC);
return 0;
}

View File

@ -0,0 +1,31 @@
// Copyright NVIDIA Corporation 2007 -- Ignacio Castano <icastano@nvidia.com>
//
// Permission is hereby granted, free of charge, to any person
// obtaining a copy of this software and associated documentation
// files (the "Software"), to deal in the Software without
// restriction, including without limitation the rights to use,
// copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the
// Software is furnished to do so, subject to the following
// conditions:
//
// The above copyright notice and this permission notice shall be
// included in all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
// OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
// WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
// OTHER DEALINGS IN THE SOFTWARE.
#include "configdialog.h"
ConfigDialog::ConfigDialog(QWidget *parent/*=0*/) : QDialog(parent)
{
ui.setupUi(this);
}

View File

@ -0,0 +1,43 @@
// Copyright NVIDIA Corporation 2007 -- Ignacio Castano <icastano@nvidia.com>
//
// Permission is hereby granted, free of charge, to any person
// obtaining a copy of this software and associated documentation
// files (the "Software"), to deal in the Software without
// restriction, including without limitation the rights to use,
// copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the
// Software is furnished to do so, subject to the following
// conditions:
//
// The above copyright notice and this permission notice shall be
// included in all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
// OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
// WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
// OTHER DEALINGS IN THE SOFTWARE.
#ifndef CONFIGDIALOG_H
#define CONFIGDIALOG_H
#include <QtGui/QDialog>
#include "ui_nvdxtdialog.h"
class ConfigDialog : public QDialog
{
Q_OBJECT
public:
ConfigDialog(QWidget *parent = 0);
private:
Ui::ConfigDialog ui;
};
#endif // CONFIGDIALOG_H

View File

@ -0,0 +1,983 @@
<ui version="4.0" >
<class>ConfigDialog</class>
<widget class="QDialog" name="ConfigDialog" >
<property name="geometry" >
<rect>
<x>0</x>
<y>0</y>
<width>626</width>
<height>532</height>
</rect>
</property>
<property name="windowTitle" >
<string>Dialog</string>
</property>
<property name="sizeGripEnabled" >
<bool>true</bool>
</property>
<layout class="QVBoxLayout" >
<property name="margin" >
<number>9</number>
</property>
<property name="spacing" >
<number>6</number>
</property>
<item>
<layout class="QHBoxLayout" >
<property name="margin" >
<number>0</number>
</property>
<property name="spacing" >
<number>6</number>
</property>
<item>
<widget class="QListWidget" name="listWidget" >
<property name="sizePolicy" >
<sizepolicy>
<hsizetype>7</hsizetype>
<vsizetype>7</vsizetype>
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="minimumSize" >
<size>
<width>64</width>
<height>0</height>
</size>
</property>
<property name="maximumSize" >
<size>
<width>128</width>
<height>16777215</height>
</size>
</property>
<property name="horizontalScrollBarPolicy" >
<enum>Qt::ScrollBarAlwaysOff</enum>
</property>
<property name="movement" >
<enum>QListView::Static</enum>
</property>
<property name="flow" >
<enum>QListView::TopToBottom</enum>
</property>
<property name="isWrapping" stdset="0" >
<bool>false</bool>
</property>
<property name="resizeMode" >
<enum>QListView::Adjust</enum>
</property>
<property name="viewMode" >
<enum>QListView::IconMode</enum>
</property>
<item>
<property name="text" >
<string>Input</string>
</property>
<property name="icon" >
<iconset>../../../../../../castano-stuff/qshaderedit/src/images/win/fileopen.png</iconset>
</property>
</item>
<item>
<property name="text" >
<string>Output</string>
</property>
<property name="icon" >
<iconset>../../../../../../castano-stuff/qshaderedit/src/images/win/filesave.png</iconset>
</property>
</item>
<item>
<property name="text" >
<string>Settings</string>
</property>
<property name="icon" >
<iconset>../../../../../../castano-stuff/qshaderedit/src/images/toolbutton.png</iconset>
</property>
</item>
<item>
<property name="text" >
<string>Preview</string>
</property>
<property name="icon" >
<iconset>../../../../../../castano-stuff/qshaderedit/src/images/colorpicker.png</iconset>
</property>
</item>
<item>
<property name="text" >
<string>3D Preview</string>
</property>
<property name="icon" >
<iconset>../../../../../../castano-stuff/qshaderedit/src/images/colorpicker.png</iconset>
</property>
</item>
</widget>
</item>
<item>
<widget class="QTabWidget" name="tabWidget" >
<property name="sizePolicy" >
<sizepolicy>
<hsizetype>7</hsizetype>
<vsizetype>7</vsizetype>
<horstretch>5</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="minimumSize" >
<size>
<width>400</width>
<height>0</height>
</size>
</property>
<property name="tabPosition" >
<enum>QTabWidget::North</enum>
</property>
<property name="tabShape" >
<enum>QTabWidget::Rounded</enum>
</property>
<property name="currentIndex" >
<number>0</number>
</property>
<widget class="QWidget" name="tab_5" >
<attribute name="title" >
<string>Input</string>
</attribute>
<layout class="QVBoxLayout" >
<property name="margin" >
<number>9</number>
</property>
<property name="spacing" >
<number>6</number>
</property>
<item>
<layout class="QHBoxLayout" >
<property name="margin" >
<number>0</number>
</property>
<property name="spacing" >
<number>6</number>
</property>
<item>
<widget class="QLineEdit" name="lineEdit" />
</item>
<item>
<widget class="QPushButton" name="openButton" >
<property name="text" >
<string>Open</string>
</property>
</widget>
</item>
</layout>
</item>
<item>
<layout class="QHBoxLayout" >
<property name="margin" >
<number>0</number>
</property>
<property name="spacing" >
<number>6</number>
</property>
<item>
<layout class="QVBoxLayout" >
<property name="margin" >
<number>0</number>
</property>
<property name="spacing" >
<number>6</number>
</property>
<item>
<widget class="QLabel" name="label_4" >
<property name="sizePolicy" >
<sizepolicy>
<hsizetype>0</hsizetype>
<vsizetype>0</vsizetype>
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="minimumSize" >
<size>
<width>172</width>
<height>172</height>
</size>
</property>
<property name="baseSize" >
<size>
<width>172</width>
<height>172</height>
</size>
</property>
<property name="acceptDrops" >
<bool>true</bool>
</property>
<property name="toolTip" >
<string>Drop images here</string>
</property>
<property name="frameShape" >
<enum>QFrame::StyledPanel</enum>
</property>
<property name="text" >
<string/>
</property>
<property name="pixmap" >
<pixmap>../../../../../../castano-stuff/qshaderedit/src/images/default.png</pixmap>
</property>
<property name="scaledContents" >
<bool>true</bool>
</property>
<property name="margin" >
<number>1</number>
</property>
</widget>
</item>
<item>
<widget class="QTextEdit" name="textEdit" >
<property name="enabled" >
<bool>false</bool>
</property>
<property name="sizePolicy" >
<sizepolicy>
<hsizetype>0</hsizetype>
<vsizetype>7</vsizetype>
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="minimumSize" >
<size>
<width>172</width>
<height>0</height>
</size>
</property>
<property name="frameShape" >
<enum>QFrame::StyledPanel</enum>
</property>
</widget>
</item>
</layout>
</item>
<item>
<layout class="QVBoxLayout" >
<property name="margin" >
<number>0</number>
</property>
<property name="spacing" >
<number>4</number>
</property>
<item>
<widget class="QGroupBox" name="groupBox_4" >
<property name="sizePolicy" >
<sizepolicy>
<hsizetype>5</hsizetype>
<vsizetype>5</vsizetype>
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="title" >
<string>Type</string>
</property>
<layout class="QVBoxLayout" >
<property name="margin" >
<number>4</number>
</property>
<property name="spacing" >
<number>0</number>
</property>
<item>
<widget class="QRadioButton" name="radioButton" >
<property name="text" >
<string>RGB</string>
</property>
<property name="checked" >
<bool>true</bool>
</property>
</widget>
</item>
<item>
<widget class="QRadioButton" name="radioButton_2" >
<property name="text" >
<string>RGBA</string>
</property>
</widget>
</item>
<item>
<widget class="QRadioButton" name="radioButton_3" >
<property name="text" >
<string>Monochrome</string>
</property>
</widget>
</item>
<item>
<widget class="QRadioButton" name="radioButton_4" >
<property name="text" >
<string>Normal Map</string>
</property>
</widget>
</item>
</layout>
</widget>
</item>
<item>
<widget class="QCheckBox" name="checkBox_5" >
<property name="enabled" >
<bool>false</bool>
</property>
<property name="text" >
<string>Alpha is opacity</string>
</property>
</widget>
</item>
<item>
<widget class="QCheckBox" name="checkBox_2" >
<property name="enabled" >
<bool>false</bool>
</property>
<property name="text" >
<string>Convert to normal map</string>
</property>
</widget>
</item>
<item>
<widget class="QCheckBox" name="checkBox" >
<property name="text" >
<string>Generate mipmaps</string>
</property>
<property name="checked" >
<bool>true</bool>
</property>
</widget>
</item>
<item>
<layout class="QHBoxLayout" >
<property name="margin" >
<number>0</number>
</property>
<property name="spacing" >
<number>6</number>
</property>
<item>
<widget class="QLabel" name="label_8" >
<property name="text" >
<string>Mipmap filter</string>
</property>
<property name="buddy" >
<cstring>comboBox</cstring>
</property>
</widget>
</item>
<item>
<widget class="QComboBox" name="comboBox" >
<item>
<property name="text" >
<string>Box</string>
</property>
</item>
<item>
<property name="text" >
<string>Triangle</string>
</property>
</item>
<item>
<property name="text" >
<string>Mitchell</string>
</property>
</item>
<item>
<property name="text" >
<string>Kaiser</string>
</property>
</item>
</widget>
</item>
</layout>
</item>
<item>
<layout class="QHBoxLayout" >
<property name="margin" >
<number>0</number>
</property>
<property name="spacing" >
<number>6</number>
</property>
<item>
<widget class="QLabel" name="label_5" >
<property name="sizePolicy" >
<sizepolicy>
<hsizetype>1</hsizetype>
<vsizetype>5</vsizetype>
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="text" >
<string>Gamma</string>
</property>
<property name="buddy" >
<cstring>gammaSpinBox</cstring>
</property>
</widget>
</item>
<item>
<widget class="QDoubleSpinBox" name="gammaSpinBox" >
<property name="buttonSymbols" >
<enum>QAbstractSpinBox::UpDownArrows</enum>
</property>
<property name="maximum" >
<double>4.000000000000000</double>
</property>
<property name="minimum" >
<double>0.050000000000000</double>
</property>
<property name="singleStep" >
<double>0.050000000000000</double>
</property>
<property name="value" >
<double>2.200000000000000</double>
</property>
</widget>
</item>
</layout>
</item>
<item>
<spacer>
<property name="orientation" >
<enum>Qt::Vertical</enum>
</property>
<property name="sizeHint" >
<size>
<width>204</width>
<height>71</height>
</size>
</property>
</spacer>
</item>
</layout>
</item>
</layout>
</item>
</layout>
</widget>
<widget class="QWidget" name="tab_3" >
<attribute name="title" >
<string>Output</string>
</attribute>
<layout class="QVBoxLayout" >
<property name="margin" >
<number>9</number>
</property>
<property name="spacing" >
<number>6</number>
</property>
<item>
<layout class="QHBoxLayout" >
<property name="margin" >
<number>0</number>
</property>
<property name="spacing" >
<number>6</number>
</property>
<item>
<layout class="QVBoxLayout" >
<property name="margin" >
<number>0</number>
</property>
<property name="spacing" >
<number>6</number>
</property>
<item>
<widget class="QLabel" name="label_3" >
<property name="text" >
<string>Format:</string>
</property>
<property name="textFormat" >
<enum>Qt::PlainText</enum>
</property>
<property name="textInteractionFlags" >
<enum>Qt::NoTextInteraction</enum>
</property>
<property name="buddy" >
<cstring>formatComboBox</cstring>
</property>
</widget>
</item>
<item>
<widget class="QComboBox" name="formatComboBox" >
<item>
<property name="text" >
<string>BC1 (DXT1)</string>
</property>
</item>
<item>
<property name="text" >
<string>BC2 (DXT3)</string>
</property>
</item>
<item>
<property name="text" >
<string>BC3 (DXT5)</string>
</property>
</item>
</widget>
</item>
<item>
<widget class="QLabel" name="label_9" >
<property name="text" >
<string>Color Space:</string>
</property>
<property name="buddy" >
<cstring>comboBox_2</cstring>
</property>
</widget>
</item>
<item>
<widget class="QComboBox" name="comboBox_2" >
<item>
<property name="text" >
<string>RGB</string>
</property>
</item>
<item>
<property name="text" >
<string>YCoCg</string>
</property>
</item>
<item>
<property name="text" >
<string>JPEG LS (R-G, G, B-G)</string>
</property>
</item>
</widget>
</item>
</layout>
</item>
<item>
<spacer>
<property name="orientation" >
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeHint" >
<size>
<width>40</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
<item>
<widget class="QPushButton" name="pushButton_5" >
<property name="text" >
<string>Export</string>
</property>
</widget>
</item>
</layout>
</item>
<item>
<spacer>
<property name="orientation" >
<enum>Qt::Vertical</enum>
</property>
<property name="sizeHint" >
<size>
<width>20</width>
<height>40</height>
</size>
</property>
</spacer>
</item>
</layout>
</widget>
<widget class="QWidget" name="tab_4" >
<attribute name="title" >
<string>Settings</string>
</attribute>
<widget class="QWidget" name="verticalLayout_3" >
<property name="geometry" >
<rect>
<x>10</x>
<y>10</y>
<width>202</width>
<height>242</height>
</rect>
</property>
<layout class="QVBoxLayout" >
<property name="margin" >
<number>0</number>
</property>
<property name="spacing" >
<number>6</number>
</property>
<item>
<widget class="QGroupBox" name="groupBox_3" >
<property name="title" >
<string>Quality</string>
</property>
<layout class="QVBoxLayout" >
<property name="margin" >
<number>9</number>
</property>
<property name="spacing" >
<number>6</number>
</property>
<item>
<widget class="QSlider" name="horizontalSlider" >
<property name="maximum" >
<number>9</number>
</property>
<property name="value" >
<number>9</number>
</property>
<property name="orientation" >
<enum>Qt::Horizontal</enum>
</property>
</widget>
</item>
<item>
<widget class="QLabel" name="label_2" >
<property name="frameShape" >
<enum>QFrame::StyledPanel</enum>
</property>
<property name="frameShadow" >
<enum>QFrame::Plain</enum>
</property>
<property name="text" >
<string>9 - Best</string>
</property>
<property name="textFormat" >
<enum>Qt::PlainText</enum>
</property>
<property name="textInteractionFlags" >
<enum>Qt::NoTextInteraction</enum>
</property>
<property name="buddy" >
<cstring>horizontalSlider</cstring>
</property>
</widget>
</item>
<item>
<layout class="QHBoxLayout" >
<property name="margin" >
<number>0</number>
</property>
<property name="spacing" >
<number>6</number>
</property>
<item>
<widget class="QLabel" name="label" >
<property name="text" >
<string>Threshold</string>
</property>
</widget>
</item>
<item>
<widget class="QDoubleSpinBox" name="doubleSpinBox" />
</item>
</layout>
</item>
</layout>
</widget>
</item>
<item>
<widget class="QGroupBox" name="groupBox_6" >
<property name="title" >
<string>Color Weights</string>
</property>
<layout class="QVBoxLayout" >
<property name="margin" >
<number>9</number>
</property>
<property name="spacing" >
<number>0</number>
</property>
<item>
<layout class="QHBoxLayout" >
<property name="margin" >
<number>0</number>
</property>
<property name="spacing" >
<number>6</number>
</property>
<item>
<widget class="QLabel" name="label_10" >
<property name="text" >
<string>Red</string>
</property>
<property name="buddy" >
<cstring>doubleSpinBox_2</cstring>
</property>
</widget>
</item>
<item>
<widget class="QDoubleSpinBox" name="doubleSpinBox_2" />
</item>
</layout>
</item>
<item>
<layout class="QHBoxLayout" >
<property name="margin" >
<number>0</number>
</property>
<property name="spacing" >
<number>6</number>
</property>
<item>
<widget class="QLabel" name="label_11" >
<property name="text" >
<string>Green</string>
</property>
<property name="buddy" >
<cstring>doubleSpinBox_3</cstring>
</property>
</widget>
</item>
<item>
<widget class="QDoubleSpinBox" name="doubleSpinBox_3" />
</item>
</layout>
</item>
<item>
<layout class="QHBoxLayout" >
<property name="margin" >
<number>0</number>
</property>
<property name="spacing" >
<number>6</number>
</property>
<item>
<widget class="QLabel" name="label_12" >
<property name="text" >
<string>Blue</string>
</property>
<property name="buddy" >
<cstring>doubleSpinBox_4</cstring>
</property>
</widget>
</item>
<item>
<widget class="QDoubleSpinBox" name="doubleSpinBox_4" />
</item>
</layout>
</item>
</layout>
</widget>
</item>
</layout>
</widget>
</widget>
<widget class="QWidget" name="tab" >
<attribute name="title" >
<string>Preview</string>
</attribute>
<layout class="QVBoxLayout" >
<property name="margin" >
<number>9</number>
</property>
<property name="spacing" >
<number>6</number>
</property>
<item>
<layout class="QHBoxLayout" >
<property name="margin" >
<number>0</number>
</property>
<property name="spacing" >
<number>6</number>
</property>
<item>
<widget class="QGroupBox" name="groupBox" >
<property name="title" >
<string>Input</string>
</property>
<layout class="QHBoxLayout" >
<property name="margin" >
<number>3</number>
</property>
<property name="spacing" >
<number>6</number>
</property>
</layout>
</widget>
</item>
<item>
<widget class="QGroupBox" name="groupBox_2" >
<property name="title" >
<string>Output</string>
</property>
<layout class="QHBoxLayout" >
<property name="margin" >
<number>3</number>
</property>
<property name="spacing" >
<number>6</number>
</property>
</layout>
</widget>
</item>
</layout>
</item>
<item>
<layout class="QHBoxLayout" >
<property name="margin" >
<number>0</number>
</property>
<property name="spacing" >
<number>6</number>
</property>
<item>
<widget class="QCheckBox" name="filterCheckBox" >
<property name="text" >
<string>Bilinear Filter</string>
</property>
<property name="checked" >
<bool>true</bool>
</property>
</widget>
</item>
<item>
<widget class="QCheckBox" name="diffCheckBox" >
<property name="text" >
<string>View difference</string>
</property>
</widget>
</item>
</layout>
</item>
</layout>
</widget>
<widget class="QWidget" name="tab_2" >
<attribute name="title" >
<string>3D Preview</string>
</attribute>
<layout class="QVBoxLayout" >
<property name="margin" >
<number>9</number>
</property>
<property name="spacing" >
<number>6</number>
</property>
<item>
<layout class="QHBoxLayout" >
<property name="margin" >
<number>0</number>
</property>
<property name="spacing" >
<number>6</number>
</property>
<item>
<spacer>
<property name="orientation" >
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeHint" >
<size>
<width>40</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
<item>
<widget class="QComboBox" name="comboBox_3" >
<item>
<property name="text" >
<string>Quad</string>
</property>
</item>
<item>
<property name="text" >
<string>Sphere</string>
</property>
</item>
<item>
<property name="text" >
<string>Cylinder</string>
</property>
</item>
<item>
<property name="text" >
<string>Teapot</string>
</property>
</item>
</widget>
</item>
</layout>
</item>
<item>
<widget class="QFrame" name="frame" >
<property name="frameShape" >
<enum>QFrame::StyledPanel</enum>
</property>
<property name="frameShadow" >
<enum>QFrame::Raised</enum>
</property>
</widget>
</item>
</layout>
</widget>
</widget>
</item>
</layout>
</item>
<item>
<widget class="Line" name="line" >
<property name="orientation" >
<enum>Qt::Horizontal</enum>
</property>
</widget>
</item>
<item>
<layout class="QHBoxLayout" >
<property name="margin" >
<number>0</number>
</property>
<property name="spacing" >
<number>6</number>
</property>
<item>
<widget class="QPushButton" name="pushButton_6" >
<property name="text" >
<string>Default</string>
</property>
</widget>
</item>
<item>
<widget class="QProgressBar" name="progressBar" >
<property name="value" >
<number>24</number>
</property>
<property name="orientation" >
<enum>Qt::Horizontal</enum>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="pushButton" >
<property name="text" >
<string>Quit</string>
</property>
</widget>
</item>
</layout>
</item>
</layout>
</widget>
<resources/>
<connections>
<connection>
<sender>listWidget</sender>
<signal>currentRowChanged(int)</signal>
<receiver>tabWidget</receiver>
<slot>setCurrentPage(int)</slot>
<hints>
<hint type="sourcelabel" >
<x>114</x>
<y>67</y>
</hint>
<hint type="destinationlabel" >
<x>173</x>
<y>95</y>
</hint>
</hints>
</connection>
</connections>
</ui>

View File

@ -7,7 +7,10 @@ SET(MATH_SRCS
Box.h Box.h
Color.h Color.h
Eigen.h Eigen.cpp Eigen.h Eigen.cpp
Fitting.h Fitting.cpp) Fitting.h Fitting.cpp
Montecarlo.h Montecarlo.cpp
Random.h Random.cpp
SphericalHarmonic.h SphericalHarmonic.cpp)
INCLUDE_DIRECTORIES(${CMAKE_CURRENT_SOURCE_DIR}) INCLUDE_DIRECTORIES(${CMAKE_CURRENT_SOURCE_DIR})

View File

@ -33,11 +33,12 @@ public:
Vector4 row(uint i) const; Vector4 row(uint i) const;
Vector4 column(uint i) const; Vector4 column(uint i) const;
void scale(double s);
void scale(scalar s);
void scale(Vector3::Arg s); void scale(Vector3::Arg s);
void translate(Vector3::Arg t); void translate(Vector3::Arg t);
void rotate(scalar theta, scalar v0, scalar v1, scalar v2); void rotate(scalar theta, scalar v0, scalar v1, scalar v2);
Matrix inverse();
double determinant();
void apply(Matrix::Arg m); void apply(Matrix::Arg m);
@ -109,11 +110,12 @@ inline Vector4 Matrix::column(uint i) const
} }
/// Apply scale. /// Apply scale.
inline void Matrix::scale(scalar s) inline void Matrix::scale(double s)
{ {
m_data[0] *= s; m_data[1] *= s; m_data[2] *= s; m_data[3] *= s; m_data[0] *= s; m_data[1] *= s; m_data[2] *= s; m_data[3] *= s;
m_data[4] *= s; m_data[5] *= s; m_data[6] *= s; m_data[7] *= s; m_data[4] *= s; m_data[5] *= s; m_data[6] *= s; m_data[7] *= s;
m_data[8] *= s; m_data[9] *= s; m_data[10] *= s; m_data[11] *= s; m_data[8] *= s; m_data[9] *= s; m_data[10] *= s; m_data[11] *= s;
m_data[12] *= s; m_data[13] *= s; m_data[14] *= s; m_data[15] *= s;
} }
/// Apply scale. /// Apply scale.
@ -303,24 +305,42 @@ inline Matrix perspective(scalar fovy, scalar aspect, scalar zNear)
} }
/// Get matrix determinant. /// Get matrix determinant.
inline scalar determinant(Matrix::Arg m) inline double Matrix::determinant()
{ {
// @@ not sure this is correct. return m_data[3] * m_data[6] * m_data[9] * m_data[12]-m_data[2] * m_data[7] * m_data[9] * m_data[12]-m_data[3] * m_data[5] * m_data[10] * m_data[12]+m_data[1] * m_data[7] * m_data[10] * m_data[12]+
return m(0,0) * m(1,1) * m(2,2) * m(3,3) - m_data[2] * m_data[5] * m_data[11] * m_data[12]-m_data[1] * m_data[6] * m_data[11] * m_data[12]-m_data[3] * m_data[6] * m_data[8] * m_data[13]+m_data[2] * m_data[7] * m_data[8] * m_data[13]+
m(1,0) * m(2,1) * m(3,2) * m(0,3) + m_data[3] * m_data[4] * m_data[10] * m_data[13]-m_data[0] * m_data[7] * m_data[10] * m_data[13]-m_data[2] * m_data[4] * m_data[11] * m_data[13]+m_data[0] * m_data[6] * m_data[11] * m_data[13]+
m(2,0) * m(3,1) * m(0,2) * m(1,3) - m_data[3] * m_data[5] * m_data[8] * m_data[14]-m_data[1] * m_data[7] * m_data[8] * m_data[14]-m_data[3] * m_data[4] * m_data[9] * m_data[14]+m_data[0] * m_data[7] * m_data[9] * m_data[14]+
m(3,0) * m(0,1) * m(1,2) * m(2,3) - m_data[1] * m_data[4] * m_data[11] * m_data[14]-m_data[0] * m_data[5] * m_data[11] * m_data[14]-m_data[2] * m_data[5] * m_data[8] * m_data[15]+m_data[1] * m_data[6] * m_data[8] * m_data[15]+
m(3,0) * m(2,1) * m(1,2) * m(0,3) + m_data[2] * m_data[4] * m_data[9] * m_data[15]-m_data[0] * m_data[6] * m_data[9] * m_data[15]-m_data[1] * m_data[4] * m_data[10] * m_data[15]+m_data[0] * m_data[5] * m_data[10] * m_data[15];
m(2,0) * m(1,1) * m(0,2) * m(3,3) -
m(1,0) * m(0,1) * m(3,2) * m(2,3) +
m(0,0) * m(3,1) * m(2,2) * m(1,3);
} }
//inline Matrix transpose(Matrix::Arg m) //inline Matrix transpose(Matrix::Arg m)
//{ //{
//} //}
inline Matrix Matrix::inverse()
{
Matrix r;
r.m_data[ 0] = m_data[6]*m_data[11]*m_data[13] - m_data[7]*m_data[10]*m_data[13] + m_data[7]*m_data[9]*m_data[14] - m_data[5]*m_data[11]*m_data[14] - m_data[6]*m_data[9]*m_data[15] + m_data[5]*m_data[10]*m_data[15];
r.m_data[ 1] = m_data[3]*m_data[10]*m_data[13] - m_data[2]*m_data[11]*m_data[13] - m_data[3]*m_data[9]*m_data[14] + m_data[1]*m_data[11]*m_data[14] + m_data[2]*m_data[9]*m_data[15] - m_data[1]*m_data[10]*m_data[15];
r.m_data[ 2] = m_data[2]*m_data[7]*m_data[13] - m_data[3]*m_data[6]*m_data[13] + m_data[3]*m_data[5]*m_data[14] - m_data[1]*m_data[7]*m_data[14] - m_data[2]*m_data[5]*m_data[15] + m_data[1]*m_data[6]*m_data[15];
r.m_data[ 3] = m_data[3]*m_data[6]*m_data[9] - m_data[2]*m_data[7]*m_data[9] - m_data[3]*m_data[5]*m_data[10] + m_data[1]*m_data[7]*m_data[10] + m_data[2]*m_data[5]*m_data[11] - m_data[1]*m_data[6]*m_data[11];
r.m_data[ 4] = m_data[7]*m_data[10]*m_data[12] - m_data[6]*m_data[11]*m_data[12] - m_data[7]*m_data[8]*m_data[14] + m_data[4]*m_data[11]*m_data[14] + m_data[6]*m_data[8]*m_data[15] - m_data[4]*m_data[10]*m_data[15];
r.m_data[ 5] = m_data[2]*m_data[11]*m_data[12] - m_data[3]*m_data[10]*m_data[12] + m_data[3]*m_data[8]*m_data[14] - m_data[0]*m_data[11]*m_data[14] - m_data[2]*m_data[8]*m_data[15] + m_data[0]*m_data[10]*m_data[15];
r.m_data[ 6] = m_data[3]*m_data[6]*m_data[12] - m_data[2]*m_data[7]*m_data[12] - m_data[3]*m_data[4]*m_data[14] + m_data[0]*m_data[7]*m_data[14] + m_data[2]*m_data[4]*m_data[15] - m_data[0]*m_data[6]*m_data[15];
r.m_data[ 7] = m_data[2]*m_data[7]*m_data[8] - m_data[3]*m_data[6]*m_data[8] + m_data[3]*m_data[4]*m_data[10] - m_data[0]*m_data[7]*m_data[10] - m_data[2]*m_data[4]*m_data[11] + m_data[0]*m_data[6]*m_data[11];
r.m_data[ 8] = m_data[5]*m_data[11]*m_data[12] - m_data[7]*m_data[9]*m_data[12] + m_data[7]*m_data[8]*m_data[13] - m_data[4]*m_data[11]*m_data[13] - m_data[5]*m_data[8]*m_data[15] + m_data[4]*m_data[9]*m_data[15];
r.m_data[ 9] = m_data[3]*m_data[9]*m_data[12] - m_data[1]*m_data[11]*m_data[12] - m_data[3]*m_data[8]*m_data[13] + m_data[0]*m_data[11]*m_data[13] + m_data[1]*m_data[8]*m_data[15] - m_data[0]*m_data[9]*m_data[15];
r.m_data[10] = m_data[1]*m_data[7]*m_data[12] - m_data[3]*m_data[5]*m_data[12] + m_data[3]*m_data[4]*m_data[13] - m_data[0]*m_data[7]*m_data[13] - m_data[1]*m_data[4]*m_data[15] + m_data[0]*m_data[5]*m_data[15];
r.m_data[11] = m_data[3]*m_data[5]*m_data[8] - m_data[1]*m_data[7]*m_data[8] - m_data[3]*m_data[4]*m_data[9] + m_data[0]*m_data[7]*m_data[9] + m_data[1]*m_data[4]*m_data[11] - m_data[0]*m_data[5]*m_data[11];
r.m_data[12] = m_data[6]*m_data[9]*m_data[12] - m_data[5]*m_data[10]*m_data[12] - m_data[6]*m_data[8]*m_data[13] + m_data[4]*m_data[10]*m_data[13] + m_data[5]*m_data[8]*m_data[14] - m_data[4]*m_data[9]*m_data[14];
r.m_data[13] = m_data[1]*m_data[10]*m_data[12] - m_data[2]*m_data[9]*m_data[12] + m_data[2]*m_data[8]*m_data[13] - m_data[0]*m_data[10]*m_data[13] - m_data[1]*m_data[8]*m_data[14] + m_data[0]*m_data[9]*m_data[14];
r.m_data[14] = m_data[2]*m_data[5]*m_data[12] - m_data[1]*m_data[6]*m_data[12] - m_data[2]*m_data[4]*m_data[13] + m_data[0]*m_data[6]*m_data[13] + m_data[1]*m_data[4]*m_data[14] - m_data[0]*m_data[5]*m_data[14];
r.m_data[15] = m_data[1]*m_data[6]*m_data[8] - m_data[2]*m_data[5]*m_data[8] + m_data[2]*m_data[4]*m_data[9] - m_data[0]*m_data[6]*m_data[9] - m_data[1]*m_data[4]*m_data[10] + m_data[0]*m_data[5]*m_data[10];
r.scale(1./determinant());
return r;
}
//Matrix inverse(Matrix::Arg m);
//Matrix isometryInverse(Matrix::Arg m); //Matrix isometryInverse(Matrix::Arg m);
//Matrix affineInverse(Matrix::Arg m); //Matrix affineInverse(Matrix::Arg m);

156
src/nvmath/Montecarlo.cpp Normal file
View File

@ -0,0 +1,156 @@
// This code is in the public domain -- castanyo@yahoo.es
#include <nvmath/Montecarlo.h>
using namespace nv;
void SampleDistribution::redistribute(Method method/*=Method_NRook*/, Distribution dist/*=Distribution_Cosine*/)
{
switch(method)
{
case Method_Random:
redistributeRandom(dist);
break;
case Method_Stratified:
redistributeStratified(dist);
break;
case Method_NRook:
redistributeNRook(dist);
break;
};
}
void SampleDistribution::redistributeRandom(const Distribution dist)
{
const uint sampleCount = m_sampleArray.count();
// This is the worst method possible!
for(uint i = 0; i < sampleCount; i++)
{
float x = m_rand.getReal();
float y = m_rand.getReal();
// Map uniform distribution in the square to the (hemi)sphere.
if( dist == Distribution_Uniform ) {
m_sampleArray[i].setUV(acosf(1 - 2 * x), 2 * PI * y);
}
else {
nvDebugCheck(dist == Distribution_Cosine);
m_sampleArray[i].setUV(acosf(sqrtf(x)), 2 * PI * y);
}
}
}
void SampleDistribution::redistributeStratified(const Distribution dist)
{
const uint sampleCount = m_sampleArray.count();
const uint sqrtSampleCount = uint(sqrtf(float(sampleCount)));
nvDebugCheck(sqrtSampleCount*sqrtSampleCount == sampleCount); // Must use exact powers!
// Create a uniform distribution of points on the hemisphere with low variance.
for(uint v = 0, i = 0; v < sqrtSampleCount; v++) {
for(uint u = 0; u < sqrtSampleCount; u++, i++) {
float x = (u + m_rand.getReal()) / float(sqrtSampleCount);
float y = (v + m_rand.getReal()) / float(sqrtSampleCount);
// Map uniform distribution in the square to the (hemi)sphere.
if( dist == Distribution_Uniform ) {
m_sampleArray[i].setUV(acosf(1 - 2 * x), 2 * PI * y);
}
else {
nvDebugCheck(dist == Distribution_Cosine);
m_sampleArray[i].setUV(acosf(sqrtf(x)), 2 * PI * y);
}
}
}
}
/** Multi-Stage N-rooks Sampling Method.
* See: http://www.acm.org/jgt/papers/WangSung9/9
*/
void SampleDistribution::multiStageNRooks(const int size, int* cells)
{
if (size == 1) {
return;
}
int size1 = size >> 1;
int size2 = size >> 1;
if (size & 1) {
if (m_rand.getReal() > 0.5) {
size1++;
}
else {
size2++;
}
}
int* upper_cells = new int[size1];
int* lower_cells = new int[size2];
int i, j;
for(i = 0, j = 0; i < size - 1; i += 2, j++) {
if (m_rand.get() & 1) {
upper_cells[j] = cells[i];
lower_cells[j] = cells[i + 1];
}
else {
upper_cells[j] = cells[i + 1];
lower_cells[j] = cells[i];
}
}
if (size1 != size2) {
if (size1 > size2) {
upper_cells[j] = cells[i];
}
else {
lower_cells[j] = cells[i];
}
}
multiStageNRooks(size1, upper_cells);
memcpy(cells, upper_cells, size1 * sizeof(int));
delete [] upper_cells;
multiStageNRooks(size2, lower_cells);
memcpy(cells + size1, lower_cells, size2 * sizeof(int));
delete [] lower_cells;
}
void SampleDistribution::redistributeNRook(const Distribution dist)
{
const uint sampleCount = m_sampleArray.count();
// Generate nrook cells
int * cells = new int[sampleCount];
for(uint32 i = 0; i < sampleCount; i++)
{
cells[i] = i;
}
multiStageNRooks(sampleCount, cells);
for(uint i = 0; i < sampleCount; i++)
{
float x = (i + m_rand.getReal()) / sampleCount;
float y = (cells[i] + m_rand.getReal()) / sampleCount;
// Map uniform distribution in the square to the (hemi)sphere.
if( dist == Distribution_Uniform ) {
m_sampleArray[i].setUV(acosf(1 - 2 * x), 2 * PI * y);
}
else {
nvDebugCheck(dist == Distribution_Cosine);
m_sampleArray[i].setUV(acosf(sqrtf(x)), 2 * PI * y);
}
}
delete [] cells;
}

84
src/nvmath/Montecarlo.h Normal file
View File

@ -0,0 +1,84 @@
// This code is in the public domain -- castanyo@yahoo.es
#ifndef NV_MATH_MONTECARLO_H
#define NV_MATH_MONTECARLO_H
#include <nvmath/Vector.h>
#include <nvmath/Random.h>
namespace nv
{
/// A random sample distribution.
class SampleDistribution
{
public:
// Sampling method.
enum Method {
Method_Random,
Method_Stratified,
Method_NRook
};
// Distribution functions.
enum Distribution {
Distribution_Uniform,
Distribution_Cosine
};
/// Constructor.
SampleDistribution(int num)
{
m_sampleArray.resize(num);
}
void redistribute(Method method=Method_NRook, Distribution dist=Distribution_Cosine);
/// Get parametric coordinates of the sample.
Vector2 sample(int i) { return m_sampleArray[i].uv; }
/// Get sample direction.
Vector3 sampleDir(int i) { return m_sampleArray[i].dir; }
/// Get number of samples.
uint sampleCount() const { return m_sampleArray.count(); }
private:
void redistributeRandom(const Distribution dist);
void redistributeStratified(const Distribution dist);
void multiStageNRooks(const int size, int* cells);
void redistributeNRook(const Distribution dist);
/// A sample of the random distribution.
struct Sample
{
/// Set sample given the 3d coordinates.
void setDir(float x, float y, float z) {
dir.set(x, y, z);
uv.set(acosf(z), atan2f(y, x));
}
/// Set sample given the 2d parametric coordinates.
void setUV(float u, float v) {
uv.set(u, v);
dir.set(sinf(u) * cosf(v), sinf(u) * sinf(v), cosf(u));
}
Vector2 uv;
Vector3 dir;
};
/// Random seed.
MTRand m_rand;
/// Samples.
Array<Sample> m_sampleArray;
};
} // nv namespace
#endif // NV_MATH_MONTECARLO_H

54
src/nvmath/Random.cpp Normal file
View File

@ -0,0 +1,54 @@
// This code is in the public domain -- castanyo@yahoo.es
#include <nvmath/Random.h>
#include <time.h>
using namespace nv;
// Statics
const uint16 Rand48::a0 = 0xE66D;
const uint16 Rand48::a1 = 0xDEEC;
const uint16 Rand48::a2 = 0x0005;
const uint16 Rand48::c0 = 0x000B;
/// Get a random seed based on the current time.
uint Rand::randomSeed()
{
return time(NULL);
}
void MTRand::initialize( uint32 seed )
{
// Initialize generator state with seed
// See Knuth TAOCP Vol 2, 3rd Ed, p.106 for multiplier.
// In previous versions, most significant bits (MSBs) of the seed affect
// only MSBs of the state array. Modified 9 Jan 2002 by Makoto Matsumoto.
uint32 *s = state;
uint32 *r = state;
int i = 1;
*s++ = seed & 0xffffffffUL;
for( ; i < N; ++i )
{
*s++ = ( 1812433253UL * ( *r ^ (*r >> 30) ) + i ) & 0xffffffffUL;
r++;
}
}
void MTRand::reload()
{
// Generate N new values in state
// Made clearer and faster by Matthew Bellew (matthew.bellew@home.com)
uint32 *p = state;
int i;
for( i = N - M; i--; ++p )
*p = twist( p[M], p[0], p[1] );
for( i = M; --i; ++p )
*p = twist( p[M-N], p[0], p[1] );
*p = twist( p[M-N], p[0], state[0] );
left = N, next = state;
}

353
src/nvmath/Random.h Normal file
View File

@ -0,0 +1,353 @@
// This code is in the public domain -- castanyo@yahoo.es
#ifndef NV_MATH_RANDOM_H
#define NV_MATH_RANDOM_H
#include <nvcore/Containers.h> // nextPowerOfTwo
#include <nvmath/nvmath.h>
namespace nv
{
/// Interface of the random number generators.
class Rand
{
public:
virtual ~Rand() {}
enum time_e { Time };
/// Provide a new seed.
virtual void seed( uint s ) { /* empty */ };
/// Get an integer random number.
virtual uint get() = 0;
/// Get a random number on [0, max] interval.
uint getRange( uint max )
{
uint n;
// uint mask = Bitmask( max );
// do { n = Get() & mask; } while( n > max );
uint np2 = nextPowerOfTwo( max );
do { n = get() & (np2-1); } while( n > max );
return n;
}
/// Random number on [0.0, 1.0] interval.
double getReal()
{
return double(get()) * (1.0/4294967295.0); // 2^32-1
}
/// Random number on [0.0, 1.0) interval.
double getRealExclusive()
{
return double(get()) * (1.0/4294967296.0); // 2^32
}
/// Get the max value of the random number.
uint max() const { return 4294967295U; }
// Get a random seed.
static uint randomSeed();
};
/// Very simple random number generator with low storage requirements.
class SimpleRand : public Rand
{
public:
/// Constructor that uses the current time as the seed.
SimpleRand( time_e )
{
seed(randomSeed());
}
/// Constructor that uses the given seed.
SimpleRand( uint s = 0 )
{
seed(s);
}
/// Set the given seed.
virtual void seed( uint s )
{
current = s;
}
/// Get a random number.
virtual uint get()
{
return current = current * 1103515245 + 12345;
}
private:
uint current;
};
/// Mersenne twister random number generator.
class MTRand : public Rand
{
public:
enum { N = 624 }; // length of state vector
enum { M = 397 };
/// Constructor that uses the current time as the seed.
MTRand( time_e )
{
seed(randomSeed());
}
/// Constructor that uses the given seed.
MTRand( uint s = 0 )
{
seed(s);
}
/// Constructor that uses the given seeds.
NVMATH_API MTRand( const uint * seed_array, uint length );
/// Provide a new seed.
virtual void seed( uint s )
{
initialize(s);
reload();
}
/// Get a random number between 0 - 65536.
virtual uint get()
{
// Pull a 32-bit integer from the generator state
// Every other access function simply transforms the numbers extracted here
if( left == 0 ) {
reload();
}
left--;
uint s1;
s1 = *next++;
s1 ^= (s1 >> 11);
s1 ^= (s1 << 7) & 0x9d2c5680U;
s1 ^= (s1 << 15) & 0xefc60000U;
return ( s1 ^ (s1 >> 18) );
};
private:
NVMATH_API void initialize( uint32 seed );
NVMATH_API void reload();
uint hiBit( uint u ) const { return u & 0x80000000U; }
uint loBit( uint u ) const { return u & 0x00000001U; }
uint loBits( uint u ) const { return u & 0x7fffffffU; }
uint mixBits( uint u, uint v ) const { return hiBit(u) | loBits(v); }
uint twist( uint m, uint s0, uint s1 ) const { return m ^ (mixBits(s0,s1)>>1) ^ ((~loBit(s1)+1) & 0x9908b0dfU); }
private:
uint state[N]; // internal state
uint * next; // next value to get from state
int left; // number of values left before reload needed
};
/** George Marsaglia's random number generator.
* Code based on Thatcher Ulrich public domain source code:
* http://cvs.sourceforge.net/viewcvs.py/tu-testbed/tu-testbed/base/tu_random.cpp?rev=1.7&view=auto
*
* PRNG code adapted from the complimentary-multiply-with-carry
* code in the article: George Marsaglia, "Seeds for Random Number
* Generators", Communications of the ACM, May 2003, Vol 46 No 5,
* pp90-93.
*
* The article says:
*
* "Any one of the choices for seed table size and multiplier will
* provide a RNG that has passed extensive tests of randomness,
* particularly those in [3], yet is simple and fast --
* approximately 30 million random 32-bit integers per second on a
* 850MHz PC. The period is a*b^n, where a is the multiplier, n
* the size of the seed table and b=2^32-1. (a is chosen so that
* b is a primitive root of the prime a*b^n + 1.)"
*
* [3] Marsaglia, G., Zaman, A., and Tsang, W. Toward a universal
* random number generator. _Statistics and Probability Letters
* 8_ (1990), 35-39.
*/
class GMRand : public Rand
{
public:
enum { SEED_COUNT = 8 };
// const uint64 a = 123471786; // for SEED_COUNT=1024
// const uint64 a = 123554632; // for SEED_COUNT=512
// const uint64 a = 8001634; // for SEED_COUNT=255
// const uint64 a = 8007626; // for SEED_COUNT=128
// const uint64 a = 647535442; // for SEED_COUNT=64
// const uint64 a = 547416522; // for SEED_COUNT=32
// const uint64 a = 487198574; // for SEED_COUNT=16
// const uint64 a = 716514398U; // for SEED_COUNT=8
enum { a = 716514398U };
GMRand( time_e )
{
seed(randomSeed());
}
GMRand(uint s = 987654321)
{
seed(s);
}
/// Provide a new seed.
virtual void seed( uint s )
{
c = 362436;
i = SEED_COUNT - 1;
for(int i = 0; i < SEED_COUNT; i++) {
s = s ^ (s << 13);
s = s ^ (s >> 17);
s = s ^ (s << 5);
Q[i] = s;
}
}
/// Get a random number between 0 - 65536.
virtual uint get()
{
const uint32 r = 0xFFFFFFFE;
uint64 t;
uint32 x;
i = (i + 1) & (SEED_COUNT - 1);
t = a * Q[i] + c;
c = uint32(t >> 32);
x = uint32(t + c);
if( x < c ) {
x++;
c++;
}
uint32 val = r - x;
Q[i] = val;
return val;
};
private:
uint32 c;
uint32 i;
uint32 Q[8];
};
/** Random number implementation from the GNU Sci. Lib. (GSL).
* Adapted from Nicholas Chapman version:
*
* Copyright (C) 1996, 1997, 1998, 1999, 2000 James Theiler, Brian Gough
* This is the Unix rand48() generator. The generator returns the
* upper 32 bits from each term of the sequence,
*
* x_{n+1} = (a x_n + c) mod m
*
* using 48-bit unsigned arithmetic, with a = 0x5DEECE66D , c = 0xB
* and m = 2^48. The seed specifies the upper 32 bits of the initial
* value, x_1, with the lower 16 bits set to 0x330E.
*
* The theoretical value of x_{10001} is 244131582646046.
*
* The period of this generator is ? FIXME (probably around 2^48).
*/
class Rand48 : public Rand
{
public:
Rand48( time_e )
{
seed(randomSeed());
}
Rand48( uint s = 0x1234ABCD )
{
seed(s);
}
/** Set the given seed. */
virtual void seed( uint s ) {
vstate.x0 = 0x330E;
vstate.x1 = uint16(s & 0xFFFF);
vstate.x2 = uint16((s >> 16) & 0xFFFF);
}
/** Get a random number. */
virtual uint Get() {
advance();
uint x1 = vstate.x1;
uint x2 = vstate.x2;
return (x2 << 16) + x1;
}
private:
void advance()
{
/* work with unsigned long ints throughout to get correct integer
promotions of any unsigned short ints */
const uint32 x0 = vstate.x0;
const uint32 x1 = vstate.x1;
const uint32 x2 = vstate.x2;
uint32 a;
a = a0 * x0 + c0;
vstate.x0 = uint16(a & 0xFFFF);
a >>= 16;
/* although the next line may overflow we only need the top 16 bits
in the following stage, so it does not matter */
a += a0 * x1 + a1 * x0;
vstate.x1 = uint16(a & 0xFFFF);
a >>= 16;
a += a0 * x2 + a1 * x1 + a2 * x0;
vstate.x2 = uint16(a & 0xFFFF);
}
private:
NVMATH_API static const uint16 a0, a1, a2, c0;
struct rand48_state_t {
uint16 x0, x1, x2;
} vstate;
};
} // nv namespace
#endif // NV_MATH_RANDOM_H

View File

@ -0,0 +1,241 @@
// 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 )
{
if (v == 0) {
return 1;
}
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, 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 x) {
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 );
}

View File

@ -0,0 +1,421 @@
// This code is in the public domain -- castanyo@yahoo.es
#ifndef NV_MATH_SPHERICALHARMONIC_H
#define NV_MATH_SPHERICALHARMONIC_H
#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
{
float out = 0.0f;
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

View File

@ -74,6 +74,8 @@ public:
void operator+=(Vector3::Arg v); void operator+=(Vector3::Arg v);
void operator-=(Vector3::Arg v); void operator-=(Vector3::Arg v);
void operator*=(scalar s); void operator*=(scalar s);
inline void operator/=(scalar s)
{ m_x /= s; m_y /= s; m_z /= s; }
void operator*=(Vector3::Arg v); void operator*=(Vector3::Arg v);
friend bool operator==(Vector3::Arg a, Vector3::Arg b); friend bool operator==(Vector3::Arg a, Vector3::Arg b);