diff --git a/src/nvtt/CompressDXT.cpp b/src/nvtt/CompressDXT.cpp index 613373c..9956784 100644 --- a/src/nvtt/CompressDXT.cpp +++ b/src/nvtt/CompressDXT.cpp @@ -36,7 +36,6 @@ // squish #include "squish/colourset.h" -//#include "squish/clusterfit.h" #include "squish/fastclusterfit.h" #include "squish/weightedclusterfit.h" @@ -183,7 +182,7 @@ void nv::fastCompressBC5(const Image * image, const nvtt::OutputOptions::Private void nv::doPrecomputation() { - static bool done = false; + static bool done = false; // @@ Stop using statics for reentrancy. if (!done) { @@ -319,7 +318,7 @@ void nv::compressDXT5n(const Image * image, const OutputOptions::Private & outpu } // Compress Y. - compressGreenBlock_BruteForce(rgba, &block.color); + QuickCompress::compressDXT1G(rgba, &block.color); if (outputOptions.outputHandler != NULL) { outputOptions.outputHandler->writeData(&block, sizeof(block)); @@ -350,8 +349,7 @@ void nv::compressBC4(const Image * image, const nvtt::OutputOptions::Private & o //error = compressBlock_BoundsRange(rgba, &block); uint error = compressBlock_Iterative(rgba, &block); - if (compressionOptions.quality == Quality_Highest || - (compressionOptions.quality == Quality_Production && error > threshold)) + if (compressionOptions.quality == Quality_Highest) { // Try brute force algorithm. error = compressBlock_BruteForce(rgba, &block); @@ -364,20 +362,6 @@ void nv::compressBC4(const Image * image, const nvtt::OutputOptions::Private & o } } } - - // @@ All the compressors should work like this. - // Effect of adjusting threshold: - // (threshold: error - time) - // 0: 4.29 - 1.83 - // 32: 4.32 - 1.77 - // 48: 4.37 - 1.72 - // 64: 4.43 - 1.45 - // 74: 4.45 - 1.35 - // 92: 4.54 - 1.15 - // 128: 4.67 - 0.79 - // 256: 4.92 - 0.20 - // inf: 4.98 - 0.09 - //printf("Alpha error: %f\n", float(totalError) / (w*h)); } diff --git a/src/nvtt/QuickCompressDXT.cpp b/src/nvtt/QuickCompressDXT.cpp index 58ee48d..b2213e6 100644 --- a/src/nvtt/QuickCompressDXT.cpp +++ b/src/nvtt/QuickCompressDXT.cpp @@ -430,6 +430,124 @@ void QuickCompress::compressDXT1a(const ColorBlock & rgba, BlockDXT1 * dxtBlock) } +static int computeGreenError(const ColorBlock & rgba, const BlockDXT1 * block) +{ + nvDebugCheck(block != NULL); + + int palette[4]; + palette[0] = (block->col0.g << 2) | (block->col0.g >> 4); + palette[1] = (block->col1.g << 2) | (block->col1.g >> 4); + palette[2] = (2 * palette[0] + palette[1]) / 3; + palette[3] = (2 * palette[1] + palette[0]) / 3; + + int totalError = 0; + + for (int i = 0; i < 16; i++) + { + const int green = rgba.color(i).g; + + int error = abs(green - palette[0]); + error = min(error, abs(green - palette[1])); + error = min(error, abs(green - palette[2])); + error = min(error, abs(green - palette[3])); + + totalError += error; + } + + return totalError; +} + +static uint computeGreenIndices(const ColorBlock & rgba, const Color32 palette[4]) +{ + const int color0 = palette[0].g; + const int color1 = palette[1].g; + const int color2 = palette[2].g; + const int color3 = palette[3].g; + + uint indices = 0; + for (int i = 0; i < 16; i++) + { + const int color = rgba.color(i).g; + + uint d0 = abs(color0 - color); + uint d1 = abs(color1 - color); + uint d2 = abs(color2 - color); + uint d3 = abs(color3 - color); + + uint b0 = d0 > d3; + uint b1 = d1 > d2; + uint b2 = d0 > d2; + uint b3 = d1 > d3; + uint b4 = d2 > d3; + + uint x0 = b1 & b2; + uint x1 = b0 & b3; + uint x2 = b0 & b4; + + indices |= (x2 | ((x0 | x1) << 1)) << (2 * i); + } + + return indices; +} + +// Brute force green channel compressor +void QuickCompress::compressDXT1G(const ColorBlock & rgba, BlockDXT1 * block) +{ + nvDebugCheck(block != NULL); + + uint8 ming = 63; + uint8 maxg = 0; + + // Get min/max green. + for (uint i = 0; i < 16; i++) + { + uint8 green = rgba.color(i).g >> 2; + ming = min(ming, green); + maxg = max(maxg, green); + } + + block->col0.u = 0; + block->col1.u = 0; + block->col0.g = maxg; + block->col1.g = ming; + + if (maxg - ming > 4) + { + int besterror = computeGreenError(rgba, block); + int bestg0 = maxg; + int bestg1 = ming; + + for (int g0 = ming+5; g0 < maxg; g0++) + { + for (int g1 = ming; g1 < g0-4; g1++) + { + if ((maxg-g0) + (g1-ming) > besterror) + continue; + + block->col0.g = g0; + block->col1.g = g1; + int error = computeGreenError(rgba, block); + + if (error < besterror) + { + besterror = error; + bestg0 = g0; + bestg1 = g1; + } + } + } + + block->col0.g = bestg0; + block->col1.g = bestg1; + } + + Color32 palette[4]; + block->evaluatePalette(palette); + block->indices = computeGreenIndices(rgba, palette); +} + + + void QuickCompress::compressDXT3A(const ColorBlock & rgba, AlphaBlockDXT3 * dxtBlock) { dxtBlock->alpha0 = rgba.color(0).a >> 4; diff --git a/src/nvtt/QuickCompressDXT.h b/src/nvtt/QuickCompressDXT.h index 5a8dfc8..49433a0 100644 --- a/src/nvtt/QuickCompressDXT.h +++ b/src/nvtt/QuickCompressDXT.h @@ -40,6 +40,7 @@ namespace nv void compressDXT1(const Color32 rgba, BlockDXT1 * dxtBlock); void compressDXT1(const ColorBlock & rgba, BlockDXT1 * dxtBlock); void compressDXT1a(const ColorBlock & rgba, BlockDXT1 * dxtBlock); + void compressDXT1G(const ColorBlock & rgba, BlockDXT1 * block); void compressDXT3A(const ColorBlock & rgba, AlphaBlockDXT3 * dxtBlock); void compressDXT3(const ColorBlock & rgba, BlockDXT3 * dxtBlock);