- 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:
parent
d729ea51f6
commit
babb7e8df7
@ -40,6 +40,11 @@ IF(MSVC)
|
||||
ENDIF(MSVC)
|
||||
|
||||
#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)
|
||||
|
||||
|
@ -1,13 +1,13 @@
|
||||
|
||||
Short term:
|
||||
- support for DXT1a format.
|
||||
- Improve quality of fast compressors.
|
||||
- More accellerated compressors.
|
||||
- Accellerate mipmap generation.
|
||||
- Improve quality of fast compressors.
|
||||
- Generic RGB pixel format conversion.
|
||||
- Do not assume that alpha is used for transparency.
|
||||
|
||||
Longer term:
|
||||
- support for DXT1a format.
|
||||
- support for correct cubemap filtering.
|
||||
- support for correct cubemap borders and atlas borders. (Crytek request)
|
||||
- support for 3d textures & 3d compression.
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -336,6 +336,14 @@ namespace nv
|
||||
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!
|
||||
void removeAt( uint index )
|
||||
@ -422,7 +430,7 @@ namespace nv
|
||||
if( m_size == 0 ) {
|
||||
//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.
|
||||
nvDebugCheck(m_buffer != NULL);
|
||||
}
|
||||
|
@ -13,28 +13,26 @@
|
||||
#define NV_ABORT_IGNORE 2
|
||||
#define NV_ABORT_EXIT 3
|
||||
|
||||
#if NV_CC_MSVC
|
||||
#define nvNoAssert __noop
|
||||
#else
|
||||
#define nvNoAssert(exp)
|
||||
#endif
|
||||
|
||||
#define nvNoAssert(exp) \
|
||||
do { \
|
||||
(void)sizeof(exp); \
|
||||
} while(0)
|
||||
|
||||
#if NV_NO_ASSERT
|
||||
|
||||
# define nvAssert(exp) nvNoAssert()
|
||||
# define nvCheck(exp) nvNoAssert()
|
||||
# define nvDebugAssert(exp) nvNoAssert()
|
||||
# define nvDebugCheck(exp) nvNoAssert()
|
||||
# define nvDebugBreak()
|
||||
# define nvAssert(exp) nvNoAssert(exp)
|
||||
# define nvCheck(exp) nvNoAssert(exp)
|
||||
# define nvDebugAssert(exp) nvNoAssert(exp)
|
||||
# define nvDebugCheck(exp) nvNoAssert(exp)
|
||||
# define nvDebugBreak() nvNoAssert(0)
|
||||
|
||||
#else // NV_NO_ASSERT
|
||||
|
||||
# if NV_CC_MSVC && NV_CPU_X86 && 0
|
||||
# define nvDebugBreak() __asm int 3
|
||||
# elif NV_CC_MSVC // this is only on recent versions...
|
||||
// Do I have to include <intrin.h> ?
|
||||
# if NV_CC_MSVC
|
||||
// @@ Does this work in msvc-6 and earlier?
|
||||
// @@ Do I have to include <intrin.h> ?
|
||||
# define nvDebugBreak() __debugbreak()
|
||||
// define nvDebugBreak() __asm int 3
|
||||
# elif NV_CC_GNUC && NV_CPU_PPC && NV_OS_DARWIN
|
||||
# define nvDebugBreak() __asm__ volatile ("trap");
|
||||
# elif NV_CC_GNUC && NV_CPU_X86 && NV_OS_DARWIN
|
||||
@ -43,7 +41,8 @@
|
||||
# define nvDebugBreak() __asm__ ( "int %0" : :"I"(3) )
|
||||
# else
|
||||
# include <signal.h>
|
||||
# define nvDebugBreak() raise(SIGTRAP); //*((int *)(0)) = 0
|
||||
# define nvDebugBreak() raise(SIGTRAP);
|
||||
// define nvDebugBreak() *((int *)(0)) = 0
|
||||
# endif
|
||||
|
||||
# define nvAssertMacro(exp) \
|
||||
@ -85,11 +84,11 @@
|
||||
|
||||
|
||||
#if PI_CC_MSVC
|
||||
// I'm not sure it's a good idea to use the default static assert.
|
||||
#define nvStaticCheck(x) _STATIC_ASSERT(x)
|
||||
// @@ I'm not sure it's a good idea to use the default static assert.
|
||||
# define nvStaticCheck(x) _STATIC_ASSERT(x)
|
||||
#else
|
||||
#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) typedef char NV_DO_STRING_JOIN2(__static_assert_,__LINE__)[(x)]
|
||||
// define nvStaticCheck(x) switch(0) { case 0: case x:; }
|
||||
#endif
|
||||
|
||||
NVCORE_API int nvAbort(const char *exp, const char *file, int line, const char * func = 0);
|
||||
|
@ -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
|
||||
#if NV_CC_GNUC
|
||||
@ -22,3 +28,4 @@ __forceinline void nvPrefetch(const void * mem)
|
||||
|
||||
#endif // NV_CC_MSVC
|
||||
|
||||
#endif // NV_CORE_PREFETCH_H
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -1,176 +1,175 @@
|
||||
// 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 NV_TT_BLOCKDXT_H
|
||||
#define NV_TT_BLOCKDXT_H
|
||||
|
||||
#include <nvmath/Color.h>
|
||||
#include "nvtt.h"
|
||||
|
||||
namespace nv
|
||||
{
|
||||
struct ColorBlock;
|
||||
|
||||
/// DXT1 block.
|
||||
struct BlockDXT1
|
||||
{
|
||||
Color16 col0;
|
||||
Color16 col1;
|
||||
union {
|
||||
uint8 row[4];
|
||||
uint indices;
|
||||
};
|
||||
|
||||
bool isFourColorMode() const;
|
||||
|
||||
uint evaluatePalette(Color32 color_array[4]) const;
|
||||
uint evaluatePaletteFast(Color32 color_array[4]) const;
|
||||
void evaluatePalette3(Color32 color_array[4]) const;
|
||||
void evaluatePalette4(Color32 color_array[4]) const;
|
||||
|
||||
void decodeBlock(ColorBlock * block) const;
|
||||
|
||||
void setIndices(int * idx);
|
||||
|
||||
void flip4();
|
||||
void flip2();
|
||||
};
|
||||
|
||||
/// Return true if the block uses four color mode, false otherwise.
|
||||
inline bool BlockDXT1::isFourColorMode() const
|
||||
{
|
||||
return col0.u >= col1.u; // @@ > or >= ?
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
/// DXT3 alpha block with explicit alpha.
|
||||
struct AlphaBlockDXT3
|
||||
{
|
||||
union {
|
||||
struct {
|
||||
uint alpha0 : 4;
|
||||
uint alpha1 : 4;
|
||||
uint alpha2 : 4;
|
||||
uint alpha3 : 4;
|
||||
uint alpha4 : 4;
|
||||
uint alpha5 : 4;
|
||||
uint alpha6 : 4;
|
||||
uint alpha7 : 4;
|
||||
uint alpha8 : 4;
|
||||
uint alpha9 : 4;
|
||||
uint alphaA : 4;
|
||||
uint alphaB : 4;
|
||||
uint alphaC : 4;
|
||||
uint alphaD : 4;
|
||||
uint alphaE : 4;
|
||||
uint alphaF : 4;
|
||||
};
|
||||
uint16 row[4];
|
||||
};
|
||||
|
||||
void flip4();
|
||||
void flip2();
|
||||
};
|
||||
|
||||
|
||||
/// DXT3 block.
|
||||
struct BlockDXT3
|
||||
{
|
||||
AlphaBlockDXT3 alpha;
|
||||
BlockDXT1 color;
|
||||
|
||||
void decodeBlock(ColorBlock * block) const;
|
||||
|
||||
void flip4();
|
||||
void flip2();
|
||||
};
|
||||
|
||||
|
||||
/// DXT5 alpha block.
|
||||
struct AlphaBlockDXT5
|
||||
{
|
||||
union {
|
||||
struct {
|
||||
uint64 alpha0 : 8; // 8
|
||||
uint64 alpha1 : 8; // 16
|
||||
uint64 bits0 : 3; // 3 - 19
|
||||
uint64 bits1 : 3; // 6 - 22
|
||||
uint64 bits2 : 3; // 9 - 25
|
||||
uint64 bits3 : 3; // 12 - 28
|
||||
uint64 bits4 : 3; // 15 - 31
|
||||
uint64 bits5 : 3; // 18 - 34
|
||||
uint64 bits6 : 3; // 21 - 37
|
||||
uint64 bits7 : 3; // 24 - 40
|
||||
uint64 bits8 : 3; // 27 - 43
|
||||
uint64 bits9 : 3; // 30 - 46
|
||||
uint64 bitsA : 3; // 33 - 49
|
||||
uint64 bitsB : 3; // 36 - 52
|
||||
uint64 bitsC : 3; // 39 - 55
|
||||
uint64 bitsD : 3; // 42 - 58
|
||||
uint64 bitsE : 3; // 45 - 61
|
||||
uint64 bitsF : 3; // 48 - 64
|
||||
};
|
||||
uint64 u;
|
||||
};
|
||||
|
||||
void evaluatePalette(uint8 alpha[8]) const;
|
||||
void evaluatePalette8(uint8 alpha[8]) const;
|
||||
void evaluatePalette6(uint8 alpha[8]) const;
|
||||
void indices(uint8 index_array[16]) const;
|
||||
|
||||
uint index(uint index) const;
|
||||
void setIndex(uint index, uint value);
|
||||
|
||||
void flip4();
|
||||
void flip2();
|
||||
};
|
||||
|
||||
/// DXT5 block.
|
||||
struct BlockDXT5
|
||||
{
|
||||
AlphaBlockDXT5 alpha;
|
||||
BlockDXT1 color;
|
||||
|
||||
void decodeBlock(ColorBlock * block) const;
|
||||
|
||||
void flip4();
|
||||
void flip2();
|
||||
};
|
||||
|
||||
/// 3DC block.
|
||||
struct Block3DC
|
||||
{
|
||||
AlphaBlockDXT5 y;
|
||||
AlphaBlockDXT5 x;
|
||||
|
||||
void decodeBlock(ColorBlock * block) const;
|
||||
|
||||
void flip4();
|
||||
void flip2();
|
||||
};
|
||||
|
||||
} // nv namespace
|
||||
|
||||
#endif // NV_TT_BLOCKDXT_H
|
||||
// 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 NV_IMAGE_BLOCKDXT_H
|
||||
#define NV_IMAGE_BLOCKDXT_H
|
||||
|
||||
#include <nvmath/Color.h>
|
||||
|
||||
namespace nv
|
||||
{
|
||||
struct ColorBlock;
|
||||
|
||||
/// DXT1 block.
|
||||
struct BlockDXT1
|
||||
{
|
||||
Color16 col0;
|
||||
Color16 col1;
|
||||
union {
|
||||
uint8 row[4];
|
||||
uint indices;
|
||||
};
|
||||
|
||||
bool isFourColorMode() const;
|
||||
|
||||
uint evaluatePalette(Color32 color_array[4]) const;
|
||||
uint evaluatePaletteFast(Color32 color_array[4]) const;
|
||||
void evaluatePalette3(Color32 color_array[4]) const;
|
||||
void evaluatePalette4(Color32 color_array[4]) const;
|
||||
|
||||
void decodeBlock(ColorBlock * block) const;
|
||||
|
||||
void setIndices(int * idx);
|
||||
|
||||
void flip4();
|
||||
void flip2();
|
||||
};
|
||||
|
||||
/// Return true if the block uses four color mode, false otherwise.
|
||||
inline bool BlockDXT1::isFourColorMode() const
|
||||
{
|
||||
return col0.u >= col1.u; // @@ > or >= ?
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
/// DXT3 alpha block with explicit alpha.
|
||||
struct AlphaBlockDXT3
|
||||
{
|
||||
union {
|
||||
struct {
|
||||
uint alpha0 : 4;
|
||||
uint alpha1 : 4;
|
||||
uint alpha2 : 4;
|
||||
uint alpha3 : 4;
|
||||
uint alpha4 : 4;
|
||||
uint alpha5 : 4;
|
||||
uint alpha6 : 4;
|
||||
uint alpha7 : 4;
|
||||
uint alpha8 : 4;
|
||||
uint alpha9 : 4;
|
||||
uint alphaA : 4;
|
||||
uint alphaB : 4;
|
||||
uint alphaC : 4;
|
||||
uint alphaD : 4;
|
||||
uint alphaE : 4;
|
||||
uint alphaF : 4;
|
||||
};
|
||||
uint16 row[4];
|
||||
};
|
||||
|
||||
void flip4();
|
||||
void flip2();
|
||||
};
|
||||
|
||||
|
||||
/// DXT3 block.
|
||||
struct BlockDXT3
|
||||
{
|
||||
AlphaBlockDXT3 alpha;
|
||||
BlockDXT1 color;
|
||||
|
||||
void decodeBlock(ColorBlock * block) const;
|
||||
|
||||
void flip4();
|
||||
void flip2();
|
||||
};
|
||||
|
||||
|
||||
/// DXT5 alpha block.
|
||||
struct AlphaBlockDXT5
|
||||
{
|
||||
union {
|
||||
struct {
|
||||
uint64 alpha0 : 8; // 8
|
||||
uint64 alpha1 : 8; // 16
|
||||
uint64 bits0 : 3; // 3 - 19
|
||||
uint64 bits1 : 3; // 6 - 22
|
||||
uint64 bits2 : 3; // 9 - 25
|
||||
uint64 bits3 : 3; // 12 - 28
|
||||
uint64 bits4 : 3; // 15 - 31
|
||||
uint64 bits5 : 3; // 18 - 34
|
||||
uint64 bits6 : 3; // 21 - 37
|
||||
uint64 bits7 : 3; // 24 - 40
|
||||
uint64 bits8 : 3; // 27 - 43
|
||||
uint64 bits9 : 3; // 30 - 46
|
||||
uint64 bitsA : 3; // 33 - 49
|
||||
uint64 bitsB : 3; // 36 - 52
|
||||
uint64 bitsC : 3; // 39 - 55
|
||||
uint64 bitsD : 3; // 42 - 58
|
||||
uint64 bitsE : 3; // 45 - 61
|
||||
uint64 bitsF : 3; // 48 - 64
|
||||
};
|
||||
uint64 u;
|
||||
};
|
||||
|
||||
void evaluatePalette(uint8 alpha[8]) const;
|
||||
void evaluatePalette8(uint8 alpha[8]) const;
|
||||
void evaluatePalette6(uint8 alpha[8]) const;
|
||||
void indices(uint8 index_array[16]) const;
|
||||
|
||||
uint index(uint index) const;
|
||||
void setIndex(uint index, uint value);
|
||||
|
||||
void flip4();
|
||||
void flip2();
|
||||
};
|
||||
|
||||
/// DXT5 block.
|
||||
struct BlockDXT5
|
||||
{
|
||||
AlphaBlockDXT5 alpha;
|
||||
BlockDXT1 color;
|
||||
|
||||
void decodeBlock(ColorBlock * block) const;
|
||||
|
||||
void flip4();
|
||||
void flip2();
|
||||
};
|
||||
|
||||
/// 3DC block.
|
||||
struct Block3DC
|
||||
{
|
||||
AlphaBlockDXT5 y;
|
||||
AlphaBlockDXT5 x;
|
||||
|
||||
void decodeBlock(ColorBlock * block) const;
|
||||
|
||||
void flip4();
|
||||
void flip2();
|
||||
};
|
||||
|
||||
} // nv namespace
|
||||
|
||||
#endif // NV_IMAGE_BLOCKDXT_H
|
@ -14,6 +14,8 @@ SET(IMAGE_SRCS
|
||||
ImageIO.cpp
|
||||
ColorBlock.h
|
||||
ColorBlock.cpp
|
||||
BlockDXT.h
|
||||
BlockDXT.cpp
|
||||
HoleFilling.h
|
||||
HoleFilling.cpp
|
||||
DirectDrawSurface.h
|
||||
@ -21,7 +23,9 @@ SET(IMAGE_SRCS
|
||||
Quantize.h
|
||||
Quantize.cpp
|
||||
NormalMap.h
|
||||
NormalMap.cpp)
|
||||
NormalMap.cpp
|
||||
NormalMipmap.h
|
||||
NormalMipmap.cpp)
|
||||
|
||||
INCLUDE_DIRECTORIES(${CMAKE_CURRENT_SOURCE_DIR})
|
||||
|
||||
|
@ -53,7 +53,7 @@ void ColorBlock::init(const Image * img, uint x, uint y)
|
||||
nvDebugCheck(bw != 0);
|
||||
nvDebugCheck(bh != 0);
|
||||
|
||||
int remainder[] = {
|
||||
static int remainder[] = {
|
||||
0, 0, 0, 0,
|
||||
0, 1, 0, 1,
|
||||
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.
|
||||
// @@ 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++) {
|
||||
//const int by = i % bh;
|
||||
@ -80,7 +80,7 @@ void ColorBlock::swizzleDXT5n()
|
||||
for(int i = 0; i < 16; 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);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1,258 +1,652 @@
|
||||
// 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 <nvcore/Debug.h>
|
||||
|
||||
#include <nvimage/DirectDrawSurface.h>
|
||||
|
||||
#include <string.h> // memset
|
||||
|
||||
|
||||
using namespace nv;
|
||||
|
||||
#if !defined(MAKEFOURCC)
|
||||
# define MAKEFOURCC(ch0, ch1, ch2, ch3) \
|
||||
(uint(uint8(ch0)) | (uint(uint8(ch1)) << 8) | \
|
||||
(uint(uint8(ch2)) << 16) | (uint(uint8(ch3)) << 24 ))
|
||||
#endif
|
||||
|
||||
namespace
|
||||
{
|
||||
static const uint FOURCC_DDS = MAKEFOURCC('D', 'D', 'S', ' ');
|
||||
static const uint FOURCC_DXT1 = MAKEFOURCC('D', 'X', 'T', '1');
|
||||
static const uint FOURCC_DXT2 = MAKEFOURCC('D', 'X', 'T', '2');
|
||||
static const uint FOURCC_DXT3 = MAKEFOURCC('D', 'X', 'T', '3');
|
||||
static const uint FOURCC_DXT4 = MAKEFOURCC('D', 'X', 'T', '4');
|
||||
static const uint FOURCC_DXT5 = MAKEFOURCC('D', 'X', 'T', '5');
|
||||
static const uint FOURCC_RXGB = MAKEFOURCC('R', 'X', 'G', 'B');
|
||||
static const uint FOURCC_ATI1 = MAKEFOURCC('A', 'T', 'I', '1');
|
||||
static const uint FOURCC_ATI2 = MAKEFOURCC('A', 'T', 'I', '2');
|
||||
|
||||
static const uint DDSD_CAPS = 0x00000001U;
|
||||
static const uint DDSD_PIXELFORMAT = 0x00001000U;
|
||||
static const uint DDSD_WIDTH = 0x00000004U;
|
||||
static const uint DDSD_HEIGHT = 0x00000002U;
|
||||
static const uint DDSD_PITCH = 0x00000008U;
|
||||
static const uint DDSD_MIPMAPCOUNT = 0x00020000U;
|
||||
static const uint DDSD_LINEARSIZE = 0x00080000U;
|
||||
static const uint DDSD_DEPTH = 0x00800000U;
|
||||
|
||||
static const uint DDSCAPS_COMPLEX = 0x00000008U;
|
||||
static const uint DDSCAPS_TEXTURE = 0x00001000U;
|
||||
static const uint DDSCAPS_MIPMAP = 0x00400000U;
|
||||
static const uint DDSCAPS2_VOLUME = 0x00200000U;
|
||||
static const uint DDSCAPS2_CUBEMAP = 0x00000200U;
|
||||
|
||||
static const uint DDSCAPS2_CUBEMAP_POSITIVEX = 0x00000400U;
|
||||
static const uint DDSCAPS2_CUBEMAP_NEGATIVEX = 0x00000800U;
|
||||
static const uint DDSCAPS2_CUBEMAP_POSITIVEY = 0x00001000U;
|
||||
static const uint DDSCAPS2_CUBEMAP_NEGATIVEY = 0x00002000U;
|
||||
static const uint DDSCAPS2_CUBEMAP_POSITIVEZ = 0x00004000U;
|
||||
static const uint DDSCAPS2_CUBEMAP_NEGATIVEZ = 0x00008000U;
|
||||
static const uint DDSCAPS2_CUBEMAP_ALL_FACES = 0x0000F000U;
|
||||
|
||||
static const uint DDPF_RGB = 0x00000040U;
|
||||
static const uint DDPF_FOURCC = 0x00000004U;
|
||||
static const uint DDPF_ALPHAPIXELS = 0x00000001U;
|
||||
}
|
||||
|
||||
DDSHeader::DDSHeader()
|
||||
{
|
||||
this->fourcc = FOURCC_DDS;
|
||||
this->size = 124;
|
||||
this->flags = (DDSD_CAPS|DDSD_PIXELFORMAT);
|
||||
this->height = 0;
|
||||
this->width = 0;
|
||||
this->pitch = 0;
|
||||
this->depth = 0;
|
||||
this->mipmapcount = 0;
|
||||
memset(this->reserved, 0, sizeof(this->reserved));
|
||||
|
||||
// Store version information on the reserved header attributes.
|
||||
this->reserved[9] = MAKEFOURCC('N', 'V', 'T', 'T');
|
||||
this->reserved[10] = (0 << 16) | (1 << 8) | (0); // major.minor.revision
|
||||
|
||||
this->pf.size = 32;
|
||||
this->pf.flags = 0;
|
||||
this->pf.fourcc = 0;
|
||||
this->pf.bitcount = 0;
|
||||
this->pf.rmask = 0;
|
||||
this->pf.gmask = 0;
|
||||
this->pf.bmask = 0;
|
||||
this->pf.amask = 0;
|
||||
this->caps.caps1 = DDSCAPS_TEXTURE;
|
||||
this->caps.caps2 = 0;
|
||||
this->caps.caps3 = 0;
|
||||
this->caps.caps4 = 0;
|
||||
this->notused = 0;
|
||||
}
|
||||
|
||||
void DDSHeader::setWidth(uint w)
|
||||
{
|
||||
this->flags |= DDSD_WIDTH;
|
||||
this->width = w;
|
||||
}
|
||||
|
||||
void DDSHeader::setHeight(uint h)
|
||||
{
|
||||
this->flags |= DDSD_HEIGHT;
|
||||
this->height = h;
|
||||
}
|
||||
|
||||
void DDSHeader::setDepth(uint d)
|
||||
{
|
||||
this->flags |= DDSD_DEPTH;
|
||||
this->height = d;
|
||||
}
|
||||
|
||||
void DDSHeader::setMipmapCount(uint count)
|
||||
{
|
||||
if (count == 0)
|
||||
{
|
||||
this->flags &= ~DDSD_MIPMAPCOUNT;
|
||||
this->mipmapcount = 0;
|
||||
|
||||
if (this->caps.caps2 == 0) {
|
||||
this->caps.caps1 = DDSCAPS_TEXTURE;
|
||||
}
|
||||
else {
|
||||
this->caps.caps1 = DDSCAPS_TEXTURE | DDSCAPS_COMPLEX;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
this->flags |= DDSD_MIPMAPCOUNT;
|
||||
this->mipmapcount = count;
|
||||
|
||||
this->caps.caps1 |= DDSCAPS_COMPLEX | DDSCAPS_MIPMAP;
|
||||
}
|
||||
}
|
||||
|
||||
void DDSHeader::setTexture2D()
|
||||
{
|
||||
// nothing to do here.
|
||||
}
|
||||
|
||||
void DDSHeader::setTexture3D()
|
||||
{
|
||||
this->caps.caps2 = DDSCAPS2_VOLUME;
|
||||
}
|
||||
|
||||
void DDSHeader::setTextureCube()
|
||||
{
|
||||
this->caps.caps1 |= DDSCAPS_COMPLEX;
|
||||
this->caps.caps2 = DDSCAPS2_CUBEMAP | DDSCAPS2_CUBEMAP_ALL_FACES;
|
||||
}
|
||||
|
||||
void DDSHeader::setLinearSize(uint size)
|
||||
{
|
||||
this->flags &= ~DDSD_PITCH;
|
||||
this->flags |= DDSD_LINEARSIZE;
|
||||
this->pitch = size;
|
||||
}
|
||||
|
||||
void DDSHeader::setPitch(uint pitch)
|
||||
{
|
||||
this->flags &= ~DDSD_LINEARSIZE;
|
||||
this->flags |= DDSD_PITCH;
|
||||
this->pitch = pitch;
|
||||
}
|
||||
|
||||
void DDSHeader::setFourCC(uint8 c0, uint8 c1, uint8 c2, uint8 c3)
|
||||
{
|
||||
// set fourcc pixel format.
|
||||
this->pf.flags = DDPF_FOURCC;
|
||||
this->pf.fourcc = MAKEFOURCC(c0, c1, c2, c3);
|
||||
this->pf.bitcount = 0;
|
||||
this->pf.rmask = 0;
|
||||
this->pf.gmask = 0;
|
||||
this->pf.bmask = 0;
|
||||
this->pf.amask = 0;
|
||||
}
|
||||
|
||||
void DDSHeader::setPixelFormat(uint bitcount, uint rmask, uint gmask, uint bmask, uint amask)
|
||||
{
|
||||
// Make sure the masks are correct.
|
||||
nvCheck((rmask & gmask) == 0);
|
||||
nvCheck((rmask & bmask) == 0);
|
||||
nvCheck((rmask & amask) == 0);
|
||||
nvCheck((gmask & bmask) == 0);
|
||||
nvCheck((gmask & amask) == 0);
|
||||
nvCheck((bmask & amask) == 0);
|
||||
|
||||
this->pf.flags = DDPF_RGB;
|
||||
|
||||
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::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);
|
||||
}
|
||||
|
||||
// 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 <nvcore/Debug.h>
|
||||
#include <nvcore/Containers.h> // max
|
||||
#include <nvcore/StdStream.h>
|
||||
|
||||
#include <nvimage/DirectDrawSurface.h>
|
||||
#include <nvimage/ColorBlock.h>
|
||||
#include <nvimage/Image.h>
|
||||
#include <nvimage/BlockDXT.h>
|
||||
|
||||
#include <string.h> // memset
|
||||
|
||||
|
||||
using namespace nv;
|
||||
|
||||
#if !defined(MAKEFOURCC)
|
||||
# define MAKEFOURCC(ch0, ch1, ch2, ch3) \
|
||||
(uint(uint8(ch0)) | (uint(uint8(ch1)) << 8) | \
|
||||
(uint(uint8(ch2)) << 16) | (uint(uint8(ch3)) << 24 ))
|
||||
#endif
|
||||
|
||||
namespace
|
||||
{
|
||||
static const uint FOURCC_DDS = MAKEFOURCC('D', 'D', 'S', ' ');
|
||||
static const uint FOURCC_DXT1 = MAKEFOURCC('D', 'X', 'T', '1');
|
||||
static const uint FOURCC_DXT2 = MAKEFOURCC('D', 'X', 'T', '2');
|
||||
static const uint FOURCC_DXT3 = MAKEFOURCC('D', 'X', 'T', '3');
|
||||
static const uint FOURCC_DXT4 = MAKEFOURCC('D', 'X', 'T', '4');
|
||||
static const uint FOURCC_DXT5 = MAKEFOURCC('D', 'X', 'T', '5');
|
||||
static const uint FOURCC_RXGB = MAKEFOURCC('R', 'X', 'G', 'B');
|
||||
static const uint FOURCC_ATI1 = MAKEFOURCC('A', 'T', 'I', '1');
|
||||
static const uint FOURCC_ATI2 = MAKEFOURCC('A', 'T', 'I', '2');
|
||||
static const uint FOURCC_BC3N = MAKEFOURCC('B', 'C', '3', 'N');
|
||||
|
||||
static const uint DDSD_CAPS = 0x00000001U;
|
||||
static const uint DDSD_PIXELFORMAT = 0x00001000U;
|
||||
static const uint DDSD_WIDTH = 0x00000004U;
|
||||
static const uint DDSD_HEIGHT = 0x00000002U;
|
||||
static const uint DDSD_PITCH = 0x00000008U;
|
||||
static const uint DDSD_MIPMAPCOUNT = 0x00020000U;
|
||||
static const uint DDSD_LINEARSIZE = 0x00080000U;
|
||||
static const uint DDSD_DEPTH = 0x00800000U;
|
||||
|
||||
static const uint DDSCAPS_COMPLEX = 0x00000008U;
|
||||
static const uint DDSCAPS_TEXTURE = 0x00001000U;
|
||||
static const uint DDSCAPS_MIPMAP = 0x00400000U;
|
||||
static const uint DDSCAPS2_VOLUME = 0x00200000U;
|
||||
static const uint DDSCAPS2_CUBEMAP = 0x00000200U;
|
||||
|
||||
static const uint DDSCAPS2_CUBEMAP_POSITIVEX = 0x00000400U;
|
||||
static const uint DDSCAPS2_CUBEMAP_NEGATIVEX = 0x00000800U;
|
||||
static const uint DDSCAPS2_CUBEMAP_POSITIVEY = 0x00001000U;
|
||||
static const uint DDSCAPS2_CUBEMAP_NEGATIVEY = 0x00002000U;
|
||||
static const uint DDSCAPS2_CUBEMAP_POSITIVEZ = 0x00004000U;
|
||||
static const uint DDSCAPS2_CUBEMAP_NEGATIVEZ = 0x00008000U;
|
||||
static const uint DDSCAPS2_CUBEMAP_ALL_FACES = 0x0000FC00U;
|
||||
|
||||
static const uint DDPF_RGB = 0x00000040U;
|
||||
static const uint DDPF_FOURCC = 0x00000004U;
|
||||
static const uint DDPF_ALPHAPIXELS = 0x00000001U;
|
||||
static const uint DDPF_NORMAL = 0x80000000U; // @@ Custom flag.
|
||||
|
||||
} // namespace
|
||||
|
||||
namespace nv
|
||||
{
|
||||
static Stream & operator<< (Stream & s, DDSPixelFormat & pf)
|
||||
{
|
||||
s << pf.size;
|
||||
s << pf.flags;
|
||||
s << pf.fourcc;
|
||||
s << pf.bitcount;
|
||||
s << pf.rmask;
|
||||
s << pf.gmask;
|
||||
s << pf.bmask;
|
||||
s << pf.amask;
|
||||
return s;
|
||||
}
|
||||
|
||||
static Stream & operator<< (Stream & s, DDSCaps & caps)
|
||||
{
|
||||
s << caps.caps1;
|
||||
s << caps.caps2;
|
||||
s << caps.caps3;
|
||||
s << caps.caps4;
|
||||
return s;
|
||||
}
|
||||
|
||||
static Stream & operator<< (Stream & s, DDSHeader & header)
|
||||
{
|
||||
nvStaticCheck(sizeof(DDSHeader) == 128);
|
||||
s << header.fourcc;
|
||||
s << header.size;
|
||||
s << header.flags;
|
||||
s << header.height;
|
||||
s << header.width;
|
||||
s << header.pitch;
|
||||
s << header.depth;
|
||||
s << header.mipmapcount;
|
||||
s.serialize(header.reserved, 11 * sizeof(uint));
|
||||
s << header.pf;
|
||||
s << header.caps;
|
||||
s << header.notused;
|
||||
return s;
|
||||
}
|
||||
}
|
||||
|
||||
DDSHeader::DDSHeader()
|
||||
{
|
||||
this->fourcc = FOURCC_DDS;
|
||||
this->size = 124;
|
||||
this->flags = (DDSD_CAPS|DDSD_PIXELFORMAT);
|
||||
this->height = 0;
|
||||
this->width = 0;
|
||||
this->pitch = 0;
|
||||
this->depth = 0;
|
||||
this->mipmapcount = 0;
|
||||
memset(this->reserved, 0, sizeof(this->reserved));
|
||||
|
||||
// Store version information on the reserved header attributes.
|
||||
this->reserved[9] = MAKEFOURCC('N', 'V', 'T', 'T');
|
||||
this->reserved[10] = (0 << 16) | (1 << 8) | (0); // major.minor.revision
|
||||
|
||||
this->pf.size = 32;
|
||||
this->pf.flags = 0;
|
||||
this->pf.fourcc = 0;
|
||||
this->pf.bitcount = 0;
|
||||
this->pf.rmask = 0;
|
||||
this->pf.gmask = 0;
|
||||
this->pf.bmask = 0;
|
||||
this->pf.amask = 0;
|
||||
this->caps.caps1 = DDSCAPS_TEXTURE;
|
||||
this->caps.caps2 = 0;
|
||||
this->caps.caps3 = 0;
|
||||
this->caps.caps4 = 0;
|
||||
this->notused = 0;
|
||||
}
|
||||
|
||||
void DDSHeader::setWidth(uint w)
|
||||
{
|
||||
this->flags |= DDSD_WIDTH;
|
||||
this->width = w;
|
||||
}
|
||||
|
||||
void DDSHeader::setHeight(uint h)
|
||||
{
|
||||
this->flags |= DDSD_HEIGHT;
|
||||
this->height = h;
|
||||
}
|
||||
|
||||
void DDSHeader::setDepth(uint d)
|
||||
{
|
||||
this->flags |= DDSD_DEPTH;
|
||||
this->height = d;
|
||||
}
|
||||
|
||||
void DDSHeader::setMipmapCount(uint count)
|
||||
{
|
||||
if (count == 0)
|
||||
{
|
||||
this->flags &= ~DDSD_MIPMAPCOUNT;
|
||||
this->mipmapcount = 0;
|
||||
|
||||
if (this->caps.caps2 == 0) {
|
||||
this->caps.caps1 = DDSCAPS_TEXTURE;
|
||||
}
|
||||
else {
|
||||
this->caps.caps1 = DDSCAPS_TEXTURE | DDSCAPS_COMPLEX;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
this->flags |= DDSD_MIPMAPCOUNT;
|
||||
this->mipmapcount = count;
|
||||
|
||||
this->caps.caps1 |= DDSCAPS_COMPLEX | DDSCAPS_MIPMAP;
|
||||
}
|
||||
}
|
||||
|
||||
void DDSHeader::setTexture2D()
|
||||
{
|
||||
// nothing to do here.
|
||||
}
|
||||
|
||||
void DDSHeader::setTexture3D()
|
||||
{
|
||||
this->caps.caps2 = DDSCAPS2_VOLUME;
|
||||
}
|
||||
|
||||
void DDSHeader::setTextureCube()
|
||||
{
|
||||
this->caps.caps1 |= DDSCAPS_COMPLEX;
|
||||
this->caps.caps2 = DDSCAPS2_CUBEMAP | DDSCAPS2_CUBEMAP_ALL_FACES;
|
||||
}
|
||||
|
||||
void DDSHeader::setLinearSize(uint size)
|
||||
{
|
||||
this->flags &= ~DDSD_PITCH;
|
||||
this->flags |= DDSD_LINEARSIZE;
|
||||
this->pitch = size;
|
||||
}
|
||||
|
||||
void DDSHeader::setPitch(uint pitch)
|
||||
{
|
||||
this->flags &= ~DDSD_LINEARSIZE;
|
||||
this->flags |= DDSD_PITCH;
|
||||
this->pitch = pitch;
|
||||
}
|
||||
|
||||
void DDSHeader::setFourCC(uint8 c0, uint8 c1, uint8 c2, uint8 c3)
|
||||
{
|
||||
// set fourcc pixel format.
|
||||
this->pf.flags = DDPF_FOURCC;
|
||||
this->pf.fourcc = MAKEFOURCC(c0, c1, c2, c3);
|
||||
this->pf.bitcount = 0;
|
||||
this->pf.rmask = 0;
|
||||
this->pf.gmask = 0;
|
||||
this->pf.bmask = 0;
|
||||
this->pf.amask = 0;
|
||||
}
|
||||
|
||||
void DDSHeader::setPixelFormat(uint bitcount, uint rmask, uint gmask, uint bmask, uint amask)
|
||||
{
|
||||
// Make sure the masks are correct.
|
||||
nvCheck((rmask & gmask) == 0);
|
||||
nvCheck((rmask & bmask) == 0);
|
||||
nvCheck((rmask & amask) == 0);
|
||||
nvCheck((gmask & bmask) == 0);
|
||||
nvCheck((gmask & amask) == 0);
|
||||
nvCheck((bmask & amask) == 0);
|
||||
|
||||
this->pf.flags = DDPF_RGB;
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
@ -1,85 +1,127 @@
|
||||
// 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 NV_IMAGE_DIRECTDRAWSURFACE_H
|
||||
#define NV_IMAGE_DIRECTDRAWSURFACE_H
|
||||
|
||||
#include <nvcore/nvcore.h>
|
||||
|
||||
namespace nv
|
||||
{
|
||||
|
||||
struct DDSPixelFormat {
|
||||
uint size;
|
||||
uint flags;
|
||||
uint fourcc;
|
||||
uint bitcount;
|
||||
uint rmask;
|
||||
uint gmask;
|
||||
uint bmask;
|
||||
uint amask;
|
||||
};
|
||||
|
||||
struct DDSCaps {
|
||||
uint caps1;
|
||||
uint caps2;
|
||||
uint caps3;
|
||||
uint caps4;
|
||||
};
|
||||
|
||||
/// DDS file header.
|
||||
struct DDSHeader {
|
||||
uint fourcc;
|
||||
uint size;
|
||||
uint flags;
|
||||
uint height;
|
||||
uint width;
|
||||
uint pitch;
|
||||
uint depth;
|
||||
uint mipmapcount;
|
||||
uint reserved[11];
|
||||
DDSPixelFormat pf;
|
||||
DDSCaps caps;
|
||||
uint notused;
|
||||
|
||||
// Helper methods.
|
||||
DDSHeader();
|
||||
void setWidth(uint w);
|
||||
void setHeight(uint h);
|
||||
void setDepth(uint d);
|
||||
void setMipmapCount(uint count);
|
||||
void setLinearSize(uint size);
|
||||
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 setTexture2D();
|
||||
void setTexture3D();
|
||||
void setTextureCube();
|
||||
|
||||
void swapBytes();
|
||||
};
|
||||
|
||||
|
||||
} // nv namespace
|
||||
|
||||
#endif // NV_IMAGE_DIRECTDRAWSURFACE_H
|
||||
// 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 NV_IMAGE_DIRECTDRAWSURFACE_H
|
||||
#define NV_IMAGE_DIRECTDRAWSURFACE_H
|
||||
|
||||
#include <nvcore/nvcore.h>
|
||||
|
||||
namespace nv
|
||||
{
|
||||
class Image;
|
||||
class Stream;
|
||||
struct ColorBlock;
|
||||
|
||||
struct DDSPixelFormat {
|
||||
uint size;
|
||||
uint flags;
|
||||
uint fourcc;
|
||||
uint bitcount;
|
||||
uint rmask;
|
||||
uint gmask;
|
||||
uint bmask;
|
||||
uint amask;
|
||||
};
|
||||
|
||||
struct DDSCaps {
|
||||
uint caps1;
|
||||
uint caps2;
|
||||
uint caps3;
|
||||
uint caps4;
|
||||
};
|
||||
|
||||
/// DDS file header.
|
||||
struct DDSHeader {
|
||||
uint fourcc;
|
||||
uint size;
|
||||
uint flags;
|
||||
uint height;
|
||||
uint width;
|
||||
uint pitch;
|
||||
uint depth;
|
||||
uint mipmapcount;
|
||||
uint reserved[11];
|
||||
DDSPixelFormat pf;
|
||||
DDSCaps caps;
|
||||
uint notused;
|
||||
|
||||
// Helper methods.
|
||||
DDSHeader();
|
||||
|
||||
void setWidth(uint w);
|
||||
void setHeight(uint h);
|
||||
void setDepth(uint d);
|
||||
void setMipmapCount(uint count);
|
||||
void setTexture2D();
|
||||
void setTexture3D();
|
||||
void setTextureCube();
|
||||
void setLinearSize(uint size);
|
||||
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);
|
||||
|
||||
void swapBytes();
|
||||
};
|
||||
|
||||
/// 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
|
||||
|
@ -22,7 +22,7 @@ namespace nv
|
||||
Spline,
|
||||
Lanczos,
|
||||
Mitchell,
|
||||
Kaiser,
|
||||
Kaiser, // Kaiser-windowed sinc filter
|
||||
Num
|
||||
};
|
||||
|
||||
|
@ -1,125 +1,124 @@
|
||||
// This code is in the public domain -- castanyo@yahoo.es
|
||||
|
||||
#include <nvcore/Debug.h>
|
||||
#include <nvcore/Ptr.h>
|
||||
|
||||
#include <nvmath/Color.h>
|
||||
|
||||
#include <nvimage/Image.h>
|
||||
#include <nvimage/ImageIO.h>
|
||||
|
||||
|
||||
using namespace nv;
|
||||
|
||||
Image::Image() : m_width(0), m_height(0), m_format(Format_RGB), m_data(NULL)
|
||||
{
|
||||
}
|
||||
|
||||
Image::~Image()
|
||||
{
|
||||
free();
|
||||
}
|
||||
|
||||
void Image::allocate(uint w, uint h)
|
||||
{
|
||||
free();
|
||||
m_width = w;
|
||||
m_height = h;
|
||||
m_data = new Color32[w*h];
|
||||
}
|
||||
|
||||
bool Image::load(const char * name)
|
||||
{
|
||||
free();
|
||||
|
||||
AutoPtr<Image> img(ImageIO::load(name));
|
||||
if (img == NULL) {
|
||||
return false;
|
||||
}
|
||||
|
||||
swap(m_width, img->m_width);
|
||||
swap(m_height, img->m_height);
|
||||
swap(m_format, img->m_format);
|
||||
swap(m_data, img->m_data);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void Image::wrap(void * data, uint w, uint h)
|
||||
{
|
||||
free();
|
||||
m_data = (Color32 *)data;
|
||||
m_width = w;
|
||||
m_height = h;
|
||||
}
|
||||
|
||||
void Image::unwrap()
|
||||
{
|
||||
m_data = NULL;
|
||||
m_width = 0;
|
||||
m_height = 0;
|
||||
}
|
||||
|
||||
|
||||
void Image::free()
|
||||
{
|
||||
delete m_data;
|
||||
m_data = NULL;
|
||||
}
|
||||
|
||||
|
||||
uint Image::width() const
|
||||
{
|
||||
return m_width;
|
||||
}
|
||||
|
||||
uint Image::height() const
|
||||
{
|
||||
return m_height;
|
||||
}
|
||||
|
||||
const Color32 * Image::scanline(uint h) const
|
||||
{
|
||||
nvDebugCheck(h < m_height);
|
||||
return m_data + h * m_width;
|
||||
}
|
||||
|
||||
Color32 * Image::scanline(uint h)
|
||||
{
|
||||
nvDebugCheck(h < m_height);
|
||||
return m_data + h * m_width;
|
||||
}
|
||||
|
||||
const Color32 * Image::pixels() const
|
||||
{
|
||||
return m_data;
|
||||
}
|
||||
|
||||
Color32 * Image::pixels()
|
||||
{
|
||||
return m_data;
|
||||
}
|
||||
|
||||
const Color32 & Image::pixel(uint idx) const
|
||||
{
|
||||
nvDebugCheck(idx < m_width * m_height);
|
||||
return m_data[idx];
|
||||
}
|
||||
|
||||
Color32 & Image::pixel(uint idx)
|
||||
{
|
||||
nvDebugCheck(idx < m_width * m_height);
|
||||
return m_data[idx];
|
||||
}
|
||||
|
||||
|
||||
Image::Format Image::format() const
|
||||
{
|
||||
return m_format;
|
||||
}
|
||||
|
||||
void Image::setFormat(Image::Format f)
|
||||
{
|
||||
m_format = f;
|
||||
}
|
||||
|
||||
// This code is in the public domain -- castanyo@yahoo.es
|
||||
|
||||
#include <nvcore/Debug.h>
|
||||
#include <nvcore/Ptr.h>
|
||||
|
||||
#include <nvmath/Color.h>
|
||||
|
||||
#include <nvimage/Image.h>
|
||||
#include <nvimage/ImageIO.h>
|
||||
|
||||
|
||||
using namespace nv;
|
||||
|
||||
Image::Image() : m_width(0), m_height(0), m_format(Format_RGB), m_data(NULL)
|
||||
{
|
||||
}
|
||||
|
||||
Image::~Image()
|
||||
{
|
||||
free();
|
||||
}
|
||||
|
||||
void Image::allocate(uint w, uint h)
|
||||
{
|
||||
m_width = w;
|
||||
m_height = h;
|
||||
m_data = (Color32 *)realloc(m_data, w * h * sizeof(Color32));
|
||||
}
|
||||
|
||||
bool Image::load(const char * name)
|
||||
{
|
||||
free();
|
||||
|
||||
AutoPtr<Image> img(ImageIO::load(name));
|
||||
if (img == NULL) {
|
||||
return false;
|
||||
}
|
||||
|
||||
swap(m_width, img->m_width);
|
||||
swap(m_height, img->m_height);
|
||||
swap(m_format, img->m_format);
|
||||
swap(m_data, img->m_data);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void Image::wrap(void * data, uint w, uint h)
|
||||
{
|
||||
free();
|
||||
m_data = (Color32 *)data;
|
||||
m_width = w;
|
||||
m_height = h;
|
||||
}
|
||||
|
||||
void Image::unwrap()
|
||||
{
|
||||
m_data = NULL;
|
||||
m_width = 0;
|
||||
m_height = 0;
|
||||
}
|
||||
|
||||
|
||||
void Image::free()
|
||||
{
|
||||
::free(m_data);
|
||||
m_data = NULL;
|
||||
}
|
||||
|
||||
|
||||
uint Image::width() const
|
||||
{
|
||||
return m_width;
|
||||
}
|
||||
|
||||
uint Image::height() const
|
||||
{
|
||||
return m_height;
|
||||
}
|
||||
|
||||
const Color32 * Image::scanline(uint h) const
|
||||
{
|
||||
nvDebugCheck(h < m_height);
|
||||
return m_data + h * m_width;
|
||||
}
|
||||
|
||||
Color32 * Image::scanline(uint h)
|
||||
{
|
||||
nvDebugCheck(h < m_height);
|
||||
return m_data + h * m_width;
|
||||
}
|
||||
|
||||
const Color32 * Image::pixels() const
|
||||
{
|
||||
return m_data;
|
||||
}
|
||||
|
||||
Color32 * Image::pixels()
|
||||
{
|
||||
return m_data;
|
||||
}
|
||||
|
||||
const Color32 & Image::pixel(uint idx) const
|
||||
{
|
||||
nvDebugCheck(idx < m_width * m_height);
|
||||
return m_data[idx];
|
||||
}
|
||||
|
||||
Color32 & Image::pixel(uint idx)
|
||||
{
|
||||
nvDebugCheck(idx < m_width * m_height);
|
||||
return m_data[idx];
|
||||
}
|
||||
|
||||
|
||||
Image::Format Image::format() const
|
||||
{
|
||||
return m_format;
|
||||
}
|
||||
|
||||
void Image::setFormat(Image::Format f)
|
||||
{
|
||||
m_format = f;
|
||||
}
|
||||
|
||||
|
@ -1,138 +1,138 @@
|
||||
// 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 <nvcore/Ptr.h>
|
||||
|
||||
#include <nvmath/Color.h>
|
||||
|
||||
#include <nvimage/NormalMap.h>
|
||||
#include <nvimage/Filter.h>
|
||||
#include <nvimage/FloatImage.h>
|
||||
#include <nvimage/Image.h>
|
||||
|
||||
using namespace nv;
|
||||
|
||||
// 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)
|
||||
{
|
||||
nvCheck(kdu != NULL);
|
||||
nvCheck(kdv != NULL);
|
||||
nvCheck(img != NULL);
|
||||
|
||||
const uint w = img->width();
|
||||
const uint h = img->height();
|
||||
|
||||
AutoPtr<FloatImage> fimage(new FloatImage());
|
||||
fimage->allocate(4, w, h);
|
||||
|
||||
// Compute height and store in alpha channel:
|
||||
float * alphaChannel = fimage->channel(3);
|
||||
for(uint i = 0; i < w*h; i++)
|
||||
{
|
||||
Vector4 color = toVector4(img->pixel(i));
|
||||
alphaChannel[i] = dot(color, heightWeights);
|
||||
}
|
||||
|
||||
float heightScale = 1.0f / 16.0f; // @@ Use a user defined factor.
|
||||
|
||||
for(uint y = 0; y < h; y++)
|
||||
{
|
||||
for(uint x = 0; x < w; x++)
|
||||
{
|
||||
const float du = fimage->applyKernel(kdu, x, y, 3, wm);
|
||||
const float dv = fimage->applyKernel(kdv, x, y, 3, wm);
|
||||
|
||||
Vector3 n = normalize(Vector3(du, dv, heightScale));
|
||||
|
||||
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.z() + 0.5f, x, y, 2);
|
||||
}
|
||||
}
|
||||
|
||||
return fimage.release();
|
||||
}
|
||||
|
||||
|
||||
/// Create normal map using the given filter.
|
||||
FloatImage * nv::createNormalMap(const Image * img, FloatImage::WrapMode wm, Vector4::Arg heightWeights, NormalMapFilter filter /*= Sobel3x3*/)
|
||||
{
|
||||
nvCheck(img != NULL);
|
||||
|
||||
// Init the kernels.
|
||||
Kernel2 * kdu = NULL;
|
||||
Kernel2 * kdv = NULL;
|
||||
|
||||
switch(filter)
|
||||
{
|
||||
case NormalMapFilter_Sobel3x3:
|
||||
kdu = new Kernel2(3);
|
||||
break;
|
||||
case NormalMapFilter_Sobel5x5:
|
||||
kdu = new Kernel2(5);
|
||||
break;
|
||||
case NormalMapFilter_Sobel7x7:
|
||||
kdu = new Kernel2(7);
|
||||
break;
|
||||
case NormalMapFilter_Sobel9x9:
|
||||
kdu = new Kernel2(9);
|
||||
break;
|
||||
default:
|
||||
nvDebugCheck(false);
|
||||
};
|
||||
|
||||
kdu->initSobel();
|
||||
kdu->normalize();
|
||||
|
||||
kdv = new Kernel2(*kdu);
|
||||
kdv->transpose();
|
||||
|
||||
return ::createNormalMap(img, wm, heightWeights, kdu, kdv);
|
||||
}
|
||||
|
||||
|
||||
/// Create normal map combining multiple sobel filters.
|
||||
FloatImage * nv::createNormalMap(const Image * img, FloatImage::WrapMode wm, Vector4::Arg heightWeights, Vector4::Arg filterWeights)
|
||||
{
|
||||
nvCheck(img != NULL);
|
||||
|
||||
Kernel2 * kdu = NULL;
|
||||
Kernel2 * kdv = NULL;
|
||||
|
||||
kdu = new Kernel2(9);
|
||||
kdu->initBlendedSobel(filterWeights);
|
||||
kdu->normalize();
|
||||
|
||||
kdv = new Kernel2(*kdu);
|
||||
kdv->transpose();
|
||||
|
||||
return ::createNormalMap(img, wm, heightWeights, kdu, kdv);
|
||||
}
|
||||
|
||||
/// Normalize the given image in place.
|
||||
void nv::normalize(FloatImage * img)
|
||||
{
|
||||
nvCheck(img != NULL);
|
||||
img->normalize(0);
|
||||
}
|
||||
|
||||
// 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 <nvcore/Ptr.h>
|
||||
|
||||
#include <nvmath/Color.h>
|
||||
|
||||
#include <nvimage/NormalMap.h>
|
||||
#include <nvimage/Filter.h>
|
||||
#include <nvimage/FloatImage.h>
|
||||
#include <nvimage/Image.h>
|
||||
|
||||
using namespace nv;
|
||||
|
||||
// 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)
|
||||
{
|
||||
nvCheck(kdu != NULL);
|
||||
nvCheck(kdv != NULL);
|
||||
nvCheck(img != NULL);
|
||||
|
||||
const uint w = img->width();
|
||||
const uint h = img->height();
|
||||
|
||||
AutoPtr<FloatImage> fimage(new FloatImage());
|
||||
fimage->allocate(4, w, h);
|
||||
|
||||
// Compute height and store in alpha channel:
|
||||
float * alphaChannel = fimage->channel(3);
|
||||
for(uint i = 0; i < w*h; i++)
|
||||
{
|
||||
Vector4 color = toVector4(img->pixel(i));
|
||||
alphaChannel[i] = dot(color, heightWeights);
|
||||
}
|
||||
|
||||
float heightScale = 1.0f / 16.0f; // @@ Use a user defined factor.
|
||||
|
||||
for(uint y = 0; y < h; y++)
|
||||
{
|
||||
for(uint x = 0; x < w; x++)
|
||||
{
|
||||
const float du = fimage->applyKernel(kdu, x, y, 3, wm);
|
||||
const float dv = fimage->applyKernel(kdv, x, y, 3, wm);
|
||||
|
||||
Vector3 n = normalize(Vector3(du, dv, heightScale));
|
||||
|
||||
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.z() + 0.5f, x, y, 2);
|
||||
}
|
||||
}
|
||||
|
||||
return fimage.release();
|
||||
}
|
||||
|
||||
|
||||
/// Create normal map using the given filter.
|
||||
FloatImage * nv::createNormalMap(const Image * img, FloatImage::WrapMode wm, Vector4::Arg heightWeights, NormalMapFilter filter /*= Sobel3x3*/)
|
||||
{
|
||||
nvCheck(img != NULL);
|
||||
|
||||
// Init the kernels.
|
||||
Kernel2 * kdu = NULL;
|
||||
Kernel2 * kdv = NULL;
|
||||
|
||||
switch(filter)
|
||||
{
|
||||
case NormalMapFilter_Sobel3x3:
|
||||
kdu = new Kernel2(3);
|
||||
break;
|
||||
case NormalMapFilter_Sobel5x5:
|
||||
kdu = new Kernel2(5);
|
||||
break;
|
||||
case NormalMapFilter_Sobel7x7:
|
||||
kdu = new Kernel2(7);
|
||||
break;
|
||||
case NormalMapFilter_Sobel9x9:
|
||||
kdu = new Kernel2(9);
|
||||
break;
|
||||
default:
|
||||
nvDebugCheck(false);
|
||||
};
|
||||
|
||||
kdu->initSobel();
|
||||
kdu->normalize();
|
||||
|
||||
kdv = new Kernel2(*kdu);
|
||||
kdv->transpose();
|
||||
|
||||
return ::createNormalMap(img, wm, heightWeights, kdu, kdv);
|
||||
}
|
||||
|
||||
|
||||
/// Create normal map combining multiple sobel filters.
|
||||
FloatImage * nv::createNormalMap(const Image * img, FloatImage::WrapMode wm, Vector4::Arg heightWeights, Vector4::Arg filterWeights)
|
||||
{
|
||||
nvCheck(img != NULL);
|
||||
|
||||
Kernel2 * kdu = NULL;
|
||||
Kernel2 * kdv = NULL;
|
||||
|
||||
kdu = new Kernel2(9);
|
||||
kdu->initBlendedSobel(filterWeights);
|
||||
kdu->normalize();
|
||||
|
||||
kdv = new Kernel2(*kdu);
|
||||
kdv->transpose();
|
||||
|
||||
return ::createNormalMap(img, wm, heightWeights, kdu, kdv);
|
||||
}
|
||||
|
||||
/// Normalize the given image in place.
|
||||
void nv::normalize(FloatImage * img)
|
||||
{
|
||||
nvCheck(img != NULL);
|
||||
img->normalize(0);
|
||||
}
|
||||
|
||||
|
@ -1,24 +1,24 @@
|
||||
// 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
|
||||
// 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 NV_IMAGE_NORMALMAP_H
|
||||
|
98
src/nvimage/NormalMipmap.cpp
Normal file
98
src/nvimage/NormalMipmap.cpp
Normal 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;
|
||||
}
|
||||
|
17
src/nvimage/NormalMipmap.h
Normal file
17
src/nvimage/NormalMipmap.h
Normal 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
|
@ -10,8 +10,6 @@ SET(NVTT_SRCS
|
||||
CompressRGB.cpp
|
||||
FastCompressDXT.h
|
||||
FastCompressDXT.cpp
|
||||
BlockDXT.h
|
||||
BlockDXT.cpp
|
||||
dxtlib.cpp
|
||||
dxtlib_compat.h
|
||||
CompressionOptions.h
|
||||
@ -28,7 +26,7 @@ IF(CUDA_FOUND)
|
||||
ADD_DEFINITIONS(-DHAVE_CUDA)
|
||||
WRAP_CUDA(CUDA_SRCS cuda/CompressKernel.cu)
|
||||
SET(NVTT_SRCS ${NVTT_SRCS} ${CUDA_SRCS})
|
||||
SET(LIBS ${LIBS} ${CUDA_LIBRARY})
|
||||
SET(LIBS ${LIBS} ${CUDA_LIBRARIES})
|
||||
INCLUDE_DIRECTORIES(${CUDA_INCLUDE_PATH})
|
||||
ENDIF(CUDA_FOUND)
|
||||
|
||||
@ -46,7 +44,7 @@ TARGET_LINK_LIBRARIES(nvtt ${LIBS} nvcore nvmath nvimage squish)
|
||||
|
||||
|
||||
# test executables
|
||||
ADD_EXECUTABLE(nvcompress compress.cpp)
|
||||
ADD_EXECUTABLE(nvcompress tools/compress.cpp)
|
||||
TARGET_LINK_LIBRARIES(nvcompress nvcore nvmath nvimage nvtt)
|
||||
|
||||
INSTALL(TARGETS nvcompress DESTINATION bin)
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -1,65 +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 NV_TT_COMPRESSDXT_H
|
||||
#define NV_TT_COMPRESSDXT_H
|
||||
|
||||
#include <nvimage/nvimage.h>
|
||||
#include "nvtt.h"
|
||||
|
||||
namespace nv
|
||||
{
|
||||
class Image;
|
||||
class FloatImage;
|
||||
|
||||
void doPrecomputation();
|
||||
|
||||
// Fast compressors.
|
||||
void fastCompressDXT1(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 fastCompressDXT5n(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);
|
||||
|
||||
// Normal compressors.
|
||||
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 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 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);
|
||||
|
||||
// External compressors.
|
||||
#if defined(HAVE_S3QUANT)
|
||||
void s3CompressDXT1(const Image * image, const nvtt::OutputOptions & outputOptions);
|
||||
#endif
|
||||
|
||||
#if defined(HAVE_ATITC)
|
||||
void atiCompressDXT1(const Image * image, const nvtt::OutputOptions & outputOptions);
|
||||
#endif
|
||||
|
||||
} // nv namespace
|
||||
|
||||
|
||||
#endif // NV_TT_COMPRESSDXT_H
|
||||
// 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 NV_TT_COMPRESSDXT_H
|
||||
#define NV_TT_COMPRESSDXT_H
|
||||
|
||||
#include <nvimage/nvimage.h>
|
||||
#include "nvtt.h"
|
||||
|
||||
namespace nv
|
||||
{
|
||||
class Image;
|
||||
class FloatImage;
|
||||
|
||||
void doPrecomputation();
|
||||
|
||||
// Fast compressors.
|
||||
void fastCompressDXT1(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 fastCompressDXT5n(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);
|
||||
|
||||
// Normal compressors.
|
||||
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 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 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);
|
||||
|
||||
// External compressors.
|
||||
#if defined(HAVE_S3QUANT)
|
||||
void s3CompressDXT1(const Image * image, const nvtt::OutputOptions & outputOptions);
|
||||
#endif
|
||||
|
||||
#if defined(HAVE_ATITC)
|
||||
void atiCompressDXT1(const Image * image, const nvtt::OutputOptions & outputOptions);
|
||||
#endif
|
||||
|
||||
} // nv namespace
|
||||
|
||||
|
||||
#endif // NV_TT_COMPRESSDXT_H
|
||||
|
@ -1,153 +1,153 @@
|
||||
// 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 <string.h>
|
||||
#include <nvcore/Debug.h>
|
||||
#include <nvimage/Image.h>
|
||||
|
||||
#include "CompressRGB.h"
|
||||
#include "CompressionOptions.h"
|
||||
|
||||
|
||||
using namespace nv;
|
||||
using namespace nvtt;
|
||||
|
||||
namespace
|
||||
{
|
||||
|
||||
inline uint computePitch(uint w, uint bitsize)
|
||||
{
|
||||
uint p = w * ((bitsize + 7) / 8);
|
||||
|
||||
// Align to 32 bits.
|
||||
return ((p + 3) / 4) * 4;
|
||||
}
|
||||
|
||||
static void convert_to_rgba8888(void * src, void * dst, uint w)
|
||||
{
|
||||
// @@ TODO
|
||||
}
|
||||
|
||||
static void convert_to_bgra8888(const void * src, void * dst, uint w)
|
||||
{
|
||||
memcpy(dst, src, 4 * w);
|
||||
}
|
||||
|
||||
static void convert_to_rgb888(const void * src, void * dst, uint w)
|
||||
{
|
||||
// @@ TODO
|
||||
}
|
||||
|
||||
static uint truncate(uint c, uint inbits, uint outbits)
|
||||
{
|
||||
nvDebugCheck(inbits > outbits);
|
||||
c >>= inbits - outbits;
|
||||
}
|
||||
|
||||
static uint bitexpand(uint c, uint inbits, uint outbits)
|
||||
{
|
||||
// @@ TODO
|
||||
}
|
||||
|
||||
static void maskShiftAndSize(uint mask, uint & shift, uint & size)
|
||||
{
|
||||
shift = 0;
|
||||
while((mask & 1) == 0) {
|
||||
shift++;
|
||||
mask >>= 1;
|
||||
}
|
||||
|
||||
while((mask & 1) == 1) {
|
||||
size++;
|
||||
mask >>= 1;
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
|
||||
// Pixel format converter.
|
||||
void nv::compressRGB(const Image * image, const OutputOptions & outputOptions, const CompressionOptions::Private & compressionOptions)
|
||||
{
|
||||
nvCheck(image != NULL);
|
||||
|
||||
const uint w = image->width();
|
||||
const uint h = image->height();
|
||||
|
||||
uint rshift, rsize;
|
||||
maskShiftAndSize(compressionOptions.rmask, rshift, rsize);
|
||||
|
||||
uint gshift, gsize;
|
||||
maskShiftAndSize(compressionOptions.gmask, gshift, gsize);
|
||||
|
||||
uint bshift, bsize;
|
||||
maskShiftAndSize(compressionOptions.bmask, bshift, bsize);
|
||||
|
||||
uint ashift, asize;
|
||||
maskShiftAndSize(compressionOptions.amask, ashift, asize);
|
||||
|
||||
|
||||
// Determine pitch.
|
||||
uint pitch = computePitch(w, compressionOptions.bitcount);
|
||||
|
||||
void * dst = malloc(pitch);
|
||||
|
||||
for (uint y = 0; y < h; y++)
|
||||
{
|
||||
const Color32 * src = image->scanline(y);
|
||||
|
||||
convert_to_bgra8888(src, dst, w);
|
||||
|
||||
if (false)
|
||||
{
|
||||
// uint c = 0;
|
||||
// c |= (src[i].r >> (8 - rsize)) << rshift;
|
||||
// c |= (src[i].g >> (8 - gsize)) << gshift;
|
||||
// c |= (src[i].b >> (8 - bsize)) << bshift;
|
||||
}
|
||||
|
||||
/*
|
||||
if (rmask == 0xFF000000 && gmask == 0xFF0000 && bmask == 0xFF00 && amask == 0xFF)
|
||||
{
|
||||
convert_to_rgba8888(src, dst, w);
|
||||
}
|
||||
else if (rmask == 0xFF0000 && gmask == 0xFF00 && bmask == 0xFF && amask == 0)
|
||||
{
|
||||
convert_to_rgb888(src, dst, w);
|
||||
}
|
||||
else
|
||||
{
|
||||
// @@ Not supported.
|
||||
}
|
||||
*/
|
||||
|
||||
if (outputOptions.outputHandler != NULL)
|
||||
{
|
||||
outputOptions.outputHandler->writeData(dst, pitch);
|
||||
}
|
||||
}
|
||||
|
||||
free(dst);
|
||||
}
|
||||
|
||||
|
||||
// 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 <string.h>
|
||||
#include <nvcore/Debug.h>
|
||||
#include <nvimage/Image.h>
|
||||
|
||||
#include "CompressRGB.h"
|
||||
#include "CompressionOptions.h"
|
||||
|
||||
|
||||
using namespace nv;
|
||||
using namespace nvtt;
|
||||
|
||||
namespace
|
||||
{
|
||||
|
||||
inline uint computePitch(uint w, uint bitsize)
|
||||
{
|
||||
uint p = w * ((bitsize + 7) / 8);
|
||||
|
||||
// Align to 32 bits.
|
||||
return ((p + 3) / 4) * 4;
|
||||
}
|
||||
|
||||
static void convert_to_rgba8888(void * src, void * dst, uint w)
|
||||
{
|
||||
// @@ TODO
|
||||
}
|
||||
|
||||
static void convert_to_bgra8888(const void * src, void * dst, uint w)
|
||||
{
|
||||
memcpy(dst, src, 4 * w);
|
||||
}
|
||||
|
||||
static void convert_to_rgb888(const void * src, void * dst, uint w)
|
||||
{
|
||||
// @@ TODO
|
||||
}
|
||||
|
||||
static uint truncate(uint c, uint inbits, uint outbits)
|
||||
{
|
||||
nvDebugCheck(inbits > outbits);
|
||||
c >>= inbits - outbits;
|
||||
}
|
||||
|
||||
static uint bitexpand(uint c, uint inbits, uint outbits)
|
||||
{
|
||||
// @@ TODO
|
||||
}
|
||||
|
||||
static void maskShiftAndSize(uint mask, uint & shift, uint & size)
|
||||
{
|
||||
shift = 0;
|
||||
while((mask & 1) == 0) {
|
||||
shift++;
|
||||
mask >>= 1;
|
||||
}
|
||||
|
||||
while((mask & 1) == 1) {
|
||||
size++;
|
||||
mask >>= 1;
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
|
||||
// Pixel format converter.
|
||||
void nv::compressRGB(const Image * image, const OutputOptions & outputOptions, const CompressionOptions::Private & compressionOptions)
|
||||
{
|
||||
nvCheck(image != NULL);
|
||||
|
||||
const uint w = image->width();
|
||||
const uint h = image->height();
|
||||
|
||||
uint rshift, rsize;
|
||||
maskShiftAndSize(compressionOptions.rmask, rshift, rsize);
|
||||
|
||||
uint gshift, gsize;
|
||||
maskShiftAndSize(compressionOptions.gmask, gshift, gsize);
|
||||
|
||||
uint bshift, bsize;
|
||||
maskShiftAndSize(compressionOptions.bmask, bshift, bsize);
|
||||
|
||||
uint ashift, asize;
|
||||
maskShiftAndSize(compressionOptions.amask, ashift, asize);
|
||||
|
||||
|
||||
// Determine pitch.
|
||||
uint pitch = computePitch(w, compressionOptions.bitcount);
|
||||
|
||||
void * dst = malloc(pitch);
|
||||
|
||||
for (uint y = 0; y < h; y++)
|
||||
{
|
||||
const Color32 * src = image->scanline(y);
|
||||
|
||||
convert_to_bgra8888(src, dst, w);
|
||||
|
||||
if (false)
|
||||
{
|
||||
// uint c = 0;
|
||||
// c |= (src[i].r >> (8 - rsize)) << rshift;
|
||||
// c |= (src[i].g >> (8 - gsize)) << gshift;
|
||||
// c |= (src[i].b >> (8 - bsize)) << bshift;
|
||||
}
|
||||
|
||||
/*
|
||||
if (rmask == 0xFF000000 && gmask == 0xFF0000 && bmask == 0xFF00 && amask == 0xFF)
|
||||
{
|
||||
convert_to_rgba8888(src, dst, w);
|
||||
}
|
||||
else if (rmask == 0xFF0000 && gmask == 0xFF00 && bmask == 0xFF && amask == 0)
|
||||
{
|
||||
convert_to_rgb888(src, dst, w);
|
||||
}
|
||||
else
|
||||
{
|
||||
// @@ Not supported.
|
||||
}
|
||||
*/
|
||||
|
||||
if (outputOptions.outputHandler != NULL)
|
||||
{
|
||||
outputOptions.outputHandler->writeData(dst, pitch);
|
||||
}
|
||||
}
|
||||
|
||||
free(dst);
|
||||
}
|
||||
|
||||
|
||||
|
@ -1,24 +1,24 @@
|
||||
// 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
|
||||
// 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 NV_TT_COMPRESSRGB_H
|
||||
|
@ -1,113 +1,114 @@
|
||||
// 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 "nvtt.h"
|
||||
#include "CompressionOptions.h"
|
||||
|
||||
using namespace nv;
|
||||
using namespace nvtt;
|
||||
|
||||
|
||||
/// Constructor. Sets compression options to the default values.
|
||||
CompressionOptions::CompressionOptions() : m(*new CompressionOptions::Private())
|
||||
{
|
||||
reset();
|
||||
}
|
||||
|
||||
|
||||
/// Destructor.
|
||||
CompressionOptions::~CompressionOptions()
|
||||
{
|
||||
delete &m;
|
||||
}
|
||||
|
||||
|
||||
/// Set default compression options.
|
||||
void CompressionOptions::reset()
|
||||
{
|
||||
m.format = Format_DXT1;
|
||||
m.quality = Quality_Normal;
|
||||
m.colorWeight.set(1.0f, 1.0f, 1.0f);
|
||||
m.useCuda = true;
|
||||
m.bitcount = 32;
|
||||
m.bmask = 0x000000FF;
|
||||
m.gmask = 0x0000FF00;
|
||||
m.rmask = 0x00FF0000;
|
||||
m.amask = 0xFF000000;
|
||||
}
|
||||
|
||||
|
||||
/// Set desired compression format.
|
||||
void CompressionOptions::setFormat(Format format)
|
||||
{
|
||||
m.format = format;
|
||||
}
|
||||
|
||||
|
||||
/// Set compression quality settings.
|
||||
void CompressionOptions::setQuality(Quality quality, float errorThreshold /*= 0.5f*/)
|
||||
{
|
||||
m.quality = quality;
|
||||
m.errorThreshold = errorThreshold;
|
||||
}
|
||||
|
||||
|
||||
/// Set the weights of each color channel.
|
||||
/// 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
|
||||
/// 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
|
||||
/// the compressor should use a non linear colour metric as described here:
|
||||
/// http://www.compuphase.com/cmetric.htm
|
||||
void CompressionOptions::setColorWeights(float red, float green, float blue)
|
||||
{
|
||||
float total = red + green + blue;
|
||||
float x = blue / total;
|
||||
float y = green / total;
|
||||
|
||||
m.colorWeight.set(x, y, 1.0f - x - y);
|
||||
}
|
||||
|
||||
|
||||
/// Enable or disable hardware compression.
|
||||
void CompressionOptions::enableHardwareCompression(bool enable)
|
||||
{
|
||||
m.useCuda = enable;
|
||||
}
|
||||
|
||||
|
||||
/// Set color mask to describe the RGB/RGBA format.
|
||||
void CompressionOptions::setPixelFormat(uint bitcount, uint rmask, uint gmask, uint bmask, uint amask)
|
||||
{
|
||||
m.bitcount = bitcount;
|
||||
m.rmask = rmask;
|
||||
m.gmask = gmask;
|
||||
m.bmask = bmask;
|
||||
m.amask = amask;
|
||||
}
|
||||
|
||||
/// Use external compressor.
|
||||
void CompressionOptions::setExternalCompressor(const char * name)
|
||||
{
|
||||
m.externalCompressor = name;
|
||||
}
|
||||
// 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 "nvtt.h"
|
||||
#include "CompressionOptions.h"
|
||||
|
||||
using namespace nv;
|
||||
using namespace nvtt;
|
||||
|
||||
|
||||
/// Constructor. Sets compression options to the default values.
|
||||
CompressionOptions::CompressionOptions() : m(*new CompressionOptions::Private())
|
||||
{
|
||||
reset();
|
||||
}
|
||||
|
||||
|
||||
/// Destructor.
|
||||
CompressionOptions::~CompressionOptions()
|
||||
{
|
||||
delete &m;
|
||||
}
|
||||
|
||||
|
||||
/// Set default compression options.
|
||||
void CompressionOptions::reset()
|
||||
{
|
||||
m.format = Format_DXT1;
|
||||
m.quality = Quality_Normal;
|
||||
m.colorWeight.set(1.0f, 1.0f, 1.0f);
|
||||
m.useCuda = true;
|
||||
m.bitcount = 32;
|
||||
m.bmask = 0x000000FF;
|
||||
m.gmask = 0x0000FF00;
|
||||
m.rmask = 0x00FF0000;
|
||||
m.amask = 0xFF000000;
|
||||
}
|
||||
|
||||
|
||||
/// Set desired compression format.
|
||||
void CompressionOptions::setFormat(Format format)
|
||||
{
|
||||
m.format = format;
|
||||
}
|
||||
|
||||
|
||||
/// Set compression quality settings.
|
||||
void CompressionOptions::setQuality(Quality quality, float errorThreshold /*= 0.5f*/)
|
||||
{
|
||||
m.quality = quality;
|
||||
m.errorThreshold = errorThreshold;
|
||||
}
|
||||
|
||||
|
||||
/// Set the weights of each color channel.
|
||||
/// 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
|
||||
/// 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
|
||||
/// the compressor should use a non linear colour metric as described here:
|
||||
/// http://www.compuphase.com/cmetric.htm
|
||||
void CompressionOptions::setColorWeights(float red, float green, float blue)
|
||||
{
|
||||
float total = red + green + blue;
|
||||
float x = blue / total;
|
||||
float y = green / total;
|
||||
|
||||
m.colorWeight.set(x, y, 1.0f - x - y);
|
||||
}
|
||||
|
||||
|
||||
/// Enable or disable hardware compression.
|
||||
void CompressionOptions::enableHardwareCompression(bool enable)
|
||||
{
|
||||
m.useCuda = enable;
|
||||
}
|
||||
|
||||
|
||||
/// Set color mask to describe the RGB/RGBA format.
|
||||
void CompressionOptions::setPixelFormat(uint bitcount, uint rmask, uint gmask, uint bmask, uint amask)
|
||||
{
|
||||
m.bitcount = bitcount;
|
||||
m.rmask = rmask;
|
||||
m.gmask = gmask;
|
||||
m.bmask = bmask;
|
||||
m.amask = amask;
|
||||
}
|
||||
|
||||
/// Use external compressor.
|
||||
void CompressionOptions::setExternalCompressor(const char * name)
|
||||
{
|
||||
m.externalCompressor = name;
|
||||
}
|
||||
|
||||
|
@ -1,57 +1,57 @@
|
||||
// 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 NV_TT_COMPRESSIONOPTIONS_H
|
||||
#define NV_TT_COMPRESSIONOPTIONS_H
|
||||
|
||||
#include <nvcore/StrLib.h>
|
||||
#include <nvmath/Vector.h>
|
||||
#include "nvtt.h"
|
||||
|
||||
namespace nvtt
|
||||
{
|
||||
|
||||
struct CompressionOptions::Private
|
||||
{
|
||||
Format format;
|
||||
|
||||
Quality quality;
|
||||
float errorThreshold;
|
||||
|
||||
nv::Vector3 colorWeight;
|
||||
|
||||
uint bitcount;
|
||||
uint rmask;
|
||||
uint gmask;
|
||||
uint bmask;
|
||||
uint amask;
|
||||
|
||||
bool useCuda;
|
||||
|
||||
nv::String externalCompressor;
|
||||
};
|
||||
|
||||
} // nvtt namespace
|
||||
|
||||
|
||||
#endif // NV_TT_COMPRESSIONOPTIONS_H
|
||||
// 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 NV_TT_COMPRESSIONOPTIONS_H
|
||||
#define NV_TT_COMPRESSIONOPTIONS_H
|
||||
|
||||
#include <nvcore/StrLib.h>
|
||||
#include <nvmath/Vector.h>
|
||||
#include "nvtt.h"
|
||||
|
||||
namespace nvtt
|
||||
{
|
||||
|
||||
struct CompressionOptions::Private
|
||||
{
|
||||
Format format;
|
||||
|
||||
Quality quality;
|
||||
float errorThreshold;
|
||||
|
||||
nv::Vector3 colorWeight;
|
||||
|
||||
uint bitcount;
|
||||
uint rmask;
|
||||
uint gmask;
|
||||
uint bmask;
|
||||
uint amask;
|
||||
|
||||
bool useCuda;
|
||||
|
||||
nv::String externalCompressor;
|
||||
};
|
||||
|
||||
} // nvtt namespace
|
||||
|
||||
|
||||
#endif // NV_TT_COMPRESSIONOPTIONS_H
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -1,81 +1,84 @@
|
||||
// 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 NV_TT_FASTCOMPRESSDXT_H
|
||||
#define NV_TT_FASTCOMPRESSDXT_H
|
||||
|
||||
#include <nvimage/nvimage.h>
|
||||
|
||||
namespace nv
|
||||
{
|
||||
struct ColorBlock;
|
||||
struct BlockDXT1;
|
||||
struct BlockDXT3;
|
||||
struct BlockDXT5;
|
||||
struct AlphaBlockDXT3;
|
||||
struct AlphaBlockDXT5;
|
||||
|
||||
// Color compression:
|
||||
|
||||
// Compressor that uses the extremes of the luminance axis.
|
||||
void compressBlock_DiameterAxis(const ColorBlock & rgba, BlockDXT1 * block);
|
||||
|
||||
// Compressor that uses the extremes of the luminance axis.
|
||||
void compressBlock_LuminanceAxis(const ColorBlock & rgba, BlockDXT1 * block);
|
||||
|
||||
// Compressor that uses bounding box.
|
||||
void compressBlock_BoundsRange(const ColorBlock & rgba, BlockDXT1 * block);
|
||||
|
||||
// Compressor that uses the best fit axis.
|
||||
void compressBlock_BestFitAxis(const ColorBlock & rgba, BlockDXT1 * block);
|
||||
|
||||
|
||||
// Simple, but slow compressor that tests all color pairs.
|
||||
void compressBlock_TestAllPairs(const ColorBlock & rgba, BlockDXT1 * block);
|
||||
|
||||
// Brute force 6d search along the best fit axis.
|
||||
void compressBlock_AnalyzeBestFitAxis(const ColorBlock & rgba, BlockDXT1 * block);
|
||||
|
||||
// Spatial greedy search.
|
||||
void refineSolution_1dSearch(const ColorBlock & rgba, BlockDXT1 * block);
|
||||
void refineSolution_3dSearch(const ColorBlock & rgba, BlockDXT1 * block);
|
||||
void refineSolution_6dSearch(const ColorBlock & rgba, BlockDXT1 * block);
|
||||
|
||||
// Minimize error of the endpoints.
|
||||
void optimizeEndPoints(const ColorBlock & rgba, BlockDXT1 * block);
|
||||
|
||||
uint blockError(const ColorBlock & rgba, const BlockDXT1 & block);
|
||||
uint blockError(const ColorBlock & rgba, const AlphaBlockDXT5 & block);
|
||||
|
||||
// Alpha compression:
|
||||
void compressBlock(const ColorBlock & rgba, AlphaBlockDXT3 * block);
|
||||
void compressBlock_BoundsRange(const ColorBlock & rgba, BlockDXT3 * block);
|
||||
void compressBlock_BoundsRange(const ColorBlock & rgba, BlockDXT5 * block);
|
||||
|
||||
uint compressBlock_BoundsRange(const ColorBlock & rgba, AlphaBlockDXT5 * block);
|
||||
uint compressBlock_BruteForce(const ColorBlock & rgba, AlphaBlockDXT5 * block);
|
||||
uint compressBlock_Iterative(const ColorBlock & rgba, AlphaBlockDXT5 * block);
|
||||
|
||||
} // nv namespace
|
||||
|
||||
#endif // NV_TT_FASTCOMPRESSDXT_H
|
||||
// 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 NV_TT_FASTCOMPRESSDXT_H
|
||||
#define NV_TT_FASTCOMPRESSDXT_H
|
||||
|
||||
#include <nvimage/nvimage.h>
|
||||
|
||||
namespace nv
|
||||
{
|
||||
struct ColorBlock;
|
||||
struct BlockDXT1;
|
||||
struct BlockDXT3;
|
||||
struct BlockDXT5;
|
||||
struct AlphaBlockDXT3;
|
||||
struct AlphaBlockDXT5;
|
||||
|
||||
// Color compression:
|
||||
|
||||
// Compressor that uses the extremes of the luminance axis.
|
||||
void compressBlock_DiameterAxis(const ColorBlock & rgba, BlockDXT1 * block);
|
||||
|
||||
// Compressor that uses the extremes of the luminance axis.
|
||||
void compressBlock_LuminanceAxis(const ColorBlock & rgba, BlockDXT1 * block);
|
||||
|
||||
// Compressor that uses bounding box.
|
||||
void compressBlock_BoundsRange(const ColorBlock & rgba, BlockDXT1 * block);
|
||||
|
||||
// Compressor that uses the best fit axis.
|
||||
void compressBlock_BestFitAxis(const ColorBlock & rgba, BlockDXT1 * block);
|
||||
|
||||
|
||||
// Simple, but slow compressor that tests all color pairs.
|
||||
void compressBlock_TestAllPairs(const ColorBlock & rgba, BlockDXT1 * block);
|
||||
|
||||
// Brute force 6d search along the best fit axis.
|
||||
void compressBlock_AnalyzeBestFitAxis(const ColorBlock & rgba, BlockDXT1 * block);
|
||||
|
||||
// Spatial greedy search.
|
||||
void refineSolution_1dSearch(const ColorBlock & rgba, BlockDXT1 * block);
|
||||
void refineSolution_3dSearch(const ColorBlock & rgba, BlockDXT1 * block);
|
||||
void refineSolution_6dSearch(const ColorBlock & rgba, BlockDXT1 * block);
|
||||
|
||||
// Brute force compressor for DXT5n
|
||||
void compressGreenBlock_BruteForce(const ColorBlock & rgba, BlockDXT1 * block);
|
||||
|
||||
// Minimize error of the endpoints.
|
||||
void optimizeEndPoints(const ColorBlock & rgba, BlockDXT1 * block);
|
||||
|
||||
uint blockError(const ColorBlock & rgba, const BlockDXT1 & block);
|
||||
uint blockError(const ColorBlock & rgba, const AlphaBlockDXT5 & block);
|
||||
|
||||
// Alpha compression:
|
||||
void compressBlock(const ColorBlock & rgba, AlphaBlockDXT3 * block);
|
||||
void compressBlock_BoundsRange(const ColorBlock & rgba, BlockDXT3 * block);
|
||||
void compressBlock_BoundsRange(const ColorBlock & rgba, BlockDXT5 * block);
|
||||
|
||||
uint compressBlock_BoundsRange(const ColorBlock & rgba, AlphaBlockDXT5 * block);
|
||||
uint compressBlock_BruteForce(const ColorBlock & rgba, AlphaBlockDXT5 * block);
|
||||
uint compressBlock_Iterative(const ColorBlock & rgba, AlphaBlockDXT5 * block);
|
||||
|
||||
} // nv namespace
|
||||
|
||||
#endif // NV_TT_FASTCOMPRESSDXT_H
|
||||
|
@ -1,250 +1,254 @@
|
||||
// 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 <string.h> // memcpy
|
||||
|
||||
#include <nvcore/Memory.h>
|
||||
|
||||
#include "nvtt.h"
|
||||
#include "InputOptions.h"
|
||||
|
||||
using namespace nv;
|
||||
using namespace nvtt;
|
||||
|
||||
namespace
|
||||
{
|
||||
|
||||
static int countMipmaps(int w, int h, int d)
|
||||
{
|
||||
int mipmap = 0;
|
||||
|
||||
while (w != 1 && h != 1) {
|
||||
w = max(1, w / 2);
|
||||
h = max(1, h / 2);
|
||||
d = max(1, d / 2);
|
||||
mipmap++;
|
||||
}
|
||||
|
||||
return mipmap + 1;
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
|
||||
/// Constructor.
|
||||
InputOptions::InputOptions() : m(*new InputOptions::Private())
|
||||
{
|
||||
reset();
|
||||
}
|
||||
|
||||
// Delete images.
|
||||
InputOptions::~InputOptions()
|
||||
{
|
||||
resetTextureLayout();
|
||||
|
||||
delete &m;
|
||||
}
|
||||
|
||||
|
||||
// Reset input options.
|
||||
void InputOptions::reset()
|
||||
{
|
||||
m.wrapMode = WrapMode_Repeat;
|
||||
m.textureType = TextureType_2D;
|
||||
m.inputFormat = InputFormat_BGRA_8UB;
|
||||
|
||||
m.enableColorDithering = false;
|
||||
m.enableAlphaDithering = false;
|
||||
m.binaryAlpha = false;
|
||||
m.alphaThreshold = 127;
|
||||
|
||||
m.alphaTransparency = true;
|
||||
|
||||
m.inputGamma = 2.2f;
|
||||
m.outputGamma = 2.2f;
|
||||
|
||||
m.generateMipmaps = false;
|
||||
m.maxLevel = -1;
|
||||
m.mipmapFilter = MipmapFilter_Box;
|
||||
|
||||
m.normalizeMipmaps = false;
|
||||
m.convertToNormalMap = false;
|
||||
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);
|
||||
}
|
||||
|
||||
|
||||
// Setup the input image.
|
||||
void InputOptions::setTextureLayout(TextureType type, int w, int h, int d /*= 1*/)
|
||||
{
|
||||
// Validate arguments.
|
||||
nvCheck(w >= 0);
|
||||
nvCheck(h >= 0);
|
||||
nvCheck(d >= 0);
|
||||
|
||||
// Correct arguments.
|
||||
if (w == 0) w = 1;
|
||||
if (h == 0) h = 1;
|
||||
if (d == 0) d = 1;
|
||||
|
||||
// Delete previous images.
|
||||
resetTextureLayout();
|
||||
|
||||
m.textureType = type;
|
||||
|
||||
// Allocate images.
|
||||
m.mipmapCount = countMipmaps(w, h, d);
|
||||
m.faceCount = (type == TextureType_Cube) ? 6 : 1;
|
||||
m.imageCount = m.mipmapCount * m.faceCount;
|
||||
|
||||
m.images = new Private::Image[m.imageCount];
|
||||
|
||||
for(int f = 0; f < m.faceCount; f++)
|
||||
{
|
||||
for (int mipLevel = 0; mipLevel < m.mipmapCount; mipLevel++)
|
||||
{
|
||||
Private::Image & img = m.images[f * m.mipmapCount + mipLevel];
|
||||
img.width = w;
|
||||
img.height = h;
|
||||
img.depth = d;
|
||||
img.mipLevel = mipLevel;
|
||||
img.face = f;
|
||||
|
||||
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.
|
||||
delete [] m.images;
|
||||
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);
|
||||
|
||||
const int idx = face * m.mipmapCount + mipLevel;
|
||||
|
||||
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)
|
||||
{
|
||||
// Invalid dimension or index.
|
||||
return false;
|
||||
}
|
||||
|
||||
m.images[idx].data = new nv::Image();
|
||||
m.images[idx].data->allocate(width, height);
|
||||
memcpy(m.images[idx].data->pixels(), data, width * height * 4);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
/// Describe the format of the input.
|
||||
void InputOptions::setFormat(InputFormat format, bool alphaTransparency)
|
||||
{
|
||||
m.inputFormat = format;
|
||||
m.alphaTransparency = alphaTransparency;
|
||||
}
|
||||
|
||||
|
||||
/// Set gamma settings.
|
||||
void InputOptions::setGamma(float inputGamma, float outputGamma)
|
||||
{
|
||||
m.inputGamma = inputGamma;
|
||||
m.outputGamma = outputGamma;
|
||||
}
|
||||
|
||||
|
||||
/// Set texture wrappign mode.
|
||||
void InputOptions::setWrapMode(WrapMode mode)
|
||||
{
|
||||
m.wrapMode = mode;
|
||||
}
|
||||
|
||||
|
||||
/// Set mipmapping options.
|
||||
void InputOptions::setMipmapping(bool generateMipmaps, MipmapFilter filter/*= MipmapFilter_Kaiser*/, int maxLevel/*= -1*/)
|
||||
{
|
||||
m.generateMipmaps = generateMipmaps;
|
||||
m.mipmapFilter = filter;
|
||||
m.maxLevel = maxLevel;
|
||||
}
|
||||
|
||||
|
||||
/// Set quantization options.
|
||||
/// @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.
|
||||
void InputOptions::setQuantization(bool colorDithering, bool alphaDithering, bool binaryAlpha, int alphaThreshold/*= 127*/)
|
||||
{
|
||||
m.enableColorDithering = colorDithering;
|
||||
m.enableAlphaDithering = alphaDithering;
|
||||
m.binaryAlpha = binaryAlpha;
|
||||
m.alphaThreshold = alphaThreshold;
|
||||
}
|
||||
|
||||
|
||||
/// Enable normal map conversion.
|
||||
void InputOptions::setConvertToNormalMap(bool convert)
|
||||
{
|
||||
m.convertToNormalMap = convert;
|
||||
}
|
||||
|
||||
/// Set height evaluation factors.
|
||||
void InputOptions::setHeightEvaluation(float redScale, float greenScale, float blueScale, float alphaScale)
|
||||
{
|
||||
// Do not normalize height factors.
|
||||
// float total = redScale + greenScale + blueScale + alphaScale;
|
||||
m.heightFactors = Vector4(redScale, greenScale, blueScale, alphaScale);
|
||||
}
|
||||
|
||||
/// Set normal map conversion filter.
|
||||
void InputOptions::setNormalFilter(float small, float medium, float big, float large)
|
||||
{
|
||||
float total = small + medium + big + large;
|
||||
m.bumpFrequencyScale = Vector4(small, medium, big, large) / total;
|
||||
}
|
||||
|
||||
/// Enable mipmap normalization.
|
||||
void InputOptions::setNormalizeMipmaps(bool normalize)
|
||||
{
|
||||
m.normalizeMipmaps = normalize;
|
||||
}
|
||||
// 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 <string.h> // memcpy
|
||||
|
||||
#include <nvcore/Memory.h>
|
||||
|
||||
#include "nvtt.h"
|
||||
#include "InputOptions.h"
|
||||
|
||||
using namespace nv;
|
||||
using namespace nvtt;
|
||||
|
||||
namespace
|
||||
{
|
||||
|
||||
static int countMipmaps(int w, int h, int d)
|
||||
{
|
||||
int mipmap = 0;
|
||||
|
||||
while (w != 1 && h != 1) {
|
||||
w = max(1, w / 2);
|
||||
h = max(1, h / 2);
|
||||
d = max(1, d / 2);
|
||||
mipmap++;
|
||||
}
|
||||
|
||||
return mipmap + 1;
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
|
||||
/// Constructor.
|
||||
InputOptions::InputOptions() : m(*new InputOptions::Private())
|
||||
{
|
||||
reset();
|
||||
}
|
||||
|
||||
// Delete images.
|
||||
InputOptions::~InputOptions()
|
||||
{
|
||||
resetTextureLayout();
|
||||
|
||||
delete &m;
|
||||
}
|
||||
|
||||
|
||||
// Reset input options.
|
||||
void InputOptions::reset()
|
||||
{
|
||||
m.wrapMode = WrapMode_Repeat;
|
||||
m.textureType = TextureType_2D;
|
||||
m.inputFormat = InputFormat_BGRA_8UB;
|
||||
|
||||
m.enableColorDithering = false;
|
||||
m.enableAlphaDithering = false;
|
||||
m.binaryAlpha = false;
|
||||
m.alphaThreshold = 127;
|
||||
|
||||
m.alphaTransparency = true;
|
||||
|
||||
m.inputGamma = 2.2f;
|
||||
m.outputGamma = 2.2f;
|
||||
|
||||
m.generateMipmaps = false;
|
||||
m.maxLevel = -1;
|
||||
m.mipmapFilter = MipmapFilter_Box;
|
||||
|
||||
m.normalizeMipmaps = false;
|
||||
m.convertToNormalMap = false;
|
||||
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);
|
||||
}
|
||||
|
||||
|
||||
// Setup the input image.
|
||||
void InputOptions::setTextureLayout(TextureType type, int width, int height, int depth /*= 1*/)
|
||||
{
|
||||
// Validate arguments.
|
||||
nvCheck(width >= 0);
|
||||
nvCheck(height >= 0);
|
||||
nvCheck(depth >= 0);
|
||||
|
||||
// Correct arguments.
|
||||
if (width == 0) width = 1;
|
||||
if (height == 0) height = 1;
|
||||
if (depth == 0) depth = 1;
|
||||
|
||||
// Delete previous images.
|
||||
resetTextureLayout();
|
||||
|
||||
m.textureType = type;
|
||||
|
||||
// Allocate images.
|
||||
m.mipmapCount = countMipmaps(width, height, depth);
|
||||
m.faceCount = (type == TextureType_Cube) ? 6 : 1;
|
||||
m.imageCount = m.mipmapCount * m.faceCount;
|
||||
|
||||
m.images = new Private::Image[m.imageCount];
|
||||
|
||||
for(int f = 0; f < m.faceCount; f++)
|
||||
{
|
||||
int w = width;
|
||||
int h = height;
|
||||
int d = depth;
|
||||
|
||||
for (int mipLevel = 0; mipLevel < m.mipmapCount; mipLevel++)
|
||||
{
|
||||
Private::Image & img = m.images[f * m.mipmapCount + mipLevel];
|
||||
img.width = w;
|
||||
img.height = h;
|
||||
img.depth = d;
|
||||
img.mipLevel = mipLevel;
|
||||
img.face = f;
|
||||
|
||||
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.
|
||||
delete [] m.images;
|
||||
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);
|
||||
|
||||
const int idx = face * m.mipmapCount + mipLevel;
|
||||
|
||||
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)
|
||||
{
|
||||
// Invalid dimension or index.
|
||||
return false;
|
||||
}
|
||||
|
||||
m.images[idx].data = new nv::Image();
|
||||
m.images[idx].data->allocate(width, height);
|
||||
memcpy(m.images[idx].data->pixels(), data, width * height * 4);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
/// Describe the format of the input.
|
||||
void InputOptions::setFormat(InputFormat format, bool alphaTransparency)
|
||||
{
|
||||
m.inputFormat = format;
|
||||
m.alphaTransparency = alphaTransparency;
|
||||
}
|
||||
|
||||
|
||||
/// Set gamma settings.
|
||||
void InputOptions::setGamma(float inputGamma, float outputGamma)
|
||||
{
|
||||
m.inputGamma = inputGamma;
|
||||
m.outputGamma = outputGamma;
|
||||
}
|
||||
|
||||
|
||||
/// Set texture wrappign mode.
|
||||
void InputOptions::setWrapMode(WrapMode mode)
|
||||
{
|
||||
m.wrapMode = mode;
|
||||
}
|
||||
|
||||
|
||||
/// Set mipmapping options.
|
||||
void InputOptions::setMipmapping(bool generateMipmaps, MipmapFilter filter/*= MipmapFilter_Kaiser*/, int maxLevel/*= -1*/)
|
||||
{
|
||||
m.generateMipmaps = generateMipmaps;
|
||||
m.mipmapFilter = filter;
|
||||
m.maxLevel = maxLevel;
|
||||
}
|
||||
|
||||
|
||||
/// Set quantization options.
|
||||
/// @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.
|
||||
void InputOptions::setQuantization(bool colorDithering, bool alphaDithering, bool binaryAlpha, int alphaThreshold/*= 127*/)
|
||||
{
|
||||
m.enableColorDithering = colorDithering;
|
||||
m.enableAlphaDithering = alphaDithering;
|
||||
m.binaryAlpha = binaryAlpha;
|
||||
m.alphaThreshold = alphaThreshold;
|
||||
}
|
||||
|
||||
|
||||
/// Enable normal map conversion.
|
||||
void InputOptions::setConvertToNormalMap(bool convert)
|
||||
{
|
||||
m.convertToNormalMap = convert;
|
||||
}
|
||||
|
||||
/// Set height evaluation factors.
|
||||
void InputOptions::setHeightEvaluation(float redScale, float greenScale, float blueScale, float alphaScale)
|
||||
{
|
||||
// Do not normalize height factors.
|
||||
// float total = redScale + greenScale + blueScale + alphaScale;
|
||||
m.heightFactors = Vector4(redScale, greenScale, blueScale, alphaScale);
|
||||
}
|
||||
|
||||
/// Set normal map conversion filter.
|
||||
void InputOptions::setNormalFilter(float small, float medium, float big, float large)
|
||||
{
|
||||
float total = small + medium + big + large;
|
||||
m.bumpFrequencyScale = Vector4(small, medium, big, large) / total;
|
||||
}
|
||||
|
||||
/// Enable mipmap normalization.
|
||||
void InputOptions::setNormalizeMipmaps(bool normalize)
|
||||
{
|
||||
m.normalizeMipmaps = normalize;
|
||||
}
|
||||
|
@ -1,24 +1,24 @@
|
||||
// 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
|
||||
// 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 NV_TT_INPUTOPTIONS_H
|
||||
|
@ -1,32 +1,32 @@
|
||||
// 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 "nvtt.h"
|
||||
|
||||
using namespace nvtt;
|
||||
|
||||
/// Set default output options.
|
||||
void OutputOptions::reset()
|
||||
{
|
||||
// endiannes = native...
|
||||
}
|
||||
// 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 "nvtt.h"
|
||||
|
||||
using namespace nvtt;
|
||||
|
||||
/// Set default output options.
|
||||
void OutputOptions::reset()
|
||||
{
|
||||
// endiannes = native...
|
||||
}
|
||||
|
@ -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
|
@ -28,7 +28,7 @@
|
||||
|
||||
#include "CudaMath.h"
|
||||
|
||||
#define THREAD_NUM 64 // Number of threads per block.
|
||||
#define NUM_THREADS 64 // Number of threads per block.
|
||||
|
||||
#if __DEVICE_EMULATION__
|
||||
#define __debugsync() __syncthreads()
|
||||
@ -94,7 +94,6 @@ static __device__ float evalPermutation4(const float3 * colors, uint permutation
|
||||
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);
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
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
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
__device__ void sortColors(float * values, float3 * colors, int * xrefs)
|
||||
{
|
||||
#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)
|
||||
__device__ void sortColors(float * values, float3 * colors, int * cmp)
|
||||
{
|
||||
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[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;
|
||||
}
|
||||
|
||||
__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__
|
||||
|
||||
for(int d = THREAD_NUM/2; d > 0; d >>= 1)
|
||||
for(int d = NUM_THREADS/2; d > 0; d >>= 1)
|
||||
{
|
||||
__syncthreads();
|
||||
|
||||
@ -287,7 +349,7 @@ __device__ void minimizeError(float * errors, int * indices)
|
||||
|
||||
#else
|
||||
|
||||
for(int d = THREAD_NUM/2; d > 32; d >>= 1)
|
||||
for(int d = NUM_THREADS/2; d > 32; d >>= 1)
|
||||
{
|
||||
__syncthreads();
|
||||
|
||||
@ -295,7 +357,7 @@ __device__ void minimizeError(float * errors, int * indices)
|
||||
{
|
||||
float err0 = errors[idx];
|
||||
float err1 = errors[idx + d];
|
||||
|
||||
|
||||
if (err1 < err0) {
|
||||
errors[idx] = err1;
|
||||
indices[idx] = indices[idx + d];
|
||||
@ -338,7 +400,7 @@ __device__ void minimizeError(float * errors, int * indices)
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// 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 idx = threadIdx.x;
|
||||
@ -349,19 +411,14 @@ __global__ void compress(const uint * permutations, const uint * image, uint * r
|
||||
|
||||
if (idx < 16)
|
||||
{
|
||||
// Read color.
|
||||
// Read color and copy to shared mem.
|
||||
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].y = ((c >> 8) & 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__
|
||||
} __debugsync(); if (idx < 16) {
|
||||
#endif
|
||||
@ -383,15 +440,66 @@ __global__ void compress(const uint * permutations, const uint * image, uint * r
|
||||
float bestError = FLT_MAX;
|
||||
|
||||
__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;
|
||||
uint permutation = permutations[idx + THREAD_NUM * i];
|
||||
uint permutation = permutations[pidx];
|
||||
float error = evalPermutation4(colors, permutation, &start, &end);
|
||||
|
||||
|
||||
if (error < bestError)
|
||||
{
|
||||
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)
|
||||
{
|
||||
swap(bestEnd, bestStart);
|
||||
bestPermutation ^= 0x55555555; // Flip indices.
|
||||
bestPermutation ^= 0x55555555; // Flip indices.
|
||||
}
|
||||
|
||||
for(int i = 0; i < 3; i++)
|
||||
{
|
||||
if (i == 2 && idx >= 32) break;
|
||||
|
||||
ushort start, end;
|
||||
uint permutation = permutations[idx + THREAD_NUM * i];
|
||||
float error = evalPermutation3(colors, permutation, &start, &end);
|
||||
|
||||
if (error < bestError)
|
||||
{
|
||||
bestError = error;
|
||||
bestPermutation = permutation;
|
||||
bestStart = start;
|
||||
bestEnd = end;
|
||||
|
||||
if (bestStart > bestEnd)
|
||||
|
||||
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.
|
||||
}
|
||||
}
|
||||
|
||||
error = evalPermutation4(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.
|
||||
bestPermutation ^= 0x55555555; // Flip indices.
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (bestStart == bestEnd)
|
||||
{
|
||||
bestPermutation = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
__syncthreads();
|
||||
|
||||
// Use a parallel reduction to find minimum error.
|
||||
__shared__ float errors[THREAD_NUM];
|
||||
__shared__ int indices[THREAD_NUM];
|
||||
__shared__ float errors[NUM_THREADS];
|
||||
__shared__ int indices[NUM_THREADS];
|
||||
|
||||
errors[idx] = bestError;
|
||||
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.
|
||||
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 * i)) & 3) << (2 * ref);
|
||||
perm |= ((bestPermutation >> (2 * ref)) & 3) << (2 * i);
|
||||
}
|
||||
|
||||
// Write endpoints. (bestStart, bestEnd)
|
||||
result[2 * bid + 0] = (bestEnd << 16) | bestStart;
|
||||
result[bid].x = (bestEnd << 16) | bestStart;
|
||||
|
||||
// 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
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
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);
|
||||
}
|
||||
|
74
src/nvimage/nvtt/cuda/ConvolveKernel.cu
Normal file
74
src/nvimage/nvtt/cuda/ConvolveKernel.cu
Normal 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
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
|
||||
|
||||
|
@ -24,7 +24,10 @@
|
||||
#include <nvcore/Debug.h>
|
||||
#include <nvcore/Containers.h>
|
||||
#include <nvmath/Color.h>
|
||||
#include <nvmath/Fitting.h>
|
||||
#include <nvimage/Image.h>
|
||||
#include <nvimage/ColorBlock.h>
|
||||
#include <nvimage/BlockDXT.h>
|
||||
#include <nvimage/nvtt/CompressionOptions.h>
|
||||
|
||||
#include "CudaCompressDXT.h"
|
||||
@ -34,13 +37,17 @@
|
||||
#include <cuda_runtime.h>
|
||||
#endif
|
||||
|
||||
#include <time.h>
|
||||
#include <stdio.h>
|
||||
|
||||
using namespace nv;
|
||||
using namespace nvtt;
|
||||
|
||||
#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;
|
||||
|
||||
@ -86,7 +93,7 @@ static void doPrecomputation()
|
||||
}
|
||||
|
||||
bitmaps[num] = bitmap;
|
||||
|
||||
|
||||
num++;
|
||||
}
|
||||
}
|
||||
@ -95,7 +102,7 @@ static void doPrecomputation()
|
||||
// Align to 160.
|
||||
for(int i = 0; i < 9; i++)
|
||||
{
|
||||
bitmaps[num] = 0x000AA555;
|
||||
bitmaps[num] = 0x555AA000;
|
||||
num++;
|
||||
}
|
||||
nvDebugCheck(num == 160);
|
||||
@ -153,25 +160,35 @@ static void doPrecomputation()
|
||||
// Align to 1024.
|
||||
for(int i = 0; i < 49; i++)
|
||||
{
|
||||
bitmaps[num] = 0x00AAFF55;
|
||||
bitmaps[num] = 0x555AA000;
|
||||
num++;
|
||||
}
|
||||
|
||||
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.
|
||||
cudaMalloc((void**) &d_bitmaps, 1024 * sizeof(uint));
|
||||
cudaMemcpy(d_bitmaps, bitmaps, 1024 * sizeof(uint), cudaMemcpyHostToDevice);
|
||||
|
||||
// @@ Check for errors.
|
||||
|
||||
// @@ Free allocated memory.
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
/// 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());
|
||||
#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);
|
||||
|
||||
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;
|
||||
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;
|
||||
cudaMalloc((void**) &d_result, min(compressedSize, blockMax * 8U));
|
||||
|
||||
setupCompressKernel(compressionOptions.colorWeight.ptr());
|
||||
|
||||
clock_t start = clock();
|
||||
|
||||
// TODO: Add support for multiple GPUs.
|
||||
uint bn = 0;
|
||||
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);
|
||||
|
||||
// Launch kernel.
|
||||
float weights[3];
|
||||
weights[0] = compressionOptions.colorWeight.x();
|
||||
weights[1] = compressionOptions.colorWeight.y();
|
||||
weights[2] = compressionOptions.colorWeight.z();
|
||||
compressKernel(count, d_data, d_result, d_bitmaps, weights);
|
||||
compressKernel(count, d_data, d_result, d_bitmaps);
|
||||
|
||||
// Check for errors.
|
||||
cudaError_t err = cudaGetLastError();
|
||||
@ -234,7 +251,7 @@ void nv::cudaCompressDXT1(const Image * image, const OutputOptions & outputOptio
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
clock_t end = clock();
|
||||
printf("\rCUDA time taken: %.3f seconds\n", float(end-start) / CLOCKS_PER_SEC);
|
||||
|
||||
free(blockLinearImage);
|
||||
cudaFree(d_data);
|
||||
cudaFree(d_result);
|
||||
@ -262,3 +282,189 @@ void nv::cudaCompressDXT1(const Image * image, const OutputOptions & outputOptio
|
||||
#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
|
||||
}
|
||||
|
||||
|
||||
|
@ -32,7 +32,8 @@ namespace nv
|
||||
class Image;
|
||||
|
||||
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
|
||||
|
||||
|
||||
|
@ -111,7 +111,7 @@ inline __device__ __host__ float3 clamp(float3 v, float3 a, float3 b)
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
|
@ -73,8 +73,12 @@ static bool isWow32()
|
||||
bool nv::cuda::isHardwarePresent()
|
||||
{
|
||||
#if defined HAVE_CUDA
|
||||
#if NV_OS_WIN32
|
||||
return !isWindowsVista() && deviceCount() > 0;
|
||||
//return !isWindowsVista() && isWow32() && deviceCount() > 0;
|
||||
#else
|
||||
return deviceCount() > 0;
|
||||
#endif
|
||||
#else
|
||||
return false;
|
||||
#endif
|
||||
|
@ -1,486 +1,485 @@
|
||||
// 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 <nvcore/Memory.h>
|
||||
#include <nvcore/Ptr.h>
|
||||
|
||||
#include <nvimage/DirectDrawSurface.h>
|
||||
#include <nvimage/ColorBlock.h>
|
||||
#include <nvimage/Image.h>
|
||||
#include <nvimage/FloatImage.h>
|
||||
#include <nvimage/Filter.h>
|
||||
#include <nvimage/Quantize.h>
|
||||
#include <nvimage/NormalMap.h>
|
||||
|
||||
#include "CompressDXT.h"
|
||||
#include "FastCompressDXT.h"
|
||||
#include "CompressRGB.h"
|
||||
#include "BlockDXT.h"
|
||||
#include "InputOptions.h"
|
||||
#include "CompressionOptions.h"
|
||||
#include "cuda/CudaUtils.h"
|
||||
#include "cuda/CudaCompressDXT.h"
|
||||
|
||||
|
||||
using namespace nv;
|
||||
using namespace nvtt;
|
||||
|
||||
namespace
|
||||
{
|
||||
|
||||
static int blockSize(Format format)
|
||||
{
|
||||
if (format == Format_DXT1 /*|| format == Format_DXT1a*/) {
|
||||
return 8;
|
||||
}
|
||||
else if (format == Format_DXT3) {
|
||||
return 16;
|
||||
}
|
||||
else if (format == Format_DXT5 || format == Format_DXT5n) {
|
||||
return 16;
|
||||
}
|
||||
else if (format == Format_BC4) {
|
||||
return 8;
|
||||
}
|
||||
else if (format == Format_BC5) {
|
||||
return 16;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int computeImageSize(int w, int h, Format format)
|
||||
{
|
||||
if (format == Format_RGBA) {
|
||||
return w * h * sizeof(Color32);
|
||||
}
|
||||
else {
|
||||
return ((w + 3) / 4) * ((h + 3) / 4) * blockSize(format);
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
//
|
||||
// compress
|
||||
//
|
||||
|
||||
static void outputHeader(const InputOptions::Private & inputOptions, const OutputOptions & outputOptions, const CompressionOptions::Private & compressionOptions)
|
||||
{
|
||||
// Output DDS header.
|
||||
if (outputOptions.outputHandler != NULL && outputOptions.outputHeader)
|
||||
{
|
||||
DDSHeader header;
|
||||
|
||||
// Only 1 face and 2d textures supported.
|
||||
nvCheck(inputOptions.faceCount == 1);
|
||||
|
||||
InputOptions::Private::Image * img = inputOptions.images;
|
||||
nvCheck(img != NULL);
|
||||
|
||||
header.setWidth(img->width);
|
||||
header.setHeight(img->height);
|
||||
|
||||
int mipmapCount = inputOptions.mipmapCount;
|
||||
if (!inputOptions.generateMipmaps) mipmapCount = 0;
|
||||
else if (inputOptions.maxLevel != -1 && inputOptions.maxLevel < mipmapCount) mipmapCount = inputOptions.maxLevel;
|
||||
header.setMipmapCount(mipmapCount);
|
||||
|
||||
if (inputOptions.textureType == TextureType_2D) {
|
||||
header.setTexture2D();
|
||||
}
|
||||
else if (inputOptions.textureType == TextureType_Cube) {
|
||||
header.setTextureCube();
|
||||
}
|
||||
/*else if (inputOptions.textureType == TextureType_3D) {
|
||||
header.setTexture3D();
|
||||
header.setDepth(img->depth);
|
||||
}*/
|
||||
|
||||
if (compressionOptions.format == Format_RGBA)
|
||||
{
|
||||
header.setPitch(4 * img->width);
|
||||
header.setPixelFormat(compressionOptions.bitcount, compressionOptions.rmask, compressionOptions.gmask, compressionOptions.bmask, compressionOptions.amask);
|
||||
}
|
||||
else
|
||||
{
|
||||
header.setLinearSize(computeImageSize(img->width, img->height, compressionOptions.format));
|
||||
|
||||
if (compressionOptions.format == Format_DXT1 /*|| compressionOptions.format == Format_DXT1a*/) {
|
||||
header.setFourCC('D', 'X', 'T', '1');
|
||||
}
|
||||
else if (compressionOptions.format == Format_DXT3) {
|
||||
header.setFourCC('D', 'X', 'T', '3');
|
||||
}
|
||||
else if (compressionOptions.format == Format_DXT5) {
|
||||
header.setFourCC('D', 'X', 'T', '5');
|
||||
}
|
||||
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_BC5) {
|
||||
header.setFourCC('A', 'T', 'I', '2');
|
||||
}
|
||||
}
|
||||
|
||||
// Swap bytes if necessary.
|
||||
header.swapBytes();
|
||||
|
||||
nvStaticCheck(sizeof(DDSHeader) == 128);
|
||||
outputOptions.outputHandler->writeData(&header, 128);
|
||||
|
||||
// Revert swap.
|
||||
header.swapBytes();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static bool compressMipmap(const Image * image, const OutputOptions & outputOptions, const CompressionOptions::Private & compressionOptions)
|
||||
{
|
||||
nvDebugCheck(image != NULL);
|
||||
|
||||
if (compressionOptions.format == Format_RGBA || compressionOptions.format == Format_RGB)
|
||||
{
|
||||
compressRGB(image, outputOptions, compressionOptions);
|
||||
}
|
||||
else if (compressionOptions.format == Format_DXT1)
|
||||
{
|
||||
#if defined(HAVE_S3QUANT)
|
||||
if (compressionOptions.externalCompressor == "s3")
|
||||
{
|
||||
s3CompressDXT1(image, outputOptions);
|
||||
}
|
||||
else
|
||||
#endif
|
||||
|
||||
#if defined(HAVE_ATITC)
|
||||
if (compressionOptions.externalCompressor == "ati")
|
||||
{
|
||||
printf("ATI\n");
|
||||
atiCompressDXT1(image, outputOptions);
|
||||
}
|
||||
else
|
||||
#endif
|
||||
if (compressionOptions.useCuda && nv::cuda::isHardwarePresent())
|
||||
{
|
||||
cudaCompressDXT1(image, outputOptions, compressionOptions);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (compressionOptions.quality == Quality_Fastest)
|
||||
{
|
||||
fastCompressDXT1(image, outputOptions);
|
||||
}
|
||||
else
|
||||
{
|
||||
compressDXT1(image, outputOptions, compressionOptions);
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (compressionOptions.format == Format_DXT3)
|
||||
{
|
||||
if (compressionOptions.quality == Quality_Fastest)
|
||||
{
|
||||
fastCompressDXT3(image, outputOptions);
|
||||
}
|
||||
else
|
||||
{
|
||||
compressDXT3(image, outputOptions, compressionOptions);
|
||||
}
|
||||
}
|
||||
else if (compressionOptions.format == Format_DXT5)
|
||||
{
|
||||
if (compressionOptions.quality == Quality_Fastest)
|
||||
{
|
||||
fastCompressDXT5(image, outputOptions);
|
||||
}
|
||||
else
|
||||
{
|
||||
compressDXT5(image, outputOptions, compressionOptions);
|
||||
}
|
||||
}
|
||||
else if (compressionOptions.format == Format_DXT5n)
|
||||
{
|
||||
if (compressionOptions.quality == Quality_Fastest)
|
||||
{
|
||||
fastCompressDXT5n(image, outputOptions);
|
||||
}
|
||||
else
|
||||
{
|
||||
compressDXT5n(image, outputOptions, compressionOptions);
|
||||
}
|
||||
}
|
||||
else if (compressionOptions.format == Format_BC4)
|
||||
{
|
||||
compressBC4(image, outputOptions, compressionOptions);
|
||||
}
|
||||
else if (compressionOptions.format == Format_BC5)
|
||||
{
|
||||
compressBC5(image, outputOptions, compressionOptions);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
// Convert input image to linear float image.
|
||||
static FloatImage * toFloatImage(const Image * image, const InputOptions::Private & inputOptions)
|
||||
{
|
||||
nvDebugCheck(image != NULL);
|
||||
|
||||
FloatImage * floatImage = new FloatImage(image);
|
||||
|
||||
// Convert to linear space.
|
||||
if (inputOptions.inputGamma != 1.0f) {
|
||||
floatImage->toLinear(0, 3, inputOptions.inputGamma);
|
||||
}
|
||||
|
||||
return floatImage;
|
||||
}
|
||||
|
||||
|
||||
// Convert linear float image to output image.
|
||||
static Image * toFixedImage(const FloatImage * floatImage, const InputOptions::Private & inputOptions)
|
||||
{
|
||||
nvDebugCheck(floatImage != NULL);
|
||||
|
||||
return floatImage->createImageGammaCorrect(inputOptions.outputGamma);
|
||||
}
|
||||
|
||||
|
||||
// Create mipmap from the given image.
|
||||
static FloatImage * createMipmap(const FloatImage * floatImage, const InputOptions::Private & inputOptions)
|
||||
{
|
||||
FloatImage * result = NULL;
|
||||
|
||||
if (inputOptions.mipmapFilter == MipmapFilter_Box)
|
||||
{
|
||||
// Use fast downsample.
|
||||
result = floatImage->fastDownSample();
|
||||
}
|
||||
else if (inputOptions.mipmapFilter == MipmapFilter_Triangle)
|
||||
{
|
||||
Kernel1 kernel(4);
|
||||
kernel.initFilter(Filter::Triangle);
|
||||
result = floatImage->downSample(kernel, (FloatImage::WrapMode)inputOptions.wrapMode);
|
||||
}
|
||||
else /*if (inputOptions.mipmapFilter == MipmapFilter_Kaiser)*/
|
||||
{
|
||||
Kernel1 kernel(10);
|
||||
kernel.initKaiser(8.0, 0.75f);
|
||||
result = floatImage->downSample(kernel, (FloatImage::WrapMode)inputOptions.wrapMode);
|
||||
}
|
||||
|
||||
// Normalize mipmap.
|
||||
if (inputOptions.normalizeMipmaps)
|
||||
{
|
||||
normalize(result);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
// Quantize the input image to the precision of the output format.
|
||||
static void quantize(Image * img, const InputOptions::Private & inputOptions, Format format)
|
||||
{
|
||||
if (inputOptions.enableColorDithering)
|
||||
{
|
||||
if (format >= Format_DXT1 && format <= Format_DXT5)
|
||||
{
|
||||
Quantize::FloydSteinberg_RGB16(img);
|
||||
}
|
||||
}
|
||||
if (inputOptions.binaryAlpha)
|
||||
{
|
||||
if (inputOptions.enableAlphaDithering)
|
||||
{
|
||||
Quantize::FloydSteinberg_BinaryAlpha(img, inputOptions.alphaThreshold);
|
||||
}
|
||||
else
|
||||
{
|
||||
Quantize::BinaryAlpha(img, inputOptions.alphaThreshold);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (inputOptions.enableAlphaDithering)
|
||||
{
|
||||
if (format == Format_DXT3)
|
||||
{
|
||||
Quantize::Alpha4(img);
|
||||
}
|
||||
/*else if (format == Format_DXT1a)
|
||||
{
|
||||
Quantize::BinaryAlpha(img, inputOptions.alphaThreshold);
|
||||
}*/
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/// Compress the input texture with the given compression options.
|
||||
bool nvtt::compress(const InputOptions & inputOptions, const OutputOptions & outputOptions, const CompressionOptions & compressionOptions)
|
||||
{
|
||||
// Make sure enums match.
|
||||
nvStaticCheck(FloatImage::WrapMode_Clamp == (FloatImage::WrapMode)WrapMode_Clamp);
|
||||
nvStaticCheck(FloatImage::WrapMode_Mirror == (FloatImage::WrapMode)WrapMode_Mirror);
|
||||
nvStaticCheck(FloatImage::WrapMode_Repeat == (FloatImage::WrapMode)WrapMode_Repeat);
|
||||
|
||||
// Output DDS header.
|
||||
outputHeader(inputOptions.m, outputOptions, compressionOptions.m);
|
||||
|
||||
Format format = compressionOptions.m.format;
|
||||
|
||||
for (int f = 0; f < inputOptions.m.faceCount; f++)
|
||||
{
|
||||
Image * lastImage = NULL;
|
||||
AutoPtr<FloatImage> floatImage(NULL);
|
||||
|
||||
for (int m = 0; m < inputOptions.m.mipmapCount; m++)
|
||||
{
|
||||
int idx = f * inputOptions.m.mipmapCount + m;
|
||||
InputOptions::Private::Image & mipmap = inputOptions.m.images[idx];
|
||||
|
||||
if (outputOptions.outputHandler)
|
||||
{
|
||||
int size = computeImageSize(mipmap.width, mipmap.height, format);
|
||||
outputOptions.outputHandler->mipmap(size, mipmap.width, mipmap.height, mipmap.depth, mipmap.face, mipmap.mipLevel);
|
||||
}
|
||||
|
||||
Image * img; // Image to compress.
|
||||
|
||||
if (mipmap.data != NULL) // Mipmap provided.
|
||||
{
|
||||
// Convert to normal map.
|
||||
if (inputOptions.m.convertToNormalMap)
|
||||
{
|
||||
floatImage = createNormalMap(mipmap.data, (FloatImage::WrapMode)inputOptions.m.wrapMode, inputOptions.m.heightFactors, inputOptions.m.bumpFrequencyScale);
|
||||
}
|
||||
else
|
||||
{
|
||||
lastImage = img = mipmap.data;
|
||||
|
||||
// Delete float image.
|
||||
floatImage = NULL;
|
||||
}
|
||||
}
|
||||
else // Create mipmap from last.
|
||||
{
|
||||
if (m == 0) {
|
||||
// First mipmap missing.
|
||||
if (outputOptions.errorHandler != NULL) outputOptions.errorHandler->error(Error_InvalidInput);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (floatImage == NULL)
|
||||
{
|
||||
nvDebugCheck(lastImage != NULL);
|
||||
floatImage = toFloatImage(lastImage, inputOptions.m);
|
||||
}
|
||||
|
||||
// Create mipmap.
|
||||
floatImage = createMipmap(floatImage.ptr(), inputOptions.m);
|
||||
}
|
||||
|
||||
if (floatImage != NULL)
|
||||
{
|
||||
// Convert to fixed.
|
||||
img = toFixedImage(floatImage.ptr(), inputOptions.m);
|
||||
}
|
||||
|
||||
quantize(img, inputOptions.m, format);
|
||||
|
||||
compressMipmap(img, outputOptions, compressionOptions.m);
|
||||
|
||||
if (img != mipmap.data)
|
||||
{
|
||||
delete img;
|
||||
}
|
||||
|
||||
if (!inputOptions.m.generateMipmaps || (inputOptions.m.maxLevel >= 0 && m >= inputOptions.m.maxLevel)) {
|
||||
// continue with next face.
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
/// Estimate the size of compressing the input with the given options.
|
||||
int nvtt::estimateSize(const InputOptions & inputOptions, const CompressionOptions & compressionOptions)
|
||||
{
|
||||
Format format = compressionOptions.m.format;
|
||||
|
||||
int size = 0;
|
||||
|
||||
for (int f = 0; f < inputOptions.m.faceCount; f++)
|
||||
{
|
||||
for (int m = 0; m < inputOptions.m.mipmapCount; m++)
|
||||
{
|
||||
int idx = f * inputOptions.m.mipmapCount + m;
|
||||
const InputOptions::Private::Image & img = inputOptions.m.images[idx];
|
||||
|
||||
size += computeImageSize(img.width, img.height, format);
|
||||
|
||||
if (!inputOptions.m.generateMipmaps || (inputOptions.m.maxLevel >= 0 && m >= inputOptions.m.maxLevel)) {
|
||||
// continue with next face.
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return size;
|
||||
}
|
||||
|
||||
|
||||
/// Return a string for the given error.
|
||||
const char * nvtt::errorString(Error e)
|
||||
{
|
||||
switch(e)
|
||||
{
|
||||
case Error_InvalidInput:
|
||||
return "Invalid input";
|
||||
case Error_UserInterruption:
|
||||
return "User interruption";
|
||||
case Error_UnsupportedFeature:
|
||||
return "Unsupported feature";
|
||||
case Error_CudaError:
|
||||
return "CUDA error";
|
||||
case Error_Unknown:
|
||||
return "Unknown error";
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// 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 <nvcore/Memory.h>
|
||||
#include <nvcore/Ptr.h>
|
||||
|
||||
#include <nvimage/DirectDrawSurface.h>
|
||||
#include <nvimage/ColorBlock.h>
|
||||
#include <nvimage/BlockDXT.h>
|
||||
#include <nvimage/Image.h>
|
||||
#include <nvimage/FloatImage.h>
|
||||
#include <nvimage/Filter.h>
|
||||
#include <nvimage/Quantize.h>
|
||||
#include <nvimage/NormalMap.h>
|
||||
|
||||
#include "CompressDXT.h"
|
||||
#include "FastCompressDXT.h"
|
||||
#include "CompressRGB.h"
|
||||
#include "InputOptions.h"
|
||||
#include "CompressionOptions.h"
|
||||
#include "cuda/CudaUtils.h"
|
||||
#include "cuda/CudaCompressDXT.h"
|
||||
|
||||
|
||||
using namespace nv;
|
||||
using namespace nvtt;
|
||||
|
||||
namespace
|
||||
{
|
||||
|
||||
static int blockSize(Format format)
|
||||
{
|
||||
if (format == Format_DXT1 /*|| format == Format_DXT1a*/) {
|
||||
return 8;
|
||||
}
|
||||
else if (format == Format_DXT3) {
|
||||
return 16;
|
||||
}
|
||||
else if (format == Format_DXT5 || format == Format_DXT5n) {
|
||||
return 16;
|
||||
}
|
||||
else if (format == Format_BC4) {
|
||||
return 8;
|
||||
}
|
||||
else if (format == Format_BC5) {
|
||||
return 16;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int computeImageSize(int w, int h, Format format)
|
||||
{
|
||||
if (format == Format_RGBA) {
|
||||
return w * h * sizeof(Color32);
|
||||
}
|
||||
else {
|
||||
return ((w + 3) / 4) * ((h + 3) / 4) * blockSize(format);
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
//
|
||||
// compress
|
||||
//
|
||||
|
||||
static void outputHeader(const InputOptions::Private & inputOptions, const OutputOptions & outputOptions, const CompressionOptions::Private & compressionOptions)
|
||||
{
|
||||
// Output DDS header.
|
||||
if (outputOptions.outputHandler != NULL && outputOptions.outputHeader)
|
||||
{
|
||||
DDSHeader header;
|
||||
|
||||
InputOptions::Private::Image * img = inputOptions.images;
|
||||
nvCheck(img != NULL);
|
||||
|
||||
header.setWidth(img->width);
|
||||
header.setHeight(img->height);
|
||||
|
||||
int mipmapCount = inputOptions.mipmapCount;
|
||||
if (!inputOptions.generateMipmaps) mipmapCount = 0;
|
||||
else if (inputOptions.maxLevel != -1 && inputOptions.maxLevel < mipmapCount) mipmapCount = inputOptions.maxLevel;
|
||||
header.setMipmapCount(mipmapCount);
|
||||
|
||||
if (inputOptions.textureType == TextureType_2D) {
|
||||
header.setTexture2D();
|
||||
}
|
||||
else if (inputOptions.textureType == TextureType_Cube) {
|
||||
header.setTextureCube();
|
||||
}
|
||||
/*else if (inputOptions.textureType == TextureType_3D) {
|
||||
header.setTexture3D();
|
||||
header.setDepth(img->depth);
|
||||
}*/
|
||||
|
||||
if (compressionOptions.format == Format_RGBA)
|
||||
{
|
||||
header.setPitch(4 * img->width);
|
||||
header.setPixelFormat(compressionOptions.bitcount, compressionOptions.rmask, compressionOptions.gmask, compressionOptions.bmask, compressionOptions.amask);
|
||||
}
|
||||
else
|
||||
{
|
||||
header.setLinearSize(computeImageSize(img->width, img->height, compressionOptions.format));
|
||||
|
||||
if (compressionOptions.format == Format_DXT1 /*|| compressionOptions.format == Format_DXT1a*/) {
|
||||
header.setFourCC('D', 'X', 'T', '1');
|
||||
}
|
||||
else if (compressionOptions.format == Format_DXT3) {
|
||||
header.setFourCC('D', 'X', 'T', '3');
|
||||
}
|
||||
else if (compressionOptions.format == Format_DXT5) {
|
||||
header.setFourCC('D', 'X', 'T', '5');
|
||||
}
|
||||
else if (compressionOptions.format == Format_DXT5n) {
|
||||
header.setFourCC('D', 'X', 'T', '5');
|
||||
header.setNormalFlag(true);
|
||||
}
|
||||
else if (compressionOptions.format == Format_BC4) {
|
||||
header.setFourCC('A', 'T', 'I', '1');
|
||||
}
|
||||
else if (compressionOptions.format == Format_BC5) {
|
||||
header.setFourCC('A', 'T', 'I', '2');
|
||||
header.setNormalFlag(true);
|
||||
}
|
||||
}
|
||||
|
||||
// Swap bytes if necessary.
|
||||
header.swapBytes();
|
||||
|
||||
nvStaticCheck(sizeof(DDSHeader) == 128);
|
||||
outputOptions.outputHandler->writeData(&header, 128);
|
||||
|
||||
// Revert swap.
|
||||
header.swapBytes();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static bool compressMipmap(const Image * image, const OutputOptions & outputOptions, const CompressionOptions::Private & compressionOptions)
|
||||
{
|
||||
nvDebugCheck(image != NULL);
|
||||
|
||||
if (compressionOptions.format == Format_RGBA || compressionOptions.format == Format_RGB)
|
||||
{
|
||||
compressRGB(image, outputOptions, compressionOptions);
|
||||
}
|
||||
else if (compressionOptions.format == Format_DXT1)
|
||||
{
|
||||
#if defined(HAVE_S3QUANT)
|
||||
if (compressionOptions.externalCompressor == "s3")
|
||||
{
|
||||
s3CompressDXT1(image, outputOptions);
|
||||
}
|
||||
else
|
||||
#endif
|
||||
|
||||
#if defined(HAVE_ATITC)
|
||||
if (compressionOptions.externalCompressor == "ati")
|
||||
{
|
||||
printf("ATI\n");
|
||||
atiCompressDXT1(image, outputOptions);
|
||||
}
|
||||
else
|
||||
#endif
|
||||
if (compressionOptions.useCuda && nv::cuda::isHardwarePresent())
|
||||
{
|
||||
cudaCompressDXT1(image, outputOptions, compressionOptions);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (compressionOptions.quality == Quality_Fastest)
|
||||
{
|
||||
fastCompressDXT1(image, outputOptions);
|
||||
}
|
||||
else
|
||||
{
|
||||
compressDXT1(image, outputOptions, compressionOptions);
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (compressionOptions.format == Format_DXT3)
|
||||
{
|
||||
if (compressionOptions.quality == Quality_Fastest)
|
||||
{
|
||||
fastCompressDXT3(image, outputOptions);
|
||||
}
|
||||
else
|
||||
{
|
||||
compressDXT3(image, outputOptions, compressionOptions);
|
||||
}
|
||||
}
|
||||
else if (compressionOptions.format == Format_DXT5)
|
||||
{
|
||||
if (compressionOptions.quality == Quality_Fastest)
|
||||
{
|
||||
fastCompressDXT5(image, outputOptions);
|
||||
}
|
||||
else
|
||||
{
|
||||
compressDXT5(image, outputOptions, compressionOptions);
|
||||
}
|
||||
}
|
||||
else if (compressionOptions.format == Format_DXT5n)
|
||||
{
|
||||
if (compressionOptions.quality == Quality_Fastest)
|
||||
{
|
||||
fastCompressDXT5n(image, outputOptions);
|
||||
}
|
||||
else
|
||||
{
|
||||
compressDXT5n(image, outputOptions, compressionOptions);
|
||||
}
|
||||
}
|
||||
else if (compressionOptions.format == Format_BC4)
|
||||
{
|
||||
compressBC4(image, outputOptions, compressionOptions);
|
||||
}
|
||||
else if (compressionOptions.format == Format_BC5)
|
||||
{
|
||||
compressBC5(image, outputOptions, compressionOptions);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
// Convert input image to linear float image.
|
||||
static FloatImage * toFloatImage(const Image * image, const InputOptions::Private & inputOptions)
|
||||
{
|
||||
nvDebugCheck(image != NULL);
|
||||
|
||||
FloatImage * floatImage = new FloatImage(image);
|
||||
|
||||
// Convert to linear space.
|
||||
if (inputOptions.inputGamma != 1.0f) {
|
||||
floatImage->toLinear(0, 3, inputOptions.inputGamma);
|
||||
}
|
||||
|
||||
return floatImage;
|
||||
}
|
||||
|
||||
|
||||
// Convert linear float image to output image.
|
||||
static Image * toFixedImage(const FloatImage * floatImage, const InputOptions::Private & inputOptions)
|
||||
{
|
||||
nvDebugCheck(floatImage != NULL);
|
||||
|
||||
return floatImage->createImageGammaCorrect(inputOptions.outputGamma);
|
||||
}
|
||||
|
||||
|
||||
// Create mipmap from the given image.
|
||||
static FloatImage * createMipmap(const FloatImage * floatImage, const InputOptions::Private & inputOptions)
|
||||
{
|
||||
FloatImage * result = NULL;
|
||||
|
||||
if (inputOptions.mipmapFilter == MipmapFilter_Box)
|
||||
{
|
||||
// Use fast downsample.
|
||||
result = floatImage->fastDownSample();
|
||||
}
|
||||
else if (inputOptions.mipmapFilter == MipmapFilter_Triangle)
|
||||
{
|
||||
Kernel1 kernel(4);
|
||||
kernel.initFilter(Filter::Triangle);
|
||||
result = floatImage->downSample(kernel, (FloatImage::WrapMode)inputOptions.wrapMode);
|
||||
}
|
||||
else /*if (inputOptions.mipmapFilter == MipmapFilter_Kaiser)*/
|
||||
{
|
||||
Kernel1 kernel(10);
|
||||
kernel.initKaiser(8.0, 0.75f);
|
||||
result = floatImage->downSample(kernel, (FloatImage::WrapMode)inputOptions.wrapMode);
|
||||
}
|
||||
|
||||
// Normalize mipmap.
|
||||
if (inputOptions.normalizeMipmaps)
|
||||
{
|
||||
normalize(result);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
// Quantize the input image to the precision of the output format.
|
||||
static void quantize(Image * img, const InputOptions::Private & inputOptions, Format format)
|
||||
{
|
||||
if (inputOptions.enableColorDithering)
|
||||
{
|
||||
if (format >= Format_DXT1 && format <= Format_DXT5)
|
||||
{
|
||||
Quantize::FloydSteinberg_RGB16(img);
|
||||
}
|
||||
}
|
||||
if (inputOptions.binaryAlpha)
|
||||
{
|
||||
if (inputOptions.enableAlphaDithering)
|
||||
{
|
||||
Quantize::FloydSteinberg_BinaryAlpha(img, inputOptions.alphaThreshold);
|
||||
}
|
||||
else
|
||||
{
|
||||
Quantize::BinaryAlpha(img, inputOptions.alphaThreshold);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (inputOptions.enableAlphaDithering)
|
||||
{
|
||||
if (format == Format_DXT3)
|
||||
{
|
||||
Quantize::Alpha4(img);
|
||||
}
|
||||
/*else if (format == Format_DXT1a)
|
||||
{
|
||||
Quantize::BinaryAlpha(img, inputOptions.alphaThreshold);
|
||||
}*/
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/// Compress the input texture with the given compression options.
|
||||
bool nvtt::compress(const InputOptions & inputOptions, const OutputOptions & outputOptions, const CompressionOptions & compressionOptions)
|
||||
{
|
||||
// Make sure enums match.
|
||||
nvStaticCheck(FloatImage::WrapMode_Clamp == (FloatImage::WrapMode)WrapMode_Clamp);
|
||||
nvStaticCheck(FloatImage::WrapMode_Mirror == (FloatImage::WrapMode)WrapMode_Mirror);
|
||||
nvStaticCheck(FloatImage::WrapMode_Repeat == (FloatImage::WrapMode)WrapMode_Repeat);
|
||||
|
||||
// Output DDS header.
|
||||
outputHeader(inputOptions.m, outputOptions, compressionOptions.m);
|
||||
|
||||
Format format = compressionOptions.m.format;
|
||||
|
||||
for (int f = 0; f < inputOptions.m.faceCount; f++)
|
||||
{
|
||||
Image * lastImage = NULL;
|
||||
AutoPtr<FloatImage> floatImage(NULL);
|
||||
|
||||
for (int m = 0; m < inputOptions.m.mipmapCount; m++)
|
||||
{
|
||||
int idx = f * inputOptions.m.mipmapCount + m;
|
||||
InputOptions::Private::Image & mipmap = inputOptions.m.images[idx];
|
||||
|
||||
if (outputOptions.outputHandler)
|
||||
{
|
||||
int size = computeImageSize(mipmap.width, mipmap.height, format);
|
||||
outputOptions.outputHandler->mipmap(size, mipmap.width, mipmap.height, mipmap.depth, mipmap.face, mipmap.mipLevel);
|
||||
}
|
||||
|
||||
Image * img; // Image to compress.
|
||||
|
||||
if (mipmap.data != NULL) // Mipmap provided.
|
||||
{
|
||||
// Convert to normal map.
|
||||
if (inputOptions.m.convertToNormalMap)
|
||||
{
|
||||
floatImage = createNormalMap(mipmap.data, (FloatImage::WrapMode)inputOptions.m.wrapMode, inputOptions.m.heightFactors, inputOptions.m.bumpFrequencyScale);
|
||||
}
|
||||
else
|
||||
{
|
||||
lastImage = img = mipmap.data;
|
||||
|
||||
// Delete float image.
|
||||
floatImage = NULL;
|
||||
}
|
||||
}
|
||||
else // Create mipmap from last.
|
||||
{
|
||||
if (m == 0) {
|
||||
// First mipmap missing.
|
||||
if (outputOptions.errorHandler != NULL) outputOptions.errorHandler->error(Error_InvalidInput);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (floatImage == NULL)
|
||||
{
|
||||
nvDebugCheck(lastImage != NULL);
|
||||
floatImage = toFloatImage(lastImage, inputOptions.m);
|
||||
}
|
||||
|
||||
// Create mipmap.
|
||||
floatImage = createMipmap(floatImage.ptr(), inputOptions.m);
|
||||
}
|
||||
|
||||
if (floatImage != NULL)
|
||||
{
|
||||
// Convert to fixed.
|
||||
img = toFixedImage(floatImage.ptr(), inputOptions.m);
|
||||
}
|
||||
|
||||
quantize(img, inputOptions.m, format);
|
||||
|
||||
compressMipmap(img, outputOptions, compressionOptions.m);
|
||||
|
||||
if (img != mipmap.data)
|
||||
{
|
||||
delete img;
|
||||
}
|
||||
|
||||
if (!inputOptions.m.generateMipmaps || (inputOptions.m.maxLevel >= 0 && m >= inputOptions.m.maxLevel)) {
|
||||
// continue with next face.
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
/// Estimate the size of compressing the input with the given options.
|
||||
int nvtt::estimateSize(const InputOptions & inputOptions, const CompressionOptions & compressionOptions)
|
||||
{
|
||||
Format format = compressionOptions.m.format;
|
||||
|
||||
int size = 0;
|
||||
|
||||
for (int f = 0; f < inputOptions.m.faceCount; f++)
|
||||
{
|
||||
for (int m = 0; m < inputOptions.m.mipmapCount; m++)
|
||||
{
|
||||
int idx = f * inputOptions.m.mipmapCount + m;
|
||||
const InputOptions::Private::Image & img = inputOptions.m.images[idx];
|
||||
|
||||
size += computeImageSize(img.width, img.height, format);
|
||||
|
||||
if (!inputOptions.m.generateMipmaps || (inputOptions.m.maxLevel >= 0 && m >= inputOptions.m.maxLevel)) {
|
||||
// continue with next face.
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return size;
|
||||
}
|
||||
|
||||
|
||||
/// Return a string for the given error.
|
||||
const char * nvtt::errorString(Error e)
|
||||
{
|
||||
switch(e)
|
||||
{
|
||||
case Error_InvalidInput:
|
||||
return "Invalid input";
|
||||
case Error_UserInterruption:
|
||||
return "User interruption";
|
||||
case Error_UnsupportedFeature:
|
||||
return "Unsupported feature";
|
||||
case Error_CudaError:
|
||||
return "CUDA error";
|
||||
case Error_Unknown:
|
||||
return "Unknown error";
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
@ -1,242 +1,245 @@
|
||||
// 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 NV_TT_H
|
||||
#define NV_TT_H
|
||||
|
||||
#include <nvcore/nvcore.h>
|
||||
|
||||
// Function linkage
|
||||
#if NVTT_SHARED
|
||||
#ifdef NVTT_EXPORTS
|
||||
#define NVTT_API DLL_EXPORT
|
||||
#define NVTT_CLASS DLL_EXPORT_CLASS
|
||||
#else
|
||||
#define NVTT_API DLL_IMPORT
|
||||
#define NVTT_CLASS DLL_IMPORT
|
||||
#endif
|
||||
#else
|
||||
#define NVTT_API
|
||||
#define NVTT_CLASS
|
||||
#endif
|
||||
|
||||
// Public interface.
|
||||
namespace nvtt
|
||||
{
|
||||
/// Supported compression formats.
|
||||
enum Format
|
||||
{
|
||||
// No compression.
|
||||
Format_RGB,
|
||||
Format_RGBA = Format_RGB,
|
||||
|
||||
// DX9 formats.
|
||||
Format_DXT1,
|
||||
// Format_DXT1a, // DXT1 with binary alpha.
|
||||
Format_DXT3,
|
||||
Format_DXT5,
|
||||
Format_DXT5n, // Compressed HILO: R=0, G=x, B=0, A=y
|
||||
|
||||
// DX10 formats.
|
||||
Format_BC1 = Format_DXT1,
|
||||
Format_BC2 = Format_DXT3,
|
||||
Format_BC3 = Format_DXT5,
|
||||
Format_BC3n = Format_DXT5n,
|
||||
Format_BC4, // ATI1
|
||||
Format_BC5, // 3DC, ATI2
|
||||
|
||||
// OpenGL formats.
|
||||
Format_LATC = Format_BC5,
|
||||
};
|
||||
|
||||
/// Quality modes.
|
||||
enum Quality
|
||||
{
|
||||
Quality_Fastest,
|
||||
Quality_Normal,
|
||||
Quality_Production,
|
||||
Quality_Highest,
|
||||
};
|
||||
|
||||
/// Compression options. This class describes the desired compression format and other compression settings.
|
||||
class CompressionOptions
|
||||
{
|
||||
public:
|
||||
NVTT_API CompressionOptions();
|
||||
NVTT_API ~CompressionOptions();
|
||||
|
||||
NVTT_API void reset();
|
||||
|
||||
NVTT_API void setFormat(Format format);
|
||||
NVTT_API void setQuality(Quality quality, float errorThreshold = 0.5f);
|
||||
NVTT_API void setColorWeights(float red, float green, float blue);
|
||||
NVTT_API void enableHardwareCompression(bool enable);
|
||||
|
||||
NVTT_API void setExternalCompressor(const char * name);
|
||||
|
||||
// Set color mask to describe the RGB/RGBA format.
|
||||
NVTT_API void setPixelFormat(uint bitcount, uint rmask, uint gmask, uint bmask, uint amask);
|
||||
|
||||
//private:
|
||||
struct Private;
|
||||
Private & m;
|
||||
};
|
||||
|
||||
|
||||
/// Wrap modes. // This matches FloatImage::WrapMode.
|
||||
enum WrapMode
|
||||
{
|
||||
WrapMode_Clamp,
|
||||
WrapMode_Repeat,
|
||||
WrapMode_Mirror,
|
||||
};
|
||||
|
||||
/// Texture types.
|
||||
enum TextureType
|
||||
{
|
||||
TextureType_2D,
|
||||
TextureType_Cube,
|
||||
// TextureType_3D,
|
||||
};
|
||||
|
||||
/// Input formats.
|
||||
enum InputFormat
|
||||
{
|
||||
InputFormat_BGRA_8UB,
|
||||
// InputFormat_RGBE_8UB,
|
||||
// InputFormat_BGRA_32F,
|
||||
};
|
||||
|
||||
/// Mipmap downsampling filters.
|
||||
enum MipmapFilter
|
||||
{
|
||||
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();
|
||||
NVTT_API ~InputOptions();
|
||||
|
||||
// Set default options.
|
||||
NVTT_API void reset();
|
||||
|
||||
// Setup input layout.
|
||||
NVTT_API void setTextureLayout(TextureType type, int w, int h, int d = 1);
|
||||
NVTT_API void resetTextureLayout();
|
||||
|
||||
// Set mipmap data. Copies the data.
|
||||
NVTT_API bool setMipmapData(const void * data, int w, int h, int d = 1, int face = 0, int mipmap = 0);
|
||||
|
||||
// Describe the format of the input.
|
||||
NVTT_API void setFormat(InputFormat fmt, bool alphaTransparency);
|
||||
|
||||
// Set gamma settings.
|
||||
NVTT_API void setGamma(float inputGamma, float outputGamma);
|
||||
|
||||
// Set texture wrappign mode.
|
||||
NVTT_API void setWrapMode(WrapMode mode);
|
||||
|
||||
// Set mipmapping options.
|
||||
NVTT_API void setMipmapping(bool generateMipmaps, MipmapFilter filter = MipmapFilter_Kaiser, int maxLevel = -1);
|
||||
|
||||
// Set quantization options.
|
||||
NVTT_API void setQuantization(bool colorDithering, bool alphaDithering, bool binaryAlpha, int alphaThreshold = 127);
|
||||
|
||||
// Set normal map options.
|
||||
NVTT_API void setConvertToNormalMap(bool convert);
|
||||
NVTT_API void setHeightEvaluation(float redScale, float greenScale, float blueScale, float alphaScale);
|
||||
NVTT_API void setNormalFilter(float small, float medium, float big, float large);
|
||||
NVTT_API void setNormalizeMipmaps(bool b);
|
||||
|
||||
//private:
|
||||
struct Private;
|
||||
Private & m;
|
||||
};
|
||||
|
||||
|
||||
/// Output handler.
|
||||
struct OutputHandler
|
||||
{
|
||||
virtual ~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;
|
||||
|
||||
/// Output data. Compressed data is output as soon as it's generated to minimize memory allocations.
|
||||
virtual void writeData(const void * data, int size) = 0;
|
||||
};
|
||||
|
||||
/// Error codes.
|
||||
enum Error
|
||||
{
|
||||
Error_InvalidInput,
|
||||
Error_UserInterruption,
|
||||
Error_UnsupportedFeature,
|
||||
Error_CudaError,
|
||||
Error_Unknown,
|
||||
};
|
||||
|
||||
/// Error handler.
|
||||
struct ErrorHandler
|
||||
{
|
||||
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
|
||||
{
|
||||
OutputOptions() : outputHandler(NULL), outputHeader(true) { reset(); }
|
||||
OutputOptions(OutputHandler * oh, ErrorHandler * eh) : outputHandler(oh), errorHandler(eh), outputHeader(true) { reset(); }
|
||||
|
||||
// Set default options.
|
||||
NVTT_API void reset();
|
||||
|
||||
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.
|
||||
NVTT_API int estimateSize(const InputOptions & inputOptions, const CompressionOptions & compressionOptions);
|
||||
|
||||
// Return string for the given error.
|
||||
NVTT_API const char * errorString(Error e);
|
||||
|
||||
} // nvtt namespace
|
||||
|
||||
#endif // NV_TT_H
|
||||
// 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 NV_TT_H
|
||||
#define NV_TT_H
|
||||
|
||||
#include <nvcore/nvcore.h>
|
||||
|
||||
//#define HAVE_S3QUANT
|
||||
//#define HAVE_ATITC
|
||||
|
||||
// Function linkage
|
||||
#if NVTT_SHARED
|
||||
#ifdef NVTT_EXPORTS
|
||||
#define NVTT_API DLL_EXPORT
|
||||
#define NVTT_CLASS DLL_EXPORT_CLASS
|
||||
#else
|
||||
#define NVTT_API DLL_IMPORT
|
||||
#define NVTT_CLASS DLL_IMPORT
|
||||
#endif
|
||||
#else
|
||||
#define NVTT_API
|
||||
#define NVTT_CLASS
|
||||
#endif
|
||||
|
||||
// Public interface.
|
||||
namespace nvtt
|
||||
{
|
||||
/// Supported compression formats.
|
||||
enum Format
|
||||
{
|
||||
// No compression.
|
||||
Format_RGB,
|
||||
Format_RGBA = Format_RGB,
|
||||
|
||||
// DX9 formats.
|
||||
Format_DXT1,
|
||||
// Format_DXT1a, // DXT1 with binary alpha.
|
||||
Format_DXT3,
|
||||
Format_DXT5,
|
||||
Format_DXT5n, // Compressed HILO: R=0, G=x, B=0, A=y
|
||||
|
||||
// DX10 formats.
|
||||
Format_BC1 = Format_DXT1,
|
||||
Format_BC2 = Format_DXT3,
|
||||
Format_BC3 = Format_DXT5,
|
||||
Format_BC3n = Format_DXT5n,
|
||||
Format_BC4, // ATI1
|
||||
Format_BC5, // 3DC, ATI2
|
||||
|
||||
// OpenGL formats.
|
||||
Format_LATC = Format_BC5,
|
||||
};
|
||||
|
||||
/// Quality modes.
|
||||
enum Quality
|
||||
{
|
||||
Quality_Fastest,
|
||||
Quality_Normal,
|
||||
Quality_Production,
|
||||
Quality_Highest,
|
||||
};
|
||||
|
||||
/// Compression options. This class describes the desired compression format and other compression settings.
|
||||
class CompressionOptions
|
||||
{
|
||||
public:
|
||||
NVTT_API CompressionOptions();
|
||||
NVTT_API ~CompressionOptions();
|
||||
|
||||
NVTT_API void reset();
|
||||
|
||||
NVTT_API void setFormat(Format format);
|
||||
NVTT_API void setQuality(Quality quality, float errorThreshold = 0.5f);
|
||||
NVTT_API void setColorWeights(float red, float green, float blue);
|
||||
NVTT_API void enableHardwareCompression(bool enable);
|
||||
|
||||
NVTT_API void setExternalCompressor(const char * name);
|
||||
|
||||
// Set color mask to describe the RGB/RGBA format.
|
||||
NVTT_API void setPixelFormat(uint bitcount, uint rmask, uint gmask, uint bmask, uint amask);
|
||||
|
||||
//private:
|
||||
struct Private;
|
||||
Private & m;
|
||||
};
|
||||
|
||||
|
||||
/// Wrap modes. // This matches FloatImage::WrapMode.
|
||||
enum WrapMode
|
||||
{
|
||||
WrapMode_Clamp,
|
||||
WrapMode_Repeat,
|
||||
WrapMode_Mirror,
|
||||
};
|
||||
|
||||
/// Texture types.
|
||||
enum TextureType
|
||||
{
|
||||
TextureType_2D,
|
||||
TextureType_Cube,
|
||||
// TextureType_3D,
|
||||
};
|
||||
|
||||
/// Input formats.
|
||||
enum InputFormat
|
||||
{
|
||||
InputFormat_BGRA_8UB,
|
||||
// InputFormat_RGBE_8UB,
|
||||
// InputFormat_BGRA_32F,
|
||||
};
|
||||
|
||||
/// Mipmap downsampling filters.
|
||||
enum MipmapFilter
|
||||
{
|
||||
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();
|
||||
NVTT_API ~InputOptions();
|
||||
|
||||
// Set default options.
|
||||
NVTT_API void reset();
|
||||
|
||||
// Setup input layout.
|
||||
NVTT_API void setTextureLayout(TextureType type, int w, int h, int d = 1);
|
||||
NVTT_API void resetTextureLayout();
|
||||
|
||||
// Set mipmap data. Copies the data.
|
||||
NVTT_API bool setMipmapData(const void * data, int w, int h, int d = 1, int face = 0, int mipmap = 0);
|
||||
|
||||
// Describe the format of the input.
|
||||
NVTT_API void setFormat(InputFormat fmt, bool alphaTransparency);
|
||||
|
||||
// Set gamma settings.
|
||||
NVTT_API void setGamma(float inputGamma, float outputGamma);
|
||||
|
||||
// Set texture wrappign mode.
|
||||
NVTT_API void setWrapMode(WrapMode mode);
|
||||
|
||||
// Set mipmapping options.
|
||||
NVTT_API void setMipmapping(bool generateMipmaps, MipmapFilter filter = MipmapFilter_Kaiser, int maxLevel = -1);
|
||||
|
||||
// Set quantization options.
|
||||
NVTT_API void setQuantization(bool colorDithering, bool alphaDithering, bool binaryAlpha, int alphaThreshold = 127);
|
||||
|
||||
// Set normal map options.
|
||||
NVTT_API void setConvertToNormalMap(bool convert);
|
||||
NVTT_API void setHeightEvaluation(float redScale, float greenScale, float blueScale, float alphaScale);
|
||||
NVTT_API void setNormalFilter(float small, float medium, float big, float large);
|
||||
NVTT_API void setNormalizeMipmaps(bool b);
|
||||
|
||||
//private:
|
||||
struct Private;
|
||||
Private & m;
|
||||
};
|
||||
|
||||
|
||||
/// Output handler.
|
||||
struct OutputHandler
|
||||
{
|
||||
virtual ~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;
|
||||
|
||||
/// Output data. Compressed data is output as soon as it's generated to minimize memory allocations.
|
||||
virtual void writeData(const void * data, int size) = 0;
|
||||
};
|
||||
|
||||
/// Error codes.
|
||||
enum Error
|
||||
{
|
||||
Error_InvalidInput,
|
||||
Error_UserInterruption,
|
||||
Error_UnsupportedFeature,
|
||||
Error_CudaError,
|
||||
Error_Unknown,
|
||||
};
|
||||
|
||||
/// Error handler.
|
||||
struct ErrorHandler
|
||||
{
|
||||
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
|
||||
{
|
||||
OutputOptions() : outputHandler(NULL), outputHeader(true) { reset(); }
|
||||
OutputOptions(OutputHandler * oh, ErrorHandler * eh) : outputHandler(oh), errorHandler(eh), outputHeader(true) { reset(); }
|
||||
|
||||
// Set default options.
|
||||
NVTT_API void reset();
|
||||
|
||||
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.
|
||||
NVTT_API int estimateSize(const InputOptions & inputOptions, const CompressionOptions & compressionOptions);
|
||||
|
||||
// Return string for the given error.
|
||||
NVTT_API const char * errorString(Error e);
|
||||
|
||||
} // nvtt namespace
|
||||
|
||||
#endif // NV_TT_H
|
||||
|
65
src/nvimage/nvtt/tools/cmdline.h
Normal file
65
src/nvimage/nvtt/tools/cmdline.h
Normal 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
|
@ -1,354 +1,427 @@
|
||||
// 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 <nvcore/StrLib.h>
|
||||
#include <nvcore/StdStream.h>
|
||||
|
||||
#include <nvimage/Image.h>
|
||||
#include <nvimage/nvtt/nvtt.h>
|
||||
|
||||
#include "cmdline.h"
|
||||
|
||||
#include <time.h> // clock
|
||||
|
||||
struct MyOutputHandler : public nvtt::OutputHandler
|
||||
{
|
||||
MyOutputHandler() : total(0), progress(0), percentage(0), stream(NULL) {}
|
||||
MyOutputHandler(const char * name) : total(0), progress(0), percentage(0), stream(new nv::StdOutputStream(name)) {}
|
||||
virtual ~MyOutputHandler() { delete stream; }
|
||||
|
||||
bool open(const char * name)
|
||||
{
|
||||
stream = new nv::StdOutputStream(name);
|
||||
percentage = progress = 0;
|
||||
if (stream->isError()) {
|
||||
printf("Error opening '%s' for writting\n", name);
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
virtual void setTotal(int t)
|
||||
{
|
||||
total = t;
|
||||
}
|
||||
|
||||
virtual void mipmap(int size, int width, int height, int depth, int face, int miplevel)
|
||||
{
|
||||
// ignore.
|
||||
}
|
||||
|
||||
// Output data.
|
||||
virtual void writeData(const void * data, int size)
|
||||
{
|
||||
nvDebugCheck(stream != NULL);
|
||||
stream->serialize(const_cast<void *>(data), size);
|
||||
|
||||
progress += size;
|
||||
int p = (100 * progress) / total;
|
||||
if (p != percentage)
|
||||
{
|
||||
percentage = p;
|
||||
printf("\r%d%%", percentage);
|
||||
fflush(stdout);
|
||||
}
|
||||
}
|
||||
|
||||
int total;
|
||||
int progress;
|
||||
int percentage;
|
||||
nv::StdOutputStream * stream;
|
||||
};
|
||||
|
||||
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);
|
||||
//inputOptions.setNormalFilter(1.0f, 0, 0, 0);
|
||||
//inputOptions.setNormalFilter(0.0f, 0, 0, 1);
|
||||
inputOptions.setGamma(1.0f, 1.0f);
|
||||
inputOptions.setNormalizeMipmaps(true);
|
||||
}
|
||||
|
||||
// Set options for normal maps.
|
||||
void setNormalMap(nvtt::InputOptions & inputOptions)
|
||||
{
|
||||
inputOptions.setConvertToNormalMap(false);
|
||||
inputOptions.setGamma(1.0f, 1.0f);
|
||||
inputOptions.setNormalizeMipmaps(true);
|
||||
}
|
||||
|
||||
// Set options for color maps.
|
||||
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;
|
||||
|
||||
bool normal = false;
|
||||
bool color2normal = false;
|
||||
bool wrapRepeat = false;
|
||||
bool noMipmaps = false;
|
||||
bool fast = false;
|
||||
bool nocuda = false;
|
||||
nvtt::Format format = nvtt::Format_BC1;
|
||||
|
||||
const char * externalCompressor = NULL;
|
||||
|
||||
nv::Path input;
|
||||
nv::Path output;
|
||||
|
||||
|
||||
// Parse arguments.
|
||||
for (int i = 1; i < argc; i++)
|
||||
{
|
||||
// Input options.
|
||||
if (strcmp("-color", argv[i]) == 0)
|
||||
{
|
||||
}
|
||||
else if (strcmp("-normal", argv[i]) == 0)
|
||||
{
|
||||
normal = true;
|
||||
}
|
||||
else if (strcmp("-tonormal", argv[i]) == 0)
|
||||
{
|
||||
color2normal = true;
|
||||
}
|
||||
else if (strcmp("-clamp", argv[i]) == 0)
|
||||
{
|
||||
}
|
||||
else if (strcmp("-repeat", argv[i]) == 0)
|
||||
{
|
||||
wrapRepeat = true;
|
||||
}
|
||||
else if (strcmp("-nomips", argv[i]) == 0)
|
||||
{
|
||||
noMipmaps = true;
|
||||
}
|
||||
|
||||
// Compression options.
|
||||
else if (strcmp("-fast", argv[i]) == 0)
|
||||
{
|
||||
fast = true;
|
||||
}
|
||||
else if (strcmp("-nocuda", argv[i]) == 0)
|
||||
{
|
||||
nocuda = true;
|
||||
}
|
||||
else if (strcmp("-rgb", argv[i]) == 0)
|
||||
{
|
||||
format = nvtt::Format_RGB;
|
||||
}
|
||||
else if (strcmp("-bc1", argv[i]) == 0)
|
||||
{
|
||||
format = nvtt::Format_BC1;
|
||||
}
|
||||
else if (strcmp("-bc2", argv[i]) == 0)
|
||||
{
|
||||
format = nvtt::Format_BC2;
|
||||
}
|
||||
else if (strcmp("-bc3", argv[i]) == 0)
|
||||
{
|
||||
format = nvtt::Format_BC3;
|
||||
}
|
||||
else if (strcmp("-bc3n", argv[i]) == 0)
|
||||
{
|
||||
format = nvtt::Format_BC3n;
|
||||
}
|
||||
else if (strcmp("-bc4", argv[i]) == 0)
|
||||
{
|
||||
format = nvtt::Format_BC4;
|
||||
}
|
||||
else if (strcmp("-bc5", argv[i]) == 0)
|
||||
{
|
||||
format = nvtt::Format_BC5;
|
||||
}
|
||||
|
||||
// Undocumented option. Mainly used for testing.
|
||||
else if (strcmp("-ext", argv[i]) == 0)
|
||||
{
|
||||
if (i+1 < argc && argv[i+1][0] != '-') {
|
||||
externalCompressor = argv[i+1];
|
||||
printf("using %s\n", argv[i+1]);
|
||||
i++;
|
||||
}
|
||||
}
|
||||
|
||||
else if (argv[i][0] != '-')
|
||||
{
|
||||
input = argv[i];
|
||||
|
||||
if (i+1 < argc && argv[i+1][0] != '-') {
|
||||
output = argv[i+1];
|
||||
}
|
||||
else
|
||||
{
|
||||
output.copy(input.str());
|
||||
output.stripExtension();
|
||||
output.append(".dds");
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (input.empty())
|
||||
{
|
||||
printf("NVIDIA Texture Tools - Copyright NVIDIA Corporation 2007\n\n");
|
||||
|
||||
printf("usage: nvcompress [options] infile [outfile]\n\n");
|
||||
|
||||
printf("Input options:\n");
|
||||
printf(" -color \tThe input image is a color map (default).\n");
|
||||
printf(" -normal \tThe input image is a normal map.\n");
|
||||
printf(" -tonormal\tConvert input to normal map.\n");
|
||||
printf(" -clamp \tClamp wrapping mode (default).\n");
|
||||
printf(" -repeat \tRepeat wrapping mode.\n");
|
||||
printf(" -nomips \tDisable mipmap generation.\n\n");
|
||||
|
||||
printf("Compression options:\n");
|
||||
printf(" -fast \tFast compression.\n");
|
||||
printf(" -nocuda \tDo not use cuda compressor.\n");
|
||||
printf(" -rgb \tRGBA format\n");
|
||||
printf(" -bc1 \tBC1 format (DXT1)\n");
|
||||
printf(" -bc2 \tBC2 format (DXT3)\n");
|
||||
printf(" -bc3 \tBC3 format (DXT5)\n");
|
||||
printf(" -bc3n \tBC3 normal map format (DXT5n/RXGB)\n");
|
||||
printf(" -bc4 \tBC4 format (ATI1)\n");
|
||||
printf(" -bc5 \tBC5 format (3Dc/ATI2)\n\n");
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
nv::Image image;
|
||||
if (!image.load(input))
|
||||
{
|
||||
printf("The file '%s' is not a supported image type.\n", input.str());
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
MyErrorHandler errorHandler;
|
||||
MyOutputHandler outputHandler(output);
|
||||
if (outputHandler.stream->isError())
|
||||
{
|
||||
printf("Error opening '%s' for writting\n", output.str());
|
||||
return 1;
|
||||
}
|
||||
|
||||
// Set input options.
|
||||
nvtt::InputOptions inputOptions;
|
||||
inputOptions.setTextureLayout(nvtt::TextureType_2D, image.width(), image.height());
|
||||
inputOptions.setMipmapData(image.pixels(), image.width(), image.height());
|
||||
|
||||
if (fast)
|
||||
{
|
||||
inputOptions.setMipmapping(true, nvtt::MipmapFilter_Box);
|
||||
}
|
||||
else
|
||||
{
|
||||
inputOptions.setMipmapping(true, nvtt::MipmapFilter_Kaiser);
|
||||
}
|
||||
|
||||
if (wrapRepeat)
|
||||
{
|
||||
inputOptions.setWrapMode(nvtt::WrapMode_Repeat);
|
||||
}
|
||||
else
|
||||
{
|
||||
inputOptions.setWrapMode(nvtt::WrapMode_Clamp);
|
||||
}
|
||||
|
||||
if (normal)
|
||||
{
|
||||
setNormalMap(inputOptions);
|
||||
}
|
||||
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);
|
||||
}
|
||||
|
||||
outputHandler.setTotal(nvtt::estimateSize(inputOptions, compressionOptions));
|
||||
|
||||
nvtt::OutputOptions outputOptions(&outputHandler, &errorHandler);
|
||||
|
||||
clock_t start = clock();
|
||||
|
||||
nvtt::compress(inputOptions, outputOptions, compressionOptions);
|
||||
|
||||
clock_t end = clock();
|
||||
printf("\rtime taken: %.3f seconds\n", float(end-start) / CLOCKS_PER_SEC);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
// 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 <nvcore/StrLib.h>
|
||||
#include <nvcore/StdStream.h>
|
||||
|
||||
#include <nvimage/Image.h>
|
||||
#include <nvimage/DirectDrawSurface.h>
|
||||
#include <nvimage/nvtt/nvtt.h>
|
||||
|
||||
#include "cmdline.h"
|
||||
|
||||
#include <time.h> // clock
|
||||
|
||||
//#define WINDOWS_LEAN_AND_MEAN
|
||||
//#include <windows.h> // TIMER
|
||||
|
||||
struct MyOutputHandler : public nvtt::OutputHandler
|
||||
{
|
||||
MyOutputHandler() : total(0), progress(0), percentage(0), stream(NULL) {}
|
||||
MyOutputHandler(const char * name) : total(0), progress(0), percentage(0), stream(new nv::StdOutputStream(name)) {}
|
||||
virtual ~MyOutputHandler() { delete stream; }
|
||||
|
||||
bool open(const char * name)
|
||||
{
|
||||
stream = new nv::StdOutputStream(name);
|
||||
percentage = progress = 0;
|
||||
if (stream->isError()) {
|
||||
printf("Error opening '%s' for writting\n", name);
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
virtual void setTotal(int t)
|
||||
{
|
||||
total = t;
|
||||
}
|
||||
|
||||
virtual void mipmap(int size, int width, int height, int depth, int face, int miplevel)
|
||||
{
|
||||
// ignore.
|
||||
}
|
||||
|
||||
// Output data.
|
||||
virtual void writeData(const void * data, int size)
|
||||
{
|
||||
nvDebugCheck(stream != NULL);
|
||||
stream->serialize(const_cast<void *>(data), size);
|
||||
|
||||
progress += size;
|
||||
int p = (100 * progress) / total;
|
||||
if (p != percentage)
|
||||
{
|
||||
percentage = p;
|
||||
printf("\r%d%%", percentage);
|
||||
fflush(stdout);
|
||||
}
|
||||
}
|
||||
|
||||
int total;
|
||||
int progress;
|
||||
int percentage;
|
||||
nv::StdOutputStream * stream;
|
||||
};
|
||||
|
||||
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);
|
||||
//inputOptions.setNormalFilter(1.0f, 0, 0, 0);
|
||||
//inputOptions.setNormalFilter(0.0f, 0, 0, 1);
|
||||
inputOptions.setGamma(1.0f, 1.0f);
|
||||
inputOptions.setNormalizeMipmaps(true);
|
||||
}
|
||||
|
||||
// Set options for normal maps.
|
||||
void setNormalMap(nvtt::InputOptions & inputOptions)
|
||||
{
|
||||
inputOptions.setConvertToNormalMap(false);
|
||||
inputOptions.setGamma(1.0f, 1.0f);
|
||||
inputOptions.setNormalizeMipmaps(true);
|
||||
}
|
||||
|
||||
// Set options for color maps.
|
||||
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;
|
||||
|
||||
bool normal = false;
|
||||
bool color2normal = false;
|
||||
bool wrapRepeat = false;
|
||||
bool noMipmaps = false;
|
||||
bool fast = false;
|
||||
bool nocuda = false;
|
||||
nvtt::Format format = nvtt::Format_BC1;
|
||||
|
||||
const char * externalCompressor = NULL;
|
||||
|
||||
nv::Path input;
|
||||
nv::Path output;
|
||||
|
||||
|
||||
// Parse arguments.
|
||||
for (int i = 1; i < argc; i++)
|
||||
{
|
||||
// Input options.
|
||||
if (strcmp("-color", argv[i]) == 0)
|
||||
{
|
||||
}
|
||||
else if (strcmp("-normal", argv[i]) == 0)
|
||||
{
|
||||
normal = true;
|
||||
}
|
||||
else if (strcmp("-tonormal", argv[i]) == 0)
|
||||
{
|
||||
color2normal = true;
|
||||
}
|
||||
else if (strcmp("-clamp", argv[i]) == 0)
|
||||
{
|
||||
}
|
||||
else if (strcmp("-repeat", argv[i]) == 0)
|
||||
{
|
||||
wrapRepeat = true;
|
||||
}
|
||||
else if (strcmp("-nomips", argv[i]) == 0)
|
||||
{
|
||||
noMipmaps = true;
|
||||
}
|
||||
|
||||
// Compression options.
|
||||
else if (strcmp("-fast", argv[i]) == 0)
|
||||
{
|
||||
fast = true;
|
||||
}
|
||||
else if (strcmp("-nocuda", argv[i]) == 0)
|
||||
{
|
||||
nocuda = true;
|
||||
}
|
||||
else if (strcmp("-rgb", argv[i]) == 0)
|
||||
{
|
||||
format = nvtt::Format_RGB;
|
||||
}
|
||||
else if (strcmp("-bc1", argv[i]) == 0)
|
||||
{
|
||||
format = nvtt::Format_BC1;
|
||||
}
|
||||
else if (strcmp("-bc2", argv[i]) == 0)
|
||||
{
|
||||
format = nvtt::Format_BC2;
|
||||
}
|
||||
else if (strcmp("-bc3", argv[i]) == 0)
|
||||
{
|
||||
format = nvtt::Format_BC3;
|
||||
}
|
||||
else if (strcmp("-bc3n", argv[i]) == 0)
|
||||
{
|
||||
format = nvtt::Format_BC3n;
|
||||
}
|
||||
else if (strcmp("-bc4", argv[i]) == 0)
|
||||
{
|
||||
format = nvtt::Format_BC4;
|
||||
}
|
||||
else if (strcmp("-bc5", argv[i]) == 0)
|
||||
{
|
||||
format = nvtt::Format_BC5;
|
||||
}
|
||||
|
||||
// Undocumented option. Mainly used for testing.
|
||||
else if (strcmp("-ext", argv[i]) == 0)
|
||||
{
|
||||
if (i+1 < argc && argv[i+1][0] != '-') {
|
||||
externalCompressor = argv[i+1];
|
||||
i++;
|
||||
}
|
||||
}
|
||||
|
||||
else if (argv[i][0] != '-')
|
||||
{
|
||||
input = argv[i];
|
||||
|
||||
if (i+1 < argc && argv[i+1][0] != '-') {
|
||||
output = argv[i+1];
|
||||
}
|
||||
else
|
||||
{
|
||||
output.copy(input.str());
|
||||
output.stripExtension();
|
||||
output.append(".dds");
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (input.empty())
|
||||
{
|
||||
printf("NVIDIA Texture Tools - Copyright NVIDIA Corporation 2007\n\n");
|
||||
|
||||
printf("usage: nvcompress [options] infile [outfile]\n\n");
|
||||
|
||||
printf("Input options:\n");
|
||||
printf(" -color \tThe input image is a color map (default).\n");
|
||||
printf(" -normal \tThe input image is a normal map.\n");
|
||||
printf(" -tonormal\tConvert input to normal map.\n");
|
||||
printf(" -clamp \tClamp wrapping mode (default).\n");
|
||||
printf(" -repeat \tRepeat wrapping mode.\n");
|
||||
printf(" -nomips \tDisable mipmap generation.\n\n");
|
||||
|
||||
printf("Compression options:\n");
|
||||
printf(" -fast \tFast compression.\n");
|
||||
printf(" -nocuda \tDo not use cuda compressor.\n");
|
||||
printf(" -rgb \tRGBA format\n");
|
||||
printf(" -bc1 \tBC1 format (DXT1)\n");
|
||||
printf(" -bc2 \tBC2 format (DXT3)\n");
|
||||
printf(" -bc3 \tBC3 format (DXT5)\n");
|
||||
printf(" -bc3n \tBC3 normal map format (DXT5nm)\n");
|
||||
printf(" -bc4 \tBC4 format (ATI1)\n");
|
||||
printf(" -bc5 \tBC5 format (3Dc/ATI2)\n\n");
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
// @@ Make sure input file exists.
|
||||
|
||||
// Set input options.
|
||||
nvtt::InputOptions inputOptions;
|
||||
|
||||
if (nv::strCaseCmp(input.extension(), ".dds") == 0)
|
||||
{
|
||||
// Load surface.
|
||||
printf("The file '%s' is not a supported image type.\n", input.str());
|
||||
|
||||
nv::DirectDrawSurface dds(input);
|
||||
if (!dds.isValid())
|
||||
{
|
||||
printf("The file '%s' is not a valid DDS file.\n", input.str());
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (!dds.isSupported() || dds.isTexture3D())
|
||||
{
|
||||
printf("The file '%s' is not a supported DDS file.\n", input.str());
|
||||
return 1;
|
||||
}
|
||||
|
||||
uint faceCount;
|
||||
if (dds.isTexture2D())
|
||||
{
|
||||
inputOptions.setTextureLayout(nvtt::TextureType_2D, dds.width(), dds.height());
|
||||
faceCount = 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
nvDebugCheck(dds.isTextureCube());
|
||||
inputOptions.setTextureLayout(nvtt::TextureType_Cube, dds.width(), dds.height());
|
||||
faceCount = 6;
|
||||
}
|
||||
|
||||
uint mipmapCount = dds.mipmapCount();
|
||||
|
||||
nv::Image mipmap;
|
||||
|
||||
for (uint f = 0; f < faceCount; f++)
|
||||
{
|
||||
for (uint m = 0; m <= mipmapCount; m++)
|
||||
{
|
||||
dds.mipmap(&mipmap, f, m);
|
||||
|
||||
inputOptions.setMipmapData(mipmap.pixels(), mipmap.width(), mipmap.height(), 1, f, m);
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// Regular image.
|
||||
nv::Image image;
|
||||
if (!image.load(input))
|
||||
{
|
||||
printf("The file '%s' is not a supported image type.\n", input.str());
|
||||
return 1;
|
||||
}
|
||||
|
||||
inputOptions.setTextureLayout(nvtt::TextureType_2D, image.width(), image.height());
|
||||
inputOptions.setMipmapData(image.pixels(), image.width(), image.height());
|
||||
}
|
||||
|
||||
if (fast)
|
||||
{
|
||||
inputOptions.setMipmapping(true, nvtt::MipmapFilter_Box);
|
||||
}
|
||||
else
|
||||
{
|
||||
inputOptions.setMipmapping(true, nvtt::MipmapFilter_Kaiser);
|
||||
}
|
||||
|
||||
if (wrapRepeat)
|
||||
{
|
||||
inputOptions.setWrapMode(nvtt::WrapMode_Repeat);
|
||||
}
|
||||
else
|
||||
{
|
||||
inputOptions.setWrapMode(nvtt::WrapMode_Clamp);
|
||||
}
|
||||
|
||||
if (normal)
|
||||
{
|
||||
setNormalMap(inputOptions);
|
||||
}
|
||||
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;
|
||||
}
|
||||
|
31
src/nvimage/nvtt/tools/configdialog.cpp
Normal file
31
src/nvimage/nvtt/tools/configdialog.cpp
Normal 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);
|
||||
}
|
||||
|
43
src/nvimage/nvtt/tools/configdialog.h
Normal file
43
src/nvimage/nvtt/tools/configdialog.h
Normal 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
|
983
src/nvimage/nvtt/tools/configdialog.ui
Normal file
983
src/nvimage/nvtt/tools/configdialog.ui
Normal 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>
|
@ -7,7 +7,10 @@ SET(MATH_SRCS
|
||||
Box.h
|
||||
Color.h
|
||||
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})
|
||||
|
||||
|
@ -33,11 +33,12 @@ public:
|
||||
Vector4 row(uint i) const;
|
||||
Vector4 column(uint i) const;
|
||||
|
||||
|
||||
void scale(scalar s);
|
||||
void scale(double s);
|
||||
void scale(Vector3::Arg s);
|
||||
void translate(Vector3::Arg t);
|
||||
void rotate(scalar theta, scalar v0, scalar v1, scalar v2);
|
||||
Matrix inverse();
|
||||
double determinant();
|
||||
|
||||
void apply(Matrix::Arg m);
|
||||
|
||||
@ -109,11 +110,12 @@ inline Vector4 Matrix::column(uint i) const
|
||||
}
|
||||
|
||||
/// 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[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[12] *= s; m_data[13] *= s; m_data[14] *= s; m_data[15] *= s;
|
||||
}
|
||||
|
||||
/// Apply scale.
|
||||
@ -303,24 +305,42 @@ inline Matrix perspective(scalar fovy, scalar aspect, scalar zNear)
|
||||
}
|
||||
|
||||
/// Get matrix determinant.
|
||||
inline scalar determinant(Matrix::Arg m)
|
||||
inline double Matrix::determinant()
|
||||
{
|
||||
// @@ not sure this is correct.
|
||||
return m(0,0) * m(1,1) * m(2,2) * m(3,3) -
|
||||
m(1,0) * m(2,1) * m(3,2) * m(0,3) +
|
||||
m(2,0) * m(3,1) * m(0,2) * m(1,3) -
|
||||
m(3,0) * m(0,1) * m(1,2) * m(2,3) -
|
||||
m(3,0) * m(2,1) * m(1,2) * m(0,3) +
|
||||
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);
|
||||
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]+
|
||||
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_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_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_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_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];
|
||||
}
|
||||
|
||||
//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 affineInverse(Matrix::Arg m);
|
||||
|
||||
|
156
src/nvmath/Montecarlo.cpp
Normal file
156
src/nvmath/Montecarlo.cpp
Normal 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
84
src/nvmath/Montecarlo.h
Normal 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
54
src/nvmath/Random.cpp
Normal 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
353
src/nvmath/Random.h
Normal 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
|
241
src/nvmath/SphericalHarmonic.cpp
Normal file
241
src/nvmath/SphericalHarmonic.cpp
Normal 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 );
|
||||
}
|
||||
|
||||
|
||||
|
421
src/nvmath/SphericalHarmonic.h
Normal file
421
src/nvmath/SphericalHarmonic.h
Normal 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
|
@ -74,6 +74,8 @@ public:
|
||||
void operator+=(Vector3::Arg v);
|
||||
void operator-=(Vector3::Arg v);
|
||||
void operator*=(scalar s);
|
||||
inline void operator/=(scalar s)
|
||||
{ m_x /= s; m_y /= s; m_z /= s; }
|
||||
void operator*=(Vector3::Arg v);
|
||||
|
||||
friend bool operator==(Vector3::Arg a, Vector3::Arg b);
|
||||
|
Loading…
Reference in New Issue
Block a user