diff --git a/src/nvtt/CMakeLists.txt b/src/nvtt/CMakeLists.txt index de17b79..74514e2 100644 --- a/src/nvtt/CMakeLists.txt +++ b/src/nvtt/CMakeLists.txt @@ -15,13 +15,17 @@ SET(NVTT_SRCS FastCompressDXT.cpp QuickCompressDXT.h QuickCompressDXT.cpp + SingleColorLookup.h CompressionOptions.h CompressionOptions.cpp InputOptions.h InputOptions.cpp + OutputOptions.h OutputOptions.cpp cuda/CudaUtils.h cuda/CudaUtils.cpp + cuda/CudaMath.h + cuda/Bitmaps.h cuda/CudaCompressDXT.h cuda/CudaCompressDXT.cpp) @@ -45,23 +49,62 @@ ENDIF(NVTT_SHARED) TARGET_LINK_LIBRARIES(nvtt ${LIBS} nvcore nvmath nvimage squish) +INSTALL(TARGETS nvtt + RUNTIME DESTINATION bin + LIBRARY DESTINATION lib + ARCHIVE DESTINATION lib/static) + +INSTALL(FILES nvtt.h DESTINATION include/nvtt) + + # test executables -ADD_EXECUTABLE(nvcompress tools/compress.cpp) +ADD_EXECUTABLE(nvcompress tools/compress.cpp tools/cmdline.h) TARGET_LINK_LIBRARIES(nvcompress nvcore nvmath nvimage nvtt) -ADD_EXECUTABLE(nvdecompress tools/decompress.cpp) +ADD_EXECUTABLE(nvdecompress tools/decompress.cpp tools/cmdline.h) TARGET_LINK_LIBRARIES(nvdecompress nvcore nvmath nvimage) -ADD_EXECUTABLE(nvddsinfo tools/ddsinfo.cpp) +ADD_EXECUTABLE(nvddsinfo tools/ddsinfo.cpp tools/cmdline.h) TARGET_LINK_LIBRARIES(nvddsinfo nvcore nvmath nvimage) -ADD_EXECUTABLE(nvimgdiff tools/imgdiff.cpp) +ADD_EXECUTABLE(nvimgdiff tools/imgdiff.cpp tools/cmdline.h) TARGET_LINK_LIBRARIES(nvimgdiff nvcore nvmath nvimage) -ADD_EXECUTABLE(nvassemble tools/assemble.cpp) +ADD_EXECUTABLE(nvassemble tools/assemble.cpp tools/cmdline.h) TARGET_LINK_LIBRARIES(nvassemble nvcore nvmath nvimage) -INSTALL(TARGETS nvcompress nvdecompress nvddsinfo nvimgdiff nvassemble DESTINATION bin) +ADD_EXECUTABLE(filtertest tests/filtertest.cpp tools/cmdline.h) +TARGET_LINK_LIBRARIES(filtertest nvcore nvmath nvimage) + +ADD_EXECUTABLE(nvzoom tools/resize.cpp tools/cmdline.h) +TARGET_LINK_LIBRARIES(nvzoom nvcore nvmath nvimage) + +INSTALL(TARGETS nvcompress nvdecompress nvddsinfo nvimgdiff nvassemble nvzoom DESTINATION bin) + +# UI tools +IF(QT4_FOUND) + SET(QT_USE_QTOPENGL TRUE) + INCLUDE_DIRECTORIES(${QT_INCLUDE_DIR} ${CMAKE_CURRENT_BINARY_DIR}) + + SET(SRCS + tools/main.cpp + tools/configdialog.h + tools/configdialog.cpp) + + SET(LIBS + nvtt + ${QT_QTCORE_LIBRARY} + ${QT_QTGUI_LIBRARY} + ${QT_QTOPENGL_LIBRARY}) + + QT4_WRAP_UI(UICS tools/configdialog.ui) + QT4_WRAP_CPP(MOCS tools/configdialog.h) + #QT4_ADD_RESOURCES(RCCS tools/configdialog.rc) + + ADD_EXECUTABLE(nvcompressui MACOSX_BUNDLE ${SRCS} ${UICS} ${MOCS}) + TARGET_LINK_LIBRARIES(nvcompressui ${LIBS}) + +ENDIF(QT4_FOUND) diff --git a/src/nvtt/CompressDXT.cpp b/src/nvtt/CompressDXT.cpp index 365ee88..613373c 100644 --- a/src/nvtt/CompressDXT.cpp +++ b/src/nvtt/CompressDXT.cpp @@ -32,6 +32,7 @@ #include "FastCompressDXT.h" #include "QuickCompressDXT.h" #include "CompressionOptions.h" +#include "OutputOptions.h" // squish #include "squish/colourset.h" @@ -55,7 +56,7 @@ using namespace nv; using namespace nvtt; -void nv::fastCompressDXT1(const Image * image, const OutputOptions & outputOptions) +void nv::fastCompressDXT1(const Image * image, const OutputOptions::Private & outputOptions) { const uint w = image->width(); const uint h = image->height(); @@ -77,7 +78,7 @@ void nv::fastCompressDXT1(const Image * image, const OutputOptions & outputOptio } -void nv::fastCompressDXT1a(const Image * image, const OutputOptions & outputOptions) +void nv::fastCompressDXT1a(const Image * image, const OutputOptions::Private & outputOptions) { const uint w = image->width(); const uint h = image->height(); @@ -99,7 +100,7 @@ void nv::fastCompressDXT1a(const Image * image, const OutputOptions & outputOpti } -void nv::fastCompressDXT3(const Image * image, const nvtt::OutputOptions & outputOptions) +void nv::fastCompressDXT3(const Image * image, const nvtt::OutputOptions::Private & outputOptions) { const uint w = image->width(); const uint h = image->height(); @@ -120,7 +121,7 @@ void nv::fastCompressDXT3(const Image * image, const nvtt::OutputOptions & outpu } -void nv::fastCompressDXT5(const Image * image, const nvtt::OutputOptions & outputOptions) +void nv::fastCompressDXT5(const Image * image, const nvtt::OutputOptions::Private & outputOptions) { const uint w = image->width(); const uint h = image->height(); @@ -141,7 +142,7 @@ void nv::fastCompressDXT5(const Image * image, const nvtt::OutputOptions & outpu } -void nv::fastCompressDXT5n(const Image * image, const nvtt::OutputOptions & outputOptions) +void nv::fastCompressDXT5n(const Image * image, const nvtt::OutputOptions::Private & outputOptions) { const uint w = image->width(); const uint h = image->height(); @@ -166,14 +167,14 @@ void nv::fastCompressDXT5n(const Image * image, const nvtt::OutputOptions & outp } -void nv::fastCompressBC4(const Image * image, const nvtt::OutputOptions & outputOptions) +void nv::fastCompressBC4(const Image * image, const nvtt::OutputOptions::Private & outputOptions) { // @@ TODO // compress red channel (X) } -void nv::fastCompressBC5(const Image * image, const nvtt::OutputOptions & outputOptions) +void nv::fastCompressBC5(const Image * image, const nvtt::OutputOptions::Private & outputOptions) { // @@ TODO // compress red, green channels (X,Y) @@ -192,7 +193,7 @@ void nv::doPrecomputation() } -void nv::compressDXT1(const Image * image, const OutputOptions & outputOptions, const CompressionOptions::Private & compressionOptions) +void nv::compressDXT1(const Image * image, const OutputOptions::Private & outputOptions, const CompressionOptions::Private & compressionOptions) { const uint w = image->width(); const uint h = image->height(); @@ -225,7 +226,7 @@ void nv::compressDXT1(const Image * image, const OutputOptions & outputOptions, } -void nv::compressDXT3(const Image * image, const OutputOptions & outputOptions, const CompressionOptions::Private & compressionOptions) +void nv::compressDXT3(const Image * image, const OutputOptions::Private & outputOptions, const CompressionOptions::Private & compressionOptions) { const uint w = image->width(); const uint h = image->height(); @@ -254,7 +255,7 @@ void nv::compressDXT3(const Image * image, const OutputOptions & outputOptions, } } -void nv::compressDXT5(const Image * image, const OutputOptions & outputOptions, const CompressionOptions::Private & compressionOptions) +void nv::compressDXT5(const Image * image, const OutputOptions::Private & outputOptions, const CompressionOptions::Private & compressionOptions) { const uint w = image->width(); const uint h = image->height(); @@ -292,7 +293,7 @@ void nv::compressDXT5(const Image * image, const OutputOptions & outputOptions, } -void nv::compressDXT5n(const Image * image, const OutputOptions & outputOptions, const CompressionOptions::Private & compressionOptions) +void nv::compressDXT5n(const Image * image, const OutputOptions::Private & outputOptions, const CompressionOptions::Private & compressionOptions) { const uint w = image->width(); const uint h = image->height(); @@ -328,7 +329,7 @@ void nv::compressDXT5n(const Image * image, const OutputOptions & outputOptions, } -void nv::compressBC4(const Image * image, const nvtt::OutputOptions & outputOptions, const CompressionOptions::Private & compressionOptions) +void nv::compressBC4(const Image * image, const nvtt::OutputOptions::Private & outputOptions, const CompressionOptions::Private & compressionOptions) { const uint w = image->width(); const uint h = image->height(); @@ -380,7 +381,7 @@ void nv::compressBC4(const Image * image, const nvtt::OutputOptions & outputOpti } -void nv::compressBC5(const Image * image, const nvtt::OutputOptions & outputOptions, const CompressionOptions::Private & compressionOptions) +void nv::compressBC5(const Image * image, const nvtt::OutputOptions::Private & outputOptions, const CompressionOptions::Private & compressionOptions) { const uint w = image->width(); const uint h = image->height(); @@ -423,7 +424,7 @@ void nv::compressBC5(const Image * image, const nvtt::OutputOptions & outputOpti #if defined(HAVE_S3QUANT) -void nv::s3CompressDXT1(const Image * image, const nvtt::OutputOptions & outputOptions) +void nv::s3CompressDXT1(const Image * image, const nvtt::OutputOptions::Private & outputOptions) { const uint w = image->width(); const uint h = image->height(); @@ -518,7 +519,7 @@ void nv::s3CompressDXT1(const Image * image, const nvtt::OutputOptions & outputO #if defined(HAVE_ATITC) -void nv::atiCompressDXT1(const Image * image, const OutputOptions & outputOptions) +void nv::atiCompressDXT1(const Image * image, const OutputOptions::Private & outputOptions) { // Init source texture ATI_TC_Texture srcTexture; diff --git a/src/nvtt/CompressDXT.h b/src/nvtt/CompressDXT.h index 34bb74f..eee7324 100644 --- a/src/nvtt/CompressDXT.h +++ b/src/nvtt/CompressDXT.h @@ -35,29 +35,29 @@ namespace nv void doPrecomputation(); // Fast compressors. - void fastCompressDXT1(const Image * image, const nvtt::OutputOptions & outputOptions); - void fastCompressDXT1a(const Image * image, const nvtt::OutputOptions & outputOptions); - void fastCompressDXT3(const Image * image, const nvtt::OutputOptions & outputOptions); - void fastCompressDXT5(const Image * image, const nvtt::OutputOptions & outputOptions); - void fastCompressDXT5n(const Image * image, const nvtt::OutputOptions & outputOptions); - void fastCompressBC4(const Image * image, const nvtt::OutputOptions & outputOptions); - void fastCompressBC5(const Image * image, const nvtt::OutputOptions & outputOptions); + void fastCompressDXT1(const Image * image, const nvtt::OutputOptions::Private & outputOptions); + void fastCompressDXT1a(const Image * image, const nvtt::OutputOptions::Private & outputOptions); + void fastCompressDXT3(const Image * image, const nvtt::OutputOptions::Private & outputOptions); + void fastCompressDXT5(const Image * image, const nvtt::OutputOptions::Private & outputOptions); + void fastCompressDXT5n(const Image * image, const nvtt::OutputOptions::Private & outputOptions); + void fastCompressBC4(const Image * image, const nvtt::OutputOptions::Private & outputOptions); + void fastCompressBC5(const Image * image, const nvtt::OutputOptions::Private & outputOptions); // Normal compressors. - void compressDXT1(const Image * image, const nvtt::OutputOptions & outputOptions, const nvtt::CompressionOptions::Private & compressionOptions); - void compressDXT3(const Image * image, const nvtt::OutputOptions & outputOptions, const nvtt::CompressionOptions::Private & compressionOptions); - void compressDXT5(const Image * image, const nvtt::OutputOptions & outputOptions, const nvtt::CompressionOptions::Private & compressionOptions); - void compressDXT5n(const Image * image, const nvtt::OutputOptions & outputOptions, const nvtt::CompressionOptions::Private & compressionOptions); - void compressBC4(const Image * image, const nvtt::OutputOptions & outputOptions, const nvtt::CompressionOptions::Private & compressionOptions); - void compressBC5(const Image * image, const nvtt::OutputOptions & outputOptions, const nvtt::CompressionOptions::Private & compressionOptions); + void compressDXT1(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); + void compressBC4(const Image * image, const nvtt::OutputOptions::Private & outputOptions, const nvtt::CompressionOptions::Private & compressionOptions); + void compressBC5(const Image * image, const nvtt::OutputOptions::Private & outputOptions, const nvtt::CompressionOptions::Private & compressionOptions); // External compressors. #if defined(HAVE_S3QUANT) - void s3CompressDXT1(const Image * image, const nvtt::OutputOptions & outputOptions); + void s3CompressDXT1(const Image * image, const nvtt::OutputOptions::Private & outputOptions); #endif #if defined(HAVE_ATITC) - void atiCompressDXT1(const Image * image, const nvtt::OutputOptions & outputOptions); + void atiCompressDXT1(const Image * image, const nvtt::OutputOptions::Private & outputOptions); #endif } // nv namespace diff --git a/src/nvtt/CompressRGB.cpp b/src/nvtt/CompressRGB.cpp index 3ef7dad..33b41e5 100644 --- a/src/nvtt/CompressRGB.cpp +++ b/src/nvtt/CompressRGB.cpp @@ -29,7 +29,7 @@ #include "CompressRGB.h" #include "CompressionOptions.h" - +#include "OutputOptions.h" using namespace nv; using namespace nvtt; @@ -59,7 +59,7 @@ namespace // Pixel format converter. -void nv::compressRGB(const Image * image, const OutputOptions & outputOptions, const CompressionOptions::Private & compressionOptions) +void nv::compressRGB(const Image * image, const OutputOptions::Private & outputOptions, const CompressionOptions::Private & compressionOptions) { nvCheck(image != NULL); diff --git a/src/nvtt/CompressRGB.h b/src/nvtt/CompressRGB.h index 6a965d9..3bab47d 100644 --- a/src/nvtt/CompressRGB.h +++ b/src/nvtt/CompressRGB.h @@ -19,21 +19,21 @@ // HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, // WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR -// OTHER DEALINGS IN THE SOFTWARE. - -#ifndef NV_TT_COMPRESSRGB_H -#define NV_TT_COMPRESSRGB_H - -#include "nvtt.h" - -namespace nv -{ - class Image; - - // Pixel format converter. - void compressRGB(const Image * image, const nvtt::OutputOptions & outputOptions, const nvtt::CompressionOptions::Private & compressionOptions); - -} // nv namespace - - -#endif // NV_TT_COMPRESSDXT_H +// OTHER DEALINGS IN THE SOFTWARE. + +#ifndef NV_TT_COMPRESSRGB_H +#define NV_TT_COMPRESSRGB_H + +#include "nvtt.h" + +namespace nv +{ + class Image; + + // Pixel format converter. + void compressRGB(const Image * image, const nvtt::OutputOptions::Private & outputOptions, const nvtt::CompressionOptions::Private & compressionOptions); + +} // nv namespace + + +#endif // NV_TT_COMPRESSDXT_H diff --git a/src/nvtt/CompressionOptions.cpp b/src/nvtt/CompressionOptions.cpp index 8fb251c..5feafd9 100644 --- a/src/nvtt/CompressionOptions.cpp +++ b/src/nvtt/CompressionOptions.cpp @@ -87,12 +87,18 @@ void CompressionOptions::setColorWeights(float red, float green, float blue) } -/// Enable or disable hardware compression. +/// Enable or disable CUDA compression. void CompressionOptions::enableHardwareCompression(bool enable) { m.useCuda = enable; } +/// Enable or disable CUDA compression. +void CompressionOptions::enableCudaCompression(bool enable) +{ + m.useCuda = enable; +} + /// Set color mask to describe the RGB/RGBA format. void CompressionOptions::setPixelFormat(uint bitcount, uint rmask, uint gmask, uint bmask, uint amask) diff --git a/src/nvtt/InputOptions.cpp b/src/nvtt/InputOptions.cpp index 1da3206..b6d05f6 100644 --- a/src/nvtt/InputOptions.cpp +++ b/src/nvtt/InputOptions.cpp @@ -34,9 +34,9 @@ using namespace nvtt; namespace { - static int countMipmaps(int w, int h, int d) + static uint countMipmaps(int w, int h, int d) { - int mipmap = 0; + uint mipmap = 0; while (w != 1 || h != 1 || d != 1) { w = max(1, w / 2); @@ -48,6 +48,27 @@ namespace 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; + } + } + } // namespace @@ -69,7 +90,7 @@ InputOptions::~InputOptions() // Reset input options. void InputOptions::reset() { - m.wrapMode = WrapMode_Repeat; + m.wrapMode = WrapMode_Mirror; m.textureType = TextureType_2D; m.inputFormat = InputFormat_BGRA_8UB; @@ -78,26 +99,30 @@ void InputOptions::reset() m.binaryAlpha = false; m.alphaThreshold = 127; - m.alphaTransparency = true; + m.alphaMode = AlphaMode_Transparency; m.inputGamma = 2.2f; m.outputGamma = 2.2f; - m.colorTransform = ColorTransform_None; - m.linearTransform = Matrix(identity); + m.colorTransform = ColorTransform_None; + m.linearTransform = Matrix(identity); m.generateMipmaps = false; m.maxLevel = -1; m.mipmapFilter = MipmapFilter_Box; - m.kaiserWidth = 10; - m.kaiserAlpha = 8.0f; - m.kaiserStretch = 0.75f; + m.kaiserWidth = 3; + m.kaiserAlpha = 4.0f; + m.kaiserStretch = 1.0f; - m.normalizeMipmaps = false; + 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; } @@ -126,13 +151,13 @@ void InputOptions::setTextureLayout(TextureType type, int width, int height, int m.images = new Private::Image[m.imageCount]; - for(int f = 0; f < m.faceCount; f++) + for(uint f = 0; f < m.faceCount; f++) { - int w = width; - int h = height; - int d = depth; + uint w = width; + uint h = height; + uint d = depth; - for (int mipLevel = 0; mipLevel < m.mipmapCount; mipLevel++) + for (uint mipLevel = 0; mipLevel < m.mipmapCount; mipLevel++) { Private::Image & img = m.images[f * m.mipmapCount + mipLevel]; img.width = w; @@ -143,9 +168,9 @@ void InputOptions::setTextureLayout(TextureType type, int width, int height, int img.data = NULL; - w = max(1, w / 2); - h = max(1, h / 2); - d = max(1, d / 2); + w = max(1U, w / 2); + h = max(1U, h / 2); + d = max(1U, d / 2); } } } @@ -188,10 +213,21 @@ bool InputOptions::setMipmapData(const void * data, int width, int height, int d /// Describe the format of the input. -void InputOptions::setFormat(InputFormat format, bool alphaTransparency) +void InputOptions::setFormat(InputFormat format, /*deprecated*/bool alphaTransparency) +{ + m.inputFormat = format; + //m.alphaTransparency = alphaTransparency; +} +void InputOptions::setFormat(InputFormat format) { m.inputFormat = format; - m.alphaTransparency = alphaTransparency; +} + + +/// Set the way the input alpha channel is interpreted. +void InputOptions::setAlphaMode(AlphaMode alphaMode) +{ + m.alphaMode = alphaMode; } @@ -219,7 +255,7 @@ void InputOptions::setMipmapping(bool generateMipmaps, MipmapFilter filter/*= Mi } /// Set Kaiser filter parameters. -void InputOptions::setKaiserParameters(int width, float alpha, float stretch) +void InputOptions::setKaiserParameters(float width, float alpha, float stretch) { m.kaiserWidth = width; m.kaiserAlpha = alpha; @@ -233,6 +269,7 @@ void InputOptions::setKaiserParameters(int width, float alpha, float stretch) /// 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; @@ -243,7 +280,7 @@ void InputOptions::setQuantization(bool colorDithering, bool alphaDithering, boo /// Indicate whether input is a normal map or not. void InputOptions::setNormalMap(bool b) { - m.normalMap = b; + m.isNormalMap = b; } /// Enable normal map conversion. @@ -287,3 +324,103 @@ void InputOptions::setLinearTransfrom(int channel, float w0, float w1, float w2, Vector4 w(w0, w1, w2, w3); //m.linearTransform.setRow(channel, w); } + +void InputOptions::setMaxExtents(int e) +{ + nvDebugCheck(e > 0); + m.maxExtent = e; +} + +void InputOptions::setRoundMode(RoundMode mode) +{ + m.roundMode = mode; +} + + +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; +} + + +// Called everytime max extents or rounding mode changes. +int InputOptions::Private::firstMipmap(int face) const +{ + nvCheck(images != NULL); + + // @@ Find the last image that's not NULL and is greater than target extents. + + uint first = 0; + for (uint f = 0; f < mipmapCount; f++) + { + + } + + return first; +} + + + diff --git a/src/nvtt/InputOptions.h b/src/nvtt/InputOptions.h index e6eb2c7..b288300 100644 --- a/src/nvtt/InputOptions.h +++ b/src/nvtt/InputOptions.h @@ -36,54 +36,65 @@ namespace nvtt struct InputOptions::Private { Private() : images(NULL) {} - + WrapMode wrapMode; TextureType textureType; InputFormat inputFormat; + AlphaMode alphaMode; - int faceCount; - int mipmapCount; - int imageCount; + uint faceCount; + uint mipmapCount; + uint imageCount; struct Image; Image * images; - + // Quantization. bool enableColorDithering; bool enableAlphaDithering; bool binaryAlpha; int alphaThreshold; // reference value used for binary alpha quantization. - - bool alphaTransparency; // set to true if alpha is used for transparency. // Gamma conversion. float inputGamma; float outputGamma; - + // Color transform. ColorTransform colorTransform; nv::Matrix linearTransform; - + // Mipmap generation options. bool generateMipmaps; int maxLevel; MipmapFilter mipmapFilter; - - // Kaiser filter parameters. - uint kaiserWidth; - float kaiserAlpha; - float kaiserStretch; - + + // Kaiser filter parameters. + float kaiserWidth; + float kaiserAlpha; + float kaiserStretch; + // Normal map options. - bool normalMap; + bool isNormalMap; bool normalizeMipmaps; bool convertToNormalMap; - nv::Vector4 heightFactors; // Used for cone mapping too. + nv::Vector4 heightFactors; nv::Vector4 bumpFrequencyScale; - - // Cone map options. - bool convertToConeMap; - + + // Adjust extents. + uint maxExtent; + RoundMode roundMode; + + // @@ 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; + int firstMipmap(int face) const; + }; // Internal image structure. diff --git a/src/nvtt/OutputOptions.cpp b/src/nvtt/OutputOptions.cpp index 3592f9a..b847500 100644 --- a/src/nvtt/OutputOptions.cpp +++ b/src/nvtt/OutputOptions.cpp @@ -21,12 +21,105 @@ // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR // OTHER DEALINGS IN THE SOFTWARE. -#include "nvtt.h" +#include "OutputOptions.h" using namespace nvtt; + +OutputOptions::OutputOptions() : m(*new OutputOptions::Private()) +{ + reset(); +} + +OutputOptions::OutputOptions(OutputHandler * oh, ErrorHandler * eh) : m(*new OutputOptions::Private()) +{ + reset(); + outputHandler = oh; + errorHandler = eh; +} + +OutputOptions::~OutputOptions() +{ + delete &m; +} + /// Set default output options. void OutputOptions::reset() { - // endiannes = native... + m.fileName.reset(); + m.outputHandler = NULL; + m.errorHandler = NULL; + m.outputHeader = true; + + outputHandler = NULL; + errorHandler = NULL; + outputHeader = true; +} + + +/// Set output file name. +void OutputOptions::setFileName(const char * fileName) +{ + m.fileName = fileName; + outputHandler = NULL; } + +/// Set output handler. +void OutputOptions::setOutputHandler(OutputHandler * outputHandler) +{ + m.fileName.reset(); + this->outputHandler = outputHandler; +} + +/// Set error handler. +void OutputOptions::setErrorHandler(ErrorHandler * errorHandler) +{ + this->errorHandler = errorHandler; +} + +/// Set output header. +void OutputOptions::setOutputHeader(bool outputHeader) +{ + this->outputHeader = outputHeader; +} + + +bool OutputOptions::Private::openFile() const +{ + if (!fileName.isNull()) + { + nvCheck(outputHandler == NULL); + + DefaultOutputHandler * oh = new DefaultOutputHandler(fileName.str()); + if (oh->stream.isError()) + { + return false; + } + + outputHandler = oh; + } + + return true; +} + +void OutputOptions::Private::closeFile() const +{ + if (!fileName.isNull()) + { + delete outputHandler; + outputHandler = NULL; + } +} + + +void nvtt::initOptions(OutputOptions * outputOptions) +{ + nvDebugCheck(outputOptions != NULL); + + OutputOptions::Private & pimpl = outputOptions->m; + + pimpl.outputHandler = outputOptions->outputHandler; + pimpl.errorHandler = outputOptions->errorHandler; + pimpl.outputHeader = outputOptions->outputHeader; +} + diff --git a/src/nvtt/OutputOptions.h b/src/nvtt/OutputOptions.h new file mode 100644 index 0000000..47621cb --- /dev/null +++ b/src/nvtt/OutputOptions.h @@ -0,0 +1,76 @@ +// Copyright NVIDIA Corporation 2007 -- Ignacio Castano +// +// Permission is hereby granted, free of charge, to any person +// obtaining a copy of this software and associated documentation +// files (the "Software"), to deal in the Software without +// restriction, including without limitation the rights to use, +// copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the +// Software is furnished to do so, subject to the following +// conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES +// OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT +// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, +// WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR +// OTHER DEALINGS IN THE SOFTWARE. + +#ifndef NV_TT_OUTPUTOPTIONS_H +#define NV_TT_OUTPUTOPTIONS_H + +#include +#include +#include "nvtt.h" + +namespace nvtt +{ + + struct DefaultOutputHandler : public nvtt::OutputHandler + { + DefaultOutputHandler(const char * fileName) : stream(fileName) {} + + virtual ~DefaultOutputHandler() + { + } + + virtual void mipmap(int size, int width, int height, int depth, int face, int miplevel) + { + // ignore. + } + + // Output data. + virtual void writeData(const void * data, int size) + { + stream.serialize(const_cast(data), size); + } + + nv::StdOutputStream stream; + }; + + + struct OutputOptions::Private + { + nv::Path fileName; + + mutable OutputHandler * outputHandler; + mutable ErrorHandler * errorHandler; + mutable bool outputHeader; + + bool openFile() const; + void closeFile() const; + }; + + // @@ temporary hack to copy public attributes to pimpl. + void initOptions(OutputOptions * outputOptions); + + +} // nvtt namespace + + +#endif // NV_TT_OUTPUTOPTIONS_H diff --git a/src/nvtt/nvtt.cpp b/src/nvtt/nvtt.cpp index a476d78..56c14f9 100644 --- a/src/nvtt/nvtt.cpp +++ b/src/nvtt/nvtt.cpp @@ -38,6 +38,7 @@ #include "CompressRGB.h" #include "InputOptions.h" #include "CompressionOptions.h" +#include "OutputOptions.h" #include "cuda/CudaUtils.h" #include "cuda/CudaCompressDXT.h" @@ -96,24 +97,21 @@ namespace // compress // -static void outputHeader(const InputOptions::Private & inputOptions, const OutputOptions & outputOptions, const CompressionOptions::Private & compressionOptions) +static void outputHeader(const InputOptions::Private & inputOptions, const OutputOptions::Private & outputOptions, const CompressionOptions::Private & compressionOptions) { // Output DDS header. if (outputOptions.outputHandler != NULL && outputOptions.outputHeader) { DDSHeader header; - InputOptions::Private::Image * img = inputOptions.images; - nvCheck(img != NULL); + header.setWidth(inputOptions.targetWidth); + header.setHeight(inputOptions.targetHeight); - header.setWidth(img->width); - header.setHeight(img->height); + int mipmapCount = inputOptions.realMipmapCount(); + nvDebugCheck(mipmapCount > 0); + + header.setMipmapCount(mipmapCount - 1); - int mipmapCount = inputOptions.mipmapCount; - if (!inputOptions.generateMipmaps) mipmapCount = 0; - else if (inputOptions.maxLevel != -1 && inputOptions.maxLevel < mipmapCount) mipmapCount = inputOptions.maxLevel; - header.setMipmapCount(mipmapCount); - if (inputOptions.textureType == TextureType_2D) { header.setTexture2D(); } @@ -122,17 +120,17 @@ static void outputHeader(const InputOptions::Private & inputOptions, const Outpu } /*else if (inputOptions.textureType == TextureType_3D) { header.setTexture3D(); - header.setDepth(img->depth); + header.setDepth(inputOptions.targetDepth); }*/ if (compressionOptions.format == Format_RGBA) { - header.setPitch(4 * img->width); + header.setPitch(4 * inputOptions.targetWidth); header.setPixelFormat(compressionOptions.bitcount, compressionOptions.rmask, compressionOptions.gmask, compressionOptions.bmask, compressionOptions.amask); } else { - header.setLinearSize(computeImageSize(img->width, img->height, compressionOptions.bitcount, compressionOptions.format)); + header.setLinearSize(computeImageSize(inputOptions.targetWidth, inputOptions.targetHeight, compressionOptions.bitcount, compressionOptions.format)); if (compressionOptions.format == Format_DXT1 || compressionOptions.format == Format_DXT1a) { header.setFourCC('D', 'X', 'T', '1'); @@ -145,14 +143,14 @@ static void outputHeader(const InputOptions::Private & inputOptions, const Outpu } else if (compressionOptions.format == Format_DXT5n) { header.setFourCC('D', 'X', 'T', '5'); - header.setNormalFlag(true); + if (inputOptions.isNormalMap) header.setNormalFlag(true); } else if (compressionOptions.format == Format_BC4) { header.setFourCC('A', 'T', 'I', '1'); } else if (compressionOptions.format == Format_BC5) { header.setFourCC('A', 'T', 'I', '2'); - header.setNormalFlag(true); + if (inputOptions.isNormalMap) header.setNormalFlag(true); } } @@ -175,7 +173,7 @@ static void outputHeader(const InputOptions::Private & inputOptions, const Outpu } -static bool compressMipmap(const Image * image, const OutputOptions & outputOptions, const CompressionOptions::Private & compressionOptions) +static bool compressMipmap(const Image * image, const OutputOptions::Private & outputOptions, const CompressionOptions::Private & compressionOptions) { nvDebugCheck(image != NULL); @@ -196,7 +194,6 @@ static bool compressMipmap(const Image * image, const OutputOptions & outputOpti #if defined(HAVE_ATITC) if (compressionOptions.externalCompressor == "ati") { - printf("ATI\n"); atiCompressDXT1(image, outputOptions); } else @@ -289,7 +286,7 @@ static FloatImage * toFloatImage(const Image * image, const InputOptions::Privat FloatImage * floatImage = new FloatImage(image); - if (inputOptions.normalMap) + if (inputOptions.isNormalMap) { // Expand normals. to [-1, 1] range. // floatImage->expandNormals(0); @@ -309,7 +306,14 @@ static Image * toFixedImage(const FloatImage * floatImage, const InputOptions::P { nvDebugCheck(floatImage != NULL); - return floatImage->createImageGammaCorrect(inputOptions.outputGamma); + if (inputOptions.isNormalMap || inputOptions.outputGamma == 1.0f) + { + return floatImage->createImage(); + } + else + { + return floatImage->createImageGammaCorrect(inputOptions.outputGamma); + } } @@ -331,13 +335,13 @@ static FloatImage * createMipmap(const FloatImage * floatImage, const InputOptio else /*if (inputOptions.mipmapFilter == MipmapFilter_Kaiser)*/ { nvDebugCheck(inputOptions.mipmapFilter == MipmapFilter_Kaiser); - KaiserFilter filter(float(inputOptions.kaiserWidth)); + KaiserFilter filter(inputOptions.kaiserWidth); filter.setParameters(inputOptions.kaiserAlpha, inputOptions.kaiserStretch); result = floatImage->downSample(filter, (FloatImage::WrapMode)inputOptions.wrapMode); } // Normalize mipmap. - if (inputOptions.normalizeMipmaps) + if ((inputOptions.isNormalMap || inputOptions.convertToNormalMap) && inputOptions.normalizeMipmaps) { normalizeNormalMap(result); } @@ -383,50 +387,297 @@ static void quantize(Image * img, const InputOptions::Private & inputOptions, Fo } } +// Process the input, convert to normal map, normalize or convert to linear space. +static FloatImage * processInput(const InputOptions::Private & inputOptions, int idx) +{ + const InputOptions::Private::Image & mipmap = inputOptions.images[idx]; + + if (inputOptions.convertToNormalMap) + { + // Scale height factor by 1 / 2 ^ m // @@ Compute scale factor exactly... + Vector4 heightScale = inputOptions.heightFactors / float(1 << idx); + return createNormalMap(mipmap.data.ptr(), (FloatImage::WrapMode)inputOptions.wrapMode, heightScale, inputOptions.bumpFrequencyScale); + } + else if (inputOptions.isNormalMap) + { + if (inputOptions.normalizeMipmaps) + { + FloatImage * img = new FloatImage(mipmap.data.ptr()); + img->normalize(0); + return img; + } + } + else + { + if (inputOptions.inputGamma != inputOptions.outputGamma) + { + FloatImage * img = new FloatImage(mipmap.data.ptr()); + img->toLinear(0, 3, inputOptions.inputGamma); + return img; + } + } + + return NULL; +} -/// Compress the input texture with the given compression options. -bool nvtt::compress(const InputOptions & inputOptions, const OutputOptions & outputOptions, const CompressionOptions & compressionOptions) + + + +struct ImagePair +{ + ImagePair() : m_floatImage(NULL), m_fixedImage(NULL), m_deleteFixedImage(false) {} + ~ImagePair() + { + if (m_deleteFixedImage) { + delete m_fixedImage; + } + } + + void setFloatImage(FloatImage * image) + { + m_floatImage = image; + if (m_deleteFixedImage) delete m_fixedImage; + m_fixedImage = NULL; + } + + void setFixedImage(Image * image, bool deleteImage) + { + m_floatImage = NULL; + if (m_deleteFixedImage) delete m_fixedImage; + m_fixedImage = image; + m_deleteFixedImage = deleteImage; + } + + FloatImage * floatImage() const { return m_floatImage.ptr(); } + Image * fixedImage() const { return m_fixedImage; } + + void toFixed(const InputOptions::Private & inputOptions) + { + if (m_floatImage != NULL) + { + // Convert to fixed. + m_fixedImage = toFixedImage(m_floatImage.ptr(), inputOptions); + } + } + +private: + AutoPtr m_floatImage; + Image * m_fixedImage; + bool m_deleteFixedImage; +}; + + + + +// Find the first mipmap provided that is greater or equal to the target image size. +static int findMipmap(const InputOptions::Private & inputOptions, uint f, int firstMipmap, uint w, uint h, uint d) +{ + int bestIdx = -1; + + for (int m = firstMipmap; m < inputOptions.mipmapCount; m++) + { + int idx = f * inputOptions.mipmapCount + m; + const InputOptions::Private::Image & mipmap = inputOptions.images[idx]; + + if (mipmap.width >= w && mipmap.height >= h && mipmap.depth >= d) + { + if (mipmap.data != NULL) + { + bestIdx = idx; + } + } + else + { + // Do not look further down. + break; + } + } + + return bestIdx; +} + + + +static int findImage(const InputOptions::Private & inputOptions, uint f, uint w, uint h, uint d, int inputImageIdx, ImagePair * pair) +{ + nvDebugCheck(w > 0 && h > 0); + nvDebugCheck(inputImageIdx >= 0 && inputImageIdx < inputOptions.mipmapCount); + nvDebugCheck(pair != NULL); + + int bestIdx = findMipmap(inputOptions, f, inputImageIdx, w, h, d); + const InputOptions::Private::Image & mipmap = inputOptions.images[bestIdx]; + + if (mipmap.width == w && mipmap.height == h && mipmap.depth == d) + { + // Generate from input image. + AutoPtr processedImage( processInput(inputOptions, bestIdx) ); + + if (processedImage != NULL) + { + pair->setFloatImage(processedImage.release()); + } + else + { + pair->setFixedImage(mipmap.data.ptr(), false); + } + + return bestIdx; + } + else + { + if (pair->floatImage() == NULL && pair->fixedImage() == NULL) + { + // Generate from input image and resize. + AutoPtr processedImage( processInput(inputOptions, bestIdx) ); + + if (processedImage == NULL) + { + processedImage = new FloatImage(mipmap.data.ptr()); + } + + // Resize image. @@ Add more filters. @@ Distinguish between downscaling and reconstruction filters. + BoxFilter boxFilter; + pair->setFloatImage(processedImage->downSample(boxFilter, w, h, (FloatImage::WrapMode)inputOptions.wrapMode)); + } + else + { + // Generate from previous mipmap. + if (pair->floatImage() == NULL) + { + nvDebugCheck(pair->fixedImage() != NULL); + pair->setFloatImage(toFloatImage(pair->fixedImage(), inputOptions)); + } + + // Create mipmap. + pair->setFloatImage(createMipmap(pair->floatImage(), inputOptions)); + } + } +} + + +static bool compressMipmaps(uint f, const InputOptions::Private & inputOptions, const OutputOptions::Private & outputOptions, const CompressionOptions::Private & compressionOptions) +{ + uint w = inputOptions.targetWidth; + uint h = inputOptions.targetHeight; + uint d = inputOptions.targetDepth; + + int inputImageIdx = findMipmap(inputOptions, f, 0, w, h, d); + if (inputImageIdx == -1) + { + // First mipmap missing. + if (outputOptions.errorHandler != NULL) outputOptions.errorHandler->error(Error_InvalidInput); + return false; + } + + ImagePair pair; + + for (uint m = 0; m < inputOptions.mipmapCount; m++) + { + if (outputOptions.outputHandler) + { + int size = computeImageSize(w, h, compressionOptions.bitcount, compressionOptions.format); + outputOptions.outputHandler->mipmap(size, w, h, d, f, m); + } + + inputImageIdx = findImage(inputOptions, f, w, h, d, inputImageIdx, &pair); + + // @@ 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. + + + pair.toFixed(inputOptions); + + // @@ Quantization should be done in compressMipmap! @@ It should not modify the input image!!! + quantize(pair.fixedImage(), inputOptions, compressionOptions.format); + + compressMipmap(pair.fixedImage(), outputOptions, compressionOptions); + + // Compute extents of next mipmap: + w = max(1U, w / 2); + h = max(1U, h / 2); + d = max(1U, d / 2); + } + + return true; +} + + + + + + + +static bool compress(const InputOptions::Private & inputOptions, const OutputOptions::Private & outputOptions, const CompressionOptions::Private & compressionOptions) { // Make sure enums match. nvStaticCheck(FloatImage::WrapMode_Clamp == (FloatImage::WrapMode)WrapMode_Clamp); nvStaticCheck(FloatImage::WrapMode_Mirror == (FloatImage::WrapMode)WrapMode_Mirror); nvStaticCheck(FloatImage::WrapMode_Repeat == (FloatImage::WrapMode)WrapMode_Repeat); + // Get output handler. + if (!outputOptions.openFile()) + { + if (outputOptions.errorHandler) outputOptions.errorHandler->error(Error_FileOpen); + // @@ Should return here? + } + + inputOptions.computeTargetExtents(); + + uint mipmapCount = inputOptions.realMipmapCount(); + nvDebugCheck(mipmapCount > 0); + // Output DDS header. - outputHeader(inputOptions.m, outputOptions, compressionOptions.m); + outputHeader(inputOptions, outputOptions, compressionOptions); - Format format = compressionOptions.m.format; - const uint bitCount = compressionOptions.m.bitcount; - - for (int f = 0; f < inputOptions.m.faceCount; f++) + for (uint f = 0; f < inputOptions.faceCount; f++) { + if (!compressMipmaps(f, inputOptions, outputOptions, compressionOptions)) + { + return false; + } + + /* Image * lastImage = NULL; AutoPtr floatImage(NULL); - for (int m = 0; m < inputOptions.m.mipmapCount; m++) + uint w = inputOptions.targetWidth; + uint h = inputOptions.targetHeight; + uint d = inputOptions.targetDepth; + + for (uint m = 0; m < mipmapCount; m++) { - int idx = f * inputOptions.m.mipmapCount + m; - InputOptions::Private::Image & mipmap = inputOptions.m.images[idx]; - if (outputOptions.outputHandler) { - int size = computeImageSize(mipmap.width, mipmap.height, bitCount, format); - outputOptions.outputHandler->mipmap(size, mipmap.width, mipmap.height, mipmap.depth, mipmap.face, mipmap.mipLevel); + int size = computeImageSize(w, h, bitCount, format); + outputOptions.outputHandler->mipmap(size, w, h, d, f, m); } - Image * img; // Image to compress. + // @@ 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.m.convertToNormalMap) + if (inputOptions.convertToNormalMap) { - floatImage = createNormalMap(mipmap.data.ptr(), (FloatImage::WrapMode)inputOptions.m.wrapMode, inputOptions.m.heightFactors, inputOptions.m.bumpFrequencyScale); + // 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 if (inputOptions.m.convertToConeMap) - { - floatImage = createConeMap(mipmap.data, inputOptions.m.heightFactors); - }*/ else { lastImage = img = mipmap.data.ptr(); @@ -446,70 +697,88 @@ bool nvtt::compress(const InputOptions & inputOptions, const OutputOptions & out if (floatImage == NULL) { nvDebugCheck(lastImage != NULL); - floatImage = toFloatImage(lastImage, inputOptions.m); + floatImage = toFloatImage(lastImage, inputOptions); } // Create mipmap. - floatImage = createMipmap(floatImage.ptr(), inputOptions.m); + floatImage = createMipmap(floatImage.ptr(), inputOptions); } if (floatImage != NULL) { // Convert to fixed. - img = toFixedImage(floatImage.ptr(), inputOptions.m); + 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 provied. + // @@ 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! - - quantize(img, inputOptions.m, format); - compressMipmap(img, outputOptions, compressionOptions.m); + + // @@ Quantization should be done in compressMipmap! + quantize(img, inputOptions, format); + + compressMipmap(img, outputOptions, compressionOptions); if (img != mipmap.data) { delete img; } - if (!inputOptions.m.generateMipmaps || (inputOptions.m.maxLevel >= 0 && m >= inputOptions.m.maxLevel)) { - // continue with next face. - break; - } + // Compute extents of next mipmap: + w = max(1U, w / 2); + h = max(1U, h / 2); + d = max(1U, d / 2); } + */ } + outputOptions.closeFile(); + return true; } +/// Compress the input texture with the given compression options. +bool nvtt::compress(const InputOptions & inputOptions, const OutputOptions & outputOptions, const CompressionOptions & compressionOptions) +{ + // @@ Hack this is necessary because of the pimpl transition. + initOptions(const_cast(&outputOptions)); + + return ::compress(inputOptions.m, outputOptions.m, compressionOptions.m); +} /// Estimate the size of compressing the input with the given options. int nvtt::estimateSize(const InputOptions & inputOptions, const CompressionOptions & compressionOptions) { - Format format = compressionOptions.m.format; + const Format format = compressionOptions.m.format; const uint bitCount = compressionOptions.m.bitcount; + inputOptions.m.computeTargetExtents(); + + uint mipmapCount = inputOptions.m.realMipmapCount(); + int size = 0; - for (int f = 0; f < inputOptions.m.faceCount; f++) + for (uint f = 0; f < inputOptions.m.faceCount; f++) { - for (int m = 0; m < inputOptions.m.mipmapCount; m++) + uint w = inputOptions.m.targetWidth; + uint h = inputOptions.m.targetHeight; + uint d = inputOptions.m.targetDepth; + + for (uint m = 0; m < mipmapCount; m++) { - int idx = f * inputOptions.m.mipmapCount + m; - const InputOptions::Private::Image & img = inputOptions.m.images[idx]; - - size += computeImageSize(img.width, img.height, bitCount, format); + size += computeImageSize(w, h, bitCount, format); - if (!inputOptions.m.generateMipmaps || (inputOptions.m.maxLevel >= 0 && m >= inputOptions.m.maxLevel)) { - // continue with next face. - break; - } + // Compute extents of next mipmap: + w = max(1U, w / 2); + h = max(1U, h / 2); + d = max(1U, d / 2); } } @@ -530,9 +799,15 @@ const char * nvtt::errorString(Error e) return "Unsupported feature"; case Error_CudaError: return "CUDA error"; + case Error_FileOpen: + return "Error opening file"; + case Error_FileWrite: + return "Error writing through output handler"; case Error_Unknown: - default: + //default: return "Unknown error"; } + + return "Invalid error"; } diff --git a/src/nvtt/nvtt.h b/src/nvtt/nvtt.h index e4e67b8..eb9f5c0 100644 --- a/src/nvtt/nvtt.h +++ b/src/nvtt/nvtt.h @@ -40,6 +40,9 @@ #define NVTT_CLASS #endif +#define NVTT_DEPRECATED NVTT_API NV_DEPRECATED + + // Public interface. namespace nvtt { @@ -49,7 +52,7 @@ namespace nvtt // No compression. Format_RGB, Format_RGBA = Format_RGB, - + // DX9 formats. Format_DXT1, Format_DXT1a, // DXT1 with binary alpha. @@ -65,9 +68,6 @@ namespace nvtt Format_BC3n = Format_DXT5n, Format_BC4, // ATI1 Format_BC5, // 3DC, ATI2 - - // OpenGL formats. - Format_LATC = Format_BC5, }; /// Quality modes. @@ -91,7 +91,9 @@ namespace nvtt NVTT_API void setFormat(Format format); NVTT_API void setQuality(Quality quality, float errorThreshold = 0.5f); NVTT_API void setColorWeights(float red, float green, float blue); - NVTT_API void enableHardwareCompression(bool enable); + + NVTT_DEPRECATED void enableHardwareCompression(bool enable); + NVTT_API void enableCudaCompression(bool enable); NVTT_API void setExternalCompressor(const char * name); @@ -136,12 +138,28 @@ namespace nvtt MipmapFilter_Kaiser, ///< Kaiser-windowed Sinc filter is the best downsampling filter. }; + /// Color transformation. enum ColorTransform { ColorTransform_None, ColorTransform_Linear, - ColorTransform_CoYCg, - ColorTransform_CoSCgY, + }; + + /// Extents rounding mode. + enum RoundMode + { + RoundMode_None, + RoundMode_ToNextPowerOfTwo, + RoundMode_ToNearestPowerOfTwo, + RoundMode_ToPreviousPowerOfTwo, + }; + + /// Alpha mode. + enum AlphaMode + { + AlphaMode_None, + AlphaMode_Transparency, + AlphaMode_Premultiplied, }; /// Input options. Specify format and layout of the input texture. @@ -156,37 +174,45 @@ namespace nvtt // Setup input layout. NVTT_API void setTextureLayout(TextureType type, int w, int h, int d = 1); NVTT_API void resetTextureLayout(); - + // Set mipmap data. Copies the data. NVTT_API bool setMipmapData(const void * data, int w, int h, int d = 1, int face = 0, int mipmap = 0); - + // Describe the format of the input. - NVTT_API void setFormat(InputFormat fmt, bool alphaTransparency); - + NVTT_DEPRECATED void setFormat(InputFormat format, bool alphaTransparency); + NVTT_API void setFormat(InputFormat format); + + // Set the way the input alpha channel is interpreted. + NVTT_API void setAlphaMode(AlphaMode alphaMode); + // Set gamma settings. NVTT_API void setGamma(float inputGamma, float outputGamma); - + // Set texture wrappign mode. NVTT_API void setWrapMode(WrapMode mode); - + // Set mipmapping options. NVTT_API void setMipmapping(bool generateMipmaps, MipmapFilter filter = MipmapFilter_Box, int maxLevel = -1); - NVTT_API void setKaiserParameters(int width, float alpha, float stretch); + NVTT_API void setKaiserParameters(float width, float alpha, float stretch); // Set quantization options. - NVTT_API void setQuantization(bool colorDithering, bool alphaDithering, bool binaryAlpha, int alphaThreshold = 127); - + NVTT_DEPRECATED void setQuantization(bool colorDithering, bool alphaDithering, bool binaryAlpha, int alphaThreshold = 127); + // 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 small, float medium, float big, float large); NVTT_API void setNormalizeMipmaps(bool b); - + // Set color transforms. NVTT_API void setColorTransform(ColorTransform t); NVTT_API void setLinearTransfrom(int channel, float w0, float w1, float w2, float w3); - + + // Set resizing options. + NVTT_API void setMaxExtents(int d); + NVTT_API void setRoundMode(RoundMode mode); + //private: struct Private; Private & m; @@ -213,6 +239,8 @@ namespace nvtt Error_UnsupportedFeature, Error_CudaError, Error_Unknown, + Error_FileOpen, + Error_FileWrite, }; /// Error handler. @@ -229,15 +257,26 @@ namespace nvtt /// the compressor to the user. struct OutputOptions { - OutputOptions() : outputHandler(NULL), outputHeader(true) { reset(); } - OutputOptions(OutputHandler * oh, ErrorHandler * eh) : outputHandler(oh), errorHandler(eh), outputHeader(true) { reset(); } + NVTT_API OutputOptions(); + NVTT_DEPRECATED OutputOptions(OutputHandler * oh, ErrorHandler * eh); + NVTT_API ~OutputOptions(); // Set default options. NVTT_API void reset(); - OutputHandler * outputHandler; - ErrorHandler * errorHandler; - bool outputHeader; + 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_DEPRECATED OutputHandler * outputHandler; + NVTT_DEPRECATED ErrorHandler * errorHandler; + NVTT_DEPRECATED bool outputHeader; + + //private: + struct Private; + Private & m; };