// Copyright (c) 2009-2011 Ignacio Castano // Copyright (c) 2007-2009 NVIDIA Corporation -- 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. #include "CompressionOptions.h" #include "nvimage/DirectDrawSurface.h" #include "nvmath/Vector.inl" using namespace nv; using namespace nvtt; /// Constructor. Sets compression options to the default values. CompressionOptions::CompressionOptions() : m(*new CompressionOptions::Private()) { reset(); } /// Destructor. CompressionOptions::~CompressionOptions() { delete &m; } /// Set default compression options. void CompressionOptions::reset() { m.format = Format_DXT1; m.quality = Quality_Normal; m.colorWeight.set(1.0f, 1.0f, 1.0f, 1.0f); m.rgbmThreshold = 0.15f; m.bitcount = 32; m.bmask = 0x000000FF; m.gmask = 0x0000FF00; m.rmask = 0x00FF0000; m.amask = 0xFF000000; m.rsize = 8; m.gsize = 8; m.bsize = 8; m.asize = 8; m.pixelType = PixelType_UnsignedNorm; m.pitchAlignment = 1; m.enableColorDithering = false; m.enableAlphaDithering = false; m.binaryAlpha = false; m.alphaThreshold = 127; m.decoder = Decoder_D3D10; } /// Set desired compression format. void CompressionOptions::setFormat(Format format) { m.format = format; } /// Set compression quality settings. void CompressionOptions::setQuality(Quality quality) { m.quality = quality; } /// Set the weights of each color channel. /// The choice for these values is subjective. In most cases uniform color weights /// (1.0, 1.0, 1.0) work very well. A popular choice is to use the NTSC luma encoding /// weights (0.2126, 0.7152, 0.0722), but I think that blue contributes to our /// perception more than a 7%. A better choice in my opinion is (3, 4, 2). void CompressionOptions::setColorWeights(float red, float green, float blue, float alpha/*=1.0f*/) { // float total = red + green + blue; // float x = red / total; // float y = green / total; // m.colorWeight.set(x, y, 1.0f - x - y); m.colorWeight.set(red, green, blue, alpha); } void CompressionOptions::setRGBMThreshold(float min_m) { m.rgbmThreshold = min_m; } /// Set color mask to describe the RGB/RGBA format. void CompressionOptions::setPixelFormat(uint bitCount, uint rmask, uint gmask, uint bmask, uint amask) { // Validate arguments. nvCheck(bitCount <= 32); nvCheck((rmask & gmask) == 0); nvCheck((rmask & bmask) == 0); nvCheck((rmask & amask) == 0); nvCheck((gmask & bmask) == 0); nvCheck((gmask & amask) == 0); nvCheck((bmask & amask) == 0); if (bitCount != 32) { uint maxMask = (1 << bitCount); nvCheck(maxMask > rmask); nvCheck(maxMask > gmask); nvCheck(maxMask > bmask); nvCheck(maxMask > amask); } m.bitcount = bitCount; m.rmask = rmask; m.gmask = gmask; m.bmask = bmask; m.amask = amask; m.rsize = 0; m.gsize = 0; m.bsize = 0; m.asize = 0; } void CompressionOptions::setPixelFormat(uint8 rsize, uint8 gsize, uint8 bsize, uint8 asize) { nvCheck(rsize <= 32 && gsize <= 32 && bsize <= 32 && asize <= 32); m.bitcount = 0; m.rmask = 0; m.gmask = 0; m.bmask = 0; m.amask = 0; m.rsize = rsize; m.gsize = gsize; m.bsize = bsize; m.asize = asize; } /// Set pixel type. void CompressionOptions::setPixelType(PixelType pixelType) { m.pixelType = pixelType; } /// Set pitch alignment in bytes. void CompressionOptions::setPitchAlignment(int pitchAlignment) { nvDebugCheck(pitchAlignment > 0 && isPowerOfTwo(U32(pitchAlignment))); m.pitchAlignment = pitchAlignment; } /// Use external compressor. 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; } /// Set target decoder to optimize for. void CompressionOptions::setTargetDecoder(Decoder decoder) { m.decoder = decoder; } Format CompressionOptions::format() const { return m.format; } // Translate to and from D3D formats. unsigned int CompressionOptions::d3d9Format() const { if (m.format == Format_RGB) { if (m.pixelType == PixelType_UnsignedNorm) { uint bitcount = m.bitcount; uint rmask = m.rmask; uint gmask = m.gmask; uint bmask = m.bmask; uint amask = m.amask; if (bitcount == 0) { bitcount = m.rsize + m.gsize + m.bsize + m.asize; rmask = ((1 << m.rsize) - 1) << (m.asize + m.bsize + m.gsize); gmask = ((1 << m.gsize) - 1) << (m.asize + m.bsize); bmask = ((1 << m.bsize) - 1) << m.asize; amask = ((1 << m.asize) - 1) << 0; } if (bitcount <= 32) { return nv::findD3D9Format(bitcount, rmask, gmask, bmask, amask); } else { //if (m.rsize == 16 && m.gsize == 16 && m.bsize == 0 && m.asize == 0) return D3DFMT_G16R16; if (m.rsize == 16 && m.gsize == 16 && m.bsize == 16 && m.asize == 16) return D3DFMT_A16B16G16R16; } } else if (m.pixelType == PixelType_Float) { if (m.rsize == 16 && m.gsize == 0 && m.bsize == 0 && m.asize == 0) return D3DFMT_R16F; if (m.rsize == 32 && m.gsize == 0 && m.bsize == 0 && m.asize == 0) return D3DFMT_R32F; if (m.rsize == 16 && m.gsize == 16 && m.bsize == 0 && m.asize == 0) return D3DFMT_G16R16F; if (m.rsize == 32 && m.gsize == 32 && m.bsize == 0 && m.asize == 0) return D3DFMT_G32R32F; if (m.rsize == 16 && m.gsize == 16 && m.bsize == 16 && m.asize == 16) return D3DFMT_A16B16G16R16F; if (m.rsize == 32 && m.gsize == 32 && m.bsize == 32 && m.asize == 32) return D3DFMT_A32B32G32R32F; } return 0; } else { uint d3d9_formats[] = { 0, // Format_RGB, FOURCC_DXT1, // Format_DXT1 FOURCC_DXT1, // Format_DXT1a FOURCC_DXT3, // Format_DXT3 FOURCC_DXT5, // Format_DXT5 FOURCC_DXT5, // Format_DXT5n FOURCC_ATI1, // Format_BC4 FOURCC_ATI2, // Format_BC5 FOURCC_DXT1, // Format_DXT1n 0, // Format_CTX1 FOURCC_BC6H, // Format_BC6 FOURCC_BC7L, // Format_BC7 FOURCC_DXT5, // Format_BC3_RGBM NV_MAKEFOURCC('E', 'T', 'C', '1'), // Format_ETC1 0, // Format_ETC2_R 0, // Format_ETC2_RG NV_MAKEFOURCC('E', 'T', 'C', '2'), // Format_ETC2_RGB 0, // Format_ETC2_RGBA 0, // Format_ETC2_RGB_A1 0, // Format_ETC2_RGBM FOURCC_PVR0, FOURCC_PVR1, FOURCC_PVR2, FOURCC_PVR3, }; NV_COMPILER_CHECK(NV_ARRAY_SIZE(d3d9_formats) == Format_Count); return d3d9_formats[m.format]; } } unsigned int CompressionOptions::dxgiFormat() const // @@ Add srgb flag. { if (m.format == Format_RGB) { if (m.pixelType == PixelType_UnsignedNorm) { uint bitcount = m.bitcount; uint rmask = m.rmask; uint gmask = m.gmask; uint bmask = m.bmask; uint amask = m.amask; if (bitcount == 0) { bitcount = m.rsize + m.gsize + m.bsize + m.asize; rmask = ((1 << m.rsize) - 1) << (m.asize + m.bsize + m.gsize); gmask = ((1 << m.gsize) - 1) << (m.asize + m.bsize); bmask = ((1 << m.bsize) - 1) << m.asize; amask = ((1 << m.asize) - 1) << 0; } if (bitcount <= 32) { return nv::findDXGIFormat(bitcount, rmask, gmask, bmask, amask); } else { if (m.rsize == 16 && m.gsize == 16 && m.bsize == 0 && m.asize == 0) return DXGI_FORMAT_R16G16_UNORM; if (m.rsize == 16 && m.gsize == 16 && m.bsize == 16 && m.asize == 16) return DXGI_FORMAT_R16G16B16A16_UNORM; } } else if (m.pixelType == PixelType_Float) { if (m.rsize == 16 && m.gsize == 0 && m.bsize == 0 && m.asize == 0) return DXGI_FORMAT_R16_FLOAT; if (m.rsize == 32 && m.gsize == 0 && m.bsize == 0 && m.asize == 0) return DXGI_FORMAT_R32_FLOAT; if (m.rsize == 16 && m.gsize == 16 && m.bsize == 0 && m.asize == 0) return DXGI_FORMAT_R16G16_FLOAT; if (m.rsize == 32 && m.gsize == 32 && m.bsize == 0 && m.asize == 0) return DXGI_FORMAT_R32G32_FLOAT; if (m.rsize == 16 && m.gsize == 16 && m.bsize == 16 && m.asize == 16) return DXGI_FORMAT_R16G16B16A16_FLOAT; if (m.rsize == 32 && m.gsize == 32 && m.bsize == 32 && m.asize == 32) return DXGI_FORMAT_R32G32B32A32_FLOAT; } return 0; } else { uint dxgi_formats[] = { 0, // Format_RGB, DXGI_FORMAT_BC1_UNORM, // Format_DXT1 DXGI_FORMAT_BC1_UNORM, // Format_DXT1a DXGI_FORMAT_BC2_UNORM, // Format_DXT3 DXGI_FORMAT_BC3_UNORM, // Format_DXT5 DXGI_FORMAT_BC3_UNORM, // Format_DXT5n DXGI_FORMAT_BC4_UNORM, // Format_BC4 DXGI_FORMAT_BC5_UNORM, // Format_BC5 DXGI_FORMAT_BC1_UNORM, // Format_DXT1n 0, // Format_CTX1 DXGI_FORMAT_BC6H_UF16, // Format_BC6 DXGI_FORMAT_BC7_UNORM, // Format_BC7 DXGI_FORMAT_BC5_UNORM, // Format_BC3_RGBM 0, // Format_ETC1 0, // Format_ETC2_R 0, // Format_ETC2_RG 0, // Format_ETC2_RGB 0, // Format_ETC2_RGBA 0, // Format_ETC2_RGB_A1 0, // Format_ETC2_RGBM 0, // Format_PVR_2BPP_RGB 0, // Format_PVR_4BPP_RGB 0, // Format_PVR_2BPP_RGBA 0, // Format_PVR_4BPP_RGB }; NV_COMPILER_CHECK(NV_ARRAY_SIZE(dxgi_formats) == Format_Count); return dxgi_formats[m.format]; } } /* bool CompressionOptions::setDirect3D9Format(unsigned int format) { } bool CompressionOptions::setDXGIFormat(unsigned int format) { } */