diff --git a/src/nvcore/DefsGnucWin32.h b/src/nvcore/DefsGnucWin32.h index 2f8e3cc..11a3e75 100644 --- a/src/nvcore/DefsGnucWin32.h +++ b/src/nvcore/DefsGnucWin32.h @@ -2,6 +2,8 @@ #error "Do not include this file directly." #endif +#include // size_t, NULL + // Function linkage #define DLL_IMPORT __declspec(dllimport) #define DLL_EXPORT __declspec(dllexport) diff --git a/src/nvcore/StrLib.cpp b/src/nvcore/StrLib.cpp index 605c924..4b77fe0 100644 --- a/src/nvcore/StrLib.cpp +++ b/src/nvcore/StrLib.cpp @@ -542,7 +542,7 @@ const char * Path::extension(const char * str) l = length = (int)strlen( str ); while (length > 0 && str[length] != '.') { length--; - if (str[length] != '\\' || str[length] != '/') { + if (str[length] == '\\' || str[length] == '/') { return &str[l]; // no extension } } diff --git a/src/nvcore/nvcore.h b/src/nvcore/nvcore.h index 7317667..08a2d4f 100644 --- a/src/nvcore/nvcore.h +++ b/src/nvcore/nvcore.h @@ -154,9 +154,6 @@ /// Null index. @@ Move this somewhere else... This could have collisions with other definitions! #define NIL uint(~0) -// @@ Move this to DefsGnuc? -#include // size_t, NULL - /// Null pointer. #ifndef NULL #define NULL 0 diff --git a/src/nvimage/ColorBlock.cpp b/src/nvimage/ColorBlock.cpp index 6981ed4..ff79817 100644 --- a/src/nvimage/ColorBlock.cpp +++ b/src/nvimage/ColorBlock.cpp @@ -56,34 +56,10 @@ ColorBlock::ColorBlock(const Image * img, uint x, uint y) void ColorBlock::init(const Image * img, uint x, uint y) { - nvDebugCheck(img != NULL); - - const uint bw = min(img->width() - x, 4U); - const uint bh = min(img->height() - y, 4U); - nvDebugCheck(bw != 0 && bh != 0); - - static const int remainder[] = { - 0, 0, 0, 0, - 0, 1, 0, 1, - 0, 1, 2, 0, - 0, 1, 2, 3, - }; - - // Blocks that are smaller than 4x4 are handled by repeating the pixels. - // @@ Thats only correct when block size is 1, 2 or 4, but not with 3. :( - - for(uint i = 0; i < 4; i++) { - //const int by = i % bh; - const int by = remainder[(bh - 1) * 4 + i]; - for(uint e = 0; e < 4; e++) { - //const int bx = e % bw; - const int bx = remainder[(bw - 1) * 4 + e]; - color(e, i) = img->pixel(x + bx, y + by); - } - } + init(img->width(), img->height(), (const uint *)img->pixels(), x, y); } -void ColorBlock::init(uint w, uint h, uint * data, uint x, uint y) +void ColorBlock::init(uint w, uint h, const uint * data, uint x, uint y) { nvDebugCheck(data != NULL); @@ -93,6 +69,7 @@ void ColorBlock::init(uint w, uint h, uint * data, uint x, uint y) // Blocks that are smaller than 4x4 are handled by repeating the pixels. // @@ Thats only correct when block size is 1, 2 or 4, but not with 3. :( + // @@ Ideally we should zero the weights of the pixels out of range. for (uint i = 0; i < 4; i++) { @@ -108,7 +85,7 @@ void ColorBlock::init(uint w, uint h, uint * data, uint x, uint y) } } -void ColorBlock::init(uint w, uint h, float * data, uint x, uint y) +void ColorBlock::init(uint w, uint h, const float * data, uint x, uint y) { nvDebugCheck(data != NULL); @@ -118,6 +95,9 @@ void ColorBlock::init(uint w, uint h, float * data, uint x, uint y) // Blocks that are smaller than 4x4 are handled by repeating the pixels. // @@ Thats only correct when block size is 1, 2 or 4, but not with 3. :( + // @@ Ideally we should zero the weights of the pixels out of range. + + uint srcPlane = w * h; for (uint i = 0; i < 4; i++) { @@ -126,13 +106,13 @@ void ColorBlock::init(uint w, uint h, float * data, uint x, uint y) for (uint e = 0; e < 4; e++) { const uint bx = e % bw; - const uint idx = ((y + by) * w + x + bx) * 4; + const uint idx = ((y + by) * w + x + bx); Color32 & c = color(e, i); - c.r = uint8(255 * clamp(data[idx + 0], 0.0f, 1.0f)); - c.g = uint8(255 * clamp(data[idx + 1], 0.0f, 1.0f)); - c.b = uint8(255 * clamp(data[idx + 2], 0.0f, 1.0f)); - c.a = uint8(255 * clamp(data[idx + 3], 0.0f, 1.0f)); + c.r = uint8(255 * clamp(data[idx + 0 * srcPlane], 0.0f, 1.0f)); // @@ Is this the right way to quantize floats to bytes? + c.g = uint8(255 * clamp(data[idx + 1 * srcPlane], 0.0f, 1.0f)); + c.b = uint8(255 * clamp(data[idx + 2 * srcPlane], 0.0f, 1.0f)); + c.a = uint8(255 * clamp(data[idx + 3 * srcPlane], 0.0f, 1.0f)); } } } diff --git a/src/nvimage/ColorBlock.h b/src/nvimage/ColorBlock.h index b0b43ac..d2cfb35 100644 --- a/src/nvimage/ColorBlock.h +++ b/src/nvimage/ColorBlock.h @@ -19,8 +19,8 @@ namespace nv ColorBlock(const Image * img, uint x, uint y); void init(const Image * img, uint x, uint y); - void init(uint w, uint h, uint * data, uint x, uint y); - void init(uint w, uint h, float * data, uint x, uint y); + void init(uint w, uint h, const uint * data, uint x, uint y); + void init(uint w, uint h, const float * data, uint x, uint y); void swizzle(uint x, uint y, uint z, uint w); // 0=r, 1=g, 2=b, 3=a, 4=0xFF, 5=0 diff --git a/src/nvimage/FloatImage.cpp b/src/nvimage/FloatImage.cpp index ff79b5f..1811058 100644 --- a/src/nvimage/FloatImage.cpp +++ b/src/nvimage/FloatImage.cpp @@ -206,10 +206,16 @@ void FloatImage::scaleBias(uint base_component, uint num, float scale, float bia } /// Clamp the elements of the image. -void FloatImage::clamp(float low, float high) +void FloatImage::clamp(uint base_component, uint num, float low, float high) { - for(uint i = 0; i < m_count; i++) { - m_mem[i] = nv::clamp(m_mem[i], low, high); + const uint size = m_width * m_height; + + for(uint c = 0; c < num; c++) { + float * ptr = this->channel(base_component + c); + + for(uint i = 0; i < size; i++) { + ptr[i] = nv::clamp(ptr[i], low, high); + } } } @@ -697,23 +703,24 @@ FloatImage * FloatImage::resize(const Filter & filter, uint w, uint h, WrapMode Array tmp_column(h); tmp_column.resize(h); - for (uint c = 0; c < m_componentNum; c++) + for (uint i = 0; i < m_componentNum; i++) { + // Process alpha channel first. + uint c; + if (i == 0) c = alpha; + else if (i > alpha) c = i; + else c = i - 1; + float * tmp_channel = tmp_image->channel(c); for (uint y = 0; y < m_height; y++) { - this->applyKernelHorizontal(xkernel, y, c, alpha, wm, tmp_channel + y * w); + this->applyKernelHorizontal(xkernel, y, c, wm, tmp_channel + y * w); } - } - // Process all channels before applying vertical kernel to make sure alpha has been computed. - - for (uint c = 0; c < m_componentNum; c++) - { float * dst_channel = dst_image->channel(c); for (uint x = 0; x < w; x++) { - tmp_image->applyKernelVertical(ykernel, x, c, alpha, wm, tmp_column.mutableBuffer()); + tmp_image->applyKernelVertical(ykernel, x, c, wm, tmp_column.mutableBuffer()); for (uint y = 0; y < h; y++) { dst_channel[y * w + x] = tmp_column[y]; @@ -938,69 +945,72 @@ void FloatImage::applyKernelHorizontal(const PolyphaseKernel & k, int y, uint c, } } -// Vertical flip in place. -void FloatImage::flip() -{ - const uint w = m_width; - const uint h = m_height; - const uint h2 = h / 2; - - for (uint c = 0; c < m_componentNum; c++) { - for (uint y = 0; y < h2; y++) { - float * src = scanline(y, c); - float * dst = scanline(h - 1 - y, c); - for (uint x = 0; x < w; x++) { - swap(src[x], dst[x]); - } - } - } -} - - -float FloatImage::alphaTestCoverage(float alphaRef, int alphaChannel) const -{ - const uint w = m_width; - const uint h = m_height; - - float coverage = 0.0f; - - for (uint y = 0; y < h; y++) { - const float * alpha = scanline(y, alphaChannel); - for (uint x = 0; x < w; x++) { - if (alpha[x] > alphaRef) coverage += 1.0f; // @@ gt or lt? - } - } - - return coverage / float(w * h); -} - -void FloatImage::scaleAlphaToCoverage(float desiredCoverage, float alphaRef, int alphaChannel) -{ - float minAlphaRef = 0.0f; - float maxAlphaRef = 1.0f; - float midAlphaRef = 0.5f; - - // Determine desired scale using a binary search. Hardcoded to 8 steps max. - for (int i = 0; i < 8; i++) { - float currentCoverage = alphaTestCoverage(midAlphaRef, alphaChannel); - - if (currentCoverage > desiredCoverage) { - maxAlphaRef = midAlphaRef; - } - else if (currentCoverage < desiredCoverage) { - minAlphaRef = midAlphaRef; - } - else { - break; - } - - midAlphaRef = (minAlphaRef + maxAlphaRef) * 0.5f; - } - - float alphaScale = alphaRef / midAlphaRef; - - // Scale alpha channel. - scaleBias(alphaChannel, 1, alphaScale, 0.0f); +// Vertical flip in place. +void FloatImage::flip() +{ + const uint w = m_width; + const uint h = m_height; + const uint h2 = h / 2; + + for (uint c = 0; c < m_componentNum; c++) { + for (uint y = 0; y < h2; y++) { + float * src = scanline(y, c); + float * dst = scanline(h - 1 - y, c); + for (uint x = 0; x < w; x++) { + swap(src[x], dst[x]); + } + } + } +} + + +float FloatImage::alphaTestCoverage(float alphaRef, int alphaChannel) const +{ + const uint w = m_width; + const uint h = m_height; + + float coverage = 0.0f; + + for (uint y = 0; y < h; y++) { + const float * alpha = scanline(y, alphaChannel); + for (uint x = 0; x < w; x++) { + if (alpha[x] > alphaRef) coverage += 1.0f; // @@ gt or lt? + } + } + + return coverage / float(w * h); +} + +void FloatImage::scaleAlphaToCoverage(float desiredCoverage, float alphaRef, int alphaChannel) +{ + float minAlphaRef = 0.0f; + float maxAlphaRef = 1.0f; + float midAlphaRef = 0.5f; + + // Determine desired scale using a binary search. Hardcoded to 8 steps max. + for (int i = 0; i < 10; i++) { + float currentCoverage = alphaTestCoverage(midAlphaRef, alphaChannel); + + if (currentCoverage > desiredCoverage) { + minAlphaRef = midAlphaRef; + } + else if (currentCoverage < desiredCoverage) { + maxAlphaRef = midAlphaRef; + } + else { + break; + } + + midAlphaRef = (minAlphaRef + maxAlphaRef) * 0.5f; + } + + float alphaScale = alphaRef / midAlphaRef; + + // Scale alpha channel. + scaleBias(alphaChannel, 1, alphaScale, 0.0f); + clamp(alphaChannel, 1, 0.0f, 1.0f); + + //float newCoverage = alphaTestCoverage(alphaRef, alphaChannel); } FloatImage* FloatImage::clone() const diff --git a/src/nvimage/FloatImage.h b/src/nvimage/FloatImage.h index efd85bd..1eaef62 100644 --- a/src/nvimage/FloatImage.h +++ b/src/nvimage/FloatImage.h @@ -60,8 +60,7 @@ namespace nv NVIMAGE_API void expandNormals(uint base_component); NVIMAGE_API void scaleBias(uint base_component, uint num, float scale, float add); - //NVIMAGE_API void clamp(uint base_component, uint num); - NVIMAGE_API void clamp(float low, float high); + NVIMAGE_API void clamp(uint base_component, uint num, float low, float high); NVIMAGE_API void toLinear(uint base_component, uint num, float gamma = 2.2f); NVIMAGE_API void toGamma(uint base_component, uint num, float gamma = 2.2f); diff --git a/src/nvimage/ImageIO.cpp b/src/nvimage/ImageIO.cpp index 28cdf0a..1c4e6b3 100644 --- a/src/nvimage/ImageIO.cpp +++ b/src/nvimage/ImageIO.cpp @@ -203,10 +203,15 @@ FloatImage * nv::ImageIO::loadFloat(const char * fileName, Stream & s) const char * extension = Path::extension(fileName); + FloatImage * floatImage = NULL; + + const uint spos = s.tell(); // Save stream position. + + // Try to load as a floating point image. #if defined(HAVE_FREEIMAGE) FREE_IMAGE_FORMAT fif = FreeImage_GetFIFFromFilename(fileName); if (fif != FIF_UNKNOWN && FreeImage_FIFSupportsReading(fif)) { - return loadFloatFreeImage(fif, s); + floatImage = loadFloatFreeImage(fif, s); } #else // defined(HAVE_FREEIMAGE) #pragma message(NV_FILE_LINE "TODO: Load TIFF and EXR files from stream.") @@ -222,7 +227,17 @@ FloatImage * nv::ImageIO::loadFloat(const char * fileName, Stream & s) #endif #endif // defined(HAVE_FREEIMAGE) - return NULL; + // Try to load as an RGBA8 image and convert to float. + if (floatImage == NULL) { + s.seek(spos); // Restore stream position. + + AutoPtr img = load(fileName, s); + if (img != NULL) { + floatImage = new FloatImage(img.ptr()); + } + } + + return floatImage; } bool nv::ImageIO::saveFloat(const char * fileName, Stream & s, const FloatImage * fimage, uint baseComponent, uint componentCount) @@ -357,16 +372,7 @@ Image * nv::ImageIO::loadFreeImage(FREE_IMAGE_FORMAT fif, Stream & s) const int w = FreeImage_GetWidth(bitmap); const int h = FreeImage_GetHeight(bitmap); - if (FreeImage_GetImageType(bitmap) == FIT_BITMAP) - { - if (FreeImage_GetBPP(bitmap) != 32) - { - FIBITMAP * tmp = FreeImage_ConvertTo32Bits(bitmap); - FreeImage_Unload(bitmap); - bitmap = tmp; - } - } - else + if (FreeImage_GetImageType(bitmap) != FIT_BITMAP) { // @@ Use tone mapping? FIBITMAP * tmp = FreeImage_ConvertToType(bitmap, FIT_BITMAP, true); @@ -374,6 +380,14 @@ Image * nv::ImageIO::loadFreeImage(FREE_IMAGE_FORMAT fif, Stream & s) bitmap = tmp; } + nvDebugCheck(FreeImage_GetImageType(bitmap) == FIT_BITMAP); + if (FreeImage_GetBPP(bitmap) != 32) + { + FIBITMAP * tmp = FreeImage_ConvertTo32Bits(bitmap); + FreeImage_Unload(bitmap); + bitmap = tmp; + } + Image * image = new Image(); image->allocate(w, h); diff --git a/src/nvtt/CompressorDXT.cpp b/src/nvtt/CompressorDXT.cpp index b8d1ecf..02bd374 100644 --- a/src/nvtt/CompressorDXT.cpp +++ b/src/nvtt/CompressorDXT.cpp @@ -107,11 +107,11 @@ void FixedBlockCompressor::compress(nvtt::InputFormat inputFormat, nvtt::AlphaMo ColorBlock rgba; if (inputFormat == nvtt::InputFormat_BGRA_8UB) { - rgba.init(w, h, (uint *)data, x, y); + rgba.init(w, h, (const uint *)data, x, y); } else { nvDebugCheck(inputFormat == nvtt::InputFormat_RGBA_32F); - rgba.init(w, h, (float *)data, x, y); + rgba.init(w, h, (const float *)data, x, y); } compressBlock(rgba, alphaMode, compressionOptions, mem); diff --git a/src/nvtt/CompressorRGBE.cpp b/src/nvtt/CompressorRGBE.cpp index bd1ef02..8f8d212 100644 --- a/src/nvtt/CompressorRGBE.cpp +++ b/src/nvtt/CompressorRGBE.cpp @@ -25,12 +25,12 @@ #include "CompressionOptions.h" #include "OutputOptions.h" -#include -#include +#include "nvimage/Image.h" +#include "nvimage/FloatImage.h" -#include +#include "nvmath/Color.h" -#include +#include "nvcore/Debug.h" using namespace nv; using namespace nvtt; @@ -63,7 +63,7 @@ void CompressorRGBE::compress(nvtt::InputFormat inputFormat, nvtt::AlphaMode alp uint srcPlane = w * h; // Allocate output scanline. - Color32 * dst = (Color32 *)mem::malloc(w); + Color32 * dst = new Color32[w]; for (uint y = 0; y < h; y++) { @@ -83,8 +83,6 @@ void CompressorRGBE::compress(nvtt::InputFormat inputFormat, nvtt::AlphaMode alp else { nvDebugCheck (inputFormat == nvtt::InputFormat_RGBA_32F); -#pragma message(NV_FILE_LINE "TODO: Interleave color components") - // Color components not interleaved. r = fsrc[x + 0 * srcPlane]; g = fsrc[x + 1 * srcPlane]; @@ -100,5 +98,5 @@ void CompressorRGBE::compress(nvtt::InputFormat inputFormat, nvtt::AlphaMode alp } } - mem::free(dst); + delete [] dst; } diff --git a/src/nvtt/Context.cpp b/src/nvtt/Context.cpp index 879791a..705cecd 100644 --- a/src/nvtt/Context.cpp +++ b/src/nvtt/Context.cpp @@ -337,8 +337,6 @@ bool Compressor::outputHeader(const TexImage & tex, int mipmapCount, const Compr bool Compressor::compress(const TexImage & tex, const CompressionOptions & compressionOptions, const OutputOptions & outputOptions) const { - // @@ Decide whether to change the swizzling of FloatImage. - 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)) { @@ -1493,7 +1491,7 @@ CompressorInterface * Compressor::Private::chooseGpuCompressor(const Compression bool Compressor::Private::compress2D(InputFormat inputFormat, AlphaMode alphaMode, int w, int h, const void * data, const CompressionOptions::Private & compressionOptions, const OutputOptions::Private & outputOptions) const { // Decide what compressor to use. - CompressorInterface * compressor = NULL; + AutoPtr compressor; #if defined HAVE_CUDA if (cudaEnabled && w * h >= 512) { @@ -1512,8 +1510,6 @@ bool Compressor::Private::compress2D(InputFormat inputFormat, AlphaMode alphaMod else { compressor->compress(inputFormat, alphaMode, w, h, data, compressionOptions, outputOptions); - - delete compressor; } return true; diff --git a/src/nvtt/TexImage.cpp b/src/nvtt/TexImage.cpp index 2d88c5b..e860f80 100644 --- a/src/nvtt/TexImage.cpp +++ b/src/nvtt/TexImage.cpp @@ -23,15 +23,15 @@ #include "TexImage.h" -#include -#include -#include +#include "nvmath/Vector.h" +#include "nvmath/Matrix.h" +#include "nvmath/Color.h" -#include -#include -#include -#include -#include +#include "nvimage/Filter.h" +#include "nvimage/ImageIO.h" +#include "nvimage/NormalMap.h" +#include "nvimage/BlockDXT.h" +#include "nvimage/ColorBlock.h" #include @@ -128,6 +128,7 @@ void TexImage::detach() { if (m->refCount() > 1) { + m->release(); m = new TexImage::Private(*m); m->addRef(); nvDebugCheck(m->refCount() == 1); @@ -281,6 +282,8 @@ bool TexImage::load(const char * fileName) detach(); +#pragma message(NV_FILE_LINE "TODO: Make sure that floating point image has 4 channels.") + m->imageArray.resize(1); m->imageArray[0] = img.release(); @@ -674,19 +677,21 @@ bool TexImage::buildNextMipmap(MipmapFilter filter) foreach (i, m->imageArray) { - if (m->imageArray[i] == NULL) continue; + FloatImage * img = m->imageArray[i]; + + if (img == NULL) continue; if (m->alphaMode == AlphaMode_Transparency) { if (filter == MipmapFilter_Box) { BoxFilter filter; - m->imageArray[i]->downSample(filter, wrapMode, 3); + img = img->downSample(filter, wrapMode, 3); } else if (filter == MipmapFilter_Triangle) { TriangleFilter filter; - m->imageArray[i]->downSample(filter, wrapMode, 3); + img = img->downSample(filter, wrapMode, 3); } else if (filter == MipmapFilter_Kaiser) { @@ -694,19 +699,19 @@ bool TexImage::buildNextMipmap(MipmapFilter filter) //KaiserFilter filter(inputOptions.kaiserWidth); //filter.setParameters(inputOptions.kaiserAlpha, inputOptions.kaiserStretch); KaiserFilter filter(3); - m->imageArray[i]->downSample(filter, wrapMode, 3); + img = img->downSample(filter, wrapMode, 3); } } else { if (filter == MipmapFilter_Box) { - m->imageArray[i]->fastDownSample(); + img = img->fastDownSample(); } else if (filter == MipmapFilter_Triangle) { TriangleFilter filter; - m->imageArray[i]->downSample(filter, wrapMode); + img = img->downSample(filter, wrapMode); } else //if (filter == MipmapFilter_Kaiser) { @@ -714,9 +719,12 @@ bool TexImage::buildNextMipmap(MipmapFilter filter) //KaiserFilter filter(inputOptions.kaiserWidth); //filter.setParameters(inputOptions.kaiserAlpha, inputOptions.kaiserStretch); KaiserFilter filter(3); - m->imageArray[i]->downSample(filter, wrapMode); + img = img->downSample(filter, wrapMode); } } + + delete m->imageArray[i]; + m->imageArray[i] = img; } return true; diff --git a/src/nvtt/TexImage.h b/src/nvtt/TexImage.h index 9a34f24..4821b96 100644 --- a/src/nvtt/TexImage.h +++ b/src/nvtt/TexImage.h @@ -56,7 +56,10 @@ namespace nvtt alphaMode = p.alphaMode; isNormalMap = p.isNormalMap; - imageArray = p.imageArray; + imageArray.reserve(p.imageArray.count()); + foreach(i, p.imageArray) { + imageArray.append(p.imageArray[i]->clone()); + } } ~Private() { diff --git a/src/nvtt/nvtt.h b/src/nvtt/nvtt.h index 25189ff..921f906 100644 --- a/src/nvtt/nvtt.h +++ b/src/nvtt/nvtt.h @@ -48,7 +48,7 @@ # define NVTT_API #endif -#define NVTT_VERSION 201 +#define NVTT_VERSION 020100 #define NVTT_FORBID_COPY(Class) \ private: \ diff --git a/src/nvtt/nvtt_wrapper.h b/src/nvtt/nvtt_wrapper.h index d7c94f7..63c9b5a 100644 --- a/src/nvtt/nvtt_wrapper.h +++ b/src/nvtt/nvtt_wrapper.h @@ -47,7 +47,7 @@ # define NVTT_API #endif -#define NVTT_VERSION 201 +#define NVTT_VERSION 020100 #ifdef __cplusplus typedef struct nvtt::InputOptions NvttInputOptions; diff --git a/src/nvtt/tests/imperativeapi.cpp b/src/nvtt/tests/imperativeapi.cpp index 35b39b1..07a7551 100644 --- a/src/nvtt/tests/imperativeapi.cpp +++ b/src/nvtt/tests/imperativeapi.cpp @@ -21,6 +21,7 @@ // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR // OTHER DEALINGS IN THE SOFTWARE. +#include #include #include // EXIT_SUCCESS, EXIT_FAILURE @@ -30,30 +31,54 @@ int main(int argc, char *argv[]) { if (argc != 2) return EXIT_FAILURE; - nvtt::CompressionOptions compressionOptions; - compressionOptions.setFormat(nvtt::Format_BC1); - - nvtt::OutputOptions outputOptions; - outputOptions.setFileName("output.dds"); + const char * inputFileName = argv[1]; + // Init context. nvtt::Context context; + context.enableCudaAcceleration(false); + + // Load input image. nvtt::TexImage image = context.createTexImage(); + if (!image.load(inputFileName)) { + return EXIT_FAILURE; + } - image.load(argv[1]); + // Setup compression options. + nvtt::CompressionOptions compressionOptions; + compressionOptions.setFormat(nvtt::Format_BC3); + //compressionOptions.setFormat(nvtt::Format_RGBA); - context.outputHeader(image, image.countMipmaps(), compressionOptions, outputOptions); + // Setup output options. + nvtt::OutputOptions outputOptions; + + nv::Path outputFileName(inputFileName); + outputFileName.stripExtension(); + outputFileName.append(".dds"); + + outputOptions.setFileName(outputFileName); + + // Output compressed image. + context.outputHeader(image, image.countMipmaps(), compressionOptions, outputOptions); + + image.flipVertically(); + image.setAlphaMode(nvtt::AlphaMode_Transparency); + + // Output first mipmap. + context.compress(image, compressionOptions, outputOptions); float gamma = 2.2f; image.toLinear(gamma); - float coverage = image.alphaTestCoverage(); + float alphaRef = 0.95; + float coverage = image.alphaTestCoverage(alphaRef); - while (image.buildNextMipmap(nvtt::MipmapFilter_Box)) + // Build mimaps. + while (image.buildNextMipmap(nvtt::MipmapFilter_Kaiser)) { nvtt::TexImage tmpImage = image; tmpImage.toGamma(gamma); - tmpImage.scaleAlphaToCoverage(coverage); + tmpImage.scaleAlphaToCoverage(coverage, alphaRef); context.compress(tmpImage, compressionOptions, outputOptions); }