diff --git a/src/nvcore/Debug.cpp b/src/nvcore/Debug.cpp index e3b494c..f9cb60c 100644 --- a/src/nvcore/Debug.cpp +++ b/src/nvcore/Debug.cpp @@ -35,7 +35,7 @@ # include #endif -#if NV_OS_LINUX || NV_OS_DARWIN +#if NV_OS_LINUX || NV_OS_DARWIN || NV_OS_FREEBSD # include // getpid #endif @@ -195,69 +195,69 @@ namespace static NV_NOINLINE void printStackTrace(void * trace[], int size, int start=0) { - HANDLE hProcess = GetCurrentProcess(); + HANDLE hProcess = GetCurrentProcess(); nvDebug( "\nDumping stacktrace:\n" ); - // Resolve PC to function names - for (int i = start; i < size; i++) - { - // Check for end of stack walk - DWORD64 ip = (DWORD64)trace[i]; - if (ip == NULL) - break; + // Resolve PC to function names + for (int i = start; i < size; i++) + { + // Check for end of stack walk + DWORD64 ip = (DWORD64)trace[i]; + if (ip == NULL) + break; - // Get function name - #define MAX_STRING_LEN (512) - unsigned char byBuffer[sizeof(IMAGEHLP_SYMBOL64) + MAX_STRING_LEN] = { 0 }; - IMAGEHLP_SYMBOL64 * pSymbol = (IMAGEHLP_SYMBOL64*)byBuffer; - pSymbol->SizeOfStruct = sizeof(IMAGEHLP_SYMBOL64); - pSymbol->MaxNameLength = MAX_STRING_LEN; + // Get function name + #define MAX_STRING_LEN (512) + unsigned char byBuffer[sizeof(IMAGEHLP_SYMBOL64) + MAX_STRING_LEN] = { 0 }; + IMAGEHLP_SYMBOL64 * pSymbol = (IMAGEHLP_SYMBOL64*)byBuffer; + pSymbol->SizeOfStruct = sizeof(IMAGEHLP_SYMBOL64); + pSymbol->MaxNameLength = MAX_STRING_LEN; - DWORD64 dwDisplacement; - - if (SymGetSymFromAddr64(hProcess, ip, &dwDisplacement, pSymbol)) - { - pSymbol->Name[MAX_STRING_LEN-1] = 0; - - /* - // Make the symbol readable for humans - UnDecorateSymbolName( pSym->Name, lpszNonUnicodeUnDSymbol, BUFFERSIZE, - UNDNAME_COMPLETE | - UNDNAME_NO_THISTYPE | - UNDNAME_NO_SPECIAL_SYMS | - UNDNAME_NO_MEMBER_TYPE | - UNDNAME_NO_MS_KEYWORDS | - UNDNAME_NO_ACCESS_SPECIFIERS ); - */ - - // pSymbol->Name - const char * pFunc = pSymbol->Name; - - // Get file/line number - IMAGEHLP_LINE64 theLine = { 0 }; - theLine.SizeOfStruct = sizeof(theLine); + DWORD64 dwDisplacement; - DWORD dwDisplacement; - if (!SymGetLineFromAddr64(hProcess, ip, &dwDisplacement, &theLine)) - { - nvDebug("unknown(%08X) : %s\n", (uint32)ip, pFunc); - } - else - { - /* - const char* pFile = strrchr(theLine.FileName, '\\'); - if ( pFile == NULL ) pFile = theLine.FileName; - else pFile++; - */ - const char * pFile = theLine.FileName; - - int line = theLine.LineNumber; - - nvDebug("%s(%d) : %s\n", pFile, line, pFunc); - } - } + if (SymGetSymFromAddr64(hProcess, ip, &dwDisplacement, pSymbol)) + { + pSymbol->Name[MAX_STRING_LEN-1] = 0; + + /* + // Make the symbol readable for humans + UnDecorateSymbolName( pSym->Name, lpszNonUnicodeUnDSymbol, BUFFERSIZE, + UNDNAME_COMPLETE | + UNDNAME_NO_THISTYPE | + UNDNAME_NO_SPECIAL_SYMS | + UNDNAME_NO_MEMBER_TYPE | + UNDNAME_NO_MS_KEYWORDS | + UNDNAME_NO_ACCESS_SPECIFIERS ); + */ + + // pSymbol->Name + const char * pFunc = pSymbol->Name; + + // Get file/line number + IMAGEHLP_LINE64 theLine = { 0 }; + theLine.SizeOfStruct = sizeof(theLine); + + DWORD dwDisplacement; + if (!SymGetLineFromAddr64(hProcess, ip, &dwDisplacement, &theLine)) + { + nvDebug("unknown(%08X) : %s\n", (uint32)ip, pFunc); + } + else + { + /* + const char* pFile = strrchr(theLine.FileName, '\\'); + if ( pFile == NULL ) pFile = theLine.FileName; + else pFile++; + */ + const char * pFile = theLine.FileName; + + int line = theLine.LineNumber; + + nvDebug("%s(%d) : %s\n", pFile, line, pFunc); + } } + } } @@ -294,13 +294,13 @@ namespace # if NV_CC_GNUC // defined(HAVE_CXXABI_H) char * begin = strchr(string_array[i], '('); char * end = strchr(string_array[i], '+'); - if( begin != 0 && begin < end ) { + if (begin != 0 && begin < end) { int stat; *end = '\0'; *begin = '\0'; char * module = string_array[i]; char * name = abi::__cxa_demangle(begin+1, 0, 0, &stat); - if( name == NULL || begin[1] != '_' || begin[2] != 'Z' ) { + if (name == NULL || stat != 0) { nvDebug( " In: [%s] '%s'\n", module, begin+1 ); } else { diff --git a/src/nvmath/nvmath.h b/src/nvmath/nvmath.h index f516c2c..2fb504b 100644 --- a/src/nvmath/nvmath.h +++ b/src/nvmath/nvmath.h @@ -166,8 +166,8 @@ namespace nv inline float square(float f) { return f * f; } inline int square(int i) { return i * i; } - inline float cube(float f) { return f * f; } - inline int cube(int i) { return i * i; } + inline float cube(float f) { return f * f * f; } + inline int cube(int i) { return i * i * i; } // @@ Float to int conversions to be optimized at some point. See: // http://cbloomrants.blogspot.com/2009/01/01-17-09-float-to-int.html @@ -189,10 +189,37 @@ namespace nv return int(ceilf(f)); } - inline float frac(float f) - { - return f - floor(f); - } + inline float frac(float f) + { + return f - floor(f); + } + + inline float fround(float f) + { + // @@ Do something better. + return float(iround(f)); + } + + inline float quantizeCeil(float f, int bits) + { + nvDebugCheck(f >= 0.0f && f <= 1.0f); + float scale = float(1 << bits); + return ceilf(f * scale) / scale; + } + + inline float quantizeRound(float f, int bits) + { + nvDebugCheck(f >= 0.0f && f <= 1.0f); + float scale = float(1 << bits); + return fround(f * scale) / scale; + } + + inline float quantizeFloor(float f, int bits) + { + nvDebugCheck(f >= 0.0f && f <= 1.0f); + float scale = float(1 << bits); + return floor(f * scale) / scale; + } } // nv diff --git a/src/nvtt/Compressor.h b/src/nvtt/Compressor.h index bbe8319..0e7f82d 100644 --- a/src/nvtt/Compressor.h +++ b/src/nvtt/Compressor.h @@ -32,7 +32,7 @@ namespace nv struct CompressorInterface { virtual ~CompressorInterface() {} - virtual void compress(nvtt::InputFormat inputFormat, nvtt::AlphaMode alphaMode, uint w, uint h, const void * data, const nvtt::CompressionOptions::Private & compressionOptions, const nvtt::OutputOptions::Private & outputOptions) = 0; + virtual void compress(nvtt::AlphaMode alphaMode, uint w, uint h, const float * rgba, const nvtt::CompressionOptions::Private & compressionOptions, const nvtt::OutputOptions::Private & outputOptions) = 0; }; } // nv namespace diff --git a/src/nvtt/CompressorDX9.h b/src/nvtt/CompressorDX9.h index 49ffeb0..8c6c7e7 100644 --- a/src/nvtt/CompressorDX9.h +++ b/src/nvtt/CompressorDX9.h @@ -28,112 +28,105 @@ namespace nv { - struct ColorBlock; + struct ColorBlock; - // Fast CPU compressors. - struct FastCompressorDXT1 : public FixedBlockCompressor - { - virtual void compressBlock(ColorBlock & rgba, nvtt::AlphaMode alphaMode, const nvtt::CompressionOptions::Private & compressionOptions, void * output); - virtual uint blockSize() const { return 8; } - }; + // Fast CPU compressors. + struct FastCompressorDXT1 : public FixedBlockCompressor + { + virtual void compressBlock(ColorBlock & rgba, nvtt::AlphaMode alphaMode, const nvtt::CompressionOptions::Private & compressionOptions, void * output); + virtual uint blockSize() const { return 8; } + }; - struct FastCompressorDXT1a : public FixedBlockCompressor - { - virtual void compressBlock(ColorBlock & rgba, nvtt::AlphaMode alphaMode, const nvtt::CompressionOptions::Private & compressionOptions, void * output); - virtual uint blockSize() const { return 8; } - }; + struct FastCompressorDXT1a : public FixedBlockCompressor + { + virtual void compressBlock(ColorBlock & rgba, nvtt::AlphaMode alphaMode, const nvtt::CompressionOptions::Private & compressionOptions, void * output); + virtual uint blockSize() const { return 8; } + }; - struct FastCompressorDXT3 : public FixedBlockCompressor - { - virtual void compressBlock(ColorBlock & rgba, nvtt::AlphaMode alphaMode, const nvtt::CompressionOptions::Private & compressionOptions, void * output); - virtual uint blockSize() const { return 16; } - }; + struct FastCompressorDXT3 : public FixedBlockCompressor + { + virtual void compressBlock(ColorBlock & rgba, nvtt::AlphaMode alphaMode, const nvtt::CompressionOptions::Private & compressionOptions, void * output); + virtual uint blockSize() const { return 16; } + }; - struct FastCompressorDXT5 : public FixedBlockCompressor - { - virtual void compressBlock(ColorBlock & rgba, nvtt::AlphaMode alphaMode, const nvtt::CompressionOptions::Private & compressionOptions, void * output); - virtual uint blockSize() const { return 16; } - }; + struct FastCompressorDXT5 : public FixedBlockCompressor + { + virtual void compressBlock(ColorBlock & rgba, nvtt::AlphaMode alphaMode, const nvtt::CompressionOptions::Private & compressionOptions, void * output); + virtual uint blockSize() const { return 16; } + }; - struct FastCompressorDXT5n : public FixedBlockCompressor - { - virtual void compressBlock(ColorBlock & rgba, nvtt::AlphaMode alphaMode, const nvtt::CompressionOptions::Private & compressionOptions, void * output); - virtual uint blockSize() const { return 16; } - }; + struct FastCompressorDXT5n : public FixedBlockCompressor + { + virtual void compressBlock(ColorBlock & rgba, nvtt::AlphaMode alphaMode, const nvtt::CompressionOptions::Private & compressionOptions, void * output); + virtual uint blockSize() const { return 16; } + }; - // Normal CPU compressors. - struct NormalCompressorDXT1 : public FixedBlockCompressor - { - virtual void compressBlock(ColorBlock & rgba, nvtt::AlphaMode alphaMode, const nvtt::CompressionOptions::Private & compressionOptions, void * output); - virtual uint blockSize() const { return 8; } - }; + // Normal CPU compressors. + struct NormalCompressorDXT1 : public FixedBlockCompressor + { + virtual void compressBlock(ColorBlock & rgba, nvtt::AlphaMode alphaMode, const nvtt::CompressionOptions::Private & compressionOptions, void * output); + virtual uint blockSize() const { return 8; } + }; - struct NormalCompressorDXT1a : public FixedBlockCompressor - { - virtual void compressBlock(ColorBlock & rgba, nvtt::AlphaMode alphaMode, const nvtt::CompressionOptions::Private & compressionOptions, void * output); - virtual uint blockSize() const { return 8; } - }; + struct NormalCompressorDXT1a : public FixedBlockCompressor + { + virtual void compressBlock(ColorBlock & rgba, nvtt::AlphaMode alphaMode, const nvtt::CompressionOptions::Private & compressionOptions, void * output); + virtual uint blockSize() const { return 8; } + }; - struct NormalCompressorDXT3 : public FixedBlockCompressor - { - virtual void compressBlock(ColorBlock & rgba, nvtt::AlphaMode alphaMode, const nvtt::CompressionOptions::Private & compressionOptions, void * output); - virtual uint blockSize() const { return 16; } - }; + struct NormalCompressorDXT3 : public FixedBlockCompressor + { + virtual void compressBlock(ColorBlock & rgba, nvtt::AlphaMode alphaMode, const nvtt::CompressionOptions::Private & compressionOptions, void * output); + virtual uint blockSize() const { return 16; } + }; - struct NormalCompressorDXT5 : public FixedBlockCompressor - { - virtual void compressBlock(ColorBlock & rgba, nvtt::AlphaMode alphaMode, const nvtt::CompressionOptions::Private & compressionOptions, void * output); - virtual uint blockSize() const { return 16; } - }; + struct NormalCompressorDXT5 : public FixedBlockCompressor + { + virtual void compressBlock(ColorBlock & rgba, nvtt::AlphaMode alphaMode, const nvtt::CompressionOptions::Private & compressionOptions, void * output); + virtual uint blockSize() const { return 16; } + }; - struct NormalCompressorDXT5n : public FixedBlockCompressor - { - virtual void compressBlock(ColorBlock & rgba, nvtt::AlphaMode alphaMode, const nvtt::CompressionOptions::Private & compressionOptions, void * output); - virtual uint blockSize() const { return 16; } - }; + struct NormalCompressorDXT5n : public FixedBlockCompressor + { + virtual void compressBlock(ColorBlock & rgba, nvtt::AlphaMode alphaMode, const nvtt::CompressionOptions::Private & compressionOptions, void * output); + virtual uint blockSize() const { return 16; } + }; - // External compressors. -#if defined(HAVE_S3QUANT) - struct S3CompressorDXT1 : public CompressorInterface - { - virtual void compress(nvtt::InputFormat inputFormat, nvtt::AlphaMode alphaMode, uint w, uint h, void * data, const nvtt::CompressionOptions::Private & compressionOptions, const nvtt::OutputOptions::Private & outputOptions); - }; -#endif - + // External compressors. #if defined(HAVE_ATITC) - struct AtiCompressorDXT1 : public CompressorInterface - { - virtual void compress(nvtt::InputFormat inputFormat, nvtt::AlphaMode alphaMode, uint w, uint h, void * data, const nvtt::CompressionOptions::Private & compressionOptions, const nvtt::OutputOptions::Private & outputOptions); - }; + struct AtiCompressorDXT1 : public CompressorInterface + { + virtual void compress(nvtt::InputFormat inputFormat, nvtt::AlphaMode alphaMode, uint w, uint h, void * data, const nvtt::CompressionOptions::Private & compressionOptions, const nvtt::OutputOptions::Private & outputOptions); + }; - struct AtiCompressorDXT5 : public CompressorInterface - { - virtual void compress(nvtt::InputFormat inputFormat, nvtt::AlphaMode alphaMode, uint w, uint h, void * data, const nvtt::CompressionOptions::Private & compressionOptions, const nvtt::OutputOptions::Private & outputOptions); - }; + struct AtiCompressorDXT5 : public CompressorInterface + { + virtual void compress(nvtt::InputFormat inputFormat, nvtt::AlphaMode alphaMode, uint w, uint h, void * data, const nvtt::CompressionOptions::Private & compressionOptions, const nvtt::OutputOptions::Private & outputOptions); + }; #endif #if defined(HAVE_SQUISH) - struct SquishCompressorDXT1 : public CompressorInterface - { - virtual void compress(nvtt::InputFormat inputFormat, nvtt::AlphaMode alphaMode, uint w, uint h, void * data, const nvtt::CompressionOptions::Private & compressionOptions, const nvtt::OutputOptions::Private & outputOptions); - }; + struct SquishCompressorDXT1 : public CompressorInterface + { + virtual void compress(nvtt::InputFormat inputFormat, nvtt::AlphaMode alphaMode, uint w, uint h, void * data, const nvtt::CompressionOptions::Private & compressionOptions, const nvtt::OutputOptions::Private & outputOptions); + }; #endif #if defined(HAVE_D3DX) - struct D3DXCompressorDXT1 : public CompressorInterface - { - virtual void compress(nvtt::InputFormat inputFormat, nvtt::AlphaMode alphaMode, uint w, uint h, void * data, const nvtt::CompressionOptions::Private & compressionOptions, const nvtt::OutputOptions::Private & outputOptions); - }; + struct D3DXCompressorDXT1 : public CompressorInterface + { + virtual void compress(nvtt::InputFormat inputFormat, nvtt::AlphaMode alphaMode, uint w, uint h, void * data, const nvtt::CompressionOptions::Private & compressionOptions, const nvtt::OutputOptions::Private & outputOptions); + }; #endif #if defined(HAVE_STB) - struct StbCompressorDXT1 : public FixedBlockCompressor - { - virtual void compressBlock(ColorBlock & rgba, nvtt::AlphaMode alphaMode, const nvtt::CompressionOptions::Private & compressionOptions, void * output); - virtual uint blockSize() const { return 8; } - }; + struct StbCompressorDXT1 : public FixedBlockCompressor + { + virtual void compressBlock(ColorBlock & rgba, nvtt::AlphaMode alphaMode, const nvtt::CompressionOptions::Private & compressionOptions, void * output); + virtual uint blockSize() const { return 8; } + }; #endif } // nv namespace diff --git a/src/nvtt/CompressorDXT.cpp b/src/nvtt/CompressorDXT.cpp index 0ad2998..b798f76 100644 --- a/src/nvtt/CompressorDXT.cpp +++ b/src/nvtt/CompressorDXT.cpp @@ -44,87 +44,75 @@ using namespace nv; using namespace nvtt; -void FixedBlockCompressor::compress(nvtt::InputFormat inputFormat, nvtt::AlphaMode alphaMode, uint w, uint h, const void * data, const nvtt::CompressionOptions::Private & compressionOptions, const nvtt::OutputOptions::Private & outputOptions) +void FixedBlockCompressor::compress(nvtt::AlphaMode alphaMode, uint w, uint h, const float * data, const nvtt::CompressionOptions::Private & compressionOptions, const nvtt::OutputOptions::Private & outputOptions) { - const uint bs = blockSize(); - const uint bw = (w + 3) / 4; - const uint bh = (h + 3) / 4; + const uint bs = blockSize(); + const uint bw = (w + 3) / 4; + const uint bh = (h + 3) / 4; #if defined(HAVE_OPENMP) - bool singleThreaded = false; + bool singleThreaded = false; #else - bool singleThreaded = true; + bool singleThreaded = true; #endif - // Use a single thread to compress small textures. - if (bw * bh < 16) singleThreaded = true; + // Use a single thread to compress small textures. + if (bw * bh < 16) singleThreaded = true; - if (singleThreaded) + if (singleThreaded) { nvDebugCheck(bs <= 16); uint8 mem[16]; // @@ Output one row at a time! - for (int y = 0; y < int(h); y += 4) { - for (uint x = 0; x < w; x += 4) { + for (int y = 0; y < int(h); y += 4) { + for (uint x = 0; x < w; x += 4) { - ColorBlock rgba; - if (inputFormat == nvtt::InputFormat_BGRA_8UB) { - rgba.init(w, h, (const uint *)data, x, y); - } - else { - nvDebugCheck(inputFormat == nvtt::InputFormat_RGBA_32F); - rgba.init(w, h, (const float *)data, x, y); - } + ColorBlock rgba; + rgba.init(w, h, data, x, y); - compressBlock(rgba, alphaMode, compressionOptions, mem); + compressBlock(rgba, alphaMode, compressionOptions, mem); - if (outputOptions.outputHandler != NULL) { - outputOptions.outputHandler->writeData(mem, bs); - } - } - } - } + if (outputOptions.outputHandler != NULL) { + outputOptions.outputHandler->writeData(mem, bs); + } + } + } + } #if defined(HAVE_OPENMP) - else - { + else + { const uint size = bs * bw * bh; uint8 * mem = new uint8[size]; - #pragma omp parallel - { - #pragma omp for - for (int i = 0; i < int(bw*bh); i++) - { - const uint x = i % bw; - const uint y = i / bw; + #pragma omp parallel + { + #pragma omp for + for (int i = 0; i < int(bw*bh); i++) + { + const uint x = i % bw; + const uint y = i / bw; - ColorBlock rgba; - if (inputFormat == nvtt::InputFormat_BGRA_8UB) { - rgba.init(w, h, (uint *)data, 4*x, 4*y); - } - else { - nvDebugCheck(inputFormat == nvtt::InputFormat_RGBA_32F); - rgba.init(w, h, (float *)data, 4*x, 4*y); - } + ColorBlock rgba; + rgba.init(w, h, data, 4*x, 4*y); - uint8 * ptr = mem + (y * bw + x) * bs; - compressBlock(rgba, alphaMode, compressionOptions, ptr); - } // omp for - } // omp parallel + uint8 * ptr = mem + (y * bw + x) * bs; + compressBlock(rgba, alphaMode, compressionOptions, ptr); + } // omp for + } // omp parallel - if (outputOptions.outputHandler != NULL) { - outputOptions.outputHandler->writeData(mem, size); - } - - delete [] mem; + if (outputOptions.outputHandler != NULL) { + outputOptions.outputHandler->writeData(mem, size); } + + delete [] mem; + } #endif } #include "bc6h/tile.h" -void TileCompressor::compress(InputFormat inputFormat, AlphaMode alphaMode, uint w, uint h, const void * data, const CompressionOptions::Private & compressionOptions, const OutputOptions::Private & outputOptions) +void TileCompressor::compress(AlphaMode alphaMode, uint w, uint h, const float * data, const CompressionOptions::Private & compressionOptions, const OutputOptions::Private & outputOptions) { const uint bs = blockSize(); const uint bw = (w + 3) / 4; @@ -141,13 +129,7 @@ void TileCompressor::compress(InputFormat inputFormat, AlphaMode alphaMode, uint for (uint x = 0; x < w; x += 4) { Tile tile; - if (inputFormat == nvtt::InputFormat_BGRA_8UB) { - //tile.init((const uint *)data, w, h, x, y); - } - else { - nvDebugCheck(inputFormat == nvtt::InputFormat_RGBA_32F); - //tile.init((const float *)data, w, h, x, y); - } + //tile.init((const float *)data, w, h, x, y); compressBlock(tile, alphaMode, compressionOptions, mem); diff --git a/src/nvtt/CompressorDXT.h b/src/nvtt/CompressorDXT.h index 9fbf945..1f211b3 100644 --- a/src/nvtt/CompressorDXT.h +++ b/src/nvtt/CompressorDXT.h @@ -30,23 +30,23 @@ class Tile; namespace nv { - struct ColorBlock; + struct ColorBlock; - struct FixedBlockCompressor : public CompressorInterface - { - virtual void compress(nvtt::InputFormat inputFormat, nvtt::AlphaMode alphaMode, uint w, uint h, const void * data, const nvtt::CompressionOptions::Private & compressionOptions, const nvtt::OutputOptions::Private & outputOptions); + struct FixedBlockCompressor : public CompressorInterface + { + virtual void compress(nvtt::AlphaMode alphaMode, uint w, uint h, const float * rgba, const nvtt::CompressionOptions::Private & compressionOptions, const nvtt::OutputOptions::Private & outputOptions); - virtual void compressBlock(ColorBlock & rgba, nvtt::AlphaMode alphaMode, const nvtt::CompressionOptions::Private & compressionOptions, void * output) = 0; - virtual uint blockSize() const = 0; - }; + virtual void compressBlock(ColorBlock & rgba, nvtt::AlphaMode alphaMode, const nvtt::CompressionOptions::Private & compressionOptions, void * output) = 0; + virtual uint blockSize() const = 0; + }; - struct TileCompressor : public CompressorInterface - { - virtual void compress(nvtt::InputFormat inputFormat, nvtt::AlphaMode alphaMode, uint w, uint h, const void * data, const nvtt::CompressionOptions::Private & compressionOptions, const nvtt::OutputOptions::Private & outputOptions); + struct TileCompressor : public CompressorInterface + { + virtual void compress(nvtt::AlphaMode alphaMode, uint w, uint h, const float * rgba, const nvtt::CompressionOptions::Private & compressionOptions, const nvtt::OutputOptions::Private & outputOptions); - virtual void compressBlock(Tile & tile, nvtt::AlphaMode alphaMode, const nvtt::CompressionOptions::Private & compressionOptions, void * output) = 0; - virtual uint blockSize() const = 0; - }; + virtual void compressBlock(Tile & tile, nvtt::AlphaMode alphaMode, const nvtt::CompressionOptions::Private & compressionOptions, void * output) = 0; + virtual uint blockSize() const = 0; + }; } // nv namespace diff --git a/src/nvtt/CompressorRGB.cpp b/src/nvtt/CompressorRGB.cpp index a1a0514..3330ee3 100644 --- a/src/nvtt/CompressorRGB.cpp +++ b/src/nvtt/CompressorRGB.cpp @@ -39,19 +39,19 @@ using namespace nvtt; namespace { - inline void convert_to_a8r8g8b8(const void * src, void * dst, uint w) - { - memcpy(dst, src, 4 * w); - } + inline void convert_to_a8r8g8b8(const void * src, void * dst, uint w) + { + memcpy(dst, src, 4 * w); + } - inline void convert_to_x8r8g8b8(const void * src, void * dst, uint w) - { - memcpy(dst, src, 4 * w); - } + inline void convert_to_x8r8g8b8(const void * src, void * dst, uint w) + { + memcpy(dst, src, 4 * w); + } static uint16 to_half(float f) { - union { float f; uint32 u; } c; + union { float f; uint32 u; } c; c.f = f; return half_from_float(c.u); } @@ -121,8 +121,10 @@ namespace -void PixelFormatConverter::compress(nvtt::InputFormat inputFormat, nvtt::AlphaMode alphaMode, uint w, uint h, const void * data, const nvtt::CompressionOptions::Private & compressionOptions, const nvtt::OutputOptions::Private & outputOptions) +void PixelFormatConverter::compress(nvtt::AlphaMode /*alphaMode*/, uint w, uint h, const float * data, const nvtt::CompressionOptions::Private & compressionOptions, const nvtt::OutputOptions::Private & outputOptions) { + nvDebugCheck (compressionOptions.format == nvtt::Format_RGBA); + uint bitCount; uint rmask, rshift, rsize; uint gmask, gshift, gsize; @@ -193,89 +195,65 @@ void PixelFormatConverter::compress(nvtt::InputFormat inputFormat, nvtt::AlphaMo const uint * src = (const uint *)data + y * w; const float * fsrc = (const float *)data + y * w; - if (inputFormat == nvtt::InputFormat_BGRA_8UB && compressionOptions.pixelType == nvtt::PixelType_UnsignedNorm && bitCount == 32 && rmask == 0xFF0000 && gmask == 0xFF00 && bmask == 0xFF && amask == 0xFF000000) - { - convert_to_a8r8g8b8(src, dst, w); - } - else - { - BitStream stream(dst); + BitStream stream(dst); - for (uint x = 0; x < w; x++) + for (uint x = 0; x < w; x++) + { + float r = fsrc[x + 0 * wh]; + float g = fsrc[x + 1 * wh]; + float b = fsrc[x + 2 * wh]; + float a = fsrc[x + 3 * wh]; + + if (compressionOptions.pixelType == nvtt::PixelType_Float) { - float r, g, b, a; + if (rsize == 32) stream.putFloat(r); + else if (rsize == 16) stream.putHalf(r); - if (inputFormat == nvtt::InputFormat_BGRA_8UB) { - Color32 c = Color32(src[x]); - r = float(c.r) / 255.0f; - g = float(c.g) / 255.0f; - b = float(c.b) / 255.0f; - a = float(c.a) / 255.0f; - } - else { - nvDebugCheck (inputFormat == nvtt::InputFormat_RGBA_32F); + if (gsize == 32) stream.putFloat(g); + else if (gsize == 16) stream.putHalf(g); - //r = ((float *)src)[4 * x + 0]; // Color components not interleaved. - //g = ((float *)src)[4 * x + 1]; - //b = ((float *)src)[4 * x + 2]; - //a = ((float *)src)[4 * x + 3]; - r = fsrc[x + 0 * wh]; - g = fsrc[x + 1 * wh]; - b = fsrc[x + 2 * wh]; - a = fsrc[x + 3 * wh]; - } + if (bsize == 32) stream.putFloat(b); + else if (bsize == 16) stream.putHalf(b); - if (compressionOptions.pixelType == nvtt::PixelType_Float) - { - if (rsize == 32) stream.putFloat(r); - else if (rsize == 16) stream.putHalf(r); - - if (gsize == 32) stream.putFloat(g); - else if (gsize == 16) stream.putHalf(g); - - if (bsize == 32) stream.putFloat(b); - else if (bsize == 16) stream.putHalf(b); - - if (asize == 32) stream.putFloat(a); - else if (asize == 16) stream.putHalf(a); - } - else - { - Color32 c; - if (compressionOptions.pixelType == nvtt::PixelType_UnsignedNorm) { - c.r = uint8(clamp(r * 255, 0.0f, 255.0f)); - c.g = uint8(clamp(g * 255, 0.0f, 255.0f)); - c.b = uint8(clamp(b * 255, 0.0f, 255.0f)); - c.a = uint8(clamp(a * 255, 0.0f, 255.0f)); - } - // @@ Add support for nvtt::PixelType_SignedInt, nvtt::PixelType_SignedNorm, nvtt::PixelType_UnsignedInt - - uint p = 0; - p |= PixelFormat::convert(c.r, 8, rsize) << rshift; - p |= PixelFormat::convert(c.g, 8, gsize) << gshift; - p |= PixelFormat::convert(c.b, 8, bsize) << bshift; - p |= PixelFormat::convert(c.a, 8, asize) << ashift; - - stream.putBits(p, bitCount); - - // Output one byte at a time. - /*for (uint i = 0; i < byteCount; i++) - { - *(dst + x * byteCount + i) = (p >> (i * 8)) & 0xFF; - }*/ - } + if (asize == 32) stream.putFloat(a); + else if (asize == 16) stream.putHalf(a); } - - // Zero padding. - stream.align(compressionOptions.pitchAlignment); - nvDebugCheck(stream.ptr == dst + pitch); - - /*for (uint x = w * byteCount; x < pitch; x++) + else { - *(dst + x) = 0; - }*/ + Color32 c; + if (compressionOptions.pixelType == nvtt::PixelType_UnsignedNorm) { + c.r = uint8(clamp(r * 255, 0.0f, 255.0f)); + c.g = uint8(clamp(g * 255, 0.0f, 255.0f)); + c.b = uint8(clamp(b * 255, 0.0f, 255.0f)); + c.a = uint8(clamp(a * 255, 0.0f, 255.0f)); + } + // @@ Add support for nvtt::PixelType_SignedInt, nvtt::PixelType_SignedNorm, nvtt::PixelType_UnsignedInt + + uint p = 0; + p |= PixelFormat::convert(c.r, 8, rsize) << rshift; + p |= PixelFormat::convert(c.g, 8, gsize) << gshift; + p |= PixelFormat::convert(c.b, 8, bsize) << bshift; + p |= PixelFormat::convert(c.a, 8, asize) << ashift; + + stream.putBits(p, bitCount); + + // Output one byte at a time. + /*for (uint i = 0; i < byteCount; i++) + { + *(dst + x * byteCount + i) = (p >> (i * 8)) & 0xFF; + }*/ + } } + // Zero padding. + stream.align(compressionOptions.pitchAlignment); + nvDebugCheck(stream.ptr == dst + pitch); + + /*for (uint x = w * byteCount; x < pitch; x++) + { + *(dst + x) = 0; + }*/ + outputOptions.writeData(dst, pitch); } diff --git a/src/nvtt/CompressorRGB.h b/src/nvtt/CompressorRGB.h index 26e7966..75dda52 100644 --- a/src/nvtt/CompressorRGB.h +++ b/src/nvtt/CompressorRGB.h @@ -29,9 +29,9 @@ namespace nv { struct PixelFormatConverter : public CompressorInterface - { - virtual void compress(nvtt::InputFormat inputFormat, nvtt::AlphaMode alphaMode, uint w, uint h, const void * data, const nvtt::CompressionOptions::Private & compressionOptions, const nvtt::OutputOptions::Private & outputOptions); - }; + { + virtual void compress(nvtt::AlphaMode alphaMode, uint w, uint h, const float * data, const nvtt::CompressionOptions::Private & compressionOptions, const nvtt::OutputOptions::Private & outputOptions); + }; } // nv namespace diff --git a/src/nvtt/CompressorRGBE.cpp b/src/nvtt/CompressorRGBE.cpp index 8f8d212..3cc22b5 100644 --- a/src/nvtt/CompressorRGBE.cpp +++ b/src/nvtt/CompressorRGBE.cpp @@ -55,7 +55,7 @@ static Color32 toRgbe8(float r, float g, float b) } -void CompressorRGBE::compress(nvtt::InputFormat inputFormat, nvtt::AlphaMode alphaMode, uint w, uint h, const void * data, const nvtt::CompressionOptions::Private & compressionOptions, const nvtt::OutputOptions::Private & outputOptions) +void CompressorRGBE::compress(nvtt::AlphaMode /*alphaMode*/, uint w, uint h, const float * data, const nvtt::CompressionOptions::Private & compressionOptions, const nvtt::OutputOptions::Private & outputOptions) { nvDebugCheck (compressionOptions.format == nvtt::Format_RGBE); @@ -63,39 +63,25 @@ void CompressorRGBE::compress(nvtt::InputFormat inputFormat, nvtt::AlphaMode alp uint srcPlane = w * h; // Allocate output scanline. - Color32 * dst = new Color32[w]; + Color32 * dst = new Color32[w]; - for (uint y = 0; y < h; y++) - { - const uint * src = (const uint *)data + y * srcPitch; - const float * fsrc = (const float *)data + y * srcPitch; + for (uint y = 0; y < h; y++) + { + const float * src = (const float *)data + y * srcPitch; - for (uint x = 0; x < w; x++) - { - float r, g, b; - - if (inputFormat == nvtt::InputFormat_BGRA_8UB) { - Color32 c = Color32(src[x]); - r = float(c.r) / 255.0f; - g = float(c.g) / 255.0f; - b = float(c.b) / 255.0f; - } - else { - nvDebugCheck (inputFormat == nvtt::InputFormat_RGBA_32F); - - // Color components not interleaved. - r = fsrc[x + 0 * srcPlane]; - g = fsrc[x + 1 * srcPlane]; - b = fsrc[x + 2 * srcPlane]; - } + for (uint x = 0; x < w; x++) + { + float r = src[x + 0 * srcPlane]; + float g = src[x + 1 * srcPlane]; + float b = src[x + 2 * srcPlane]; dst[x] = toRgbe8(r, g, b); } - if (outputOptions.outputHandler != NULL) - { - outputOptions.outputHandler->writeData(dst, w * 4); - } + if (outputOptions.outputHandler != NULL) + { + outputOptions.outputHandler->writeData(dst, w * 4); + } } delete [] dst; diff --git a/src/nvtt/CompressorRGBE.h b/src/nvtt/CompressorRGBE.h index 5be9bfa..6fcedf6 100644 --- a/src/nvtt/CompressorRGBE.h +++ b/src/nvtt/CompressorRGBE.h @@ -30,7 +30,7 @@ namespace nv { struct CompressorRGBE : public CompressorInterface { - virtual void compress(nvtt::InputFormat inputFormat, nvtt::AlphaMode alphaMode, uint w, uint h, const void * data, const nvtt::CompressionOptions::Private & compressionOptions, const nvtt::OutputOptions::Private & outputOptions); + virtual void compress(nvtt::AlphaMode alphaMode, uint w, uint h, const float * data, const nvtt::CompressionOptions::Private & compressionOptions, const nvtt::OutputOptions::Private & outputOptions); }; } // nv namespace diff --git a/src/nvtt/Context.cpp b/src/nvtt/Context.cpp index bf15a01..cc63750 100644 --- a/src/nvtt/Context.cpp +++ b/src/nvtt/Context.cpp @@ -23,21 +23,7 @@ #include "Context.h" -#include - -#include -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include +#include "nvtt.h" #include "InputOptions.h" #include "CompressionOptions.h" @@ -52,6 +38,22 @@ #include "cuda/CudaUtils.h" #include "cuda/CudaCompressorDXT.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 "nvimage/PixelFormat.h" +#include "nvimage/ColorSpace.h" + +#include "nvcore/Memory.h" +#include "nvcore/Ptr.h" + + + using namespace nv; using namespace nvtt; @@ -108,7 +110,7 @@ namespace nvtt // - a pointer to an input image. // - a fixed point image. // - a floating point image. - struct Mipmap + /*struct Mipmap { Mipmap() : m_inputImage(NULL) {} ~Mipmap() {} @@ -211,7 +213,7 @@ namespace nvtt const Image * m_inputImage; AutoPtr m_fixedImage; AutoPtr m_floatImage; - }; + };*/ } // nvtt namespace @@ -220,29 +222,10 @@ Compressor::Compressor() : m(*new Compressor::Private()) { // CUDA initialization. m.cudaSupported = cuda::isHardwarePresent(); - m.cudaEnabled = m.cudaSupported; + m.cudaEnabled = false; + m.cuda = NULL; - if (m.cudaEnabled) - { -#pragma NV_MESSAGE("FIXME: This code is duplicated below.") - // Select fastest CUDA device. - int device = cuda::getFastestDevice(); - if (!cuda::setDevice(device)) - { - m.cudaEnabled = false; - m.cuda = NULL; - } - else - { - m.cuda = new CudaContext(); - - if (!m.cuda->isValid()) - { - m.cudaEnabled = false; - m.cuda = NULL; - } - } - } + enableCudaAcceleration(m.cudaSupported); } Compressor::~Compressor() @@ -252,7 +235,6 @@ Compressor::~Compressor() } -/// Enable CUDA acceleration. void Compressor::enableCudaAcceleration(bool enable) { if (m.cudaSupported) @@ -262,7 +244,7 @@ void Compressor::enableCudaAcceleration(bool enable) if (m.cudaEnabled && m.cuda == NULL) { - // Select fastest CUDA device. + // Select fastest CUDA device. @@ This is done automatically on current CUDA versions. int device = cuda::getFastestDevice(); if (!cuda::setDevice(device)) { @@ -282,52 +264,31 @@ void Compressor::enableCudaAcceleration(bool enable) } } -/// Return true if CUDA acceleration is enabled, false otherwise. bool Compressor::isCudaAccelerationEnabled() const { return m.cudaEnabled; } -/// Compress the input texture with the given compression options. +// Input Options API. bool Compressor::process(const InputOptions & inputOptions, const CompressionOptions & compressionOptions, const OutputOptions & outputOptions) const { return m.compress(inputOptions.m, compressionOptions.m, outputOptions.m); } -/// Estimate the size of compressing the input with the given options. int Compressor::estimateSize(const InputOptions & inputOptions, const CompressionOptions & compressionOptions) const { - return m.estimateSize(inputOptions.m, compressionOptions.m); -} - - -// RAW api. -bool Compressor::compress2D(InputFormat format, int w, int h, void * data, const CompressionOptions & compressionOptions, const OutputOptions & outputOptions) const -{ - return m.compress2D(format, AlphaMode_None, w, h, data, compressionOptions.m, outputOptions.m); -} - -int Compressor::estimateSize(int w, int h, int d, const CompressionOptions & compressionOptions) const -{ - const CompressionOptions::Private & co = compressionOptions.m; - - const Format format = co.format; - - uint bitCount = co.getBitCount(); - - return computeImageSize(w, h, d, bitCount, co.pitchAlignment, format); -} - - - -/// Create a TexImage. -TexImage Compressor::createTexImage() const -{ - return *new TexImage(); + // @@ Compute w, h, mipmapCount based on inputOptions settings. + const int w = 0; + const int h = 0; + const int d = 1; + int mipmapCount = 1; + + return inputOptions.m.faceCount * estimateSize(w, h, d, mipmapCount, compressionOptions); } +// TexImage API. bool Compressor::outputHeader(const TexImage & tex, int mipmapCount, const CompressionOptions & compressionOptions, const OutputOptions & outputOptions) const { return m.outputHeader(tex, mipmapCount, compressionOptions.m, outputOptions.m); @@ -335,26 +296,47 @@ bool Compressor::outputHeader(const TexImage & tex, int mipmapCount, const Compr bool Compressor::compress(const TexImage & tex, const CompressionOptions & compressionOptions, const OutputOptions & outputOptions) const { - foreach(i, tex.m->imageArray) { - FloatImage * image = tex.m->imageArray[i]; - if (!m.compress2D(InputFormat_RGBA_32F, tex.m->alphaMode, image->width(), image->height(), image->channel(0), compressionOptions.m, outputOptions.m)) { - return false; - } + return m.compress(tex, compressionOptions.m, outputOptions.m); +} + +int Compressor::estimateSize(const TexImage & tex, int mipmapCount, const CompressionOptions & compressionOptions) const +{ + const int w = tex.width(); + const int h = tex.height(); + const int d = tex.depth(); + const int faceCount = tex.faceCount(); + + return faceCount * estimateSize(w, h, d, mipmapCount, compressionOptions); +} + + +// Raw API. +bool Compressor::compress(int w, int h, int d, const float * rgba, const CompressionOptions & compressionOptions, const OutputOptions & outputOptions) const +{ + return m.compress(AlphaMode_None, w, h, d, rgba, compressionOptions.m, outputOptions.m); +} + +int Compressor::estimateSize(int w, int h, int d, int mipmapCount, const CompressionOptions & compressionOptions) const +{ + const Format format = compressionOptions.m.format; + + const uint bitCount = compressionOptions.m.getBitCount(); + const uint pitchAlignment = compressionOptions.m.pitchAlignment; + + int size = 0; + for (int m = 0; m < mipmapCount; m++) + { + size += computeImageSize(w, h, d, bitCount, pitchAlignment, format); + + // Compute extents of next mipmap: + w = max(1, w / 2); + h = max(1, h / 2); + d = max(1, d / 2); } - return true; + return size; } -/// Estimate the size of compressing the given texture. -int Compressor::estimateSize(const TexImage & tex, const CompressionOptions & compressionOptions) const -{ - const uint w = tex.width(); - const uint h = tex.height(); - const uint d = tex.depth(); - const uint faceCount = tex.faceCount(); - - return faceCount * estimateSize(w, h, d, compressionOptions); -} @@ -373,279 +355,130 @@ bool Compressor::Private::compress(const InputOptions::Private & inputOptions, c return false; } - inputOptions.computeTargetExtents(); + nvtt::TexImage img; + img.setTextureType(inputOptions.textureType); + img.setWrapMode(inputOptions.wrapMode); + img.setAlphaMode(inputOptions.alphaMode); + img.setNormalMap(inputOptions.isNormalMap); - // Output DDS header. - if (!outputHeader(inputOptions, compressionOptions, outputOptions)) + const int faceCount = inputOptions.faceCount; + int w = inputOptions.width; + int h = inputOptions.height; + int d = inputOptions.depth; + + for (int f = 0; f < faceCount; f++) + { + img.setImage2D(inputOptions.inputFormat, w, h, f, inputOptions.images[f]); + } + + // To linear space. + if (!inputOptions.isNormalMap) { + img.toLinear(inputOptions.inputGamma); + } + + // Resize input. + img.resize(inputOptions.maxExtent, inputOptions.roundMode, ResizeFilter_Box); + + // If the extents have not change we can use source images for the mipmaps. + bool canUseSourceImages = (img.width() == w && img.height() == h); + + int mipmapCount = 1; + if (inputOptions.generateMipmaps) { + mipmapCount = img.countMipmaps(); + if (inputOptions.maxLevel > 0) mipmapCount = min(mipmapCount, inputOptions.maxLevel); + } + + if (!outputHeader(img, mipmapCount, compressionOptions, outputOptions)) { return false; } - for (uint f = 0; f < inputOptions.faceCount; f++) - { - if (!compressMipmaps(f, inputOptions, compressionOptions, outputOptions)) - { - return false; - } + nvtt::TexImage tmp = img; + if (!inputOptions.isNormalMap) { + tmp.toGamma(inputOptions.outputGamma); } + // @@ Fix order of cubemap faces! + + // @@ Apply quantization options. + + int size = computeImageSize(w, h, d, compressionOptions.bitcount, compressionOptions.pitchAlignment, compressionOptions.format); + outputOptions.beginImage(size, w, h, d, 0, 0); + + compress(tmp, compressionOptions, outputOptions); + + for (int m = 1; m < mipmapCount; m++) { + w = max(1, w/2); + h = max(1, h/2); + d = max(1, d/2); + + int size = computeImageSize(w, h, d, compressionOptions.bitcount, compressionOptions.pitchAlignment, compressionOptions.format); + outputOptions.beginImage(size, w, h, d, 0, m); + + bool useSourceImages = false; + if (canUseSourceImages) { + useSourceImages = true; + for (int f = 0; f < faceCount; f++) { + int idx = m * faceCount + f; + if (inputOptions.images[idx] == NULL) { // One face is missing in this mipmap level. + useSourceImages = false; + canUseSourceImages = false; // If one level is missing, ignore the following source images. + break; + } + } + } + + if (useSourceImages) { + for (int f = 0; f < faceCount; f++) { + int idx = m * faceCount + f; + img.setImage2D(inputOptions.inputFormat, w, h, f, inputOptions.images[idx]); + } + } + else { + if (inputOptions.mipmapFilter == MipmapFilter_Kaiser) { + float params[2] = { inputOptions.kaiserStretch, inputOptions.kaiserAlpha }; + img.buildNextMipmap(MipmapFilter_Kaiser, inputOptions.kaiserWidth, params); + } + else { + img.buildNextMipmap(inputOptions.mipmapFilter); + } + } + nvDebugCheck(img.width() == w); + nvDebugCheck(img.height() == h); + + if (inputOptions.isNormalMap) { + if (inputOptions.normalizeMipmaps) { + img.normalizeNormalMap(); + } + tmp = img; + } + else { + tmp = img; + tmp.toGamma(inputOptions.outputGamma); + } + + // @@ Apply quantization options. + + compress(tmp, compressionOptions, outputOptions); + }; + return true; } -// Output DDS header. -bool Compressor::Private::outputHeader(const InputOptions::Private & inputOptions, const CompressionOptions::Private & compressionOptions, const OutputOptions::Private & outputOptions) const +bool Compressor::Private::compress(const TexImage & tex, const CompressionOptions::Private & compressionOptions, const OutputOptions::Private & outputOptions) const { - // Output DDS header. - if (outputOptions.outputHandler == NULL || !outputOptions.outputHeader) - { - return true; - } - - if (outputOptions.container == Container_DDS || outputOptions.container == Container_DDS10) - { - DDSHeader header; - - header.setUserVersion(outputOptions.version); - - 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(inputOptions.targetDepth); - }*/ - - header.setWidth(inputOptions.targetWidth); - header.setHeight(inputOptions.targetHeight); - - int mipmapCount = inputOptions.realMipmapCount(); - nvDebugCheck(mipmapCount > 0); - - header.setMipmapCount(mipmapCount); - - bool supported = true; - - if (outputOptions.container == Container_DDS10) - { - if (compressionOptions.format == Format_RGBA) - { - int bitcount = compressionOptions.bitcount; - if (bitcount == 0) { - bitcount = compressionOptions.rsize + compressionOptions.gsize + compressionOptions.bsize + compressionOptions.asize; - } - - if (bitcount == 16) - { - if (compressionOptions.rsize == 16) - { - header.setDX10Format(56); // R16_UNORM - } - else - { - // B5G6R5_UNORM - // B5G5R5A1_UNORM - supported = false; - } - } - else if (bitcount == 32) - { - // B8G8R8A8_UNORM - // B8G8R8X8_UNORM - // R8G8B8A8_UNORM - // R10G10B10A2_UNORM - supported = false; - } - else { - supported = false; - } - } - else - { - if (compressionOptions.format == Format_DXT1 || compressionOptions.format == Format_DXT1a || compressionOptions.format == Format_DXT1n) { - header.setDX10Format(70); // DXGI_FORMAT_BC1_TYPELESS - if (compressionOptions.format == Format_DXT1a) header.setHasAlphaFlag(true); - if (inputOptions.isNormalMap) header.setNormalFlag(true); - } - else if (compressionOptions.format == Format_DXT3) { - header.setDX10Format(73); // DXGI_FORMAT_BC2_TYPELESS - } - else if (compressionOptions.format == Format_DXT5) { - header.setDX10Format(76); // DXGI_FORMAT_BC3_TYPELESS - } - else if (compressionOptions.format == Format_DXT5n) { - header.setDX10Format(76); // DXGI_FORMAT_BC3_TYPELESS - if (inputOptions.isNormalMap) header.setNormalFlag(true); - } - else if (compressionOptions.format == Format_BC4) { - header.setDX10Format(79); // DXGI_FORMAT_BC4_TYPELESS - } - else if (compressionOptions.format == Format_BC5) { - header.setDX10Format(82); // DXGI_FORMAT_BC5_TYPELESS - if (inputOptions.isNormalMap) header.setNormalFlag(true); - } - else if (compressionOptions.format == Format_BC6) { - header.setDX10Format(94); // DXGI_FORMAT_BC6H_TYPELESS - } - else if (compressionOptions.format == Format_BC7) { - header.setDX10Format(97); // DXGI_FORMAT_BC7_TYPELESS - if (inputOptions.isNormalMap) header.setNormalFlag(true); - } - else { - supported = false; - } - } - } - else - { - if (compressionOptions.format == Format_RGBA) - { - // Get output bit count. - header.setPitch(computePitch(inputOptions.targetWidth, compressionOptions.getBitCount(), compressionOptions.pitchAlignment)); - - if (compressionOptions.pixelType == PixelType_Float) - { - if (compressionOptions.rsize == 16 && compressionOptions.gsize == 0 && compressionOptions.bsize == 0 && compressionOptions.asize == 0) - { - header.setFormatCode(111); // D3DFMT_R16F - } - else if (compressionOptions.rsize == 16 && compressionOptions.gsize == 16 && compressionOptions.bsize == 0 && compressionOptions.asize == 0) - { - header.setFormatCode(112); // D3DFMT_G16R16F - } - else if (compressionOptions.rsize == 16 && compressionOptions.gsize == 16 && compressionOptions.bsize == 16 && compressionOptions.asize == 16) - { - header.setFormatCode(113); // D3DFMT_A16B16G16R16F - } - else if (compressionOptions.rsize == 32 && compressionOptions.gsize == 0 && compressionOptions.bsize == 0 && compressionOptions.asize == 0) - { - header.setFormatCode(114); // D3DFMT_R32F - } - else if (compressionOptions.rsize == 32 && compressionOptions.gsize == 32 && compressionOptions.bsize == 0 && compressionOptions.asize == 0) - { - header.setFormatCode(115); // D3DFMT_G32R32F - } - else if (compressionOptions.rsize == 32 && compressionOptions.gsize == 32 && compressionOptions.bsize == 32 && compressionOptions.asize == 32) - { - header.setFormatCode(116); // D3DFMT_A32B32G32R32F - } - else - { - supported = false; - } - } - else // Fixed point - { - const uint bitcount = compressionOptions.getBitCount(); - - if (compressionOptions.bitcount != 0) - { - // Masks already computed. - header.setPixelFormat(compressionOptions.bitcount, compressionOptions.rmask, compressionOptions.gmask, compressionOptions.bmask, compressionOptions.amask); - } - else if (bitcount <= 32) - { - // Compute pixel format masks. - const uint ashift = 0; - const uint bshift = ashift + compressionOptions.asize; - const uint gshift = bshift + compressionOptions.bsize; - const uint rshift = gshift + compressionOptions.gsize; - - const uint rmask = ((1 << compressionOptions.rsize) - 1) << rshift; - const uint gmask = ((1 << compressionOptions.gsize) - 1) << gshift; - const uint bmask = ((1 << compressionOptions.bsize) - 1) << bshift; - const uint amask = ((1 << compressionOptions.asize) - 1) << ashift; - - header.setPixelFormat(bitcount, rmask, gmask, bmask, amask); - } - else - { - supported = false; - } - } - } - else - { - header.setLinearSize(computeImageSize(inputOptions.targetWidth, inputOptions.targetHeight, inputOptions.targetDepth, compressionOptions.bitcount, compressionOptions.pitchAlignment, compressionOptions.format)); - - if (compressionOptions.format == Format_DXT1 || compressionOptions.format == Format_DXT1a || compressionOptions.format == Format_DXT1n) { - header.setFourCC('D', 'X', 'T', '1'); - if (inputOptions.isNormalMap) header.setNormalFlag(true); - } - 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'); - if (inputOptions.isNormalMap) { - header.setNormalFlag(true); - header.setSwizzleCode('A', '2', 'D', '5'); - //header.setSwizzleCode('x', 'G', 'x', 'R'); - } - } - else if (compressionOptions.format == Format_BC4) { - header.setFourCC('A', 'T', 'I', '1'); - } - else if (compressionOptions.format == Format_BC5) { - header.setFourCC('A', 'T', 'I', '2'); - if (inputOptions.isNormalMap) { - header.setNormalFlag(true); - header.setSwizzleCode('A', '2', 'X', 'Y'); - } - } - else if (compressionOptions.format == Format_BC6) { - header.setFourCC('Z', 'O', 'H', ' '); - } - else if (compressionOptions.format == Format_BC7) { - header.setFourCC('Z', 'O', 'L', 'A'); - if (inputOptions.isNormalMap) header.setNormalFlag(true); - } - else if (compressionOptions.format == Format_CTX1) { - header.setFourCC('C', 'T', 'X', '1'); - if (inputOptions.isNormalMap) header.setNormalFlag(true); - } - else { - supported = false; - } - } - } - - if (!supported) - { - // This container does not support the requested format. - outputOptions.error(Error_UnsupportedOutputFormat); + foreach(i, tex.m->imageArray) { + FloatImage * image = tex.m->imageArray[i]; + if (!compress(tex.alphaMode(), tex.width(), tex.height(), tex.depth(), image->channel(0), compressionOptions, outputOptions)) { return false; } - - // Swap bytes if necessary. - header.swapBytes(); - - uint headerSize = 128; - if (header.hasDX10Header()) - { - nvStaticCheck(sizeof(DDSHeader) == 128 + 20); - headerSize = 128 + 20; - } - - bool writeSucceed = outputOptions.outputHandler->writeData(&header, headerSize); - if (!writeSucceed) - { - outputOptions.error(Error_FileWrite); - } - - return writeSucceed; } - return true; } -bool Compressor::Private::outputHeader(const TexImage & tex, int mipmapCount, const CompressionOptions::Private & compressionOptions, const OutputOptions::Private & outputOptions) + +bool Compressor::Private::outputHeader(const TexImage & tex, int mipmapCount, const CompressionOptions::Private & compressionOptions, const OutputOptions::Private & outputOptions) const { if (tex.width() <= 0 || tex.height() <= 0 || tex.depth() <= 0 || mipmapCount <= 0) { @@ -899,429 +732,6 @@ bool Compressor::Private::outputHeader(const TexImage & tex, int mipmapCount, co } -bool Compressor::Private::compressMipmaps(uint f, const InputOptions::Private & inputOptions, const CompressionOptions::Private & compressionOptions, const OutputOptions::Private & outputOptions) const -{ - uint w = inputOptions.targetWidth; - uint h = inputOptions.targetHeight; - uint d = inputOptions.targetDepth; - - Mipmap mipmap; - - const uint mipmapCount = inputOptions.realMipmapCount(); - nvDebugCheck(mipmapCount > 0); - - for (uint m = 0; m < mipmapCount; m++) - { - int size = computeImageSize(w, h, d, compressionOptions.getBitCount(), compressionOptions.pitchAlignment, compressionOptions.format); - outputOptions.beginImage(size, w, h, d, f, m); - - if (!initMipmap(mipmap, inputOptions, w, h, d, f, m)) - { - outputOptions.error(Error_InvalidInput); - return false; - } - - if (compressionOptions.pixelType == PixelType_Float) - { - mipmap.toFloatImage(inputOptions); - - // @@ Convert to linear space. - - // @@ HACK - const FloatImage * image = mipmap.asFloatImage(); - nvDebugCheck(image != NULL); - - // @@ Ignore return value? - compress2D(InputFormat_RGBA_32F, inputOptions.alphaMode, image->width(), image->height(), image->channel(0), compressionOptions, outputOptions); - } - else - { - // Convert linear float image to fixed image ready for compression. - mipmap.toFixedImage(inputOptions); - - if (inputOptions.premultiplyAlpha) - { - premultiplyAlphaMipmap(mipmap, inputOptions); - } - -#pragma NV_MESSAGE("TODO: All color transforms should be done here!") - - // Apply gamma space color transforms: - if (inputOptions.colorTransform == ColorTransform_YCoCg) - { - ColorSpace::RGBtoYCoCg_R(mipmap.asMutableFixedImage()); - } - else if (inputOptions.colorTransform == ColorTransform_ScaledYCoCg) - { - // @@ TODO - //ColorSpace::RGBtoYCoCg_R(mipmap.asMutableFixedImage()); - } - - /*// Apply linear transforms in linear space. - if (inputOptions.colorTransform == ColorTransform_Linear) - { - FloatImage * image = mipmap.asMutableFloatImage(); - nvDebugCheck(image != NULL); - - Vector4 offset( - inputOptions.colorOffsets[0], - inputOptions.colorOffsets[1], - inputOptions.colorOffsets[2], - inputOptions.colorOffsets[3]); - - image->transform(0, inputOptions.linearTransform, offset); - } - else if (inputOptions.colorTransform == ColorTransform_Swizzle) - { - FloatImage * image = mipmap.asMutableFloatImage(); - nvDebugCheck(image != NULL); - - image->swizzle(0, inputOptions.swizzleTransform[0], inputOptions.swizzleTransform[1], inputOptions.swizzleTransform[2], inputOptions.swizzleTransform[3]); - }*/ - - quantizeMipmap(mipmap, compressionOptions); - - const Image * image = mipmap.asFixedImage(); - nvDebugCheck(image != NULL); - - // @@ Ignore return value? - compress2D(InputFormat_BGRA_8UB, inputOptions.alphaMode, image->width(), image->height(), image->pixels(), compressionOptions, outputOptions); - } - - - - - // Compute extents of next mipmap: - w = max(1U, w / 2); - h = max(1U, h / 2); - d = max(1U, d / 2); - } - - return true; -} - -bool Compressor::Private::initMipmap(Mipmap & mipmap, const InputOptions::Private & inputOptions, uint w, uint h, uint d, uint f, uint m) const -{ - // Find image from input. - int inputIdx = findExactMipmap(inputOptions, w, h, d, f); - - if ((inputIdx == -1 || inputOptions.convertToNormalMap) && m != 0) - { - // Generate from last, when mipmap not found, or normal map conversion enabled. - downsampleMipmap(mipmap, inputOptions); - } - else - { - if (inputIdx != -1) - { - // If input mipmap found, then get from input. - mipmap.setFromInput(inputOptions, inputIdx); - } - else - { - // If not found, resize closest mipmap. - inputIdx = findClosestMipmap(inputOptions, w, h, d, f); - - if (inputIdx == -1) - { - return false; - } - - mipmap.setFromInput(inputOptions, inputIdx); - - scaleMipmap(mipmap, inputOptions, w, h, d); - } - - processInputImage(mipmap, inputOptions); - } - - return true; -} - -int Compressor::Private::findExactMipmap(const InputOptions::Private & inputOptions, uint w, uint h, uint d, uint f) const -{ - for (int m = 0; m < int(inputOptions.mipmapCount); m++) - { - int idx = f * inputOptions.mipmapCount + m; - const InputOptions::Private::InputImage & inputImage = inputOptions.images[idx]; - - if (inputImage.width == int(w) && inputImage.height == int(h) && inputImage.depth == int(d)) - { - if (inputImage.hasValidData()) - { - return idx; - } - return -1; - } - else if (inputImage.width < int(w) || inputImage.height < int(h) || inputImage.depth < int(d)) - { - return -1; - } - } - - return -1; -} - -int Compressor::Private::findClosestMipmap(const InputOptions::Private & inputOptions, uint w, uint h, uint d, uint f) const -{ - int bestIdx = -1; - - for (int m = 0; m < int(inputOptions.mipmapCount); m++) - { - int idx = f * inputOptions.mipmapCount + m; - const InputOptions::Private::InputImage & inputImage = inputOptions.images[idx]; - - if (inputImage.hasValidData()) - { - int difference = (inputImage.width - w) + (inputImage.height - h) + (inputImage.depth - d); - - if (difference < 0) - { - if (bestIdx == -1) - { - bestIdx = idx; - } - - return bestIdx; - } - - bestIdx = idx; - } - } - - return bestIdx; -} - -// Create mipmap from the given image. -void Compressor::Private::downsampleMipmap(Mipmap & mipmap, const InputOptions::Private & inputOptions) const -{ - // Make sure that floating point linear representation is available. - mipmap.toFloatImage(inputOptions); - - const FloatImage * floatImage = mipmap.asFloatImage(); - FloatImage::WrapMode wrapMode = (FloatImage::WrapMode)inputOptions.wrapMode; - - if (inputOptions.alphaMode == AlphaMode_Transparency) - { - if (inputOptions.mipmapFilter == MipmapFilter_Box) - { - BoxFilter filter; - mipmap.setImage(floatImage->downSample(filter, wrapMode, 3)); - } - else if (inputOptions.mipmapFilter == MipmapFilter_Triangle) - { - TriangleFilter filter; - mipmap.setImage(floatImage->downSample(filter, wrapMode, 3)); - } - else /*if (inputOptions.mipmapFilter == MipmapFilter_Kaiser)*/ - { - nvDebugCheck(inputOptions.mipmapFilter == MipmapFilter_Kaiser); - KaiserFilter filter(inputOptions.kaiserWidth); - filter.setParameters(inputOptions.kaiserAlpha, inputOptions.kaiserStretch); - mipmap.setImage(floatImage->downSample(filter, wrapMode, 3)); - } - } - else - { - if (inputOptions.mipmapFilter == MipmapFilter_Box) - { - // Use fast downsample. - mipmap.setImage(floatImage->fastDownSample()); - } - else if (inputOptions.mipmapFilter == MipmapFilter_Triangle) - { - TriangleFilter filter; - mipmap.setImage(floatImage->downSample(filter, wrapMode)); - } - else /*if (inputOptions.mipmapFilter == MipmapFilter_Kaiser)*/ - { - nvDebugCheck(inputOptions.mipmapFilter == MipmapFilter_Kaiser); - KaiserFilter filter(inputOptions.kaiserWidth); - filter.setParameters(inputOptions.kaiserAlpha, inputOptions.kaiserStretch); - mipmap.setImage(floatImage->downSample(filter, wrapMode)); - } - } - - // Normalize mipmap. - if ((inputOptions.isNormalMap || inputOptions.convertToNormalMap) && inputOptions.normalizeMipmaps) - { - normalizeNormalMap(mipmap.asMutableFloatImage()); - } -} - - -void Compressor::Private::scaleMipmap(Mipmap & mipmap, const InputOptions::Private & inputOptions, uint w, uint h, uint d) const -{ - mipmap.toFloatImage(inputOptions); - - // @@ Add more filters. - // @@ Select different filters for downscaling and reconstruction. - - // Resize image. - BoxFilter boxFilter; - - if (inputOptions.alphaMode == AlphaMode_Transparency) - { - mipmap.setImage(mipmap.asFloatImage()->resize(boxFilter, w, h, (FloatImage::WrapMode)inputOptions.wrapMode, 3)); - } - else - { - mipmap.setImage(mipmap.asFloatImage()->resize(boxFilter, w, h, (FloatImage::WrapMode)inputOptions.wrapMode)); - } -} - - -void Compressor::Private::premultiplyAlphaMipmap(Mipmap & mipmap, const InputOptions::Private & inputOptions) const -{ - nvDebugCheck(mipmap.asFixedImage() != NULL); - - Image * image = mipmap.asMutableFixedImage(); - - const uint w = image->width(); - const uint h = image->height(); - - const uint count = w * h; - - for (uint i = 0; i < count; ++i) - { - Color32 c = image->pixel(i); - - c.r = (uint(c.r) * uint(c.a)) >> 8; - c.g = (uint(c.g) * uint(c.a)) >> 8; - c.b = (uint(c.b) * uint(c.a)) >> 8; - - image->pixel(i) = c; - } -} - -// Process an input image: Convert to normal map, normalize, or convert to linear space. -void Compressor::Private::processInputImage(Mipmap & mipmap, const InputOptions::Private & inputOptions) const -{ - if (inputOptions.convertToNormalMap) - { - mipmap.toFixedImage(inputOptions); - - Vector4 heightScale = inputOptions.heightFactors; - mipmap.setImage(createNormalMap(mipmap.asFixedImage(), (FloatImage::WrapMode)inputOptions.wrapMode, heightScale, inputOptions.bumpFrequencyScale)); - } - else if (inputOptions.isNormalMap) - { - if (inputOptions.normalizeMipmaps) - { - // If floating point image available, normalize in place. - if (mipmap.asFloatImage() == NULL) - { - FloatImage * floatImage = new FloatImage(mipmap.asFixedImage()); - normalizeNormalMap(floatImage); - mipmap.setImage(floatImage); - } - else - { - normalizeNormalMap(mipmap.asMutableFloatImage()); - mipmap.setImage(mipmap.asMutableFloatImage()); - } - } - } - else - { - if (inputOptions.inputGamma != inputOptions.outputGamma || - inputOptions.colorTransform == ColorTransform_Linear || - inputOptions.colorTransform == ColorTransform_Swizzle) - { - mipmap.toFloatImage(inputOptions); - } - -#pragma NV_MESSAGE("FIXME: Do not perform color transforms here!") - - /*// Apply linear transforms in linear space. - if (inputOptions.colorTransform == ColorTransform_Linear) - { - FloatImage * image = mipmap.asMutableFloatImage(); - nvDebugCheck(image != NULL); - - Vector4 offset( - inputOptions.colorOffsets[0], - inputOptions.colorOffsets[1], - inputOptions.colorOffsets[2], - inputOptions.colorOffsets[3]); - - image->transform(0, inputOptions.linearTransform, offset); - } - else if (inputOptions.colorTransform == ColorTransform_Swizzle) - { - FloatImage * image = mipmap.asMutableFloatImage(); - nvDebugCheck(image != NULL); - - image->swizzle(0, inputOptions.swizzleTransform[0], inputOptions.swizzleTransform[1], inputOptions.swizzleTransform[2], inputOptions.swizzleTransform[3]); - }*/ - } -} - - -// Quantize the given mipmap according to the compression options. -void Compressor::Private::quantizeMipmap(Mipmap & mipmap, const CompressionOptions::Private & compressionOptions) const -{ - nvDebugCheck(mipmap.asFixedImage() != NULL); - - if (compressionOptions.binaryAlpha) - { - if (compressionOptions.enableAlphaDithering) - { - Quantize::FloydSteinberg_BinaryAlpha(mipmap.asMutableFixedImage(), compressionOptions.alphaThreshold); - } - else - { - Quantize::BinaryAlpha(mipmap.asMutableFixedImage(), compressionOptions.alphaThreshold); - } - } - - if (compressionOptions.enableColorDithering || compressionOptions.enableAlphaDithering) - { - uint rsize = 8; - uint gsize = 8; - uint bsize = 8; - uint asize = 8; - - if (compressionOptions.enableColorDithering) - { - if (compressionOptions.format >= Format_DXT1 && compressionOptions.format <= Format_DXT5) - { - rsize = 5; - gsize = 6; - bsize = 5; - } - else if (compressionOptions.format == Format_RGB) - { - uint rshift, gshift, bshift; - PixelFormat::maskShiftAndSize(compressionOptions.rmask, &rshift, &rsize); - PixelFormat::maskShiftAndSize(compressionOptions.gmask, &gshift, &gsize); - PixelFormat::maskShiftAndSize(compressionOptions.bmask, &bshift, &bsize); - } - } - - if (compressionOptions.enableAlphaDithering) - { - if (compressionOptions.format == Format_DXT3) - { - asize = 4; - } - else if (compressionOptions.format == Format_RGB) - { - uint ashift; - PixelFormat::maskShiftAndSize(compressionOptions.amask, &ashift, &asize); - } - } - - if (compressionOptions.binaryAlpha) - { - asize = 8; // Already quantized. - } - - Quantize::FloydSteinberg(mipmap.asMutableFixedImage(), rsize, gsize, bsize, asize); - } -} - - CompressorInterface * Compressor::Private::chooseCpuCompressor(const CompressionOptions::Private & compressionOptions) const { if (compressionOptions.format == Format_RGB) @@ -1330,33 +740,28 @@ CompressorInterface * Compressor::Private::chooseCpuCompressor(const Compression } else if (compressionOptions.format == Format_DXT1) { -#if defined(HAVE_S3QUANT) - if (compressionOptions.externalCompressor == "s3") return new S3CompressorDXT1; - else -#endif - #if defined(HAVE_ATITC) - if (compressionOptions.externalCompressor == "ati") return new AtiCompressorDXT1; + if (compressionOptions.externalCompressor == "ati") return new AtiCompressorDXT1; else #endif #if defined(HAVE_SQUISH) - if (compressionOptions.externalCompressor == "squish") return new SquishCompressorDXT1; + if (compressionOptions.externalCompressor == "squish") return new SquishCompressorDXT1; else #endif #if defined(HAVE_D3DX) - if (compressionOptions.externalCompressor == "d3dx") return new D3DXCompressorDXT1; + if (compressionOptions.externalCompressor == "d3dx") return new D3DXCompressorDXT1; else #endif #if defined(HAVE_D3DX) - if (compressionOptions.externalCompressor == "stb") return new StbCompressorDXT1; + if (compressionOptions.externalCompressor == "stb") return new StbCompressorDXT1; else #endif - if (compressionOptions.quality == Quality_Fastest) - { + if (compressionOptions.quality == Quality_Fastest) + { return new FastCompressorDXT1; } @@ -1391,8 +796,8 @@ CompressorInterface * Compressor::Private::chooseCpuCompressor(const Compression else #endif - if (compressionOptions.quality == Quality_Fastest) - { + if (compressionOptions.quality == Quality_Fastest) + { return new FastCompressorDXT5; } @@ -1463,7 +868,7 @@ CompressorInterface * Compressor::Private::chooseGpuCompressor(const Compression } else if (compressionOptions.format == Format_DXT1a) { -#pragma NV_MESSAGE("TODO: Implement CUDA DXT1a compressor.") + //#pragma NV_MESSAGE("TODO: Implement CUDA DXT1a compressor.") } else if (compressionOptions.format == Format_DXT1n) { @@ -1507,18 +912,7 @@ CompressorInterface * Compressor::Private::chooseGpuCompressor(const Compression } - -// Compress the given mipmap. -/*bool Compressor::Private::compressMipmap(const Mipmap & mipmap, const InputOptions::Private & inputOptions, const CompressionOptions::Private & compressionOptions, const OutputOptions::Private & outputOptions) const -{ - // @@ This is broken, we should not assume the fixed image is the valid one. @@ Compressor should do conversion if necessary. - const Image * image = mipmap.asFixedImage(); - nvDebugCheck(image != NULL); - - return compress2D(InputFormat_BGRA_8UB, inputOptions.alphaMode, image->width(), image->height(), image->pixels(), compressionOptions, outputOptions); -}*/ - -bool Compressor::Private::compress2D(InputFormat inputFormat, AlphaMode alphaMode, int w, int h, const void * data, const CompressionOptions::Private & compressionOptions, const OutputOptions::Private & outputOptions) const +bool Compressor::Private::compress(AlphaMode alphaMode, int w, int h, int d, const float * rgba, const CompressionOptions::Private & compressionOptions, const OutputOptions::Private & outputOptions) const { // Decide what compressor to use. AutoPtr compressor; @@ -1539,12 +933,13 @@ bool Compressor::Private::compress2D(InputFormat inputFormat, AlphaMode alphaMod } else { - compressor->compress(inputFormat, alphaMode, w, h, data, compressionOptions, outputOptions); + compressor->compress(alphaMode, w, h, rgba, compressionOptions, outputOptions); } return true; } +/* int Compressor::Private::estimateSize(const InputOptions::Private & inputOptions, const CompressionOptions::Private & compressionOptions) const { const Format format = compressionOptions.format; @@ -1552,9 +947,8 @@ int Compressor::Private::estimateSize(const InputOptions::Private & inputOptions const uint bitCount = compressionOptions.getBitCount(); const uint pitchAlignment = compressionOptions.pitchAlignment; - inputOptions.computeTargetExtents(); - - const uint mipmapCount = inputOptions.realMipmapCount(); + uint mipmapCount, width, height, depth; + inputOptions.computeExtents(&mipmapCount, &width, &height, &depth); int size = 0; @@ -1577,3 +971,4 @@ int Compressor::Private::estimateSize(const InputOptions::Private & inputOptions return size; } +*/ diff --git a/src/nvtt/Context.h b/src/nvtt/Context.h index 19ca795..c777439 100644 --- a/src/nvtt/Context.h +++ b/src/nvtt/Context.h @@ -32,54 +32,49 @@ namespace nv { - class Image; + class Image; } namespace nvtt { - struct Mipmap; + struct Mipmap; - struct Compressor::Private - { - Private() {} + struct Compressor::Private + { + Private() {} - bool compress(const InputOptions::Private & inputOptions, const CompressionOptions::Private & compressionOptions, const OutputOptions::Private & outputOptions) const; + bool compress(const TexImage & tex, const CompressionOptions::Private & compressionOptions, const OutputOptions::Private & outputOptions) const; + bool compress(const InputOptions::Private & inputOptions, const CompressionOptions::Private & compressionOptions, const OutputOptions::Private & outputOptions) const; + bool compress(AlphaMode alphaMode, int w, int h, int d, const float * data, const CompressionOptions::Private & compressionOptions, const OutputOptions::Private & outputOptions) const; - bool compress2D(InputFormat inputFormat, AlphaMode alphaMode, int w, int h, const void * data, const CompressionOptions::Private & compressionOptions, const OutputOptions::Private & outputOptions) const; + //int estimateSize(const InputOptions::Private & inputOptions, const CompressionOptions::Private & compressionOptions) const; - int estimateSize(const InputOptions::Private & inputOptions, const CompressionOptions::Private & compressionOptions) const; + bool outputHeader(const TexImage & tex, int mipmapCount, const CompressionOptions::Private & compressionOptions, const OutputOptions::Private & outputOptions) const; + bool outputHeader(const InputOptions::Private & inputOptions, const CompressionOptions::Private & compressionOptions, const OutputOptions::Private & outputOptions) const; - bool outputHeader(const TexImage & tex, int mipmapCount, const CompressionOptions::Private & compressionOptions, const OutputOptions::Private & outputOptions); + nv::CompressorInterface * chooseCpuCompressor(const CompressionOptions::Private & compressionOptions) const; + nv::CompressorInterface * chooseGpuCompressor(const CompressionOptions::Private & compressionOptions) const; - private: + //bool compressMipmaps(uint f, const InputOptions::Private & inputOptions, const CompressionOptions::Private & compressionOptions, const OutputOptions::Private & outputOptions) const; - bool outputHeader(const InputOptions::Private & inputOptions, const CompressionOptions::Private & compressionOptions, const OutputOptions::Private & outputOptions) const; + //bool initMipmap(Mipmap & mipmap, const InputOptions::Private & inputOptions, uint w, uint h, uint d, uint f, uint m) const; - nv::CompressorInterface * chooseCpuCompressor(const CompressionOptions::Private & compressionOptions) const; - nv::CompressorInterface * chooseGpuCompressor(const CompressionOptions::Private & compressionOptions) const; + //int findExactMipmap(const InputOptions::Private & inputOptions, uint w, uint h, uint d, uint f) const; + //int findClosestMipmap(const InputOptions::Private & inputOptions, uint w, uint h, uint d, uint f) const; - bool compressMipmaps(uint f, const InputOptions::Private & inputOptions, const CompressionOptions::Private & compressionOptions, const OutputOptions::Private & outputOptions) const; - - bool initMipmap(Mipmap & mipmap, const InputOptions::Private & inputOptions, uint w, uint h, uint d, uint f, uint m) const; - - int findExactMipmap(const InputOptions::Private & inputOptions, uint w, uint h, uint d, uint f) const; - int findClosestMipmap(const InputOptions::Private & inputOptions, uint w, uint h, uint d, uint f) const; - - void downsampleMipmap(Mipmap & mipmap, const InputOptions::Private & inputOptions) const; - void scaleMipmap(Mipmap & mipmap, const InputOptions::Private & inputOptions, uint w, uint h, uint d) const; - void premultiplyAlphaMipmap(Mipmap & mipmap, const InputOptions::Private & inputOptions) const; - void processInputImage(Mipmap & mipmap, const InputOptions::Private & inputOptions) const; - void quantizeMipmap(Mipmap & mipmap, const CompressionOptions::Private & compressionOptions) const; + //void downsampleMipmap(Mipmap & mipmap, const InputOptions::Private & inputOptions) const; + //void scaleMipmap(Mipmap & mipmap, const InputOptions::Private & inputOptions, uint w, uint h, uint d) const; + //void premultiplyAlphaMipmap(Mipmap & mipmap, const InputOptions::Private & inputOptions) const; + //void processInputImage(Mipmap & mipmap, const InputOptions::Private & inputOptions) const; + //void quantizeMipmap(Mipmap & mipmap, const CompressionOptions::Private & compressionOptions) const; - public: + bool cudaSupported; + bool cudaEnabled; - bool cudaSupported; - bool cudaEnabled; + nv::AutoPtr cuda; - nv::AutoPtr cuda; - - }; + }; } // nvtt namespace diff --git a/src/nvtt/InputOptions.cpp b/src/nvtt/InputOptions.cpp index 8101236..7a16829 100644 --- a/src/nvtt/InputOptions.cpp +++ b/src/nvtt/InputOptions.cpp @@ -37,519 +37,311 @@ using namespace nvtt; namespace { - static uint countMipmaps(int w, int h, int d) - { - uint mipmap = 0; - - while (w != 1 || h != 1 || d != 1) { - w = max(1, w / 2); - h = max(1, h / 2); - d = max(1, d / 2); - mipmap++; - } - - return mipmap + 1; - } + static uint countMipmaps(int w, int h, int d) + { + uint mipmap = 0; + + while (w != 1 || h != 1 || d != 1) { + w = max(1, w / 2); + h = max(1, h / 2); + d = max(1, d / 2); + mipmap++; + } + + return mipmap + 1; + } + + // 1 -> 1, 2 -> 2, 3 -> 2, 4 -> 4, 5 -> 4, ... + static uint previousPowerOfTwo(const uint v) + { + return nextPowerOfTwo(v + 1) / 2; + } + + static uint nearestPowerOfTwo(const uint v) + { + const uint np2 = nextPowerOfTwo(v); + const uint pp2 = previousPowerOfTwo(v); + + if (np2 - v <= v - pp2) + { + return np2; + } + else + { + return pp2; + } + } - // 1 -> 1, 2 -> 2, 3 -> 2, 4 -> 4, 5 -> 4, ... - static uint previousPowerOfTwo(const uint v) - { - return nextPowerOfTwo(v + 1) / 2; - } - - static uint nearestPowerOfTwo(const uint v) - { - const uint np2 = nextPowerOfTwo(v); - const uint pp2 = previousPowerOfTwo(v); - - if (np2 - v <= v - pp2) - { - return np2; - } - else - { - return pp2; - } - } - } // namespace /// Constructor. InputOptions::InputOptions() : m(*new InputOptions::Private()) { - reset(); + reset(); } // Delete images. InputOptions::~InputOptions() { - resetTextureLayout(); - - delete &m; + resetTextureLayout(); + + delete &m; } // Reset input options. void InputOptions::reset() { - m.wrapMode = WrapMode_Mirror; - m.textureType = TextureType_2D; - m.inputFormat = InputFormat_BGRA_8UB; + m.wrapMode = WrapMode_Mirror; + m.textureType = TextureType_2D; + m.inputFormat = InputFormat_BGRA_8UB; - m.alphaMode = AlphaMode_None; + m.alphaMode = AlphaMode_None; - m.inputGamma = 2.2f; - m.outputGamma = 2.2f; - - m.colorTransform = ColorTransform_None; - m.linearTransform = Matrix(identity); - for (int i = 0; i < 4; i++) m.colorOffsets[i] = 0; - for (int i = 0; i < 4; i++) m.swizzleTransform[i] = i; + m.inputGamma = 2.2f; + m.outputGamma = 2.2f; - m.generateMipmaps = true; - m.maxLevel = -1; - m.mipmapFilter = MipmapFilter_Box; + m.generateMipmaps = true; + m.maxLevel = -1; + m.mipmapFilter = MipmapFilter_Box; - m.kaiserWidth = 3; - m.kaiserAlpha = 4.0f; - m.kaiserStretch = 1.0f; + m.kaiserWidth = 3; + m.kaiserAlpha = 4.0f; + m.kaiserStretch = 1.0f; - m.isNormalMap = false; - m.normalizeMipmaps = true; - 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); - - m.maxExtent = 0; - m.roundMode = RoundMode_None; + m.isNormalMap = false; + m.normalizeMipmaps = true; + 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); - m.premultiplyAlpha = false; + m.maxExtent = 0; + m.roundMode = RoundMode_None; } // 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); + // 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; + // 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::InputImage[m.imageCount]; - - for(uint f = 0; f < m.faceCount; f++) - { - uint w = width; - uint h = height; - uint d = depth; + // Delete previous images. + resetTextureLayout(); - for (uint mipLevel = 0; mipLevel < m.mipmapCount; mipLevel++) - { - Private::InputImage & img = m.images[f * m.mipmapCount + mipLevel]; - img.width = w; - img.height = h; - img.depth = d; - img.mipLevel = mipLevel; - img.face = f; - - img.uint8data = NULL; - img.floatdata = NULL; - - w = max(1U, w / 2); - h = max(1U, h / 2); - d = max(1U, d / 2); - } - } + m.textureType = type; + m.width = width; + m.height = height; + m.depth = depth; + + // Allocate images. + m.faceCount = (type == TextureType_2D) ? 1 : 6; + m.mipmapCount = countMipmaps(width, height, depth); + m.imageCount = m.mipmapCount * m.faceCount; + m.images = new void *[m.imageCount]; + + memset(m.images, 0, sizeof(void *) * m.imageCount); + + /*for (uint f = 0; f < m.faceCount; f++) + { + uint w = width; + uint h = height; + uint d = depth; + + for (uint mipLevel = 0; mipLevel < m.mipmapCount; mipLevel++) + { + Private::InputImage & img = m.images[f * m.mipmapCount + mipLevel]; + img.width = w; + img.height = h; + img.depth = d; + img.mipLevel = mipLevel; + img.face = f; + + img.uint8data = NULL; + img.floatdata = NULL; + + w = max(1U, w / 2); + h = max(1U, h / 2); + d = max(1U, d / 2); + } + }*/ } void InputOptions::resetTextureLayout() { - if (m.images != NULL) - { - // Delete image array. - delete [] m.images; - m.images = NULL; + if (m.images != NULL) + { + // Delete image array. + delete [] m.images; + m.images = NULL; - m.faceCount = 0; - m.mipmapCount = 0; - m.imageCount = 0; - } + 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; - } - - switch(m.inputFormat) - { - case InputFormat_BGRA_8UB: - if (Image * image = new nv::Image()) - { - image->allocate(width, height); - memcpy(image->pixels(), data, width * height * 4); - m.images[idx].uint8data = image; - } - else - { - // @@ Out of memory error. - return false; - } - break; - case InputFormat_RGBA_32F: - if (FloatImage * image = new nv::FloatImage()) - { - const float * floatData = (const float *)data; - image->allocate(4, width, height); - - for (int c = 0; c < 4; c++) - { - float * channel = image->channel(c); - for (int i = 0; i < width * height; i++) - { - channel[i] = floatData[i*4 + c]; - } - } - - m.images[idx].floatdata = image; - } - else - { - // @@ Out of memory error. - return false; - } - break; - default: - return false; - } - - return true; -} + if (depth != 1) { + return false; + } + if (face >= m.faceCount) { + return false; + } + if (mipLevel >= m.mipmapCount) { + return false; + } + const int idx = mipLevel * m.faceCount + face; + if (idx >= m.imageCount) { + return false; + } -// Copies data -bool InputOptions::setMipmapChannelData(const void * data, int channel, int width, int height, int depth /*= 1*/, int face /*= 0*/, int mipLevel /*= 0*/) -{ - nvCheck(depth == 1); - nvCheck(channel >= 0 && channel < 4); - - 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; - } - - // Allocate image if not allocated already. - if (m.inputFormat == InputFormat_BGRA_8UB) - { - m.images[idx].floatdata = NULL; - if (m.images[idx].uint8data == NULL) - { - m.images[idx].uint8data = new Image(); - m.images[idx].uint8data->allocate(width, height); - m.images[idx].uint8data->fill(Color32(0,0,0,0)); - } - } - else if (m.inputFormat == InputFormat_RGBA_32F) - { - m.images[idx].uint8data = NULL; - if (m.images[idx].floatdata == NULL) - { - m.images[idx].floatdata = new FloatImage(); - m.images[idx].floatdata->allocate(4, width, height); - m.images[idx].floatdata->clear(); - } + // Compute expected width, height and depth for this mipLevel. Return false if it doesn't match. + int w = m.width; + int h = m.height; + int d = m.depth; + for (int i = 0; i < mipLevel; i++) { + w = max(1, w/2); + h = max(1, h/2); + d = max(1, d/2); + } + if (w != width || h != height || d != depth) { + return false; + } - - } - else - { - m.images[idx].floatdata = NULL; - m.images[idx].uint8data = NULL; - return false; - } + int imageSize = width * height * depth * 4; + if (m.inputFormat == InputFormat_BGRA_8UB) + { + imageSize *= sizeof(uint8); + } + else if (m.inputFormat == InputFormat_RGBA_16F) + { + imageSize *= sizeof(uint16); + } + else if (m.inputFormat == InputFormat_RGBA_32F) + { + imageSize *= sizeof(float); + } + else + { + return false; + } - // Copy channel data to image. - if (m.inputFormat == InputFormat_BGRA_8UB) - { - // @@ TODO - } - else if (m.inputFormat == InputFormat_RGBA_32F) - { - const float * floatData = (const float *)data; - float * channelPtr = m.images[idx].floatdata->channel(channel); + m.images[idx] = new uint8[imageSize]; + if (m.images[idx] == NULL) { + // Out of memory. + return false; + } - for (int i = 0; i < width * height; i++) - { - channelPtr[i] = floatData[i]; - } - } + memcpy(m.images[idx], data, imageSize); - return true; + return true; } /// Describe the format of the input. void InputOptions::setFormat(InputFormat format) { - m.inputFormat = format; + m.inputFormat = format; } /// Set the way the input alpha channel is interpreted. void InputOptions::setAlphaMode(AlphaMode alphaMode) { - m.alphaMode = alphaMode; + m.alphaMode = alphaMode; } /// Set gamma settings. void InputOptions::setGamma(float inputGamma, float outputGamma) { - m.inputGamma = inputGamma; - m.outputGamma = outputGamma; + m.inputGamma = inputGamma; + m.outputGamma = outputGamma; } /// Set texture wrappign mode. void InputOptions::setWrapMode(WrapMode mode) { - m.wrapMode = mode; + m.wrapMode = mode; } /// Set mipmap filter. void InputOptions::setMipmapFilter(MipmapFilter filter) { - m.mipmapFilter = filter; + m.mipmapFilter = filter; } /// Set mipmap generation. void InputOptions::setMipmapGeneration(bool enabled, int maxLevel/*= -1*/) { - m.generateMipmaps = enabled; - m.maxLevel = maxLevel; + m.generateMipmaps = enabled; + m.maxLevel = maxLevel; } /// Set Kaiser filter parameters. void InputOptions::setKaiserParameters(float width, float alpha, float stretch) { - m.kaiserWidth = width; - m.kaiserAlpha = alpha; - m.kaiserStretch = stretch; + m.kaiserWidth = width; + m.kaiserAlpha = alpha; + m.kaiserStretch = stretch; } /// Indicate whether input is a normal map or not. void InputOptions::setNormalMap(bool b) { - m.isNormalMap = b; + m.isNormalMap = b; } /// Enable normal map conversion. void InputOptions::setConvertToNormalMap(bool convert) { - m.convertToNormalMap = 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); + // 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; + 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; -} - -/// Set color transform. -void InputOptions::setColorTransform(ColorTransform t) -{ - m.colorTransform = t; -} - -// Set linear transform for the given channel. -void InputOptions::setLinearTransform(int channel, float w0, float w1, float w2, float w3) -{ - nvCheck(channel >= 0 && channel < 4); - - m.linearTransform(channel, 0) = w0; - m.linearTransform(channel, 1) = w1; - m.linearTransform(channel, 2) = w2; - m.linearTransform(channel, 3) = w3; -} - -void InputOptions::setLinearTransform(int channel, float w0, float w1, float w2, float w3, float offset) -{ - nvCheck(channel >= 0 && channel < 4); - - setLinearTransform(channel, w0, w1, w2, w3); - - m.colorOffsets[channel] = offset; -} - -void InputOptions::setSwizzleTransform(int x, int y, int z, int w) -{ - nvCheck(x >= 0 && x <= 6); - nvCheck(y >= 0 && y <= 6); - nvCheck(z >= 0 && z <= 6); - nvCheck(w >= 0 && w <= 6); - - m.swizzleTransform[0] = x; - m.swizzleTransform[1] = y; - m.swizzleTransform[2] = z; - m.swizzleTransform[3] = w; + m.normalizeMipmaps = normalize; } void InputOptions::setMaxExtents(int e) { - nvDebugCheck(e > 0); - m.maxExtent = e; + nvDebugCheck(e > 0); + m.maxExtent = e; } void InputOptions::setRoundMode(RoundMode mode) { - m.roundMode = mode; -} - -void InputOptions::setPremultiplyAlpha(bool b) -{ - m.premultiplyAlpha = b; -} - -void InputOptions::Private::computeTargetExtents() const -{ - nvCheck(images != NULL); - - uint maxExtent = this->maxExtent; - if (roundMode != RoundMode_None) - { - // rounded max extent should never be higher than original max extent. - maxExtent = previousPowerOfTwo(maxExtent); - } - - uint w = images->width; - uint h = images->height; - uint d = images->depth; - - nvDebugCheck(w > 0); - nvDebugCheck(h > 0); - nvDebugCheck(d > 0); - - // Scale extents without changing aspect ratio. - uint maxwhd = max(max(w, h), d); - if (maxExtent != 0 && maxwhd > maxExtent) - { - w = max((w * maxExtent) / maxwhd, 1U); - h = max((h * maxExtent) / maxwhd, 1U); - d = max((d * maxExtent) / maxwhd, 1U); - } - - // Round to power of two. - if (roundMode == RoundMode_ToNextPowerOfTwo) - { - w = nextPowerOfTwo(w); - h = nextPowerOfTwo(h); - d = nextPowerOfTwo(d); - } - else if (roundMode == RoundMode_ToNearestPowerOfTwo) - { - w = nearestPowerOfTwo(w); - h = nearestPowerOfTwo(h); - d = nearestPowerOfTwo(d); - } - else if (roundMode == RoundMode_ToPreviousPowerOfTwo) - { - w = previousPowerOfTwo(w); - h = previousPowerOfTwo(h); - d = previousPowerOfTwo(d); - } - - this->targetWidth = w; - this->targetHeight = h; - this->targetDepth = d; - - this->targetMipmapCount = countMipmaps(w, h, d); -} - - -// Return real number of mipmaps, including first level. -// computeTargetExtents should have been called before. -int InputOptions::Private::realMipmapCount() const -{ - int mipmapCount = targetMipmapCount; - - if (!generateMipmaps) mipmapCount = 1; - else if (maxLevel != -1 && maxLevel < mipmapCount - 1) mipmapCount = maxLevel + 1; - - return mipmapCount; -} - - -const Image * InputOptions::Private::image(uint face, uint mipmap) const -{ - nvDebugCheck(face < faceCount); - nvDebugCheck(mipmap < mipmapCount); - - const InputImage & image = this->images[face * mipmapCount + mipmap]; - nvDebugCheck(image.face == face); - nvDebugCheck(image.mipLevel == mipmap); - - return image.uint8data.ptr(); -} - -const Image * InputOptions::Private::image(uint idx) const -{ - nvDebugCheck(idx < faceCount * mipmapCount); - - const InputImage & image = this->images[idx]; - - return image.uint8data.ptr(); -} - -const FloatImage * InputOptions::Private::floatImage(uint idx) const -{ - nvDebugCheck(idx < faceCount * mipmapCount); - - const InputImage & image = this->images[idx]; - - return image.floatdata.ptr(); + m.roundMode = mode; } diff --git a/src/nvtt/InputOptions.h b/src/nvtt/InputOptions.h index 91e0752..675e3bd 100644 --- a/src/nvtt/InputOptions.h +++ b/src/nvtt/InputOptions.h @@ -34,89 +34,49 @@ namespace nvtt { - struct InputOptions::Private - { - Private() : images(NULL) {} - - WrapMode wrapMode; - TextureType textureType; - InputFormat inputFormat; - AlphaMode alphaMode; - - uint faceCount; - uint mipmapCount; - uint imageCount; - - struct InputImage; - InputImage * images; - - // Gamma conversion. - float inputGamma; - float outputGamma; - - // Color transform. - ColorTransform colorTransform; - nv::Matrix linearTransform; - float colorOffsets[4]; - uint swizzleTransform[4]; - - // Mipmap generation options. - bool generateMipmaps; - int maxLevel; - MipmapFilter mipmapFilter; - - // Kaiser filter parameters. - float kaiserWidth; - float kaiserAlpha; - float kaiserStretch; - - // Normal map options. - bool isNormalMap; - bool normalizeMipmaps; - bool convertToNormalMap; - nv::Vector4 heightFactors; - nv::Vector4 bumpFrequencyScale; - - // Adjust extents. - uint maxExtent; - RoundMode roundMode; - - bool premultiplyAlpha; + struct InputOptions::Private + { + Private() : images(NULL) {} - // @@ These are computed in nvtt::compress, so they should be mutable or stored elsewhere... - mutable uint targetWidth; - mutable uint targetHeight; - mutable uint targetDepth; - mutable uint targetMipmapCount; - - void computeTargetExtents() const; - - int realMipmapCount() const; - - const nv::Image * image(uint face, uint mipmap) const; - const nv::Image * image(uint idx) const; + WrapMode wrapMode; + TextureType textureType; + InputFormat inputFormat; + AlphaMode alphaMode; - const nv::FloatImage * floatImage(uint idx) const; + uint width; + uint height; + uint depth; + uint faceCount; + uint mipmapCount; + uint imageCount; - }; + void ** images; - // Internal image structure. - struct InputOptions::Private::InputImage - { - InputImage() {} - - bool hasValidData() const { return uint8data != NULL || floatdata != NULL; } - - int mipLevel; - int face; - - int width; - int height; - int depth; - - nv::AutoPtr uint8data; - nv::AutoPtr floatdata; - }; + // Gamma conversion. + float inputGamma; + float outputGamma; + + // Mipmap generation options. + bool generateMipmaps; + int maxLevel; + MipmapFilter mipmapFilter; + + // Kaiser filter parameters. + float kaiserWidth; + float kaiserAlpha; + float kaiserStretch; + + // Normal map options. + bool isNormalMap; + bool normalizeMipmaps; + bool convertToNormalMap; + nv::Vector4 heightFactors; + nv::Vector4 bumpFrequencyScale; + + // Adjust extents. + uint maxExtent; + RoundMode roundMode; + }; } // nvtt namespace diff --git a/src/nvtt/OptimalCompressDXT.cpp b/src/nvtt/OptimalCompressDXT.cpp index c2538b7..bc2c24c 100644 --- a/src/nvtt/OptimalCompressDXT.cpp +++ b/src/nvtt/OptimalCompressDXT.cpp @@ -54,7 +54,7 @@ namespace return d * d; } - static uint nearestGreen4(uint green, uint maxGreen, uint minGreen) + /*static uint nearestGreen4(uint green, uint maxGreen, uint minGreen) { uint bias = maxGreen + (maxGreen - minGreen) / 6; @@ -62,7 +62,7 @@ namespace if (maxGreen - minGreen != 0) index = clamp(3 * (bias - green) / (maxGreen - minGreen), 0U, 3U); return (index * minGreen + (3 - index) * maxGreen) / 3; - } + }*/ static int computeGreenError(const ColorBlock & rgba, const BlockDXT1 * block, int bestError = INT_MAX) { @@ -164,7 +164,7 @@ namespace return (index * minAlpha + (7 - index) * maxAlpha) / 7; } - static uint computeAlphaError8(const ColorBlock & rgba, const AlphaBlockDXT5 * block, int bestError = INT_MAX) + /*static uint computeAlphaError8(const ColorBlock & rgba, const AlphaBlockDXT5 * block, int bestError = INT_MAX) { int totalError = 0; @@ -182,7 +182,7 @@ namespace } return totalError; - } + }*/ static uint computeAlphaError(const ColorBlock & rgba, const AlphaBlockDXT5 * block, int bestError = INT_MAX) { diff --git a/src/nvtt/TexImage.cpp b/src/nvtt/TexImage.cpp index a23f26a..e439636 100644 --- a/src/nvtt/TexImage.cpp +++ b/src/nvtt/TexImage.cpp @@ -26,6 +26,7 @@ #include "nvmath/Vector.h" #include "nvmath/Matrix.h" #include "nvmath/Color.h" +#include "nvmath/Half.h" #include "nvimage/Filter.h" #include "nvimage/ImageIO.h" @@ -40,209 +41,210 @@ using namespace nvtt; namespace { - // 1 -> 1, 2 -> 2, 3 -> 2, 4 -> 4, 5 -> 4, ... - static uint previousPowerOfTwo(const uint v) - { - return nextPowerOfTwo(v + 1) / 2; - } + // 1 -> 1, 2 -> 2, 3 -> 2, 4 -> 4, 5 -> 4, ... + static uint previousPowerOfTwo(const uint v) + { + return nextPowerOfTwo(v + 1) / 2; + } - static uint nearestPowerOfTwo(const uint v) - { - const uint np2 = nextPowerOfTwo(v); - const uint pp2 = previousPowerOfTwo(v); + static uint nearestPowerOfTwo(const uint v) + { + const uint np2 = nextPowerOfTwo(v); + const uint pp2 = previousPowerOfTwo(v); - if (np2 - v <= v - pp2) - { - return np2; - } - else - { - return pp2; - } + if (np2 - v <= v - pp2) + { + return np2; } + else + { + return pp2; + } + } #pragma NV_MESSAGE("TODO: Move these functions to a common location.") - static int blockSize(Format format) - { - if (format == Format_DXT1 || format == Format_DXT1a || format == Format_DXT1n) { - 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; - } - else if (format == Format_CTX1) { - return 8; - } - return 0; + static int blockSize(Format format) + { + if (format == Format_DXT1 || format == Format_DXT1a || format == Format_DXT1n) { + 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; + } + else if (format == Format_CTX1) { + return 8; + } + return 0; + } + + static uint countMipmaps(int w, int h, int d) + { + uint mipmap = 0; + + while (w != 1 || h != 1 || d != 1) { + w = max(1, w / 2); + h = max(1, h / 2); + d = max(1, d / 2); + mipmap++; } - static uint countMipmaps(int w, int h, int d) - { - uint mipmap = 0; - - while (w != 1 || h != 1 || d != 1) { - w = max(1, w / 2); - h = max(1, h / 2); - d = max(1, d / 2); - mipmap++; - } - - return mipmap + 1; - } + return mipmap + 1; + } } TexImage::TexImage() : m(new TexImage::Private()) { + m->addRef(); } TexImage::TexImage(const TexImage & tex) : m(tex.m) { - if (m != NULL) m->addRef(); + if (m != NULL) m->addRef(); } TexImage::~TexImage() { - if (m != NULL) m->release(); - m = NULL; + if (m != NULL) m->release(); + m = NULL; } void TexImage::operator=(const TexImage & tex) { - if (tex.m != NULL) tex.m->addRef(); - if (m != NULL) m->release(); - m = tex.m; + if (tex.m != NULL) tex.m->addRef(); + if (m != NULL) m->release(); + m = tex.m; } void TexImage::detach() { - if (m->refCount() > 1) - { + if (m->refCount() > 1) + { m->release(); - m = new TexImage::Private(*m); - m->addRef(); - nvDebugCheck(m->refCount() == 1); - } + m = new TexImage::Private(*m); + m->addRef(); + nvDebugCheck(m->refCount() == 1); + } } void TexImage::setTextureType(TextureType type) { - if (m->type != type) + if (m->type != type) + { + detach(); + + m->type = type; + + int count = 0; + if (type == TextureType_2D) { - detach(); - - m->type = type; - - int count = 0; - if (type == TextureType_2D) - { - count = 1; - } - else - { - nvCheck (type == TextureType_Cube); - count = 6; - } - - // Delete all but the first 'count' images. - const uint imageCount = m->imageArray.count(); - for (uint i = count; i < imageCount; i++) - { - delete m->imageArray[i]; - } - - m->imageArray.resize(count, NULL); + count = 1; } + else + { + nvCheck (type == TextureType_Cube); + count = 6; + } + + // Delete all but the first 'count' images. + const uint imageCount = m->imageArray.count(); + for (uint i = count; i < imageCount; i++) + { + delete m->imageArray[i]; + } + + m->imageArray.resize(count, NULL); + } } void TexImage::setWrapMode(WrapMode wrapMode) { - if (m->wrapMode != wrapMode) - { - detach(); - m->wrapMode = wrapMode; - } + if (m->wrapMode != wrapMode) + { + detach(); + m->wrapMode = wrapMode; + } } void TexImage::setAlphaMode(AlphaMode alphaMode) { - if (m->alphaMode != alphaMode) - { - detach(); - m->alphaMode = alphaMode; - } + if (m->alphaMode != alphaMode) + { + detach(); + m->alphaMode = alphaMode; + } } void TexImage::setNormalMap(bool isNormalMap) { - if (m->isNormalMap != isNormalMap) - { - detach(); - m->isNormalMap = isNormalMap; - } + if (m->isNormalMap != isNormalMap) + { + detach(); + m->isNormalMap = isNormalMap; + } } int TexImage::width() const { - if (m->imageArray.count() > 0) - { - return m->imageArray[0]->width(); - } - return 0; + if (m->imageArray.count() > 0) + { + return m->imageArray[0]->width(); + } + return 0; } int TexImage::height() const { - if (m->imageArray.count() > 0) - { - return m->imageArray[0]->height(); - } - return 0; + if (m->imageArray.count() > 0) + { + return m->imageArray[0]->height(); + } + return 0; } int TexImage::depth() const { - return 1; + return 1; } int TexImage::faceCount() const { - return m->imageArray.count(); + return m->imageArray.count(); } TextureType TexImage::textureType() const { - return m->type; + return m->type; } WrapMode TexImage::wrapMode() const { - return m->wrapMode; + return m->wrapMode; } AlphaMode TexImage::alphaMode() const { - return m->alphaMode; + return m->alphaMode; } bool TexImage::isNormalMap() const { - return m->isNormalMap; + return m->isNormalMap; } int TexImage::countMipmaps() const { - return ::countMipmaps(width(), height(), depth()); + return ::countMipmaps(width(), height(), depth()); } float TexImage::alphaTestCoverage(float alphaRef/*= 0.5*/) const @@ -250,15 +252,15 @@ float TexImage::alphaTestCoverage(float alphaRef/*= 0.5*/) const int imageCount = 0; float coverage = 0.0f; - foreach (i, m->imageArray) - { + foreach (i, m->imageArray) + { FloatImage * img = m->imageArray[i]; - if (img == NULL) continue; + if (img == NULL) continue; imageCount++; coverage += img->alphaTestCoverage(alphaRef, 3); - } + } if (imageCount > 0) { return coverage / imageCount; @@ -290,699 +292,785 @@ bool TexImage::save(const char * fileName) const { #pragma NV_MESSAGE("TODO: Add support for DDS textures in TexImage::save") - if (m->imageArray.count() == 0) - { - return false; - } - else - { - return ImageIO::saveFloat(fileName, m->imageArray[0], 0, 4); - } + if (m->imageArray.count() == 0) + { + return false; + } + else + { + return ImageIO::saveFloat(fileName, m->imageArray[0], 0, 4); + } } -bool TexImage::setImage2D(nvtt::InputFormat format, int w, int h, int idx, const void * restrict data) +bool TexImage::setImage2D(nvtt::InputFormat format, int w, int h, int idx, const void * data) { - if (idx < 0 || uint(idx) >= m->imageArray.count()) - { - return false; - } + if (idx < 0 || uint(idx) >= m->imageArray.count()) + { + return false; + } - FloatImage * img = m->imageArray[idx]; + FloatImage * img = m->imageArray[idx]; if (img != NULL) { if (img->width() != w || img->height() != h) { - return false; + return false; } - } + } - detach(); + detach(); if (img == NULL) { img = m->imageArray[idx] = new FloatImage(); img->allocate(4, w, h); } - const int count = w * h; + const int count = w * h; - float * restrict rdst = img->channel(0); - float * restrict gdst = img->channel(1); - float * restrict bdst = img->channel(2); - float * restrict adst = img->channel(3); + float * rdst = img->channel(0); + float * gdst = img->channel(1); + float * bdst = img->channel(2); + float * adst = img->channel(3); - if (format == InputFormat_BGRA_8UB) - { - const Color32 * src = (const Color32 *)data; + if (format == InputFormat_BGRA_8UB) + { + const Color32 * src = (const Color32 *)data; - try { - for (int i = 0; i < count; i++) - { - rdst[i] = float(src[i].r) / 255.0f; - gdst[i] = float(src[i].g) / 255.0f; - bdst[i] = float(src[i].b) / 255.0f; - adst[i] = float(src[i].a) / 255.0f; - } - } - catch(...) { - return false; - } + try { + for (int i = 0; i < count; i++) + { + rdst[i] = float(src[i].r) / 255.0f; + gdst[i] = float(src[i].g) / 255.0f; + bdst[i] = float(src[i].b) / 255.0f; + adst[i] = float(src[i].a) / 255.0f; + } } - else if (format == InputFormat_RGBA_32F) - { - const float * src = (const float *)data; - - try { - for (int i = 0; i < count; i++) - { - rdst[i] = src[4 * i + 0]; - gdst[i] = src[4 * i + 1]; - bdst[i] = src[4 * i + 2]; - adst[i] = src[4 * i + 3]; - } - } - catch(...) { - return false; - } + catch(...) { + return false; } + } + else if (format == InputFormat_RGBA_16F) + { + const uint16 * src = (const uint16 *)data; - return true; + try { + for (int i = 0; i < count; i++) + { + ((uint32 *)rdst)[i] = half_to_float(src[4*i+0]); + ((uint32 *)gdst)[i] = half_to_float(src[4*i+1]); + ((uint32 *)bdst)[i] = half_to_float(src[4*i+2]); + ((uint32 *)adst)[i] = half_to_float(src[4*i+3]); + } + } + catch(...) { + return false; + } + } + else if (format == InputFormat_RGBA_32F) + { + const float * src = (const float *)data; + + try { + for (int i = 0; i < count; i++) + { + rdst[i] = src[4 * i + 0]; + gdst[i] = src[4 * i + 1]; + bdst[i] = src[4 * i + 2]; + adst[i] = src[4 * i + 3]; + } + } + catch(...) { + return false; + } + } + + return true; } -bool TexImage::setImage2D(InputFormat format, int w, int h, int idx, const void * restrict r, const void * restrict g, const void * restrict b, const void * restrict a) +bool TexImage::setImage2D(InputFormat format, int w, int h, int idx, const void * r, const void * g, const void * b, const void * a) { - if (idx < 0 || uint(idx) >= m->imageArray.count()) - { - return false; + if (idx < 0 || uint(idx) >= m->imageArray.count()) + { + return false; + } + + FloatImage * img = m->imageArray[idx]; + if (img->width() != w || img->height() != h) + { + return false; + } + + detach(); + + const int count = w * h; + + float * rdst = img->channel(0); + float * gdst = img->channel(1); + float * bdst = img->channel(2); + float * adst = img->channel(3); + + if (format == InputFormat_BGRA_8UB) + { + const uint8 * rsrc = (const uint8 *)r; + const uint8 * gsrc = (const uint8 *)g; + const uint8 * bsrc = (const uint8 *)b; + const uint8 * asrc = (const uint8 *)a; + + try { + for (int i = 0; i < count; i++) rdst[i] = float(rsrc[i]) / 255.0f; + for (int i = 0; i < count; i++) gdst[i] = float(gsrc[i]) / 255.0f; + for (int i = 0; i < count; i++) bdst[i] = float(bsrc[i]) / 255.0f; + for (int i = 0; i < count; i++) adst[i] = float(asrc[i]) / 255.0f; } - - FloatImage * img = m->imageArray[idx]; - if (img->width() != w || img->height() != h) - { - return false; + catch(...) { + return false; } + } + else if (format == InputFormat_RGBA_16F) + { + const uint16 * rsrc = (const uint16 *)r; + const uint16 * gsrc = (const uint16 *)g; + const uint16 * bsrc = (const uint16 *)b; + const uint16 * asrc = (const uint16 *)a; - detach(); - - const int count = w * h; - - float * restrict rdst = img->channel(0); - float * restrict gdst = img->channel(1); - float * restrict bdst = img->channel(2); - float * restrict adst = img->channel(3); - - if (format == InputFormat_BGRA_8UB) - { - const uint8 * restrict rsrc = (const uint8 *)r; - const uint8 * restrict gsrc = (const uint8 *)g; - const uint8 * restrict bsrc = (const uint8 *)b; - const uint8 * restrict asrc = (const uint8 *)a; - - try { - for (int i = 0; i < count; i++) rdst[i] = float(rsrc[i]) / 255.0f; - for (int i = 0; i < count; i++) gdst[i] = float(gsrc[i]) / 255.0f; - for (int i = 0; i < count; i++) bdst[i] = float(bsrc[i]) / 255.0f; - for (int i = 0; i < count; i++) adst[i] = float(asrc[i]) / 255.0f; - } - catch(...) { - return false; - } + try { + for (int i = 0; i < count; i++) ((uint32 *)rdst)[i] = half_to_float(rsrc[i]); + for (int i = 0; i < count; i++) ((uint32 *)gdst)[i] = half_to_float(gsrc[i]); + for (int i = 0; i < count; i++) ((uint32 *)bdst)[i] = half_to_float(bsrc[i]); + for (int i = 0; i < count; i++) ((uint32 *)adst)[i] = half_to_float(asrc[i]); } - else if (format == InputFormat_RGBA_32F) - { - const float * rsrc = (const float *)r; - const float * gsrc = (const float *)g; - const float * bsrc = (const float *)b; - const float * asrc = (const float *)a; - - try { - memcpy(rdst, rsrc, count * sizeof(float)); - memcpy(gdst, gsrc, count * sizeof(float)); - memcpy(bdst, bsrc, count * sizeof(float)); - memcpy(adst, asrc, count * sizeof(float)); - } - catch(...) { - return false; - } + catch(...) { + return false; } + } + else if (format == InputFormat_RGBA_32F) + { + const float * rsrc = (const float *)r; + const float * gsrc = (const float *)g; + const float * bsrc = (const float *)b; + const float * asrc = (const float *)a; - return true; + try { + memcpy(rdst, rsrc, count * sizeof(float)); + memcpy(gdst, gsrc, count * sizeof(float)); + memcpy(bdst, bsrc, count * sizeof(float)); + memcpy(adst, asrc, count * sizeof(float)); + } + catch(...) { + return false; + } + } + + return true; } bool TexImage::setImage2D(Format format, Decoder decoder, int w, int h, int idx, const void * data) { - if (idx < 0 || uint(idx) >= m->imageArray.count()) - { - return false; - } + if (idx < 0 || uint(idx) >= m->imageArray.count()) + { + return false; + } #pragma NV_MESSAGE("TODO: Add support for all compressed formats in TexImage::setImage2D.") - if (format != nvtt::Format_BC1 && format != nvtt::Format_BC2 && format != nvtt::Format_BC3) - { - return false; - } + if (format != nvtt::Format_BC1 && format != nvtt::Format_BC2 && format != nvtt::Format_BC3) + { + return false; + } - FloatImage * img = m->imageArray[idx]; - if (img->width() != w || img->height() != h) - { - return false; - } + FloatImage * img = m->imageArray[idx]; + if (img->width() != w || img->height() != h) + { + return false; + } - detach(); + detach(); - const int count = w * h; + const int count = w * h; - const int bw = (w + 3) / 4; - const int bh = (h + 3) / 4; + const int bw = (w + 3) / 4; + const int bh = (h + 3) / 4; - const uint bs = blockSize(format); + const uint bs = blockSize(format); - const uint8 * ptr = (const uint8 *)data; + const uint8 * ptr = (const uint8 *)data; - try { - for (int y = 0; y < bh; y++) + try { + for (int y = 0; y < bh; y++) + { + for (int x = 0; x < bw; x++) + { + ColorBlock colors; + + if (format == nvtt::Format_BC1) { - for (int x = 0; x < bw; x++) - { - ColorBlock colors; + const BlockDXT1 * block = (const BlockDXT1 *)ptr; - if (format == nvtt::Format_BC1) - { - const BlockDXT1 * block = (const BlockDXT1 *)ptr; - - if (decoder == Decoder_Reference) { - block->decodeBlock(&colors); - } - else if (decoder == Decoder_NV5x) { - block->decodeBlockNV5x(&colors); - } - } - else if (format == nvtt::Format_BC2) - { - const BlockDXT3 * block = (const BlockDXT3 *)ptr; - - if (decoder == Decoder_Reference) { - block->decodeBlock(&colors); - } - else if (decoder == Decoder_NV5x) { - block->decodeBlockNV5x(&colors); - } - } - else if (format == nvtt::Format_BC3) - { - const BlockDXT5 * block = (const BlockDXT5 *)ptr; - - if (decoder == Decoder_Reference) { - block->decodeBlock(&colors); - } - else if (decoder == Decoder_NV5x) { - block->decodeBlockNV5x(&colors); - } - } - - for (int yy = 0; yy < 4; yy++) - { - for (int xx = 0; xx < 4; xx++) - { - Color32 c = colors.color(xx, yy); - - if (x * 4 + xx < w && y * 4 + yy < h) - { - img->pixel(x*4 + xx, y*4 + yy, 0) = float(c.r) * 1.0f/255.0f; - img->pixel(x*4 + xx, y*4 + yy, 1) = float(c.g) * 1.0f/255.0f; - img->pixel(x*4 + xx, y*4 + yy, 2) = float(c.b) * 1.0f/255.0f; - img->pixel(x*4 + xx, y*4 + yy, 3) = float(c.a) * 1.0f/255.0f; - } - } - } - - ptr += bs; - } + if (decoder == Decoder_Reference) { + block->decodeBlock(&colors); + } + else if (decoder == Decoder_NV5x) { + block->decodeBlockNV5x(&colors); + } } - } - catch(...) { - return false; - } + else if (format == nvtt::Format_BC2) + { + const BlockDXT3 * block = (const BlockDXT3 *)ptr; - return true; + if (decoder == Decoder_Reference) { + block->decodeBlock(&colors); + } + else if (decoder == Decoder_NV5x) { + block->decodeBlockNV5x(&colors); + } + } + else if (format == nvtt::Format_BC3) + { + const BlockDXT5 * block = (const BlockDXT5 *)ptr; + + if (decoder == Decoder_Reference) { + block->decodeBlock(&colors); + } + else if (decoder == Decoder_NV5x) { + block->decodeBlockNV5x(&colors); + } + } + + for (int yy = 0; yy < 4; yy++) + { + for (int xx = 0; xx < 4; xx++) + { + Color32 c = colors.color(xx, yy); + + if (x * 4 + xx < w && y * 4 + yy < h) + { + img->pixel(x*4 + xx, y*4 + yy, 0) = float(c.r) * 1.0f/255.0f; + img->pixel(x*4 + xx, y*4 + yy, 1) = float(c.g) * 1.0f/255.0f; + img->pixel(x*4 + xx, y*4 + yy, 2) = float(c.b) * 1.0f/255.0f; + img->pixel(x*4 + xx, y*4 + yy, 3) = float(c.a) * 1.0f/255.0f; + } + } + } + + ptr += bs; + } + } + } + catch(...) { + return false; + } + + return true; } -#pragma NV_MESSAGE("TODO: provide a TexImage::resize that can override filter width and parameters.") +static void getDefaultFilterWidthAndParams(int filter, float * filterWidth, float params[2]) +{ + if (filter == ResizeFilter_Box) { + *filterWidth = 0.5f; + } + else if (filter == ResizeFilter_Triangle) { + *filterWidth = 1.0f; + } + else if (filter == ResizeFilter_Kaiser) + { + *filterWidth = 3.0f; + params[0] = 4.0f; + params[1] = 1.0f; + } + else //if (filter == ResizeFilter_Mitchell) + { + *filterWidth = 2.0f; + params[0] = 1.0f / 3.0f; + params[1] = 1.0f / 3.0f; + } +} void TexImage::resize(int w, int h, ResizeFilter filter) { - if (m->imageArray.count() > 0) - { - if (w == m->imageArray[0]->width() && h == m->imageArray[0]->height()) return; - } + float filterWidth; + float params[2]; + getDefaultFilterWidthAndParams(filter, &filterWidth, params); - if (m->type == TextureType_Cube) - { + resize(w, h, filter, filterWidth, params); +} + +void TexImage::resize(int w, int h, ResizeFilter filter, float filterWidth, const float * params) +{ + if (m->imageArray.count() > 0) + { + if (w == m->imageArray[0]->width() && h == m->imageArray[0]->height()) return; + } + + if (m->type == TextureType_Cube) + { #pragma NV_MESSAGE("TODO: Output error when image is cubemap and w != h.") - h = w; - } + h = w; + } - detach(); + detach(); - FloatImage::WrapMode wrapMode = (FloatImage::WrapMode)m->wrapMode; + FloatImage::WrapMode wrapMode = (FloatImage::WrapMode)m->wrapMode; - foreach (i, m->imageArray) + foreach (i, m->imageArray) + { + FloatImage * img = m->imageArray[i]; + + if (img == NULL) continue; + + if (m->alphaMode == AlphaMode_Transparency) { - FloatImage * img = m->imageArray[i]; - - if (img == NULL) continue; - - if (m->alphaMode == AlphaMode_Transparency) - { - if (filter == ResizeFilter_Box) - { - BoxFilter filter; - img = img->resize(filter, w, h, wrapMode, 3); - } - else if (filter == ResizeFilter_Triangle) - { - TriangleFilter filter; - img = img->resize(filter, w, h, wrapMode, 3); - } - else if (filter == ResizeFilter_Kaiser) - { - //KaiserFilter filter(inputOptions.kaiserWidth); - //filter.setParameters(inputOptions.kaiserAlpha, inputOptions.kaiserStretch); - KaiserFilter filter(3); - img = img->resize(filter, w, h, wrapMode, 3); - } - else //if (filter == ResizeFilter_Mitchell) - { - nvDebugCheck(filter == ResizeFilter_Mitchell); - MitchellFilter filter; - img = img->resize(filter, w, h, wrapMode, 3); - } - } - else - { - if (filter == ResizeFilter_Box) - { - BoxFilter filter; - img = img->resize(filter, w, h, wrapMode); - } - else if (filter == ResizeFilter_Triangle) - { - TriangleFilter filter; - img = img->resize(filter, w, h, wrapMode); - } - else if (filter == ResizeFilter_Kaiser) - { - //KaiserFilter filter(inputOptions.kaiserWidth); - //filter.setParameters(inputOptions.kaiserAlpha, inputOptions.kaiserStretch); - KaiserFilter filter(3); - img = img->resize(filter, w, h, wrapMode); - } - else //if (filter == ResizeFilter_Mitchell) - { - nvDebugCheck(filter == ResizeFilter_Mitchell); - MitchellFilter filter; - img = img->resize(filter, w, h, wrapMode); - } - } + if (filter == ResizeFilter_Box) + { + BoxFilter filter(filterWidth); + img = img->resize(filter, w, h, wrapMode, 3); + } + else if (filter == ResizeFilter_Triangle) + { + TriangleFilter filter(filterWidth); + img = img->resize(filter, w, h, wrapMode, 3); + } + else if (filter == ResizeFilter_Kaiser) + { + KaiserFilter filter(filterWidth); + if (params != NULL) filter.setParameters(params[0], params[1]); + img = img->resize(filter, w, h, wrapMode, 3); + } + else //if (filter == ResizeFilter_Mitchell) + { + nvDebugCheck(filter == ResizeFilter_Mitchell); + MitchellFilter filter; + if (params != NULL) filter.setParameters(params[0], params[1]); + img = img->resize(filter, w, h, wrapMode, 3); + } + } + else + { + if (filter == ResizeFilter_Box) + { + BoxFilter filter(filterWidth); + img = img->resize(filter, w, h, wrapMode); + } + else if (filter == ResizeFilter_Triangle) + { + TriangleFilter filter(filterWidth); + img = img->resize(filter, w, h, wrapMode); + } + else if (filter == ResizeFilter_Kaiser) + { + KaiserFilter filter(filterWidth); + if (params != NULL) filter.setParameters(params[0], params[1]); + img = img->resize(filter, w, h, wrapMode); + } + else //if (filter == ResizeFilter_Mitchell) + { + nvDebugCheck(filter == ResizeFilter_Mitchell); + MitchellFilter filter; + if (params != NULL) filter.setParameters(params[0], params[1]); + img = img->resize(filter, w, h, wrapMode); + } + } delete m->imageArray[i]; m->imageArray[i] = img; - } + } } void TexImage::resize(int maxExtent, RoundMode roundMode, ResizeFilter filter) { - if (m->imageArray.count() > 0) + float filterWidth; + float params[2]; + getDefaultFilterWidthAndParams(filter, &filterWidth, params); + + resize(maxExtent, roundMode, filter, filterWidth, params); +} + + +void TexImage::resize(int maxExtent, RoundMode roundMode, ResizeFilter filter, float filterWidth, const float * params) +{ + if (m->imageArray.count() > 0) + { + int w = m->imageArray[0]->width(); + int h = m->imageArray[0]->height(); + + nvDebugCheck(w > 0); + nvDebugCheck(h > 0); + + if (roundMode != RoundMode_None && maxExtent > 0) { - int w = m->imageArray[0]->width(); - int h = m->imageArray[0]->height(); - - nvDebugCheck(w > 0); - nvDebugCheck(h > 0); - - if (roundMode != RoundMode_None) - { - // rounded max extent should never be higher than original max extent. - maxExtent = previousPowerOfTwo(maxExtent); - } - - // Scale extents without changing aspect ratio. - int maxwh = max(w, h); - if (maxExtent != 0 && maxwh > maxExtent) - { - w = max((w * maxExtent) / maxwh, 1); - h = max((h * maxExtent) / maxwh, 1); - } - - // Round to power of two. - if (roundMode == RoundMode_ToNextPowerOfTwo) - { - w = nextPowerOfTwo(w); - h = nextPowerOfTwo(h); - } - else if (roundMode == RoundMode_ToNearestPowerOfTwo) - { - w = nearestPowerOfTwo(w); - h = nearestPowerOfTwo(h); - } - else if (roundMode == RoundMode_ToPreviousPowerOfTwo) - { - w = previousPowerOfTwo(w); - h = previousPowerOfTwo(h); - } - - // Make sure cube faces are square. - if (m->type == TextureType_Cube) - { - w = h = max(w, h); - } - - resize(w, h, filter); + // rounded max extent should never be higher than original max extent. + maxExtent = previousPowerOfTwo(maxExtent); } + + // Scale extents without changing aspect ratio. + int maxwh = max(w, h); + if (maxExtent > 0 && maxwh > maxExtent) + { + w = max((w * maxExtent) / maxwh, 1); + h = max((h * maxExtent) / maxwh, 1); + } + + // Round to power of two. + if (roundMode == RoundMode_ToNextPowerOfTwo) + { + w = nextPowerOfTwo(w); + h = nextPowerOfTwo(h); + } + else if (roundMode == RoundMode_ToNearestPowerOfTwo) + { + w = nearestPowerOfTwo(w); + h = nearestPowerOfTwo(h); + } + else if (roundMode == RoundMode_ToPreviousPowerOfTwo) + { + w = previousPowerOfTwo(w); + h = previousPowerOfTwo(h); + } + + // Make sure cube faces are square. + if (m->type == TextureType_Cube) + { + w = h = max(w, h); + } + + resize(w, h, filter, filterWidth, params); + } } bool TexImage::buildNextMipmap(MipmapFilter filter) { - if (m->imageArray.count() > 0) + float filterWidth; + float params[2]; + getDefaultFilterWidthAndParams(filter, &filterWidth, params); + + buildNextMipmap(filter, filterWidth, params); +} + +bool TexImage::buildNextMipmap(MipmapFilter filter, float filterWidth, const float * params) +{ + if (m->imageArray.count() > 0) + { + int w = m->imageArray[0]->width(); + int h = m->imageArray[0]->height(); + + nvDebugCheck(w > 0); + nvDebugCheck(h > 0); + + if (w == 1 && h == 1) { - int w = m->imageArray[0]->width(); - int h = m->imageArray[0]->height(); - - nvDebugCheck(w > 0); - nvDebugCheck(h > 0); - - if (w == 1 && h == 1) - { - return false; - } + return false; } + } - detach(); + detach(); - FloatImage::WrapMode wrapMode = (FloatImage::WrapMode)m->wrapMode; + FloatImage::WrapMode wrapMode = (FloatImage::WrapMode)m->wrapMode; - foreach (i, m->imageArray) - { + foreach (i, m->imageArray) + { FloatImage * img = m->imageArray[i]; - if (img == NULL) continue; + if (img == NULL) continue; - if (m->alphaMode == AlphaMode_Transparency) - { - if (filter == MipmapFilter_Box) - { - BoxFilter filter; - img = img->downSample(filter, wrapMode, 3); - } - else if (filter == MipmapFilter_Triangle) - { - TriangleFilter filter; - img = img->downSample(filter, wrapMode, 3); - } - else if (filter == MipmapFilter_Kaiser) - { - nvDebugCheck(filter == MipmapFilter_Kaiser); - //KaiserFilter filter(inputOptions.kaiserWidth); - //filter.setParameters(inputOptions.kaiserAlpha, inputOptions.kaiserStretch); - KaiserFilter filter(3); - img = img->downSample(filter, wrapMode, 3); - } + if (m->alphaMode == AlphaMode_Transparency) + { + if (filter == MipmapFilter_Box) + { + BoxFilter filter(filterWidth); + img = img->downSample(filter, wrapMode, 3); + } + else if (filter == MipmapFilter_Triangle) + { + TriangleFilter filter(filterWidth); + img = img->downSample(filter, wrapMode, 3); + } + else if (filter == MipmapFilter_Kaiser) + { + nvDebugCheck(filter == MipmapFilter_Kaiser); + KaiserFilter filter(filterWidth); + if (params != NULL) filter.setParameters(params[0], params[1]); + img = img->downSample(filter, wrapMode, 3); + } + } + else + { + if (filter == MipmapFilter_Box) + { + if (filterWidth == 0.5f) { + img = img->fastDownSample(); } - else - { - if (filter == MipmapFilter_Box) - { - img = img->fastDownSample(); - } - else if (filter == MipmapFilter_Triangle) - { - TriangleFilter filter; - img = img->downSample(filter, wrapMode); - } - else //if (filter == MipmapFilter_Kaiser) - { - nvDebugCheck(filter == MipmapFilter_Kaiser); - //KaiserFilter filter(inputOptions.kaiserWidth); - //filter.setParameters(inputOptions.kaiserAlpha, inputOptions.kaiserStretch); - KaiserFilter filter(3); - img = img->downSample(filter, wrapMode); - } + else { + BoxFilter filter(filterWidth); + img = img->downSample(filter, wrapMode); } + } + else if (filter == MipmapFilter_Triangle) + { + TriangleFilter filter(filterWidth); + img = img->downSample(filter, wrapMode); + } + else //if (filter == MipmapFilter_Kaiser) + { + nvDebugCheck(filter == MipmapFilter_Kaiser); + KaiserFilter filter(filterWidth); + if (params != NULL) filter.setParameters(params[0], params[1]); + img = img->downSample(filter, wrapMode); + } + } delete m->imageArray[i]; m->imageArray[i] = img; - } + } - return true; + return true; } // Color transforms. void TexImage::toLinear(float gamma) { - if (equal(gamma, 1.0f)) return; + if (equal(gamma, 1.0f)) return; - detach(); + detach(); - foreach (i, m->imageArray) - { - if (m->imageArray[i] == NULL) continue; + foreach (i, m->imageArray) + { + if (m->imageArray[i] == NULL) continue; - m->imageArray[i]->toLinear(0, 3, gamma); - } + m->imageArray[i]->toLinear(0, 3, gamma); + } } void TexImage::toGamma(float gamma) { - if (equal(gamma, 1.0f)) return; + if (equal(gamma, 1.0f)) return; - detach(); + detach(); - foreach (i, m->imageArray) - { - if (m->imageArray[i] == NULL) continue; + foreach (i, m->imageArray) + { + if (m->imageArray[i] == NULL) continue; - m->imageArray[i]->toGamma(0, 3, gamma); - } + m->imageArray[i]->toGamma(0, 3, gamma); + } } void TexImage::transform(const float w0[4], const float w1[4], const float w2[4], const float w3[4], const float offset[4]) { - detach(); + detach(); - Matrix xform( - Vector4(w0[0], w0[1], w0[2], w0[3]), - Vector4(w1[0], w1[1], w1[2], w1[3]), - Vector4(w2[0], w2[1], w2[2], w2[3]), - Vector4(w3[0], w3[1], w3[2], w3[3])); + Matrix xform( + Vector4(w0[0], w0[1], w0[2], w0[3]), + Vector4(w1[0], w1[1], w1[2], w1[3]), + Vector4(w2[0], w2[1], w2[2], w2[3]), + Vector4(w3[0], w3[1], w3[2], w3[3])); - Vector4 voffset(offset[0], offset[1], offset[2], offset[3]); + Vector4 voffset(offset[0], offset[1], offset[2], offset[3]); - foreach (i, m->imageArray) - { - if (m->imageArray[i] == NULL) continue; + foreach (i, m->imageArray) + { + if (m->imageArray[i] == NULL) continue; - m->imageArray[i]->transform(0, xform, voffset); - } + m->imageArray[i]->transform(0, xform, voffset); + } } void TexImage::swizzle(int r, int g, int b, int a) { - if (r == 0 && g == 1 && b == 2 && a == 3) return; + if (r == 0 && g == 1 && b == 2 && a == 3) return; - detach(); + detach(); - foreach (i, m->imageArray) - { - if (m->imageArray[i] == NULL) continue; + foreach (i, m->imageArray) + { + if (m->imageArray[i] == NULL) continue; - m->imageArray[i]->swizzle(0, r, g, b, a); - } + m->imageArray[i]->swizzle(0, r, g, b, a); + } } void TexImage::scaleBias(int channel, float scale, float bias) { - if (equal(scale, 1.0f) && equal(bias, 0.0f)) return; + if (equal(scale, 1.0f) && equal(bias, 0.0f)) return; - detach(); + detach(); - foreach (i, m->imageArray) - { - if (m->imageArray[i] == NULL) continue; + foreach (i, m->imageArray) + { + if (m->imageArray[i] == NULL) continue; - m->imageArray[i]->scaleBias(channel, 1, scale, bias); - } + m->imageArray[i]->scaleBias(channel, 1, scale, bias); + } } void TexImage::clamp(int channel, float low, float high) { - detach(); + detach(); - foreach (i, m->imageArray) - { - if (m->imageArray[i] == NULL) continue; + foreach (i, m->imageArray) + { + if (m->imageArray[i] == NULL) continue; - m->imageArray[i]->clamp(channel, 1, low, high); - } + m->imageArray[i]->clamp(channel, 1, low, high); + } } void TexImage::packNormal() { - scaleBias(0, 0.5f, 0.5f); - scaleBias(1, 0.5f, 0.5f); - scaleBias(2, 0.5f, 0.5f); + scaleBias(0, 0.5f, 0.5f); + scaleBias(1, 0.5f, 0.5f); + scaleBias(2, 0.5f, 0.5f); } void TexImage::expandNormal() { - scaleBias(0, 2.0f, -1.0f); - scaleBias(1, 2.0f, -1.0f); - scaleBias(2, 2.0f, -1.0f); + scaleBias(0, 2.0f, -1.0f); + scaleBias(1, 2.0f, -1.0f); + scaleBias(2, 2.0f, -1.0f); } void TexImage::blend(float red, float green, float blue, float alpha, float t) { - detach(); + detach(); - foreach (i, m->imageArray) + foreach (i, m->imageArray) + { + FloatImage * img = m->imageArray[i]; + if (img == NULL) continue; + + float * r = img->channel(0); + float * g = img->channel(1); + float * b = img->channel(2); + float * a = img->channel(3); + + const int count = img->width() * img->height(); + for (int i = 0; i < count; i++) { - FloatImage * img = m->imageArray[i]; - if (img == NULL) continue; - - float * restrict r = img->channel(0); - float * restrict g = img->channel(1); - float * restrict b = img->channel(2); - float * restrict a = img->channel(3); - - const int count = img->width() * img->height(); - for (int i = 0; i < count; i++) - { - r[i] = lerp(r[i], red, t); - g[i] = lerp(g[i], green, t); - b[i] = lerp(b[i], blue, t); - a[i] = lerp(a[i], alpha, t); - } + r[i] = lerp(r[i], red, t); + g[i] = lerp(g[i], green, t); + b[i] = lerp(b[i], blue, t); + a[i] = lerp(a[i], alpha, t); } + } } void TexImage::premultiplyAlpha() { - detach(); + detach(); - foreach (i, m->imageArray) + foreach (i, m->imageArray) + { + FloatImage * img = m->imageArray[i]; + if (img == NULL) continue; + + float * r = img->channel(0); + float * g = img->channel(1); + float * b = img->channel(2); + float * a = img->channel(3); + + const int count = img->width() * img->height(); + for (int i = 0; i < count; i++) { - FloatImage * img = m->imageArray[i]; - if (img == NULL) continue; - - float * restrict r = img->channel(0); - float * restrict g = img->channel(1); - float * restrict b = img->channel(2); - float * restrict a = img->channel(3); - - const int count = img->width() * img->height(); - for (int i = 0; i < count; i++) - { - r[i] *= a[i]; - g[i] *= a[i]; - b[i] *= a[i]; - } + r[i] *= a[i]; + g[i] *= a[i]; + b[i] *= a[i]; } + } } void TexImage::toGreyScale(float redScale, float greenScale, float blueScale, float alphaScale) { - detach(); + detach(); - foreach (i, m->imageArray) - { - FloatImage * img = m->imageArray[i]; - if (img == NULL) continue; + foreach (i, m->imageArray) + { + FloatImage * img = m->imageArray[i]; + if (img == NULL) continue; - float sum = redScale + greenScale + blueScale + alphaScale; - redScale /= sum; - greenScale /= sum; - blueScale /= sum; - alphaScale /= sum; + float sum = redScale + greenScale + blueScale + alphaScale; + redScale /= sum; + greenScale /= sum; + blueScale /= sum; + alphaScale /= sum; - float * restrict r = img->channel(0); - float * restrict g = img->channel(1); - float * restrict b = img->channel(2); - float * restrict a = img->channel(3); + float * r = img->channel(0); + float * g = img->channel(1); + float * b = img->channel(2); + float * a = img->channel(3); - const int count = img->width() * img->height(); - for (int i = 0; i < count; i++) - { - float grey = r[i] * redScale + g[i] * greenScale + b[i] * blueScale + a[i] * alphaScale; - a[i] = b[i] = g[i] = r[i] = grey; - } - } + const int count = img->width() * img->height(); + for (int i = 0; i < count; i++) + { + float grey = r[i] * redScale + g[i] * greenScale + b[i] * blueScale + a[i] * alphaScale; + a[i] = b[i] = g[i] = r[i] = grey; + } + } } // Draw colored border. void TexImage::setBorder(float r, float g, float b, float a) { - detach(); + detach(); - foreach (i, m->imageArray) + foreach (i, m->imageArray) + { + FloatImage * img = m->imageArray[i]; + if (img == NULL) continue; + + const int w = img->width(); + const int h = img->height(); + + for (int i = 0; i < w; i++) + { + img->pixel(i, 0, 0) = r; + img->pixel(i, 0, 1) = g; + img->pixel(i, 0, 2) = b; + img->pixel(i, 0, 3) = a; + + img->pixel(i, h-1, 0) = r; + img->pixel(i, h-1, 1) = g; + img->pixel(i, h-1, 2) = b; + img->pixel(i, h-1, 3) = a; + } + + for (int i = 0; i < h; i++) { - FloatImage * img = m->imageArray[i]; - if (img == NULL) continue; + img->pixel(0, i, 0) = r; + img->pixel(0, i, 1) = g; + img->pixel(0, i, 2) = b; + img->pixel(0, i, 3) = a; - const int w = img->width(); - const int h = img->height(); - - for (int i = 0; i < w; i++) - { - img->pixel(i, 0, 0) = r; - img->pixel(i, 0, 1) = g; - img->pixel(i, 0, 2) = b; - img->pixel(i, 0, 3) = a; - - img->pixel(i, h-1, 0) = r; - img->pixel(i, h-1, 1) = g; - img->pixel(i, h-1, 2) = b; - img->pixel(i, h-1, 3) = a; - } - - for (int i = 0; i < h; i++) - { - img->pixel(0, i, 0) = r; - img->pixel(0, i, 1) = g; - img->pixel(0, i, 2) = b; - img->pixel(0, i, 3) = a; - - img->pixel(w-1, i, 0) = r; - img->pixel(w-1, i, 1) = g; - img->pixel(w-1, i, 2) = b; - img->pixel(w-1, i, 3) = a; - } + img->pixel(w-1, i, 0) = r; + img->pixel(w-1, i, 1) = g; + img->pixel(w-1, i, 2) = b; + img->pixel(w-1, i, 3) = a; } + } } // Fill image with the given color. void TexImage::fill(float red, float green, float blue, float alpha) { - detach(); + detach(); - foreach (i, m->imageArray) - { - FloatImage * img = m->imageArray[i]; - if (img == NULL) continue; + foreach (i, m->imageArray) + { + FloatImage * img = m->imageArray[i]; + if (img == NULL) continue; - float * restrict r = img->channel(0); - float * restrict g = img->channel(1); - float * restrict b = img->channel(2); - float * restrict a = img->channel(3); + float * restrict r = img->channel(0); + float * restrict g = img->channel(1); + float * restrict b = img->channel(2); + float * restrict a = img->channel(3); - const int count = img->width() * img->height(); - for (int i = 0; i < count; i++) - { - r[i] = red; - g[i] = green; - b[i] = blue; - a[i] = alpha; - } - } + const int count = img->width() * img->height(); + for (int i = 0; i < count; i++) + { + r[i] = red; + g[i] = green; + b[i] = blue; + a[i] = alpha; + } + } } @@ -990,10 +1078,10 @@ void TexImage::scaleAlphaToCoverage(float coverage, float alphaRef/*= 0.5f*/) { detach(); - foreach (i, m->imageArray) - { - FloatImage * img = m->imageArray[i]; - if (img == NULL) continue; + foreach (i, m->imageArray) + { + FloatImage * img = m->imageArray[i]; + if (img == NULL) continue; img->scaleAlphaToCoverage(coverage, alphaRef, 3); } @@ -1004,9 +1092,9 @@ bool TexImage::normalizeRange(float * rangeMin, float * rangeMax) Vector2 range(FLT_MAX, -FLT_MAX); // Compute range. - foreach (i, m->imageArray) { - FloatImage * img = m->imageArray[i]; - if (img == NULL) continue; + foreach (i, m->imageArray) { + FloatImage * img = m->imageArray[i]; + if (img == NULL) continue; const uint count = img->count(); for (uint p = 0; p < count; p++) { @@ -1037,8 +1125,8 @@ bool TexImage::normalizeRange(float * rangeMin, float * rangeMax) // Scale to range. foreach (i, m->imageArray) { - FloatImage * img = m->imageArray[i]; - if (img == NULL) continue; + FloatImage * img = m->imageArray[i]; + if (img == NULL) continue; img->scaleBias(0, 4, scale, bias); //img->clamp(0, 4, 0.0f, 1.0f); @@ -1047,205 +1135,324 @@ bool TexImage::normalizeRange(float * rangeMin, float * rangeMax) return true; } +// Ideally you should compress/quantize the RGB and M portions independently. +// Once you have M quantized, you would compute the corresponding RGB and quantize that. +void TexImage::toRGBM(float range/*= 1*/, float threshold/*= 0.25*/) +{ + detach(); + + float irange = 1.0f / range; + + foreach (idx, m->imageArray) { + FloatImage * img = m->imageArray[idx]; + if (img == NULL) continue; + + float * r = img->channel(0); + float * g = img->channel(1); + float * b = img->channel(2); + float * a = img->channel(3); + + const uint count = img->width() * img->height(); + for (uint i = 0; i < count; i++) { + float ri = nv::clamp(r[i] * irange, 0.0f, 1.0f); + float gi = nv::clamp(g[i] * irange, 0.0f, 1.0f); + float bi = nv::clamp(b[i] * irange, 0.0f, 1.0f); + + float m = max(max(ri, gi), max(bi, 1e-6f)); // Avoid division by zero. + //m = quantizeCeil(m, 8); + float im = 1.0f / m; + + r[i] = ri * im; + g[i] = gi * im; + b[i] = bi * im; + a[i] = m; + } + } +} + +// Y is in the [0, 1] range, while CoCg are in the [-1, 1] range. +void TexImage::toYCoCg() +{ + detach(); + + foreach (idx, m->imageArray) { + FloatImage * img = m->imageArray[idx]; + if (img == NULL) continue; + + float * r = img->channel(0); + float * g = img->channel(1); + float * b = img->channel(2); + float * a = img->channel(3); + + const uint count = img->width() * img->height(); + for (uint i = 0; i < count; i++) { + float ri = r[i]; + float gi = g[i]; + float bi = b[i]; + + float Y = (2*gi + ri + bi) * 0.25f; + float Co = (ri - bi); + float Cg = (2*gi - ri - bi) * 0.5f; + + r[i] = Co; + g[i] = Cg; + b[i] = 0.0f; + a[i] = Y; + } + } +} + +// img.toYCoCg(); +// img.blockScaleCoCg(); +// img.scaleBias(0, 0.5, 0.5); +// img.scaleBias(1, 0.5, 0.5); + +// @@ Add support for threshold. +// We could do something to prevent scale values from adjacent blocks from being too different to each other +// and minimize bilinear interpolation artifacts. +void TexImage::blockScaleCoCg(int bits/*= 5*/, float threshold/*= 0.0*/) +{ + detach(); + + foreach (idx, m->imageArray) { + FloatImage * img = m->imageArray[idx]; + if (img == NULL) continue; + + const uint w = img->width(); + const uint h = img->height(); + const uint bw = max(1U, w/4); + const uint bh = max(1U, h/4); + + for (uint bj = 0; bj < bh; bj++) { + for (uint bi = 0; bi < bw; bi++) { + + // Compute per block scale. + float m = 1.0f / 256.0f; + for (uint j = 0; j < 4; j++) { + for (uint i = 0; i < 4; i++) { + uint x = min(bi*4 + i, w); + uint y = min(bj*4 + j, h); + + float Co = img->pixel(x, y, 0); + float Cg = img->pixel(x, y, 1); + + m = max(m, fabsf(Co)); + m = max(m, fabsf(Cg)); + } + } + + float scale = quantizeCeil(m, bits); + nvDebugCheck(scale >= m); + + // Store block scale in blue channel and scale CoCg. + for (uint j = 0; j < 4; j++) { + for (uint i = 0; i < 4; i++) { + uint x = min(bi*4 + i, w); + uint y = min(bj*4 + j, h); + + float & Co = img->pixel(x, y, 0); + float & Cg = img->pixel(x, y, 1); + + Co /= scale; + nvDebugCheck(fabsf(Co) <= 1.0f); + + Cg /= scale; + nvDebugCheck(fabsf(Cg) <= 1.0f); + + img->pixel(x, y, 2) = scale; + } + } + } + } + } +} + + // Set normal map options. void TexImage::toNormalMap(float sm, float medium, float big, float large) { - detach(); + detach(); - const Vector4 filterWeights(sm, medium, big, large); + const Vector4 filterWeights(sm, medium, big, large); - foreach (i, m->imageArray) - { - if (m->imageArray[i] == NULL) continue; + foreach (i, m->imageArray) + { + if (m->imageArray[i] == NULL) continue; - const FloatImage * img = m->imageArray[i]; - m->imageArray[i] = nv::createNormalMap(img, (FloatImage::WrapMode)m->wrapMode, filterWeights); + const FloatImage * img = m->imageArray[i]; + m->imageArray[i] = nv::createNormalMap(img, (FloatImage::WrapMode)m->wrapMode, filterWeights); #pragma NV_MESSAGE("TODO: Pack and expand normals explicitly?") - m->imageArray[i]->packNormals(0); + m->imageArray[i]->packNormals(0); - delete img; - } + delete img; + } - m->isNormalMap = true; + m->isNormalMap = true; } -/*void TexImage::toHeightMap() -{ - detach(); - - foreach (i, m->imageArray) - { - if (m->imageArray[i] == NULL) continue; - -#pragma message(NV_FILE_LINE "TODO: Implement TexImage::toHeightMap") - } - - m->isNormalMap = false; -}*/ - void TexImage::normalizeNormalMap() { - //nvCheck(m->isNormalMap); + //nvCheck(m->isNormalMap); - detach(); + detach(); - foreach (i, m->imageArray) - { - if (m->imageArray[i] == NULL) continue; + foreach (i, m->imageArray) + { + if (m->imageArray[i] == NULL) continue; - nv::normalizeNormalMap(m->imageArray[i]); - } + nv::normalizeNormalMap(m->imageArray[i]); + } } float TexImage::rootMeanSquaredError_rgb(const TexImage & reference) const { - int totalCount = 0; - double mse = 0; + int totalCount = 0; + double mse = 0; - const int faceCount = this->faceCount(); - if (faceCount != reference.faceCount()) { - return FLT_MAX; - } + const int faceCount = this->faceCount(); + if (faceCount != reference.faceCount()) { + return FLT_MAX; + } - for (int f = 0; f < faceCount; f++) - { - const FloatImage * img = m->imageArray[f]; - const FloatImage * ref = reference.m->imageArray[f]; + for (int f = 0; f < faceCount; f++) + { + const FloatImage * img = m->imageArray[f]; + const FloatImage * ref = reference.m->imageArray[f]; - if (img == NULL || ref == NULL) { - return FLT_MAX; - } + if (img == NULL || ref == NULL) { + return FLT_MAX; + } - nvCheck(img->componentNum() == 4); - nvCheck(ref->componentNum() == 4); + nvCheck(img->componentNum() == 4); + nvCheck(ref->componentNum() == 4); - const uint count = img->width() * img->height(); - totalCount += count; + const uint count = img->width() * img->height(); + totalCount += count; - for (uint i = 0; i < count; i++) - { - float r0 = img->pixel(4 * i + count * 0); - float g0 = img->pixel(4 * i + count * 1); - float b0 = img->pixel(4 * i + count * 2); - float a0 = img->pixel(4 * i + count * 3); - float r1 = ref->pixel(4 * i + count * 0); - float g1 = ref->pixel(4 * i + count * 1); - float b1 = ref->pixel(4 * i + count * 2); - float a1 = ref->pixel(4 * i + count * 3); + for (uint i = 0; i < count; i++) + { + float r0 = img->pixel(4 * i + count * 0); + float g0 = img->pixel(4 * i + count * 1); + float b0 = img->pixel(4 * i + count * 2); + float a0 = img->pixel(4 * i + count * 3); + float r1 = ref->pixel(4 * i + count * 0); + float g1 = ref->pixel(4 * i + count * 1); + float b1 = ref->pixel(4 * i + count * 2); + float a1 = ref->pixel(4 * i + count * 3); - float r = r0 - r1; - float g = g0 - g1; - float b = b0 - b1; - float a = a0 - a1; + float r = r0 - r1; + float g = g0 - g1; + float b = b0 - b1; + float a = a0 - a1; - if (reference.alphaMode() == nvtt::AlphaMode_Transparency) - { - mse += double(r * r * a1) / 255.0; - mse += double(g * g * a1) / 255.0; - mse += double(b * b * a1) / 255.0; - } - else - { - mse += r * r; - mse += g * g; - mse += b * b; - } - } - } + if (reference.alphaMode() == nvtt::AlphaMode_Transparency) + { + mse += double(r * r * a1) / 255.0; + mse += double(g * g * a1) / 255.0; + mse += double(b * b * a1) / 255.0; + } + else + { + mse += r * r; + mse += g * g; + mse += b * b; + } + } + } - return float(sqrt(mse / totalCount)); + return float(sqrt(mse / totalCount)); } float TexImage::rootMeanSquaredError_alpha(const TexImage & reference) const { - int totalCount = 0; - double mse = 0; + int totalCount = 0; + double mse = 0; - const int faceCount = this->faceCount(); - if (faceCount != reference.faceCount()) { - return FLT_MAX; - } + const int faceCount = this->faceCount(); + if (faceCount != reference.faceCount()) { + return FLT_MAX; + } - for (int f = 0; f < faceCount; f++) - { - const FloatImage * img = m->imageArray[f]; - const FloatImage * ref = reference.m->imageArray[f]; + for (int f = 0; f < faceCount; f++) + { + const FloatImage * img = m->imageArray[f]; + const FloatImage * ref = reference.m->imageArray[f]; - if (img == NULL || ref == NULL) { - return FLT_MAX; - } + if (img == NULL || ref == NULL) { + return FLT_MAX; + } - nvCheck(img->componentNum() == 4); - nvCheck(ref->componentNum() == 4); + nvCheck(img->componentNum() == 4); + nvCheck(ref->componentNum() == 4); - const uint count = img->width() * img->height(); - totalCount += count; + const uint count = img->width() * img->height(); + totalCount += count; - for (uint i = 0; i < count; i++) - { - float a0 = img->pixel(4 * i + count * 3); - float a1 = ref->pixel(4 * i + count * 3); + for (uint i = 0; i < count; i++) + { + float a0 = img->pixel(4 * i + count * 3); + float a1 = ref->pixel(4 * i + count * 3); - float a = a0 - a1; + float a = a0 - a1; - mse += a * a; - } - } + mse += a * a; + } + } - return float(sqrt(mse / totalCount)); + return float(sqrt(mse / totalCount)); } void TexImage::flipVertically() { detach(); - foreach (i, m->imageArray) - { - if (m->imageArray[i] == NULL) continue; + foreach (i, m->imageArray) + { + if (m->imageArray[i] == NULL) continue; m->imageArray[i]->flip(); - } + } } bool TexImage::copyChannel(const TexImage & srcImage, int srcChannel) { - return copyChannel(srcImage, srcChannel, srcChannel); + return copyChannel(srcImage, srcChannel, srcChannel); } bool TexImage::copyChannel(const TexImage & srcImage, int srcChannel, int dstChannel) { - const int faceCount = this->faceCount(); - if (faceCount != srcImage.faceCount()) { - return false; - } + const int faceCount = this->faceCount(); + if (faceCount != srcImage.faceCount()) { + return false; + } - detach(); + detach(); - foreach (i, m->imageArray) - { - FloatImage * dst = m->imageArray[i]; - const FloatImage * src = srcImage.m->imageArray[i]; + foreach (i, m->imageArray) + { + FloatImage * dst = m->imageArray[i]; + const FloatImage * src = srcImage.m->imageArray[i]; - if (dst == NULL || src == NULL) { - return false; - } + if (dst == NULL || src == NULL) { + return false; + } - nvCheck(src->componentNum() == 4); - nvCheck(dst->componentNum() == 4); + nvCheck(src->componentNum() == 4); + nvCheck(dst->componentNum() == 4); - const uint w = src->width(); - const uint h = src->height(); + const uint w = src->width(); + const uint h = src->height(); - if (w != dst->width() || h != dst->height()) { - return false; - } + if (w != dst->width() || h != dst->height()) { + return false; + } - memcpy(dst->channel(dstChannel), src->channel(srcChannel), w*h*sizeof(float)); - } + memcpy(dst->channel(dstChannel), src->channel(srcChannel), w*h*sizeof(float)); + } - return true; + return true; } diff --git a/src/nvtt/TexImage.h b/src/nvtt/TexImage.h index 4821b96..6912dbc 100644 --- a/src/nvtt/TexImage.h +++ b/src/nvtt/TexImage.h @@ -42,6 +42,8 @@ namespace nvtt public: Private() { + nvDebugCheck( refCount() == 0 ); + type = TextureType_2D; wrapMode = WrapMode_Mirror; alphaMode = AlphaMode_None; @@ -49,8 +51,10 @@ namespace nvtt imageArray.resize(1, NULL); } - Private(const Private & p) // Copy ctor. inits refcount to 0. + Private(const Private & p) : RefCounted() // Copy ctor. inits refcount to 0. { + nvDebugCheck( refCount() == 0 ); + type = p.type; wrapMode = p.wrapMode; alphaMode = p.alphaMode; diff --git a/src/nvtt/bc6h/utils.cpp b/src/nvtt/bc6h/utils.cpp index b41d15d..8c557b0 100644 --- a/src/nvtt/bc6h/utils.cpp +++ b/src/nvtt/bc6h/utils.cpp @@ -262,7 +262,7 @@ static int clamp(double r, double low, double high) // match the tonemapping function used by exrdisplay -static void tonemap(const Vector3 &in, double exposure, Vector3 &out) +/*static void tonemap(const Vector3 &in, double exposure, Vector3 &out) { double r,g,b; unsigned short h; @@ -325,7 +325,7 @@ static void tonemap(const Vector3 &in, double exposure, Vector3 &out) out.x = clamp (r, 0, 255); out.y = clamp (g, 0, 255); out.z = clamp (b, 0, 255); -} +}*/ static void mpsnrmap(const Vector3 &in, int exposure, Vector3 &out) { diff --git a/src/nvtt/cuda/CudaCompressorDXT.cpp b/src/nvtt/cuda/CudaCompressorDXT.cpp index 0795bc1..1124bb5 100644 --- a/src/nvtt/cuda/CudaCompressorDXT.cpp +++ b/src/nvtt/cuda/CudaCompressorDXT.cpp @@ -124,38 +124,45 @@ CudaCompressor::CudaCompressor(CudaContext & ctx) : m_ctx(ctx) } -void CudaCompressor::compress(nvtt::InputFormat inputFormat, nvtt::AlphaMode alphaMode, uint w, uint h, const void * data, const nvtt::CompressionOptions::Private & compressionOptions, const nvtt::OutputOptions::Private & outputOptions) +void CudaCompressor::compress(nvtt::AlphaMode alphaMode, uint w, uint h, const float * data, const nvtt::CompressionOptions::Private & compressionOptions, const nvtt::OutputOptions::Private & outputOptions) { nvDebugCheck(cuda::isHardwarePresent()); #if defined HAVE_CUDA // Allocate image as a cuda array. + const uint count = w * h; + Color32 * tmp = malloc(count); + for (int i = 0; i < count; i++) { + tmp[i].r = clamp(data[i + count*0], 0.0f, 1.0f) * 255; + tmp[i].g = clamp(data[i + count*1], 0.0f, 1.0f) * 255; + tmp[i].b = clamp(data[i + count*2], 0.0f, 1.0f) * 255; + tmp[i].a = clamp(data[i + count*3], 0.0f, 1.0f) * 255; + } + cudaArray * d_image; - if (inputFormat == nvtt::InputFormat_BGRA_8UB) - { - cudaChannelFormatDesc channelDesc = cudaCreateChannelDesc(8, 8, 8, 8, cudaChannelFormatKindUnsigned); - cudaMallocArray(&d_image, &channelDesc, w, h); + cudaChannelFormatDesc channelDesc = cudaCreateChannelDesc(8, 8, 8, 8, cudaChannelFormatKindUnsigned); + cudaMallocArray(&d_image, &channelDesc, w, h); - const int imageSize = w * h * sizeof(uint); - cudaMemcpyToArray(d_image, 0, 0, data, imageSize, cudaMemcpyHostToDevice); - } - else - { -#pragma NV_MESSAGE("FIXME: Floating point textures not really supported by CUDA compressors.") // @@ What's missing??? - cudaChannelFormatDesc channelDesc = cudaCreateChannelDesc(32, 32, 32, 32, cudaChannelFormatKindFloat); - cudaMallocArray(&d_image, &channelDesc, w, h); + cudaMemcpyToArray(d_image, 0, 0, tmp, count * sizeof(Color32), cudaMemcpyHostToDevice); - const int imageSize = w * h * sizeof(uint); - cudaMemcpyToArray(d_image, 0, 0, data, imageSize, cudaMemcpyHostToDevice); - } + free(tmp); + + // To avoid the copy we could keep the data in floating point format, but the channels are not interleaved like the kernel expects. + /* + cudaChannelFormatDesc channelDesc = cudaCreateChannelDesc(32, 32, 32, 32, cudaChannelFormatKindFloat); + cudaMallocArray(&d_image, &channelDesc, w, h); + + const int imageSize = w * h * sizeof(float) * 4; + cudaMemcpyToArray(d_image, 0, 0, data, imageSize, cudaMemcpyHostToDevice); + */ // Image size in blocks. const uint bw = (w + 3) / 4; const uint bh = (h + 3) / 4; const uint bs = blockSize(); const uint blockNum = bw * bh; - const uint compressedSize = blockNum * bs; + //const uint compressedSize = blockNum * bs; void * h_result = ::malloc(min(blockNum, MAX_BLOCKS) * bs); @@ -192,9 +199,8 @@ void CudaCompressor::compress(nvtt::InputFormat inputFormat, nvtt::AlphaMode alp cudaFreeArray(d_image); #else - outputOptions.error(Error_CudaError); + outputOptions.error(Error_CudaError); #endif - } #if defined HAVE_CUDA diff --git a/src/nvtt/cuda/CudaCompressorDXT.h b/src/nvtt/cuda/CudaCompressorDXT.h index 78097fa..582b0e2 100644 --- a/src/nvtt/cuda/CudaCompressorDXT.h +++ b/src/nvtt/cuda/CudaCompressorDXT.h @@ -53,7 +53,7 @@ namespace nv { CudaCompressor(CudaContext & ctx); - virtual void compress(nvtt::InputFormat inputFormat, nvtt::AlphaMode alphaMode, uint w, uint h, const void * data, const nvtt::CompressionOptions::Private & compressionOptions, const nvtt::OutputOptions::Private & outputOptions); + virtual void compress(nvtt::AlphaMode alphaMode, uint w, uint h, const float * data, const nvtt::CompressionOptions::Private & compressionOptions, const nvtt::OutputOptions::Private & outputOptions); virtual void setup(cudaArray * image, const nvtt::CompressionOptions::Private & compressionOptions) = 0; virtual void compressBlocks(uint first, uint count, uint w, uint h, nvtt::AlphaMode alphaMode, const nvtt::CompressionOptions::Private & compressionOptions, void * output) = 0; diff --git a/src/nvtt/nvtt.h b/src/nvtt/nvtt.h index 99bc778..4293b2f 100644 --- a/src/nvtt/nvtt.h +++ b/src/nvtt/nvtt.h @@ -29,459 +29,440 @@ #if NVTT_SHARED #if defined _WIN32 || defined WIN32 || defined __NT__ || defined __WIN32__ || defined __MINGW32__ -# ifdef NVTT_EXPORTS -# define NVTT_API __declspec(dllexport) -# else -# define NVTT_API __declspec(dllimport) -# endif +# ifdef NVTT_EXPORTS +# define NVTT_API __declspec(dllexport) +# else +# define NVTT_API __declspec(dllimport) +# endif #endif #if defined __GNUC__ >= 4 -# ifdef NVTT_EXPORTS -# define NVTT_API __attribute__((visibility("default"))) -# endif +# ifdef NVTT_EXPORTS +# define NVTT_API __attribute__((visibility("default"))) +# endif #endif #endif // NVTT_SHARED #if !defined NVTT_API -# define NVTT_API +# define NVTT_API #endif #define NVTT_VERSION 20100 #define NVTT_FORBID_COPY(Class) \ - private: \ - Class(const Class &); \ - void operator=(const Class &); \ - public: + private: \ + Class(const Class &); \ + void operator=(const Class &); \ + public: #define NVTT_DECLARE_PIMPL(Class) \ - public: \ - struct Private; \ - Private & m + public: \ + struct Private; \ + Private & m // Public interface. namespace nvtt { - // Forward declarations. - struct TexImage; - - /// 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=1, G=y, B=0, A=x - - // DX10 formats. - Format_BC1 = Format_DXT1, - Format_BC1a = Format_DXT1a, - Format_BC2 = Format_DXT3, - Format_BC3 = Format_DXT5, - Format_BC3n = Format_DXT5n, - Format_BC4, // ATI1 - Format_BC5, // 3DC, ATI2 + // Forward declarations. + struct TexImage; - Format_DXT1n,// Not supported on CPU yet. - Format_CTX1, // Not supported on CPU yet. - //Format_YCoCg_DXT5, // Not supported yet. + /// Supported compression formats. + enum Format + { + // No compression. + Format_RGB, + Format_RGBA = Format_RGB, - Format_BC6, // Not supported yet. - Format_BC7, // Not supported yet. + // DX9 formats. + Format_DXT1, + Format_DXT1a, // DXT1 with binary alpha. + Format_DXT3, + Format_DXT5, + Format_DXT5n, // Compressed HILO: R=1, G=y, B=0, A=x + + // DX10 formats. + Format_BC1 = Format_DXT1, + Format_BC1a = Format_DXT1a, + Format_BC2 = Format_DXT3, + Format_BC3 = Format_DXT5, + Format_BC3n = Format_DXT5n, + Format_BC4, // ATI1 + Format_BC5, // 3DC, ATI2 + + Format_DXT1n, // Not supported on CPU yet. + Format_CTX1, // Not supported on CPU yet. + + Format_BC6, // Not supported yet. + Format_BC7, // Not supported yet. Format_RGBE, - }; + }; - /// Pixel types. These basically indicate how the output should be interpreted, but do not have any influence over the input. - enum PixelType - { - PixelType_UnsignedNorm, - PixelType_SignedNorm, // Not supported yet. - PixelType_UnsignedInt, // Not supported yet. - PixelType_SignedInt, // Not supported yet. - PixelType_Float, - PixelType_UnsignedFloat, - }; - - /// Quality modes. - enum Quality - { - Quality_Fastest, - Quality_Normal, - Quality_Production, - Quality_Highest, - }; + /// Pixel types. These basically indicate how the output should be interpreted, but do not have any influence over the input. + enum PixelType + { + PixelType_UnsignedNorm = 0, + PixelType_SignedNorm = 1, // Not supported yet. + PixelType_UnsignedInt = 2, // Not supported yet. + PixelType_SignedInt = 3, // Not supported yet. + PixelType_Float = 4, + PixelType_UnsignedFloat = 5, + }; - /// Compression options. This class describes the desired compression format and other compression settings. - struct CompressionOptions - { - NVTT_FORBID_COPY(CompressionOptions); - NVTT_DECLARE_PIMPL(CompressionOptions); + /// Quality modes. + enum Quality + { + Quality_Fastest, + Quality_Normal, + Quality_Production, + Quality_Highest, + }; - NVTT_API CompressionOptions(); - NVTT_API ~CompressionOptions(); - - NVTT_API void reset(); - - NVTT_API void setFormat(Format format); - NVTT_API void setQuality(Quality quality); - NVTT_API void setColorWeights(float red, float green, float blue, float alpha = 1.0f); - - NVTT_API void setExternalCompressor(const char * name); + /// Compression options. This class describes the desired compression format and other compression settings. + struct CompressionOptions + { + NVTT_FORBID_COPY(CompressionOptions); + NVTT_DECLARE_PIMPL(CompressionOptions); - // Set color mask to describe the RGB/RGBA format. - NVTT_API void setPixelFormat(unsigned int bitcount, unsigned int rmask, unsigned int gmask, unsigned int bmask, unsigned int amask); - NVTT_API void setPixelFormat(unsigned char rsize, unsigned char gsize, unsigned char bsize, unsigned char asize); - - NVTT_API void setPixelType(PixelType pixelType); + NVTT_API CompressionOptions(); + NVTT_API ~CompressionOptions(); + + NVTT_API void reset(); + + NVTT_API void setFormat(Format format); + NVTT_API void setQuality(Quality quality); + NVTT_API void setColorWeights(float red, float green, float blue, float alpha = 1.0f); + + NVTT_API void setExternalCompressor(const char * name); + + // Set color mask to describe the RGB/RGBA format. + NVTT_API void setPixelFormat(unsigned int bitcount, unsigned int rmask, unsigned int gmask, unsigned int bmask, unsigned int amask); + NVTT_API void setPixelFormat(unsigned char rsize, unsigned char gsize, unsigned char bsize, unsigned char asize); + + NVTT_API void setPixelType(PixelType pixelType); NVTT_API void setPitchAlignment(int pitchAlignment); - NVTT_API void setQuantization(bool colorDithering, bool alphaDithering, bool binaryAlpha, int alphaThreshold = 127); - }; + NVTT_API void setQuantization(bool colorDithering, bool alphaDithering, bool binaryAlpha, int alphaThreshold = 127); + }; - /* - // DXGI_FORMAT_R16G16_FLOAT - compressionOptions.setPixelType(PixelType_Float); - compressionOptions.setPixelFormat2(16, 16, 0, 0); - - // DXGI_FORMAT_R32G32B32A32_FLOAT - compressionOptions.setPixelType(PixelType_Float); - compressionOptions.setPixelFormat2(32, 32, 32, 32); - */ - + /* + // DXGI_FORMAT_R16G16_FLOAT + compressionOptions.setPixelType(PixelType_Float); + compressionOptions.setPixelFormat2(16, 16, 0, 0); - /// Wrap modes. - 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_RGBA_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. - }; - - /// Texture resize filters. - enum ResizeFilter - { - ResizeFilter_Box, - ResizeFilter_Triangle, - ResizeFilter_Kaiser, - ResizeFilter_Mitchell, - }; - - /// Color transformation. - enum ColorTransform - { - ColorTransform_None, - ColorTransform_Linear, ///< Not implemented. - ColorTransform_Swizzle, ///< Not implemented. - ColorTransform_YCoCg, ///< Transform into r=Co, g=Cg, b=0, a=Y - ColorTransform_ScaledYCoCg, ///< Not implemented. - }; - - /// Extents rounding mode. - enum RoundMode - { - RoundMode_None, - RoundMode_ToNextPowerOfTwo, - RoundMode_ToNearestPowerOfTwo, - RoundMode_ToPreviousPowerOfTwo, - }; - - /// Alpha mode. - enum AlphaMode - { - AlphaMode_None, - AlphaMode_Transparency, - AlphaMode_Premultiplied, - }; + // DXGI_FORMAT_R32G32B32A32_FLOAT + compressionOptions.setPixelType(PixelType_Float); + compressionOptions.setPixelFormat2(32, 32, 32, 32); + */ - /// Input options. Specify format and layout of the input texture. - struct InputOptions - { - NVTT_FORBID_COPY(InputOptions); - NVTT_DECLARE_PIMPL(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); - NVTT_API bool setMipmapChannelData(const void * data, int channel, int w, int h, int d = 1, int face = 0, int mipmap = 0); - - // Describe the format of the input. - NVTT_API void setFormat(InputFormat format); - - // Set the way the input alpha channel is interpreted. @@ Not implemented! - NVTT_API void setAlphaMode(AlphaMode alphaMode); - - // Set gamma settings. - NVTT_API void setGamma(float inputGamma, float outputGamma); - - // Set texture wrapping mode. - NVTT_API void setWrapMode(WrapMode mode); - - // Set mipmapping options. - NVTT_API void setMipmapFilter(MipmapFilter filter); - NVTT_API void setMipmapGeneration(bool enabled, int maxLevel = -1); - NVTT_API void setKaiserParameters(float width, float alpha, float stretch); + /// Wrap modes. + enum WrapMode + { + WrapMode_Clamp, + WrapMode_Repeat, + WrapMode_Mirror, + }; - // Set normal map options. - NVTT_API void setNormalMap(bool b); - NVTT_API void setConvertToNormalMap(bool convert); - NVTT_API void setHeightEvaluation(float redScale, float greenScale, float blueScale, float alphaScale); - NVTT_API void setNormalFilter(float sm, float medium, float big, float large); - NVTT_API void setNormalizeMipmaps(bool b); - - // Set color transforms. - NVTT_API void setColorTransform(ColorTransform t); - NVTT_API void setLinearTransform(int channel, float w0, float w1, float w2, float w3); - NVTT_API void setLinearTransform(int channel, float w0, float w1, float w2, float w3, float offset); - NVTT_API void setSwizzleTransform(int x, int y, int z, int w); - - // Set resizing options. - NVTT_API void setMaxExtents(int d); - NVTT_API void setRoundMode(RoundMode mode); + /// Texture types. + enum TextureType + { + TextureType_2D, + TextureType_Cube, + // TextureType_3D, + }; - // Set whether or not to premultiply color by alpha - NVTT_API void setPremultiplyAlpha(bool b); - }; - - - /// Output handler. - struct OutputHandler - { - virtual ~OutputHandler() {} - - /// Indicate the start of a new compressed image that's part of the final texture. - virtual void beginImage(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 bool writeData(const void * data, int size) = 0; - }; + /// Input formats. + enum InputFormat + { + InputFormat_BGRA_8UB, // Normalized [0, 1] 8 bit fixed point. + InputFormat_RGBA_16F, // 16 bit floating point. + InputFormat_RGBA_32F, // 32 bit floating point. + }; - /// Error codes. - enum Error - { - Error_Unknown, - Error_InvalidInput, - Error_UnsupportedFeature, - Error_CudaError, - Error_FileOpen, - Error_FileWrite, - Error_UnsupportedOutputFormat, - }; - - /// Error handler. - struct ErrorHandler - { - virtual ~ErrorHandler() {} - - // Signal error. - virtual void error(Error e) = 0; - }; + /// 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. + }; - /// Container. - enum Container - { - Container_DDS, - Container_DDS10, - }; - + /// Texture resize filters. + enum ResizeFilter + { + ResizeFilter_Box, + ResizeFilter_Triangle, + ResizeFilter_Kaiser, + ResizeFilter_Mitchell, + }; - /// Output Options. This class holds pointers to the interfaces that are used to report the output of - /// the compressor to the user. - struct OutputOptions - { - NVTT_FORBID_COPY(OutputOptions); - NVTT_DECLARE_PIMPL(OutputOptions); + /// Extents rounding mode. + enum RoundMode + { + RoundMode_None, + RoundMode_ToNextPowerOfTwo, + RoundMode_ToNearestPowerOfTwo, + RoundMode_ToPreviousPowerOfTwo, + }; - NVTT_API OutputOptions(); - NVTT_API ~OutputOptions(); - - // Set default options. - NVTT_API void reset(); - - NVTT_API void setFileName(const char * fileName); - - NVTT_API void setOutputHandler(OutputHandler * outputHandler); - NVTT_API void setErrorHandler(ErrorHandler * errorHandler); + /// Alpha mode. + enum AlphaMode + { + AlphaMode_None, + AlphaMode_Transparency, + AlphaMode_Premultiplied, + }; - NVTT_API void setOutputHeader(bool outputHeader); - NVTT_API void setContainer(Container container); + /// Input options. Specify format and layout of the input texture. + struct InputOptions + { + NVTT_FORBID_COPY(InputOptions); + NVTT_DECLARE_PIMPL(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 format); + + // Set the way the input alpha channel is interpreted. @@ Not implemented! + NVTT_API void setAlphaMode(AlphaMode alphaMode); + + // Set gamma settings. + NVTT_API void setGamma(float inputGamma, float outputGamma); + + // Set texture wrapping mode. + NVTT_API void setWrapMode(WrapMode mode); + + // Set mipmapping options. + NVTT_API void setMipmapFilter(MipmapFilter filter); + NVTT_API void setMipmapGeneration(bool enabled, int maxLevel = -1); + NVTT_API void setKaiserParameters(float width, float alpha, float stretch); + + // Set normal map options. + NVTT_API void setNormalMap(bool b); + NVTT_API void setConvertToNormalMap(bool convert); + NVTT_API void setHeightEvaluation(float redScale, float greenScale, float blueScale, float alphaScale); + NVTT_API void setNormalFilter(float sm, float medium, float big, float large); + NVTT_API void setNormalizeMipmaps(bool b); + + // Set resizing options. + NVTT_API void setMaxExtents(int d); + NVTT_API void setRoundMode(RoundMode mode); + }; + + + /// Output handler. + struct OutputHandler + { + virtual ~OutputHandler() {} + + /// Indicate the start of a new compressed image that's part of the final texture. + virtual void beginImage(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 bool writeData(const void * data, int size) = 0; + }; + + /// Error codes. + enum Error + { + Error_Unknown, + Error_InvalidInput, + Error_UnsupportedFeature, + Error_CudaError, + Error_FileOpen, + Error_FileWrite, + Error_UnsupportedOutputFormat, + }; + + /// Error handler. + struct ErrorHandler + { + virtual ~ErrorHandler() {} + + // Signal error. + virtual void error(Error e) = 0; + }; + + /// Container. + enum Container + { + Container_DDS, + Container_DDS10, + }; + + + /// Output Options. This class holds pointers to the interfaces that are used to report the output of + /// the compressor to the user. + struct OutputOptions + { + NVTT_FORBID_COPY(OutputOptions); + NVTT_DECLARE_PIMPL(OutputOptions); + + NVTT_API OutputOptions(); + NVTT_API ~OutputOptions(); + + // Set default options. + NVTT_API void reset(); + + NVTT_API void setFileName(const char * fileName); + + NVTT_API void setOutputHandler(OutputHandler * outputHandler); + NVTT_API void setErrorHandler(ErrorHandler * errorHandler); + + NVTT_API void setOutputHeader(bool outputHeader); + NVTT_API void setContainer(Container container); NVTT_API void setUserVersion(int version); - }; + }; - /// Context. - struct Compressor - { - NVTT_FORBID_COPY(Compressor); - NVTT_DECLARE_PIMPL(Compressor); + /// Context. + struct Compressor + { + NVTT_FORBID_COPY(Compressor); + NVTT_DECLARE_PIMPL(Compressor); - NVTT_API Compressor(); - NVTT_API ~Compressor(); + NVTT_API Compressor(); + NVTT_API ~Compressor(); - // Context settings. - NVTT_API void enableCudaAcceleration(bool enable); - NVTT_API bool isCudaAccelerationEnabled() const; + // Context settings. + NVTT_API void enableCudaAcceleration(bool enable); + NVTT_API bool isCudaAccelerationEnabled() const; - // InputOptions api. - NVTT_API bool process(const InputOptions & inputOptions, const CompressionOptions & compressionOptions, const OutputOptions & outputOptions) const; - NVTT_API int estimateSize(const InputOptions & inputOptions, const CompressionOptions & compressionOptions) const; + // InputOptions API. + NVTT_API bool process(const InputOptions & inputOptions, const CompressionOptions & compressionOptions, const OutputOptions & outputOptions) const; + NVTT_API int estimateSize(const InputOptions & inputOptions, const CompressionOptions & compressionOptions) const; - // RAW api. - NVTT_API bool compress2D(InputFormat format, int w, int h, void * data, const CompressionOptions & compressionOptions, const OutputOptions & outputOptions) const; - //ßNVTT_API bool compress3D(InputFormat format, int w, int h, int d, void * data, const CompressionOptions & compressionOptions, const OutputOptions & outputOptions) const; - NVTT_API int estimateSize(int w, int h, int d, const CompressionOptions & compressionOptions) const; + // TexImage API. + NVTT_API bool outputHeader(const TexImage & tex, int mipmapCount, const CompressionOptions & compressionOptions, const OutputOptions & outputOptions) const; + NVTT_API bool compress(const TexImage & tex, const CompressionOptions & compressionOptions, const OutputOptions & outputOptions) const; + NVTT_API int estimateSize(const TexImage & tex, int mipmapCount, const CompressionOptions & compressionOptions) const; - // TexImage api. - NVTT_API TexImage createTexImage() const; - NVTT_API bool outputHeader(const TexImage & tex, int mipmapCount, const CompressionOptions & compressionOptions, const OutputOptions & outputOptions) const; - NVTT_API bool compress(const TexImage & tex, const CompressionOptions & compressionOptions, const OutputOptions & outputOptions) const; - NVTT_API int estimateSize(const TexImage & tex, const CompressionOptions & compressionOptions) const; - }; + // Raw API. + NVTT_API bool compress(int w, int h, int d, const float * rgba, const CompressionOptions & compressionOptions, const OutputOptions & outputOptions) const; + NVTT_API int estimateSize(int w, int h, int d, int mipmapCount, const CompressionOptions & compressionOptions) const; + }; - // "Compressor" is deprecated. This should have been called "Context" - typedef Compressor Context; + // "Compressor" is deprecated. This should have been called "Context" + typedef Compressor Context; - - /// DXT decoder. - enum Decoder - { - Decoder_Reference, - Decoder_NV5x, - }; - /// A texture mipmap. - struct TexImage - { - NVTT_API TexImage(const TexImage & tex); - NVTT_API ~TexImage(); + /// DXT decoder. + enum Decoder + { + Decoder_Reference, + Decoder_NV5x, + }; - NVTT_API void operator=(const TexImage & tex); + /// A texture mipmap. + struct TexImage + { + NVTT_API TexImage(); + NVTT_API TexImage(const TexImage & tex); + NVTT_API ~TexImage(); - // Texture parameters. - NVTT_API void setTextureType(TextureType type); - NVTT_API void setWrapMode(WrapMode mode); - NVTT_API void setAlphaMode(AlphaMode alphaMode); - NVTT_API void setNormalMap(bool isNormalMap); + NVTT_API void operator=(const TexImage & tex); - // Accessors. - NVTT_API int width() const; - NVTT_API int height() const; - NVTT_API int depth() const; - NVTT_API int faceCount() const; - NVTT_API TextureType textureType() const; - NVTT_API WrapMode wrapMode() const; - NVTT_API AlphaMode alphaMode() const; - NVTT_API bool isNormalMap() const; - NVTT_API int countMipmaps() const; + // Texture parameters. + NVTT_API void setTextureType(TextureType type); + NVTT_API void setWrapMode(WrapMode mode); + NVTT_API void setAlphaMode(AlphaMode alphaMode); + NVTT_API void setNormalMap(bool isNormalMap); + + // Accessors. + NVTT_API int width() const; + NVTT_API int height() const; + NVTT_API int depth() const; + NVTT_API int faceCount() const; + NVTT_API TextureType textureType() const; + NVTT_API WrapMode wrapMode() const; + NVTT_API AlphaMode alphaMode() const; + NVTT_API bool isNormalMap() const; + NVTT_API int countMipmaps() const; NVTT_API float alphaTestCoverage(float alphaRef = 0.5) const; - // Texture data. - NVTT_API bool load(const char * fileName); - NVTT_API bool save(const char * fileName) const; - NVTT_API bool setImage2D(InputFormat format, int w, int h, int idx, const void * data); - NVTT_API bool setImage2D(InputFormat format, int w, int h, int idx, const void * r, const void * g, const void * b, const void * a); - NVTT_API bool setImage2D(Format format, Decoder decoder, int w, int h, int idx, const void * data); + // Texture data. + NVTT_API bool load(const char * fileName); + NVTT_API bool save(const char * fileName) const; + NVTT_API bool setImage2D(InputFormat format, int w, int h, int idx, const void * data); + NVTT_API bool setImage2D(InputFormat format, int w, int h, int idx, const void * r, const void * g, const void * b, const void * a); + NVTT_API bool setImage2D(Format format, Decoder decoder, int w, int h, int idx, const void * data); - // Resizing methods. - NVTT_API void resize(int w, int h, ResizeFilter filter); - NVTT_API void resize(int maxExtent, RoundMode mode, ResizeFilter filter); - NVTT_API bool buildNextMipmap(MipmapFilter filter); - - // Color transforms. - NVTT_API void toLinear(float gamma); - NVTT_API void toGamma(float gamma); - NVTT_API void transform(const float w0[4], const float w1[4], const float w2[4], const float w3[4], const float offset[4]); - NVTT_API void swizzle(int r, int g, int b, int a); - NVTT_API void scaleBias(int channel, float scale, float bias); + // Resizing methods. + NVTT_API void resize(int w, int h, ResizeFilter filter); + NVTT_API void resize(int w, int h, ResizeFilter filter, float filterWidth, const float * params = 0); + NVTT_API void resize(int maxExtent, RoundMode mode, ResizeFilter filter); + NVTT_API void resize(int maxExtent, RoundMode mode, ResizeFilter filter, float filterWidth, const float * params = 0); + NVTT_API bool buildNextMipmap(MipmapFilter filter); + NVTT_API bool buildNextMipmap(MipmapFilter filter, float filterWidth, const float * params = 0); + + // Color transforms. + NVTT_API void toLinear(float gamma); + NVTT_API void toGamma(float gamma); + NVTT_API void transform(const float w0[4], const float w1[4], const float w2[4], const float w3[4], const float offset[4]); + NVTT_API void swizzle(int r, int g, int b, int a); + NVTT_API void scaleBias(int channel, float scale, float bias); NVTT_API void clamp(int channel, float low = 0.0f, float high = 1.0f); - NVTT_API void packNormal(); - NVTT_API void expandNormal(); - NVTT_API void blend(float r, float g, float b, float a, float t); - NVTT_API void premultiplyAlpha(); - NVTT_API void toGreyScale(float redScale, float greenScale, float blueScale, float alphaScale); - NVTT_API void setBorder(float r, float g, float b, float a); - NVTT_API void fill(float r, float g, float b, float a); + NVTT_API void packNormal(); + NVTT_API void expandNormal(); + NVTT_API void blend(float r, float g, float b, float a, float t); + NVTT_API void premultiplyAlpha(); + NVTT_API void toGreyScale(float redScale, float greenScale, float blueScale, float alphaScale); + NVTT_API void setBorder(float r, float g, float b, float a); + NVTT_API void fill(float r, float g, float b, float a); NVTT_API void scaleAlphaToCoverage(float coverage, float alphaRef = 0.5f); NVTT_API bool normalizeRange(float * rangeMin, float * rangeMax); + NVTT_API void toRGBM(float range = 1.0f, float threshold = 0.0f); + NVTT_API void toYCoCg(); + NVTT_API void blockScaleCoCg(int bits = 5, float threshold = 0.0f); - // Set normal map options. - NVTT_API void toNormalMap(float sm, float medium, float big, float large); - //NVTT_API void toHeightMap(); - NVTT_API void normalizeNormalMap(); + // @@ Add quantization methods. - // Error compare. - NVTT_API float rootMeanSquaredError_rgb(const TexImage & reference) const; - NVTT_API float rootMeanSquaredError_alpha(const TexImage & reference) const; + // Set normal map options. + NVTT_API void toNormalMap(float sm, float medium, float big, float large); + NVTT_API void normalizeNormalMap(); + + // Error compare. + NVTT_API float rootMeanSquaredError_rgb(const TexImage & reference) const; + NVTT_API float rootMeanSquaredError_alpha(const TexImage & reference) const; // Geometric transforms. NVTT_API void flipVertically(); - // Copy image data. - NVTT_API bool copyChannel(const TexImage & srcImage, int srcChannel); - NVTT_API bool copyChannel(const TexImage & srcImage, int srcChannel, int dstChannel); + // Copy image data. + NVTT_API bool copyChannel(const TexImage & srcImage, int srcChannel); + NVTT_API bool copyChannel(const TexImage & srcImage, int srcChannel, int dstChannel); - private: - TexImage(); - void detach(); + private: + void detach(); + friend struct Compressor::Private; - friend struct Compressor; - struct Private; - Private * m; - }; + struct Private; + Private * m; + }; - // Return string for the given error code. - NVTT_API const char * errorString(Error e); + // Return string for the given error code. + NVTT_API const char * errorString(Error e); - // Return NVTT version. - NVTT_API unsigned int version(); + // Return NVTT version. + NVTT_API unsigned int version(); - // Set callbacks. - //NVTT_API void setErrorCallback(ErrorCallback callback); - //NVTT_API void setMemoryCallbacks(...); - } // nvtt namespace #endif // NVTT_H diff --git a/src/nvtt/nvtt_wrapper.cpp b/src/nvtt/nvtt_wrapper.cpp index c20f70c..08ca1fd 100644 --- a/src/nvtt/nvtt_wrapper.cpp +++ b/src/nvtt/nvtt_wrapper.cpp @@ -89,16 +89,6 @@ void nvttSetInputOptionsNormalizeMipmaps(NvttInputOptions * inputOptions, NvttBo inputOptions->setNormalizeMipmaps(b != NVTT_False); } -void nvttSetInputOptionsColorTransform(NvttInputOptions * inputOptions, NvttColorTransform t) -{ - inputOptions->setColorTransform((nvtt::ColorTransform)t); -} - -void nvttSetInputOptionsLinearTransfrom(NvttInputOptions * inputOptions, int channel, float w0, float w1, float w2, float w3) -{ - inputOptions->setLinearTransform(channel, w0, w1, w2, w3); -} - void nvttSetInputOptionsMaxExtents(NvttInputOptions * inputOptions, int dim) { inputOptions->setMaxExtents(dim); diff --git a/src/nvtt/nvtt_wrapper.h b/src/nvtt/nvtt_wrapper.h index 01ccc0d..b74ff94 100644 --- a/src/nvtt/nvtt_wrapper.h +++ b/src/nvtt/nvtt_wrapper.h @@ -123,13 +123,6 @@ typedef enum NVTT_MipmapFilter_Kaiser, } NvttMipmapFilter; -/// Color transformation. -typedef enum -{ - NVTT_ColorTransform_None, - NVTT_ColorTransform_Linear, -} NvttColorTransform; - /// Extents rounding mode. typedef enum { @@ -195,8 +188,6 @@ NVTT_API void nvttSetInputOptionsConvertToNormalMap(NvttInputOptions * inputOpti NVTT_API void nvttSetInputOptionsHeightEvaluation(NvttInputOptions * inputOptions, float redScale, float greenScale, float blueScale, float alphaScale); NVTT_API void nvttSetInputOptionsNormalFilter(NvttInputOptions * inputOptions, float sm, float medium, float big, float large); NVTT_API void nvttSetInputOptionsNormalizeMipmaps(NvttInputOptions * inputOptions, NvttBoolean b); -NVTT_API void nvttSetInputOptionsColorTransform(NvttInputOptions * inputOptions, NvttColorTransform t); -NVTT_API void nvttSetInputOptionsLinearTransform(NvttInputOptions * inputOptions, int channel, float w0, float w1, float w2, float w3); NVTT_API void nvttSetInputOptionsMaxExtents(NvttInputOptions * inputOptions, int dim); NVTT_API void nvttSetInputOptionsRoundMode(NvttInputOptions * inputOptions, NvttRoundMode mode); diff --git a/src/nvtt/tests/imperativeapi.cpp b/src/nvtt/tests/imperativeapi.cpp index 5e9589c..beb8204 100644 --- a/src/nvtt/tests/imperativeapi.cpp +++ b/src/nvtt/tests/imperativeapi.cpp @@ -38,7 +38,7 @@ int main(int argc, char *argv[]) context.enableCudaAcceleration(false); // Load input image. - nvtt::TexImage image = context.createTexImage(); + nvtt::TexImage image; if (!image.load(inputFileName)) { return EXIT_FAILURE; } diff --git a/src/nvtt/tests/process_alpha_map.cpp b/src/nvtt/tests/process_alpha_map.cpp index 87ccb3d..92d62ff 100644 --- a/src/nvtt/tests/process_alpha_map.cpp +++ b/src/nvtt/tests/process_alpha_map.cpp @@ -43,7 +43,7 @@ int main(int argc, char *argv[]) context.enableCudaAcceleration(false); // Load color map. - nvtt::TexImage colorMap = context.createTexImage(); + nvtt::TexImage colorMap; if (!colorMap.load(inputFileNameColor)) { printf("Image '%s' could not be loaded.\n", inputFileNameColor); return EXIT_FAILURE; @@ -63,9 +63,8 @@ int main(int argc, char *argv[]) colorOutputOptions.setFileName(outputFileNameColor.str()); // Load normal map. - nvtt::TexImage normalMap = context.createTexImage(); + nvtt::TexImage normalMap; if (inputFileNameNormal != NULL) { - normalMap = context.createTexImage(); if (!normalMap.load(inputFileNameColor)) { printf("Image '%s' could not be loaded.\n", inputFileNameNormal); return EXIT_FAILURE; diff --git a/src/nvtt/tests/testsuite.cpp b/src/nvtt/tests/testsuite.cpp index f74709a..2409458 100644 --- a/src/nvtt/tests/testsuite.cpp +++ b/src/nvtt/tests/testsuite.cpp @@ -37,6 +37,7 @@ #include // free #include // memcpy +#include "../tools/cmdline.h" using namespace nv; @@ -294,11 +295,15 @@ float rmsError(const Image * a, const Image * b) int main(int argc, char *argv[]) { - const uint version = nvtt::version(); - const uint major = version / 100; - const uint minor = version % 100; + MyAssertHandler assertHandler; + MyMessageHandler messageHandler; - printf("NVIDIA Texture Tools %u.%u - Copyright NVIDIA Corporation 2007 - 2008\n\n", major, minor); + const uint version = nvtt::version(); + const uint major = version / 100 / 100; + const uint minor = (version / 100) % 100; + const uint rev = version % 100; + + printf("NVIDIA Texture Tools %u.%u.%u - Copyright NVIDIA Corporation 2007\n\n", major, minor, rev); int set = 0; bool fast = false; diff --git a/src/nvtt/tools/cmdline.h b/src/nvtt/tools/cmdline.h index c9900ee..b2f7697 100644 --- a/src/nvtt/tools/cmdline.h +++ b/src/nvtt/tools/cmdline.h @@ -32,36 +32,36 @@ struct MyMessageHandler : public nv::MessageHandler { - MyMessageHandler() { - nv::debug::setMessageHandler( this ); - } - ~MyMessageHandler() { - nv::debug::resetMessageHandler(); - } + 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); - } + 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 assertion( 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); - } + MyAssertHandler() { + nv::debug::setAssertHandler( this ); + } + ~MyAssertHandler() { + nv::debug::resetAssertHandler(); + } + + // Handler method, note that func might be NULL! + virtual int assertion( 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); + } }; diff --git a/src/nvtt/tools/compress.cpp b/src/nvtt/tools/compress.cpp index f21afb8..9f4d003 100644 --- a/src/nvtt/tools/compress.cpp +++ b/src/nvtt/tools/compress.cpp @@ -412,10 +412,10 @@ int main(int argc, char *argv[]) inputOptions.setFormat(nvtt::InputFormat_RGBA_32F); inputOptions.setTextureLayout(nvtt::TextureType_2D, image->width(), image->height()); - for (uint i = 0; i < image->componentNum(); i++) + /*for (uint i = 0; i < image->componentNum(); i++) { inputOptions.setMipmapChannelData(image->channel(i), i, image->width(), image->height()); - } + }*/ } else { @@ -450,8 +450,11 @@ int main(int argc, char *argv[]) inputOptions.setAlphaMode(nvtt::AlphaMode_None); } - inputOptions.setRoundMode(nvtt::RoundMode_ToNearestPowerOfTwo); - + // Block compressed textures with mipmaps must be powers of two. + //if (!noMipmaps && format != nvtt::Format_RGB) + { + inputOptions.setRoundMode(nvtt::RoundMode_ToNearestPowerOfTwo); + } if (normal) { @@ -471,11 +474,11 @@ int main(int argc, char *argv[]) inputOptions.setMipmapGeneration(false); } - if (premultiplyAlpha) + /*if (premultiplyAlpha) { inputOptions.setPremultiplyAlpha(true); inputOptions.setAlphaMode(nvtt::AlphaMode_Premultiplied); - } + }*/ inputOptions.setMipmapFilter(mipmapFilter); diff --git a/src/nvtt/tools/resize.cpp b/src/nvtt/tools/resize.cpp index 6d74403..23390e9 100644 --- a/src/nvtt/tools/resize.cpp +++ b/src/nvtt/tools/resize.cpp @@ -169,14 +169,14 @@ int main(int argc, char *argv[]) nv::FloatImage fimage(&image); fimage.toLinear(0, 3, gamma); -#if 0 +#if 1 nv::AutoPtr fresult(fimage.resize(*filter, uint(image.width() * scale), uint(image.height() * scale), wrapMode)); nv::AutoPtr result(fresult->createImageGammaCorrect(gamma)); result->setFormat(nv::Image::Format_ARGB); - nv::StdOutputStream stream(output); - nv::ImageIO::save(output, stream, result.ptr()); + nv::StdOutputStream stream(output.str()); + nv::ImageIO::save(output.str(), stream, result.ptr()); #endif return 0; }