From 2903886498d9fd1176d5865ac249654db0982641 Mon Sep 17 00:00:00 2001 From: castano Date: Mon, 7 Jan 2008 07:28:00 +0000 Subject: [PATCH] Some progress with full DXT1a support. Move quantization settings to compression options. --- src/nvtt/CompressDXT.cpp | 31 +++++++ src/nvtt/CompressDXT.h | 1 + src/nvtt/CompressionOptions.cpp | 22 +++++ src/nvtt/CompressionOptions.h | 9 +- src/nvtt/InputOptions.cpp | 20 ----- src/nvtt/InputOptions.h | 6 -- src/nvtt/nvtt.cpp | 154 +++++++------------------------- src/nvtt/nvtt.h | 2 + 8 files changed, 96 insertions(+), 149 deletions(-) diff --git a/src/nvtt/CompressDXT.cpp b/src/nvtt/CompressDXT.cpp index 9956784..08178df 100644 --- a/src/nvtt/CompressDXT.cpp +++ b/src/nvtt/CompressDXT.cpp @@ -225,6 +225,37 @@ void nv::compressDXT1(const Image * image, const OutputOptions::Private & output } +void nv::compressDXT1a(const Image * image, const OutputOptions::Private & outputOptions, const CompressionOptions::Private & compressionOptions) +{ + const uint w = image->width(); + const uint h = image->height(); + + ColorBlock rgba; + BlockDXT1 block; + + doPrecomputation(); + + for (uint y = 0; y < h; y += 4) { + for (uint x = 0; x < w; x += 4) { + + rgba.init(image, x, y); + + // Compress color. + squish::WeightedClusterFit fit(&colours, squish::kDxt1); + squish::ClusterFit fit(&colours, squish::kDxt1); + fit.setMetric(compressionOptions.colorWeight.x(), compressionOptions.colorWeight.y(), compressionOptions.colorWeight.z()); + fit.Compress(&block); + + // @@ Use iterative cluster fit algorithm to improve error in highest quality mode. + + if (outputOptions.outputHandler != NULL) { + outputOptions.outputHandler->writeData(&block, sizeof(block)); + } + } + } +} + + void nv::compressDXT3(const Image * image, const OutputOptions::Private & outputOptions, const CompressionOptions::Private & compressionOptions) { const uint w = image->width(); diff --git a/src/nvtt/CompressDXT.h b/src/nvtt/CompressDXT.h index eee7324..c3f0ac9 100644 --- a/src/nvtt/CompressDXT.h +++ b/src/nvtt/CompressDXT.h @@ -45,6 +45,7 @@ namespace nv // Normal compressors. void compressDXT1(const Image * image, const nvtt::OutputOptions::Private & outputOptions, const nvtt::CompressionOptions::Private & compressionOptions); + void compressDXT1a(const Image * image, const nvtt::OutputOptions::Private & outputOptions, const nvtt::CompressionOptions::Private & compressionOptions); void compressDXT3(const Image * image, const nvtt::OutputOptions::Private & outputOptions, const nvtt::CompressionOptions::Private & compressionOptions); void compressDXT5(const Image * image, const nvtt::OutputOptions::Private & outputOptions, const nvtt::CompressionOptions::Private & compressionOptions); void compressDXT5n(const Image * image, const nvtt::OutputOptions::Private & outputOptions, const nvtt::CompressionOptions::Private & compressionOptions); diff --git a/src/nvtt/CompressionOptions.cpp b/src/nvtt/CompressionOptions.cpp index 5feafd9..be25c30 100644 --- a/src/nvtt/CompressionOptions.cpp +++ b/src/nvtt/CompressionOptions.cpp @@ -49,11 +49,17 @@ void CompressionOptions::reset() m.quality = Quality_Normal; m.colorWeight.set(1.0f, 1.0f, 1.0f); m.useCuda = true; + m.bitcount = 32; m.bmask = 0x000000FF; m.gmask = 0x0000FF00; m.rmask = 0x00FF0000; m.amask = 0xFF000000; + + m.enableColorDithering = false; + m.enableAlphaDithering = false; + m.binaryAlpha = false; + m.alphaThreshold = 127; } @@ -134,3 +140,19 @@ void CompressionOptions::setExternalCompressor(const char * name) m.externalCompressor = name; } +/// Set quantization options. +/// @warning Do not enable dithering unless you know what you are doing. Quantization +/// introduces errors. It's better to let the compressor quantize the result to +/// minimize the error, instead of quantizing the data before handling it to +/// the compressor. +void CompressionOptions::setQuantization(bool colorDithering, bool alphaDithering, bool binaryAlpha, int alphaThreshold/*= 127*/) +{ + nvCheck(alphaThreshold >= 0 && alphaThreshold < 256); + m.enableColorDithering = colorDithering; + m.enableAlphaDithering = alphaDithering; + m.binaryAlpha = binaryAlpha; + m.alphaThreshold = alphaThreshold; +} + + + diff --git a/src/nvtt/CompressionOptions.h b/src/nvtt/CompressionOptions.h index fe220da..c5f31b0 100644 --- a/src/nvtt/CompressionOptions.h +++ b/src/nvtt/CompressionOptions.h @@ -36,10 +36,11 @@ namespace nvtt Format format; Quality quality; - float errorThreshold; + float errorThreshold; // deprecated. nv::Vector3 colorWeight; + // Pixel format description. uint bitcount; uint rmask; uint gmask; @@ -49,6 +50,12 @@ namespace nvtt bool useCuda; nv::String externalCompressor; + + // Quantization. + bool enableColorDithering; + bool enableAlphaDithering; + bool binaryAlpha; + int alphaThreshold; // reference value used for binary alpha quantization. }; } // nvtt namespace diff --git a/src/nvtt/InputOptions.cpp b/src/nvtt/InputOptions.cpp index b6d05f6..26139ca 100644 --- a/src/nvtt/InputOptions.cpp +++ b/src/nvtt/InputOptions.cpp @@ -94,11 +94,6 @@ void InputOptions::reset() m.textureType = TextureType_2D; m.inputFormat = InputFormat_BGRA_8UB; - m.enableColorDithering = false; - m.enableAlphaDithering = false; - m.binaryAlpha = false; - m.alphaThreshold = 127; - m.alphaMode = AlphaMode_Transparency; m.inputGamma = 2.2f; @@ -262,21 +257,6 @@ void InputOptions::setKaiserParameters(float width, float alpha, float stretch) m.kaiserStretch = stretch; } -/// Set quantization options. -/// @warning Do not enable dithering unless you know what you are doing. Quantization -/// introduces errors. It's better to let the compressor quantize the result to -/// minimize the error, instead of quantizing the data before handling it to -/// the compressor. -void InputOptions::setQuantization(bool colorDithering, bool alphaDithering, bool binaryAlpha, int alphaThreshold/*= 127*/) -{ - nvCheck(alphaThreshold >= 0 && alphaThreshold < 256); - m.enableColorDithering = colorDithering; - m.enableAlphaDithering = alphaDithering; - m.binaryAlpha = binaryAlpha; - m.alphaThreshold = alphaThreshold; -} - - /// Indicate whether input is a normal map or not. void InputOptions::setNormalMap(bool b) { diff --git a/src/nvtt/InputOptions.h b/src/nvtt/InputOptions.h index b288300..2a60896 100644 --- a/src/nvtt/InputOptions.h +++ b/src/nvtt/InputOptions.h @@ -49,12 +49,6 @@ namespace nvtt struct Image; Image * images; - // Quantization. - bool enableColorDithering; - bool enableAlphaDithering; - bool binaryAlpha; - int alphaThreshold; // reference value used for binary alpha quantization. - // Gamma conversion. float inputGamma; float outputGamma; diff --git a/src/nvtt/nvtt.cpp b/src/nvtt/nvtt.cpp index 6a305d8..7c59f3c 100644 --- a/src/nvtt/nvtt.cpp +++ b/src/nvtt/nvtt.cpp @@ -216,8 +216,21 @@ static bool compressMipmap(const Image * image, const OutputOptions::Private & o } else if (compressionOptions.format == Format_DXT1a) { - // @@ Only fast compression mode for now. - fastCompressDXT1a(image, outputOptions); + if (compressionOptions.quality == Quality_Fastest) + { + fastCompressDXT1a(image, outputOptions); + } + else + { + if (compressionOptions.useCuda && nv::cuda::isHardwarePresent()) + { + /*cuda*/compressDXT1a(image, outputOptions); + } + else + { + compressDXT1a(image, outputOptions); + } + } } else if (compressionOptions.format == Format_DXT3) { @@ -351,37 +364,37 @@ static FloatImage * createMipmap(const FloatImage * floatImage, const InputOptio // Quantize the input image to the precision of the output format. -static void quantize(Image * img, const InputOptions::Private & inputOptions, Format format) +static void quantize(Image * img, const CompressionOptions::Private & compressionOptions) { - if (inputOptions.enableColorDithering) + if (compressionOptions.enableColorDithering) { - if (format >= Format_DXT1 && format <= Format_DXT5) + if (compressionOptions.format >= Format_DXT1 && compressionOptions.format <= Format_DXT5) { Quantize::FloydSteinberg_RGB16(img); } } - if (inputOptions.binaryAlpha) + if (compressionOptions.binaryAlpha) { - if (inputOptions.enableAlphaDithering) + if (compressionOptions.enableAlphaDithering) { - Quantize::FloydSteinberg_BinaryAlpha(img, inputOptions.alphaThreshold); + Quantize::FloydSteinberg_BinaryAlpha(img, compressionOptions.alphaThreshold); } else { - Quantize::BinaryAlpha(img, inputOptions.alphaThreshold); + Quantize::BinaryAlpha(img, compressionOptions.alphaThreshold); } } else { - if (inputOptions.enableAlphaDithering) + if (compressionOptions.enableAlphaDithering) { - if (format == Format_DXT3) + if (compressionOptions.format == Format_DXT3) { Quantize::Alpha4(img); } - else if (format == Format_DXT1a) + else if (compressionOptions.format == Format_DXT1a) { - Quantize::BinaryAlpha(img, inputOptions.alphaThreshold); + Quantize::BinaryAlpha(img, compressionOptions.alphaThreshold); } } } @@ -575,8 +588,11 @@ static bool compressMipmaps(uint f, const InputOptions::Private & inputOptions, } ImagePair pair; - - for (uint m = 0; m < inputOptions.mipmapCount; m++) + + const uint mipmapCount = inputOptions.realMipmapCount(); + nvDebugCheck(mipmapCount > 0); + + for (uint m = 0; m < mipmapCount; m++) { if (outputOptions.outputHandler) { @@ -594,7 +610,7 @@ static bool compressMipmaps(uint f, const InputOptions::Private & inputOptions, pair.toFixed(inputOptions); // @@ Quantization should be done in compressMipmap! @@ It should not modify the input image!!! - quantize(pair.fixedImage(), inputOptions, compressionOptions.format); + quantize(pair.fixedImage(), compressionOptions); compressMipmap(pair.fixedImage(), outputOptions, compressionOptions); @@ -609,10 +625,6 @@ static bool compressMipmaps(uint f, const InputOptions::Private & inputOptions, - - - - static bool compress(const InputOptions::Private & inputOptions, const OutputOptions::Private & outputOptions, const CompressionOptions::Private & compressionOptions) { // Make sure enums match. @@ -629,9 +641,6 @@ static bool compress(const InputOptions::Private & inputOptions, const OutputOpt inputOptions.computeTargetExtents(); - uint mipmapCount = inputOptions.realMipmapCount(); - nvDebugCheck(mipmapCount > 0); - // Output DDS header. outputHeader(inputOptions, outputOptions, compressionOptions); @@ -641,105 +650,6 @@ static bool compress(const InputOptions::Private & inputOptions, const OutputOpt { return false; } - - /* - Image * lastImage = NULL; - AutoPtr floatImage(NULL); - - uint w = inputOptions.targetWidth; - uint h = inputOptions.targetHeight; - uint d = inputOptions.targetDepth; - - for (uint m = 0; m < mipmapCount; m++) - { - if (outputOptions.outputHandler) - { - int size = computeImageSize(w, h, bitCount, format); - outputOptions.outputHandler->mipmap(size, w, h, d, f, m); - } - - // @@ Write a more sofisticated get input image, that: - // - looks for the nearest image in the input mipmap chain, resizes it to desired extents. - // - uses previous floating point image, if available. - // - uses previous byte image if available. - - - int idx = f * inputOptions.mipmapCount + m; - InputOptions::Private::Image & mipmap = inputOptions.images[idx]; - - // @@ Prescale not implemented yet. - nvCheck(w == mipmap.width); - nvCheck(h == mipmap.height); - nvCheck(d == mipmap.depth); - - Image * img = NULL; // Image to compress. - - if (mipmap.data != NULL) // Mipmap provided. - { - // Convert to normal map. - if (inputOptions.convertToNormalMap) - { - // Scale height factor by 1 / 2 ^ m - Vector4 heightScale = inputOptions.heightFactors / float(1 << m); - floatImage = createNormalMap(mipmap.data.ptr(), (FloatImage::WrapMode)inputOptions.wrapMode, heightScale, inputOptions.bumpFrequencyScale); - } - else - { - lastImage = img = mipmap.data.ptr(); - - // Delete float image. - floatImage = NULL; - } - } - else // Create mipmap from last. - { - if (m == 0) { - // First mipmap missing. - if (outputOptions.errorHandler != NULL) outputOptions.errorHandler->error(Error_InvalidInput); - return false; - } - - if (floatImage == NULL) - { - nvDebugCheck(lastImage != NULL); - floatImage = toFloatImage(lastImage, inputOptions); - } - - // Create mipmap. - floatImage = createMipmap(floatImage.ptr(), inputOptions); - } - - if (floatImage != NULL) - { - // Convert to fixed. - img = toFixedImage(floatImage.ptr(), inputOptions); - } - - // @@ Where to do the color transform? - // - Color transform may not be linear, so we cannot do before computing mipmaps. - // - Should be done in linear space, that is, after gamma correction. - - // @@ Error! gamma correction is not performed when mipmap data provided. (only if inputGamma != outputGamma) - - // @@ This code is too complicated, too prone to erros, and hard to understand. Must be simplified! - - - // @@ Quantization should be done in compressMipmap! - quantize(img, inputOptions, format); - - compressMipmap(img, outputOptions, compressionOptions); - - if (img != mipmap.data) - { - delete img; - } - - // Compute extents of next mipmap: - w = max(1U, w / 2); - h = max(1U, h / 2); - d = max(1U, d / 2); - } - */ } outputOptions.closeFile(); diff --git a/src/nvtt/nvtt.h b/src/nvtt/nvtt.h index 43ea341..1ec89df 100644 --- a/src/nvtt/nvtt.h +++ b/src/nvtt/nvtt.h @@ -100,6 +100,8 @@ namespace nvtt // 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 setQuantization(bool colorDithering, bool alphaDithering, bool binaryAlpha, int alphaThreshold/*= 127*/); + //private: struct Private; Private & m;