You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
nvidia-texture-tools/src/nvtt/CompressionOptions.cpp

362 lines
13 KiB
C++

// Copyright (c) 2009-2011 Ignacio Castano <castano@gmail.com>
// Copyright (c) 2007-2009 NVIDIA Corporation -- Ignacio Castano <icastano@nvidia.com>
//
// 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)
{
}
*/