- weighted cuda compressor.

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

File diff suppressed because it is too large Load Diff

View File

@ -1,176 +1,175 @@
// Copyright NVIDIA Corporation 2007 -- Ignacio Castano <icastano@nvidia.com>
//
// 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

View File

@ -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})

View File

@ -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);
}
}

View File

@ -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;
}

View File

@ -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

View File

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

View File

@ -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;
}

View File

@ -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);
}

View File

@ -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

View File

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

View File

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

View File

@ -10,8 +10,6 @@ SET(NVTT_SRCS
CompressRGB.cpp
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

View File

@ -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

View File

@ -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);
}

View File

@ -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

View File

@ -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;
}

View File

@ -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

View File

@ -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

View File

@ -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;
}

View File

@ -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

View File

@ -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...
}

View File

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

View File

@ -28,7 +28,7 @@
#include "CudaMath.h"
#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);
}

View File

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

View File

@ -24,7 +24,10 @@
#include <nvcore/Debug.h>
#include <nvcore/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
}

View File

@ -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

View File

@ -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);
}

View File

@ -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

View File

@ -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;
}

View File

@ -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

View File

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

View File

@ -1,354 +1,427 @@
// Copyright NVIDIA Corporation 2007 -- Ignacio Castano <icastano@nvidia.com>
//
// 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;
}

View File

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

View File

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

View File

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