Merge changes from The Witness.
This commit is contained in:
@ -152,6 +152,8 @@ int main(int argc, char *argv[])
|
||||
bool premultiplyAlpha = false;
|
||||
nvtt::MipmapFilter mipmapFilter = nvtt::MipmapFilter_Box;
|
||||
bool loadAsFloat = false;
|
||||
bool rgbm = false;
|
||||
bool rangescale = false;
|
||||
|
||||
const char * externalCompressor = NULL;
|
||||
|
||||
@ -209,6 +211,15 @@ int main(int argc, char *argv[])
|
||||
{
|
||||
loadAsFloat = true;
|
||||
}
|
||||
else if (strcmp("-rgbm", argv[i]) == 0)
|
||||
{
|
||||
rgbm = true;
|
||||
}
|
||||
else if (strcmp("-rangescale", argv[i]) == 0)
|
||||
{
|
||||
rangescale = true;
|
||||
}
|
||||
|
||||
|
||||
// Compression options.
|
||||
else if (strcmp("-fast", argv[i]) == 0)
|
||||
@ -269,6 +280,11 @@ int main(int argc, char *argv[])
|
||||
{
|
||||
format = nvtt::Format_BC7;
|
||||
}
|
||||
else if (strcmp("-bc3_rgbm", argv[i]) == 0)
|
||||
{
|
||||
format = nvtt::Format_BC3_RGBM;
|
||||
rgbm = true;
|
||||
}
|
||||
|
||||
// Undocumented option. Mainly used for testing.
|
||||
else if (strcmp("-ext", argv[i]) == 0)
|
||||
@ -332,32 +348,35 @@ int main(int argc, char *argv[])
|
||||
printf("usage: nvcompress [options] infile [outfile.dds]\n\n");
|
||||
|
||||
printf("Input options:\n");
|
||||
printf(" -color \tThe input image is a color map (default).\n");
|
||||
printf(" -alpha \tThe input image has an alpha channel used for transparency.\n");
|
||||
printf(" -normal \tThe input image is a normal map.\n");
|
||||
printf(" -tonormal \tConvert input to normal map.\n");
|
||||
printf(" -clamp \tClamp wrapping mode (default).\n");
|
||||
printf(" -repeat \tRepeat wrapping mode.\n");
|
||||
printf(" -nomips \tDisable mipmap generation.\n");
|
||||
printf(" -premula \tPremultiply alpha into color channel.\n");
|
||||
printf(" -mipfilter \tMipmap filter. One of the following: box, triangle, kaiser.\n");
|
||||
printf(" -float \tLoad as floating point image.\n\n");
|
||||
printf(" -color The input image is a color map (default).\n");
|
||||
printf(" -alpha The input image has an alpha channel used for transparency.\n");
|
||||
printf(" -normal The input image is a normal map.\n");
|
||||
printf(" -tonormal Convert input to normal map.\n");
|
||||
printf(" -clamp Clamp wrapping mode (default).\n");
|
||||
printf(" -repeat Repeat wrapping mode.\n");
|
||||
printf(" -nomips Disable mipmap generation.\n");
|
||||
printf(" -premula Premultiply alpha into color channel.\n");
|
||||
printf(" -mipfilter Mipmap filter. One of the following: box, triangle, kaiser.\n");
|
||||
printf(" -float Load as floating point image.\n\n");
|
||||
printf(" -rgbm Transform input to RGBM.\n\n");
|
||||
printf(" -rangescale Scale image to use entire color range.\n\n");
|
||||
|
||||
printf("Compression options:\n");
|
||||
printf(" -fast \tFast compression.\n");
|
||||
printf(" -nocuda \tDo not use cuda compressor.\n");
|
||||
printf(" -rgb \tRGBA format\n");
|
||||
printf(" -lumi \tLUMINANCE format\n");
|
||||
printf(" -bc1 \tBC1 format (DXT1)\n");
|
||||
printf(" -bc1n \tBC1 normal map format (DXT1nm)\n");
|
||||
printf(" -bc1a \tBC1 format with binary alpha (DXT1a)\n");
|
||||
printf(" -bc2 \tBC2 format (DXT3)\n");
|
||||
printf(" -bc3 \tBC3 format (DXT5)\n");
|
||||
printf(" -bc3n \tBC3 normal map format (DXT5nm)\n");
|
||||
printf(" -bc4 \tBC4 format (ATI1)\n");
|
||||
printf(" -bc5 \tBC5 format (3Dc/ATI2)\n");
|
||||
printf(" -bc6 \tBC6 format\n");
|
||||
printf(" -bc7 \tBC7 format\n\n");
|
||||
printf(" -fast Fast compression.\n");
|
||||
printf(" -nocuda Do not use cuda compressor.\n");
|
||||
printf(" -rgb RGBA format\n");
|
||||
printf(" -lumi LUMINANCE format\n");
|
||||
printf(" -bc1 BC1 format (DXT1)\n");
|
||||
printf(" -bc1n BC1 normal map format (DXT1nm)\n");
|
||||
printf(" -bc1a BC1 format with binary alpha (DXT1a)\n");
|
||||
printf(" -bc2 BC2 format (DXT3)\n");
|
||||
printf(" -bc3 BC3 format (DXT5)\n");
|
||||
printf(" -bc3n BC3 normal map format (DXT5nm)\n");
|
||||
printf(" -bc4 BC4 format (ATI1)\n");
|
||||
printf(" -bc5 BC5 format (3Dc/ATI2)\n");
|
||||
printf(" -bc6 BC6 format\n");
|
||||
printf(" -bc7 BC7 format\n\n");
|
||||
printf(" -bc3_rgbm BC3-rgbm format\n\n");
|
||||
|
||||
printf("Output options:\n");
|
||||
printf(" -silent \tDo not output progress messages\n");
|
||||
@ -376,145 +395,211 @@ int main(int argc, char *argv[])
|
||||
// Set input options.
|
||||
nvtt::InputOptions inputOptions;
|
||||
|
||||
if (nv::strCaseDiff(input.extension(), ".dds") == 0)
|
||||
{
|
||||
// Load surface.
|
||||
nv::DirectDrawSurface dds(input.str());
|
||||
if (!dds.isValid())
|
||||
{
|
||||
fprintf(stderr, "The file '%s' is not a valid DDS file.\n", input.str());
|
||||
bool useSurface = false; // @@ use Surface API in all cases!
|
||||
nvtt::Surface image;
|
||||
|
||||
if (true || format == nvtt::Format_BC3_RGBM || rgbm) {
|
||||
useSurface = true;
|
||||
|
||||
if (!image.load(input.str())) {
|
||||
fprintf(stderr, "Error opening input file '%s'.\n", input.str());
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
if (!dds.isSupported())
|
||||
{
|
||||
fprintf(stderr, "The file '%s' is not a supported DDS file.\n", input.str());
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
if (rangescale) {
|
||||
// get color range
|
||||
float min_color[3], max_color[3];
|
||||
image.range(0, &min_color[0], &max_color[0]);
|
||||
image.range(1, &min_color[1], &max_color[1]);
|
||||
image.range(2, &min_color[2], &max_color[2]);
|
||||
|
||||
uint faceCount;
|
||||
if (dds.isTexture2D())
|
||||
{
|
||||
inputOptions.setTextureLayout(nvtt::TextureType_2D, dds.width(), dds.height());
|
||||
faceCount = 1;
|
||||
}
|
||||
else if (dds.isTexture3D())
|
||||
{
|
||||
inputOptions.setTextureLayout(nvtt::TextureType_3D, dds.width(), dds.height(), dds.depth());
|
||||
faceCount = 1;
|
||||
//printf("Color range = %.2f %.2f %.2f\n", max_color[0], max_color[1], max_color[2]);
|
||||
|
||||
nvDebugBreak();
|
||||
}
|
||||
else
|
||||
{
|
||||
nvDebugCheck(dds.isTextureCube());
|
||||
inputOptions.setTextureLayout(nvtt::TextureType_Cube, dds.width(), dds.height());
|
||||
faceCount = 6;
|
||||
}
|
||||
float color_range = nv::max3(max_color[0], max_color[1], max_color[2]);
|
||||
const float max_color_range = 16.0f;
|
||||
|
||||
uint mipmapCount = dds.mipmapCount();
|
||||
|
||||
nv::Image mipmap;
|
||||
|
||||
for (uint f = 0; f < faceCount; f++)
|
||||
{
|
||||
for (uint m = 0; m < mipmapCount; m++)
|
||||
{
|
||||
dds.mipmap(&mipmap, f, m); // @@ Load as float.
|
||||
|
||||
inputOptions.setMipmapData(mipmap.pixels(), mipmap.width(), mipmap.height(), mipmap.depth(), f, m);
|
||||
if (color_range > max_color_range) {
|
||||
//Log::print("Clamping color range %f to %f\n", color_range, max_color_range);
|
||||
color_range = max_color_range;
|
||||
}
|
||||
//color_range = max_color_range; // Use a fixed color range for now.
|
||||
|
||||
for (int i = 0; i < 3; i++) {
|
||||
image.scaleBias(i, 1.0f / color_range, 0.0f);
|
||||
}
|
||||
image.toneMap(nvtt::ToneMapper_Linear, /*parameters=*/NULL); // Clamp without changing the hue.
|
||||
|
||||
// Clamp alpha.
|
||||
image.clamp(3);
|
||||
}
|
||||
|
||||
if (alpha) {
|
||||
image.setAlphaMode(nvtt::AlphaMode_Transparency);
|
||||
}
|
||||
|
||||
// To gamma.
|
||||
image.toGamma(2);
|
||||
|
||||
if (format != nvtt::Format_BC3_RGBM) {
|
||||
image.setAlphaMode(nvtt::AlphaMode_None);
|
||||
image.toRGBM(1, 0.15f);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (nv::strCaseDiff(input.extension(), ".exr") == 0 || nv::strCaseDiff(input.extension(), ".hdr") == 0)
|
||||
{
|
||||
loadAsFloat = true;
|
||||
else if (format == nvtt::Format_BC6) {
|
||||
//format = nvtt::Format_BC1;
|
||||
//fprintf(stderr, "BLABLABLA.\n");
|
||||
useSurface = true;
|
||||
|
||||
if (!image.load(input.str())) {
|
||||
fprintf(stderr, "Error opening input file '%s'.\n", input.str());
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
if (loadAsFloat)
|
||||
image.setAlphaMode(nvtt::AlphaMode_Transparency);
|
||||
}
|
||||
else {
|
||||
if (nv::strCaseDiff(input.extension(), ".dds") == 0)
|
||||
{
|
||||
nv::AutoPtr<nv::FloatImage> image(nv::ImageIO::loadFloat(input.str()));
|
||||
|
||||
if (image == NULL)
|
||||
// Load surface.
|
||||
nv::DirectDrawSurface dds(input.str());
|
||||
if (!dds.isValid())
|
||||
{
|
||||
fprintf(stderr, "The file '%s' is not a supported image type.\n", input.str());
|
||||
fprintf(stderr, "The file '%s' is not a valid DDS file.\n", input.str());
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
inputOptions.setFormat(nvtt::InputFormat_RGBA_32F);
|
||||
inputOptions.setTextureLayout(nvtt::TextureType_2D, image->width(), image->height());
|
||||
|
||||
/*for (uint i = 0; i < image->componentNum(); i++)
|
||||
if (!dds.isSupported())
|
||||
{
|
||||
inputOptions.setMipmapChannelData(image->channel(i), i, image->width(), image->height());
|
||||
}*/
|
||||
fprintf(stderr, "The file '%s' is not a supported DDS file.\n", input.str());
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
uint faceCount;
|
||||
if (dds.isTexture2D())
|
||||
{
|
||||
inputOptions.setTextureLayout(nvtt::TextureType_2D, dds.width(), dds.height());
|
||||
faceCount = 1;
|
||||
}
|
||||
else if (dds.isTexture3D())
|
||||
{
|
||||
inputOptions.setTextureLayout(nvtt::TextureType_3D, dds.width(), dds.height(), dds.depth());
|
||||
faceCount = 1;
|
||||
|
||||
nvDebugBreak();
|
||||
}
|
||||
else
|
||||
{
|
||||
nvDebugCheck(dds.isTextureCube());
|
||||
inputOptions.setTextureLayout(nvtt::TextureType_Cube, dds.width(), dds.height());
|
||||
faceCount = 6;
|
||||
}
|
||||
|
||||
uint mipmapCount = dds.mipmapCount();
|
||||
|
||||
nv::Image mipmap;
|
||||
|
||||
for (uint f = 0; f < faceCount; f++)
|
||||
{
|
||||
for (uint m = 0; m < mipmapCount; m++)
|
||||
{
|
||||
dds.mipmap(&mipmap, f, m); // @@ Load as float.
|
||||
|
||||
inputOptions.setMipmapData(mipmap.pixels(), mipmap.width(), mipmap.height(), mipmap.depth(), f, m);
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// Regular image.
|
||||
nv::Image image;
|
||||
if (!image.load(input.str()))
|
||||
if (nv::strCaseDiff(input.extension(), ".exr") == 0 || nv::strCaseDiff(input.extension(), ".hdr") == 0)
|
||||
{
|
||||
fprintf(stderr, "The file '%s' is not a supported image type.\n", input.str());
|
||||
return 1;
|
||||
loadAsFloat = true;
|
||||
}
|
||||
|
||||
inputOptions.setTextureLayout(nvtt::TextureType_2D, image.width(), image.height());
|
||||
inputOptions.setMipmapData(image.pixels(), image.width(), image.height());
|
||||
if (loadAsFloat)
|
||||
{
|
||||
nv::AutoPtr<nv::FloatImage> image(nv::ImageIO::loadFloat(input.str()));
|
||||
|
||||
if (image == NULL)
|
||||
{
|
||||
fprintf(stderr, "The file '%s' is not a supported image type.\n", input.str());
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
inputOptions.setFormat(nvtt::InputFormat_RGBA_32F);
|
||||
inputOptions.setTextureLayout(nvtt::TextureType_2D, image->width(), image->height());
|
||||
|
||||
/*for (uint i = 0; i < image->componentNum(); i++)
|
||||
{
|
||||
inputOptions.setMipmapChannelData(image->channel(i), i, image->width(), image->height());
|
||||
}*/
|
||||
}
|
||||
else
|
||||
{
|
||||
// Regular image.
|
||||
nv::Image image;
|
||||
if (!image.load(input.str()))
|
||||
{
|
||||
fprintf(stderr, "The file '%s' is not a supported image type.\n", input.str());
|
||||
return 1;
|
||||
}
|
||||
|
||||
inputOptions.setTextureLayout(nvtt::TextureType_2D, image.width(), image.height());
|
||||
inputOptions.setMipmapData(image.pixels(), image.width(), image.height());
|
||||
}
|
||||
}
|
||||
|
||||
if (wrapRepeat)
|
||||
{
|
||||
inputOptions.setWrapMode(nvtt::WrapMode_Repeat);
|
||||
}
|
||||
else
|
||||
{
|
||||
inputOptions.setWrapMode(nvtt::WrapMode_Clamp);
|
||||
}
|
||||
|
||||
if (alpha)
|
||||
{
|
||||
inputOptions.setAlphaMode(nvtt::AlphaMode_Transparency);
|
||||
}
|
||||
else
|
||||
{
|
||||
inputOptions.setAlphaMode(nvtt::AlphaMode_None);
|
||||
}
|
||||
|
||||
// Block compressed textures with mipmaps must be powers of two.
|
||||
if (!noMipmaps && format != nvtt::Format_RGB)
|
||||
{
|
||||
inputOptions.setRoundMode(nvtt::RoundMode_ToPreviousPowerOfTwo);
|
||||
}
|
||||
|
||||
if (normal)
|
||||
{
|
||||
setNormalMap(inputOptions);
|
||||
}
|
||||
else if (color2normal)
|
||||
{
|
||||
setColorToNormalMap(inputOptions);
|
||||
}
|
||||
else
|
||||
{
|
||||
setColorMap(inputOptions);
|
||||
}
|
||||
|
||||
if (noMipmaps)
|
||||
{
|
||||
inputOptions.setMipmapGeneration(false);
|
||||
}
|
||||
|
||||
/*if (premultiplyAlpha)
|
||||
{
|
||||
inputOptions.setPremultiplyAlpha(true);
|
||||
inputOptions.setAlphaMode(nvtt::AlphaMode_Premultiplied);
|
||||
}*/
|
||||
|
||||
inputOptions.setMipmapFilter(mipmapFilter);
|
||||
}
|
||||
|
||||
if (wrapRepeat)
|
||||
{
|
||||
inputOptions.setWrapMode(nvtt::WrapMode_Repeat);
|
||||
}
|
||||
else
|
||||
{
|
||||
inputOptions.setWrapMode(nvtt::WrapMode_Clamp);
|
||||
}
|
||||
|
||||
if (alpha)
|
||||
{
|
||||
inputOptions.setAlphaMode(nvtt::AlphaMode_Transparency);
|
||||
}
|
||||
else
|
||||
{
|
||||
inputOptions.setAlphaMode(nvtt::AlphaMode_None);
|
||||
}
|
||||
|
||||
// Block compressed textures with mipmaps must be powers of two.
|
||||
if (!noMipmaps && format != nvtt::Format_RGB)
|
||||
{
|
||||
inputOptions.setRoundMode(nvtt::RoundMode_ToPreviousPowerOfTwo);
|
||||
}
|
||||
|
||||
if (normal)
|
||||
{
|
||||
setNormalMap(inputOptions);
|
||||
}
|
||||
else if (color2normal)
|
||||
{
|
||||
setColorToNormalMap(inputOptions);
|
||||
}
|
||||
else
|
||||
{
|
||||
setColorMap(inputOptions);
|
||||
}
|
||||
|
||||
if (noMipmaps)
|
||||
{
|
||||
inputOptions.setMipmapGeneration(false);
|
||||
}
|
||||
|
||||
/*if (premultiplyAlpha)
|
||||
{
|
||||
inputOptions.setPremultiplyAlpha(true);
|
||||
inputOptions.setAlphaMode(nvtt::AlphaMode_Premultiplied);
|
||||
}*/
|
||||
|
||||
inputOptions.setMipmapFilter(mipmapFilter);
|
||||
|
||||
nvtt::CompressionOptions compressionOptions;
|
||||
compressionOptions.setFormat(format);
|
||||
@ -545,8 +630,25 @@ int main(int argc, char *argv[])
|
||||
//compressionOptions.setQuantization(/*color dithering*/true, /*alpha dithering*/false, /*binary alpha*/false);
|
||||
//compressionOptions.setPixelType(nvtt::PixelType_UnsignedNorm);
|
||||
//compressionOptions.setPixelFormat(5, 6, 5, 0);
|
||||
//compressionOptions.setPixelFormat(8, 8, 8, 8);
|
||||
|
||||
// A4R4G4B4
|
||||
//compressionOptions.setPixelFormat(16, 0xF00, 0xF0, 0xF, 0xF000);
|
||||
|
||||
//compressionOptions.setPixelFormat(32, 0xFF0000, 0xFF00, 0xFF, 0xFF000000);
|
||||
|
||||
// R10B20G10A2
|
||||
//compressionOptions.setPixelFormat(10, 10, 10, 2);
|
||||
|
||||
// DXGI_FORMAT_R11G11B10_FLOAT
|
||||
compressionOptions.setPixelType(nvtt::PixelType_Float);
|
||||
compressionOptions.setPixelFormat(11, 11, 10, 0);
|
||||
}
|
||||
}
|
||||
else if (format == nvtt::Format_BC6)
|
||||
{
|
||||
compressionOptions.setPixelType(nvtt::PixelType_UnsignedFloat);
|
||||
}
|
||||
|
||||
if (fast)
|
||||
{
|
||||
@ -599,7 +701,15 @@ int main(int argc, char *argv[])
|
||||
}
|
||||
}
|
||||
|
||||
outputHandler.setTotal(context.estimateSize(inputOptions, compressionOptions));
|
||||
int outputSize = 0;
|
||||
if (useSurface) {
|
||||
outputSize = context.estimateSize(image, 1, compressionOptions);
|
||||
}
|
||||
else {
|
||||
outputSize = context.estimateSize(inputOptions, compressionOptions);
|
||||
}
|
||||
|
||||
outputHandler.setTotal(outputSize);
|
||||
outputHandler.setDisplayProgress(!silent);
|
||||
|
||||
nvtt::OutputOptions outputOptions;
|
||||
@ -625,10 +735,22 @@ int main(int argc, char *argv[])
|
||||
nv::Timer timer;
|
||||
timer.start();
|
||||
|
||||
if (!context.process(inputOptions, compressionOptions, outputOptions))
|
||||
{
|
||||
return EXIT_FAILURE;
|
||||
if (useSurface) {
|
||||
if (!context.outputHeader(image, 1, compressionOptions, outputOptions)) {
|
||||
fprintf(stderr, "Error writing file header.\n");
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
if (!context.compress(image, 0, 0, compressionOptions, outputOptions)) {
|
||||
fprintf(stderr, "Error compressing file.\n");
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
}
|
||||
else {
|
||||
if (!context.process(inputOptions, compressionOptions, outputOptions)) {
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
}
|
||||
|
||||
timer.stop();
|
||||
|
||||
if (!silent) {
|
||||
|
@ -29,6 +29,8 @@
|
||||
|
||||
#include <nvimage/ImageIO.h>
|
||||
|
||||
#include <nvtt/nvtt.h>
|
||||
|
||||
#include "cmdline.h"
|
||||
|
||||
#include <time.h> // clock
|
||||
@ -42,6 +44,8 @@ int main(int argc, char *argv[])
|
||||
bool mipmaps = false;
|
||||
bool faces = false;
|
||||
bool savePNG = false;
|
||||
bool rgbm = false;
|
||||
bool histogram = true;
|
||||
|
||||
nv::Path input;
|
||||
nv::Path output;
|
||||
@ -57,10 +61,18 @@ int main(int argc, char *argv[])
|
||||
{
|
||||
mipmaps = true;
|
||||
}
|
||||
else if (strcmp("-rgbm", argv[i]) == 0)
|
||||
{
|
||||
rgbm = true;
|
||||
}
|
||||
else if (strcmp("-faces", argv[i]) == 0)
|
||||
{
|
||||
faces = true;
|
||||
}
|
||||
else if (strcmp("-histogram", argv[i]) == 0)
|
||||
{
|
||||
histogram = true;
|
||||
}
|
||||
else if (strcmp("-format", argv[i]) == 0)
|
||||
{
|
||||
if (i+1 == argc) break;
|
||||
@ -109,90 +121,125 @@ int main(int argc, char *argv[])
|
||||
printf("Note: the .tga or .png extension is forced on outfile\n\n");
|
||||
|
||||
printf("Input options:\n");
|
||||
printf(" -forcenormal \tThe input image is a normal map.\n");
|
||||
printf(" -mipmaps \tDecompress all mipmaps.\n");
|
||||
printf(" -faces \tDecompress all faces.\n");
|
||||
printf(" -format <format>\tOutput format ('tga' or 'png').\n");
|
||||
printf(" -forcenormal The input image is a normal map.\n");
|
||||
printf(" -mipmaps Decompress all mipmaps.\n");
|
||||
printf(" -faces Decompress all faces.\n");
|
||||
printf(" -histogram Output histogram.\n");
|
||||
printf(" -format <format> Output format ('tga' or 'png').\n");
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
// Load surface.
|
||||
// !!! DirectDrawSurface API doesn't support float images, so BC6 will be converted to 8-bit on load.
|
||||
// Should use nvtt::Surface instead.
|
||||
nv::DirectDrawSurface dds(input.str());
|
||||
if (!dds.isValid())
|
||||
{
|
||||
fprintf(stderr, "The file '%s' is not a valid DDS file.\n", input.str());
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (!dds.isSupported() || dds.isTexture3D())
|
||||
{
|
||||
fprintf(stderr, "The file '%s' is not a supported DDS file.\n", input.str());
|
||||
return 1;
|
||||
}
|
||||
|
||||
uint faceCount;
|
||||
if (dds.isTexture2D())
|
||||
{
|
||||
faceCount = 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
nvCheck(dds.isTextureCube());
|
||||
faceCount = 6;
|
||||
}
|
||||
|
||||
uint mipmapCount = dds.mipmapCount();
|
||||
|
||||
clock_t start = clock();
|
||||
|
||||
// apply arguments
|
||||
if (forcenormal)
|
||||
{
|
||||
dds.setNormalFlag(true);
|
||||
}
|
||||
if (!faces)
|
||||
{
|
||||
faceCount = 1;
|
||||
}
|
||||
if (!mipmaps)
|
||||
{
|
||||
mipmapCount = 1;
|
||||
}
|
||||
if (histogram) {
|
||||
nvtt::Surface img;
|
||||
if (!img.load(input.str())) {
|
||||
fprintf(stderr, "The file '%s' is not a valid DDS file.\n", input.str());
|
||||
return 1;
|
||||
}
|
||||
|
||||
nv::Image mipmap;
|
||||
nv::Path name;
|
||||
float exposure = 2.2f;
|
||||
float scale = 1.0f / exposure;
|
||||
img.scaleBias(0, scale, 0);
|
||||
img.scaleBias(1, scale, 0);
|
||||
img.scaleBias(2, scale, 0);
|
||||
|
||||
// strip extension, we force the tga extension
|
||||
output.stripExtension();
|
||||
//img.toneMap(nvtt::ToneMapper_Reindhart, NULL);
|
||||
//img.toSrgb();
|
||||
img.toGamma(2.2f);
|
||||
|
||||
// extract faces and mipmaps
|
||||
for (uint f = 0; f < faceCount; f++)
|
||||
{
|
||||
for (uint m = 0; m < mipmapCount; m++)
|
||||
{
|
||||
dds.mipmap(&mipmap, f, m);
|
||||
|
||||
// set output filename, if we are doing faces and/or mipmaps
|
||||
name.copy(output);
|
||||
if (faces) name.appendFormat("_face%d", f);
|
||||
if (mipmaps) name.appendFormat("_mipmap%d", m);
|
||||
name.append(savePNG ? ".png" : ".tga");
|
||||
|
||||
nv::StdOutputStream stream(name.str());
|
||||
if (stream.isError()) {
|
||||
fprintf(stderr, "Error opening '%s' for writting\n", name.str());
|
||||
return 1;
|
||||
}
|
||||
|
||||
nv::ImageIO::save(name.str(), stream, &mipmap);
|
||||
}
|
||||
}
|
||||
nvtt::Surface hist = nvtt::histogram(img, 3*512, 128);
|
||||
|
||||
clock_t end = clock();
|
||||
printf("\rtime taken: %.3f seconds\n", float(end-start) / CLOCKS_PER_SEC);
|
||||
// Resize for pretier histograms.
|
||||
hist.resize(512, 128, 1, nvtt::ResizeFilter_Box);
|
||||
|
||||
nv::Path name;
|
||||
name.copy(output);
|
||||
name.stripExtension();
|
||||
name.append(".histogram");
|
||||
name.append(savePNG ? ".png" : ".tga");
|
||||
|
||||
hist.save(name.str());
|
||||
}
|
||||
else {
|
||||
|
||||
// Load surface.
|
||||
// !!! DirectDrawSurface API doesn't support float images, so BC6 will be converted to 8-bit on load.
|
||||
// Should use nvtt::Surface instead.
|
||||
nv::DirectDrawSurface dds(input.str());
|
||||
if (!dds.isValid())
|
||||
{
|
||||
fprintf(stderr, "The file '%s' is not a valid DDS file.\n", input.str());
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (!dds.isSupported() || dds.isTexture3D())
|
||||
{
|
||||
fprintf(stderr, "The file '%s' is not a supported DDS file.\n", input.str());
|
||||
return 1;
|
||||
}
|
||||
|
||||
uint faceCount;
|
||||
if (dds.isTexture2D())
|
||||
{
|
||||
faceCount = 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
nvCheck(dds.isTextureCube());
|
||||
faceCount = 6;
|
||||
}
|
||||
|
||||
uint mipmapCount = dds.mipmapCount();
|
||||
|
||||
clock_t start = clock();
|
||||
|
||||
// apply arguments
|
||||
if (forcenormal)
|
||||
{
|
||||
dds.setNormalFlag(true);
|
||||
}
|
||||
if (!faces)
|
||||
{
|
||||
faceCount = 1;
|
||||
}
|
||||
if (!mipmaps)
|
||||
{
|
||||
mipmapCount = 1;
|
||||
}
|
||||
|
||||
nv::Image mipmap;
|
||||
nv::Path name;
|
||||
|
||||
// strip extension, we force the tga extension
|
||||
output.stripExtension();
|
||||
|
||||
// extract faces and mipmaps
|
||||
for (uint f = 0; f < faceCount; f++)
|
||||
{
|
||||
for (uint m = 0; m < mipmapCount; m++)
|
||||
{
|
||||
dds.mipmap(&mipmap, f, m);
|
||||
|
||||
// set output filename, if we are doing faces and/or mipmaps
|
||||
name.copy(output);
|
||||
if (faces) name.appendFormat("_face%d", f);
|
||||
if (mipmaps) name.appendFormat("_mipmap%d", m);
|
||||
name.append(savePNG ? ".png" : ".tga");
|
||||
|
||||
nv::StdOutputStream stream(name.str());
|
||||
if (stream.isError()) {
|
||||
fprintf(stderr, "Error opening '%s' for writting\n", name.str());
|
||||
return 1;
|
||||
}
|
||||
|
||||
nv::ImageIO::save(name.str(), stream, &mipmap);
|
||||
}
|
||||
}
|
||||
|
||||
clock_t end = clock();
|
||||
printf("\rtime taken: %.3f seconds\n", float(end-start) / CLOCKS_PER_SEC);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -23,18 +23,15 @@
|
||||
|
||||
#include "cmdline.h"
|
||||
|
||||
#include "nvmath/Color.h"
|
||||
#include "nvmath/Vector.inl"
|
||||
|
||||
#include "nvimage/Image.h"
|
||||
#include "nvimage/DirectDrawSurface.h"
|
||||
#include "nvtt/nvtt.h"
|
||||
|
||||
#include "nvcore/StrLib.h"
|
||||
#include "nvcore/StdStream.h"
|
||||
#include "nvmath/nvmath.h"
|
||||
|
||||
#include <string.h> // strstr
|
||||
#include <math.h>
|
||||
|
||||
|
||||
/*
|
||||
static bool loadImage(nv::Image & image, const char * fileName)
|
||||
{
|
||||
if (nv::strCaseDiff(nv::Path::extension(fileName), ".dds") == 0)
|
||||
@ -160,7 +157,7 @@ static float luma(const nv::Color32 & c) {
|
||||
//return 0.333f * float(c.r) + 0.334f * float(c.g) + 0.333f * float(c.b);
|
||||
//return 0.1f * float(c.r) + 0.8f * float(c.g) + 0.1f * float(c.g);
|
||||
}
|
||||
|
||||
*/
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
@ -169,6 +166,7 @@ int main(int argc, char *argv[])
|
||||
|
||||
bool compareNormal = false;
|
||||
bool compareAlpha = false;
|
||||
bool rangescale = false;
|
||||
|
||||
nv::Path input0;
|
||||
nv::Path input1;
|
||||
@ -178,14 +176,18 @@ int main(int argc, char *argv[])
|
||||
for (int i = 1; i < argc; i++)
|
||||
{
|
||||
// Input options.
|
||||
if (strcmp("-normal", argv[i]) == 0)
|
||||
if (nv::strEqual("-normal", argv[i]))
|
||||
{
|
||||
compareNormal = true;
|
||||
}
|
||||
else if (strcmp("-alpha", argv[i]) == 0)
|
||||
else if (nv::strEqual("-alpha", argv[i]))
|
||||
{
|
||||
compareAlpha = true;
|
||||
}
|
||||
else if (nv::strEqual("-rangescale", argv[i]))
|
||||
{
|
||||
rangescale = true;
|
||||
}
|
||||
else if (argv[i][0] != '-')
|
||||
{
|
||||
input0 = argv[i];
|
||||
@ -209,12 +211,105 @@ int main(int argc, char *argv[])
|
||||
printf("usage: nvimgdiff [options] original_file updated_file [output]\n\n");
|
||||
|
||||
printf("Diff options:\n");
|
||||
printf(" -normal \tCompare images as if they were normal maps.\n");
|
||||
printf(" -alpha \tCompare alpha weighted images.\n");
|
||||
printf(" -normal Compare images as if they were normal maps.\n");
|
||||
printf(" -alpha Compare alpha weighted images.\n");
|
||||
printf(" -rangescale Scale second image based on range of first one.\n");
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
nvtt::Surface image0, image1;
|
||||
|
||||
if (!image0.load(input0.str())) {
|
||||
printf("Error loading %s.", input0.str());
|
||||
return 1;
|
||||
}
|
||||
if (!image1.load(input1.str())) {
|
||||
printf("Error loading %s.", input1.str());
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (compareNormal) {
|
||||
image0.setNormalMap(true);
|
||||
image1.setNormalMap(true);
|
||||
}
|
||||
if (compareAlpha) {
|
||||
image0.setAlphaMode(nvtt::AlphaMode_Transparency);
|
||||
}
|
||||
|
||||
// Do some transforms based on the naming convention of the file.
|
||||
if (strstr(input1.str(), "rgbm")) {
|
||||
|
||||
//image0.toGamma(2);
|
||||
|
||||
image1.fromRGBM(1.0f, 0.25f);
|
||||
image1.toLinear(2);
|
||||
|
||||
image1.copyChannel(image0, 3); // Copy alpha channel from source.
|
||||
image1.setAlphaMode(nvtt::AlphaMode_Transparency);
|
||||
|
||||
rangescale = true;
|
||||
}
|
||||
|
||||
if (strstr(input1.str(), "bc6")) {
|
||||
// @@ Do any transform that we may have done before compression.
|
||||
|
||||
image1.copyChannel(image0, 3); // Copy alpha channel from source.
|
||||
image1.setAlphaMode(nvtt::AlphaMode_Transparency);
|
||||
}
|
||||
|
||||
|
||||
// Scale second image to range of the first one.
|
||||
if (rangescale) {
|
||||
float min_color[3], max_color[3];
|
||||
image0.range(0, &min_color[0], &max_color[0]);
|
||||
image0.range(1, &min_color[1], &max_color[1]);
|
||||
image0.range(2, &min_color[2], &max_color[2]);
|
||||
float color_range = nv::max3(max_color[0], max_color[1], max_color[2]);
|
||||
|
||||
const float max_color_range = 16.0f;
|
||||
if (color_range > max_color_range) color_range = max_color_range;
|
||||
|
||||
#if 0
|
||||
for (int i = 0; i < 3; i++) {
|
||||
image0.scaleBias(i, 1.0f / color_range, 0.0f);
|
||||
}
|
||||
image0.toneMap(nvtt::ToneMapper_Linear, NULL); // Clamp without changing the hue.
|
||||
#else
|
||||
for (int i = 0; i < 3; i++) {
|
||||
image1.scaleBias(i, color_range, 0.0f);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
float rmse = nvtt::rmsError(image0, image1);
|
||||
//float rmsa = nvtt::rmsAlphaError(image0, image1);
|
||||
|
||||
// In The Witness:
|
||||
// exposure = key_value / luminance
|
||||
// key_value = 0.22
|
||||
// min_luminance = 0.1 -> exposure = 2.2
|
||||
// max_luminance = 1.0 -> exposure = 0.22
|
||||
|
||||
float rmse0 = nvtt::rmsToneMappedError(image0, image1, 2.2f);
|
||||
float rmse1 = nvtt::rmsToneMappedError(image0, image1, 1.0f);
|
||||
float rmse2 = nvtt::rmsToneMappedError(image0, image1, 0.22f);
|
||||
|
||||
printf("RMSE = %.5f %.5f %.5f -> %.5f | %.5f\n", rmse0, rmse1, rmse2, (rmse0 + rmse1 + rmse2)/3, rmse);
|
||||
|
||||
|
||||
//printf("MSE = %f\n", rmse * rmse);
|
||||
//printf("RMSE = %f\n", rmse);
|
||||
//printf("PSNR = %f\n", (rmse == 0) ? 999.0 : 20.0 * log10(255.0 / rmse));
|
||||
|
||||
if (compareNormal) {
|
||||
// @@ Does this assume normal maps are packed or unpacked?
|
||||
float ae = nvtt::angularError(image0, image1);
|
||||
printf("AE = %f\n", ae);
|
||||
}
|
||||
|
||||
|
||||
#if 0
|
||||
nv::Image image0, image1;
|
||||
if (!loadImage(image0, input0.str())) return 0;
|
||||
if (!loadImage(image1, input1.str())) return 0;
|
||||
@ -304,6 +399,7 @@ int main(int argc, char *argv[])
|
||||
error_a.print();
|
||||
}
|
||||
|
||||
#endif
|
||||
// @@ Write image difference.
|
||||
|
||||
return 0;
|
||||
|
Reference in New Issue
Block a user