HDR encoding tests.

pull/216/head
castano 13 years ago
parent e46f48f0a3
commit 6d843c78cf

@ -45,7 +45,7 @@ namespace nv {
void setColourSet(const ColorSet * set);
void setMetric(Vector4::Arg w);
void setMetric(const Vector4 & w);
float bestError() const;
bool compress3(Vector3 * start, Vector3 * end);

@ -22,9 +22,9 @@
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
// OTHER DEALINGS IN THE SOFTWARE.
#include "nvtt.h"
#include "CompressionOptions.h"
#include "nvimage/DirectDrawSurface.h"
#include "nvmath/Vector.inl"
using namespace nv;
using namespace nvtt;

@ -25,9 +25,9 @@
#ifndef NV_TT_COMPRESSIONOPTIONS_H
#define NV_TT_COMPRESSIONOPTIONS_H
#include <nvcore/StrLib.h>
#include <nvmath/Vector.h>
#include "nvtt.h"
#include "nvmath/Vector.h"
#include "nvcore/StrLib.h"
namespace nvtt
{

@ -35,12 +35,14 @@
#include "nvtt.h"
#include "nvcore/Memory.h"
#include "nvimage/Image.h"
#include "nvimage/ColorBlock.h"
#include "nvimage/BlockDXT.h"
#include "nvmath/Vector.inl"
#include "nvcore/Memory.h"
#include <new> // placement new
// s3_quant
@ -79,34 +81,34 @@ using namespace nvtt;
void FastCompressorDXT1::compressBlock(ColorBlock & rgba, nvtt::AlphaMode alphaMode, const nvtt::CompressionOptions::Private & compressionOptions, void * output)
{
BlockDXT1 * block = new(output) BlockDXT1;
QuickCompress::compressDXT1(rgba, block);
BlockDXT1 * block = new(output) BlockDXT1;
QuickCompress::compressDXT1(rgba, block);
}
void FastCompressorDXT1a::compressBlock(ColorBlock & rgba, nvtt::AlphaMode alphaMode, const nvtt::CompressionOptions::Private & compressionOptions, void * output)
{
BlockDXT1 * block = new(output) BlockDXT1;
QuickCompress::compressDXT1a(rgba, block);
BlockDXT1 * block = new(output) BlockDXT1;
QuickCompress::compressDXT1a(rgba, block);
}
void FastCompressorDXT3::compressBlock(ColorBlock & rgba, nvtt::AlphaMode alphaMode, const nvtt::CompressionOptions::Private & compressionOptions, void * output)
{
BlockDXT3 * block = new(output) BlockDXT3;
QuickCompress::compressDXT3(rgba, block);
BlockDXT3 * block = new(output) BlockDXT3;
QuickCompress::compressDXT3(rgba, block);
}
void FastCompressorDXT5::compressBlock(ColorBlock & rgba, nvtt::AlphaMode alphaMode, const nvtt::CompressionOptions::Private & compressionOptions, void * output)
{
BlockDXT5 * block = new(output) BlockDXT5;
QuickCompress::compressDXT5(rgba, block);
BlockDXT5 * block = new(output) BlockDXT5;
QuickCompress::compressDXT5(rgba, block);
}
void FastCompressorDXT5n::compressBlock(ColorBlock & rgba, nvtt::AlphaMode alphaMode, const nvtt::CompressionOptions::Private & compressionOptions, void * output)
{
rgba.swizzle(4, 1, 5, 0); // 0xFF, G, 0, R
rgba.swizzle(4, 1, 5, 0); // 0xFF, G, 0, R
BlockDXT5 * block = new(output) BlockDXT5;
QuickCompress::compressDXT5(rgba, block);
BlockDXT5 * block = new(output) BlockDXT5;
QuickCompress::compressDXT5(rgba, block);
}
#if 1
@ -115,189 +117,189 @@ void NormalCompressorDXT1::compressBlock(ColorSet & set, nvtt::AlphaMode alphaMo
set.setUniformWeights();
set.createMinimalSet(false);
ClusterFit fit;
fit.setMetric(compressionOptions.colorWeight);
ClusterFit fit;
fit.setMetric(compressionOptions.colorWeight);
BlockDXT1 * block = new(output) BlockDXT1;
if (set.isSingleColor(true))
{
{
Color32 c;
c.r = uint8(clamp(set.colors[0].x, 0.0f, 1.0f) * 255);
c.g = uint8(clamp(set.colors[0].y, 0.0f, 1.0f) * 255);
c.b = uint8(clamp(set.colors[0].z, 0.0f, 1.0f) * 255);
c.a = 255;
OptimalCompress::compressDXT1(c, block);
}
else
{
fit.setColourSet(&set);
OptimalCompress::compressDXT1(c, block);
}
else
{
fit.setColourSet(&set);
Vector3 start, end;
fit.compress4(&start, &end);
QuickCompress::outputBlock4(set, start, end, block);
if (fit.compress3(&start, &end)) {
QuickCompress::outputBlock3(set, start, end, block);
}
}
}
}
#else
void NormalCompressorDXT1::compressBlock(ColorBlock & rgba, nvtt::AlphaMode alphaMode, const nvtt::CompressionOptions::Private & compressionOptions, void * output)
{
nvsquish::WeightedClusterFit fit;
fit.SetMetric(compressionOptions.colorWeight.x, compressionOptions.colorWeight.y, compressionOptions.colorWeight.z);
if (rgba.isSingleColor())
{
BlockDXT1 * block = new(output) BlockDXT1;
OptimalCompress::compressDXT1(rgba.color(0), block);
}
else
{
nvsquish::ColourSet colours((uint8 *)rgba.colors(), 0);
fit.SetColourSet(&colours, nvsquish::kDxt1);
fit.Compress(output);
}
nvsquish::WeightedClusterFit fit;
fit.SetMetric(compressionOptions.colorWeight.x, compressionOptions.colorWeight.y, compressionOptions.colorWeight.z);
if (rgba.isSingleColor())
{
BlockDXT1 * block = new(output) BlockDXT1;
OptimalCompress::compressDXT1(rgba.color(0), block);
}
else
{
nvsquish::ColourSet colours((uint8 *)rgba.colors(), 0);
fit.SetColourSet(&colours, nvsquish::kDxt1);
fit.Compress(output);
}
}
#endif
void NormalCompressorDXT1a::compressBlock(ColorBlock & rgba, nvtt::AlphaMode alphaMode, const nvtt::CompressionOptions::Private & compressionOptions, void * output)
{
uint alphaMask = 0;
for (uint i = 0; i < 16; i++)
{
if (rgba.color(i).a == 0) alphaMask |= (3 << (i * 2)); // Set two bits for each color.
}
const bool isSingleColor = rgba.isSingleColor();
if (isSingleColor)
{
BlockDXT1 * block = new(output) BlockDXT1;
for (uint i = 0; i < 16; i++)
{
if (rgba.color(i).a == 0) alphaMask |= (3 << (i * 2)); // Set two bits for each color.
}
const bool isSingleColor = rgba.isSingleColor();
if (isSingleColor)
{
BlockDXT1 * block = new(output) BlockDXT1;
OptimalCompress::compressDXT1a(rgba.color(0), alphaMask, block);
}
else
{
nvsquish::WeightedClusterFit fit;
fit.SetMetric(compressionOptions.colorWeight.x, compressionOptions.colorWeight.y, compressionOptions.colorWeight.z);
}
else
{
nvsquish::WeightedClusterFit fit;
fit.SetMetric(compressionOptions.colorWeight.x, compressionOptions.colorWeight.y, compressionOptions.colorWeight.z);
int flags = nvsquish::kDxt1;
if (alphaMode == nvtt::AlphaMode_Transparency) flags |= nvsquish::kWeightColourByAlpha;
int flags = nvsquish::kDxt1;
if (alphaMode == nvtt::AlphaMode_Transparency) flags |= nvsquish::kWeightColourByAlpha;
nvsquish::ColourSet colours((uint8 *)rgba.colors(), flags);
fit.SetColourSet(&colours, nvsquish::kDxt1);
nvsquish::ColourSet colours((uint8 *)rgba.colors(), flags);
fit.SetColourSet(&colours, nvsquish::kDxt1);
fit.Compress(output);
}
fit.Compress(output);
}
}
void NormalCompressorDXT3::compressBlock(ColorBlock & rgba, nvtt::AlphaMode alphaMode, const nvtt::CompressionOptions::Private & compressionOptions, void * output)
{
BlockDXT3 * block = new(output) BlockDXT3;
// Compress explicit alpha.
OptimalCompress::compressDXT3A(rgba, &block->alpha);
// Compress color.
if (rgba.isSingleColor())
{
OptimalCompress::compressDXT1(rgba.color(0), &block->color);
}
else
{
nvsquish::WeightedClusterFit fit;
fit.SetMetric(compressionOptions.colorWeight.x, compressionOptions.colorWeight.y, compressionOptions.colorWeight.z);
int flags = 0;
if (alphaMode == nvtt::AlphaMode_Transparency) flags |= nvsquish::kWeightColourByAlpha;
nvsquish::ColourSet colours((uint8 *)rgba.colors(), flags);
fit.SetColourSet(&colours, 0);
fit.Compress(&block->color);
}
BlockDXT3 * block = new(output) BlockDXT3;
// Compress explicit alpha.
OptimalCompress::compressDXT3A(rgba, &block->alpha);
// Compress color.
if (rgba.isSingleColor())
{
OptimalCompress::compressDXT1(rgba.color(0), &block->color);
}
else
{
nvsquish::WeightedClusterFit fit;
fit.SetMetric(compressionOptions.colorWeight.x, compressionOptions.colorWeight.y, compressionOptions.colorWeight.z);
int flags = 0;
if (alphaMode == nvtt::AlphaMode_Transparency) flags |= nvsquish::kWeightColourByAlpha;
nvsquish::ColourSet colours((uint8 *)rgba.colors(), flags);
fit.SetColourSet(&colours, 0);
fit.Compress(&block->color);
}
}
void NormalCompressorDXT5::compressBlock(ColorBlock & rgba, nvtt::AlphaMode alphaMode, const nvtt::CompressionOptions::Private & compressionOptions, void * output)
{
BlockDXT5 * block = new(output) BlockDXT5;
// Compress alpha.
if (compressionOptions.quality == Quality_Highest)
{
OptimalCompress::compressDXT5A(rgba, &block->alpha);
}
else
{
QuickCompress::compressDXT5A(rgba, &block->alpha);
}
// Compress color.
if (rgba.isSingleColor())
{
OptimalCompress::compressDXT1(rgba.color(0), &block->color);
}
else
{
nvsquish::WeightedClusterFit fit;
fit.SetMetric(compressionOptions.colorWeight.x, compressionOptions.colorWeight.y, compressionOptions.colorWeight.z);
int flags = 0;
if (alphaMode == nvtt::AlphaMode_Transparency) flags |= nvsquish::kWeightColourByAlpha;
nvsquish::ColourSet colours((uint8 *)rgba.colors(), flags);
fit.SetColourSet(&colours, 0);
fit.Compress(&block->color);
}
BlockDXT5 * block = new(output) BlockDXT5;
// Compress alpha.
if (compressionOptions.quality == Quality_Highest)
{
OptimalCompress::compressDXT5A(rgba, &block->alpha);
}
else
{
QuickCompress::compressDXT5A(rgba, &block->alpha);
}
// Compress color.
if (rgba.isSingleColor())
{
OptimalCompress::compressDXT1(rgba.color(0), &block->color);
}
else
{
nvsquish::WeightedClusterFit fit;
fit.SetMetric(compressionOptions.colorWeight.x, compressionOptions.colorWeight.y, compressionOptions.colorWeight.z);
int flags = 0;
if (alphaMode == nvtt::AlphaMode_Transparency) flags |= nvsquish::kWeightColourByAlpha;
nvsquish::ColourSet colours((uint8 *)rgba.colors(), flags);
fit.SetColourSet(&colours, 0);
fit.Compress(&block->color);
}
}
void NormalCompressorDXT5n::compressBlock(ColorBlock & rgba, nvtt::AlphaMode alphaMode, const nvtt::CompressionOptions::Private & compressionOptions, void * output)
{
BlockDXT5 * block = new(output) BlockDXT5;
// Compress Y.
if (compressionOptions.quality == Quality_Highest)
{
OptimalCompress::compressDXT1G(rgba, &block->color);
}
else
{
if (rgba.isSingleColor(Color32(0, 0xFF, 0, 0))) // Mask all but green channel.
{
OptimalCompress::compressDXT1G(rgba.color(0).g, &block->color);
}
else
{
BlockDXT5 * block = new(output) BlockDXT5;
// Compress Y.
if (compressionOptions.quality == Quality_Highest)
{
OptimalCompress::compressDXT1G(rgba, &block->color);
}
else
{
if (rgba.isSingleColor(Color32(0, 0xFF, 0, 0))) // Mask all but green channel.
{
OptimalCompress::compressDXT1G(rgba.color(0).g, &block->color);
}
else
{
ColorBlock tile = rgba;
tile.swizzle(4, 1, 5, 3); // leave alpha in alpha channel.
nvsquish::WeightedClusterFit fit;
fit.SetMetric(0, 1, 0);
int flags = 0;
if (alphaMode == nvtt::AlphaMode_Transparency) flags |= nvsquish::kWeightColourByAlpha;
nvsquish::ColourSet colours((uint8 *)tile.colors(), flags);
fit.SetColourSet(&colours, 0);
fit.Compress(&block->color);
}
}
rgba.swizzle(4, 1, 5, 0); // 1, G, 0, R
// Compress X.
if (compressionOptions.quality == Quality_Highest)
{
OptimalCompress::compressDXT5A(rgba, &block->alpha);
}
else
{
QuickCompress::compressDXT5A(rgba, &block->alpha);
}
nvsquish::WeightedClusterFit fit;
fit.SetMetric(0, 1, 0);
int flags = 0;
if (alphaMode == nvtt::AlphaMode_Transparency) flags |= nvsquish::kWeightColourByAlpha;
nvsquish::ColourSet colours((uint8 *)tile.colors(), flags);
fit.SetColourSet(&colours, 0);
fit.Compress(&block->color);
}
}
rgba.swizzle(4, 1, 5, 0); // 1, G, 0, R
// Compress X.
if (compressionOptions.quality == Quality_Highest)
{
OptimalCompress::compressDXT5A(rgba, &block->alpha);
}
else
{
QuickCompress::compressDXT5A(rgba, &block->alpha);
}
}

@ -24,16 +24,16 @@
#include "CompressorDXT.h"
#include "OutputOptions.h"
#include "nvtt.h"
#include "TaskDispatcher.h"
#include "nvcore/Memory.h"
#include "nvimage/Image.h"
#include "nvimage/ColorBlock.h"
#include "nvimage/BlockDXT.h"
#include "nvmath/Vector.inl"
#include "nvcore/Memory.h"
#include <new> // placement new

@ -31,6 +31,7 @@
#include "nvcore/Array.h"
#include "nvcore/StrLib.h"
#include <float.h> // FLT_MAX
using namespace nv;
using namespace nvtt;

@ -716,38 +716,39 @@ void QuickCompress::outputBlock4(const ColorSet & set, const Vector3 & start, co
{
Vector3 minColor = start * 255;
Vector3 maxColor = end * 255;
uint16 color0 = roundAndExpand(&maxColor);
uint16 color1 = roundAndExpand(&minColor);
uint16 color0 = roundAndExpand(&maxColor);
uint16 color1 = roundAndExpand(&minColor);
if (color0 < color1)
{
swap(maxColor, minColor);
swap(color0, color1);
}
if (color0 < color1)
{
swap(maxColor, minColor);
swap(color0, color1);
}
block->col0 = Color16(color0);
block->col1 = Color16(color1);
block->indices = computeIndices4(set, maxColor / 255, minColor / 255);
block->col0 = Color16(color0);
block->col1 = Color16(color1);
block->indices = computeIndices4(set, maxColor / 255, minColor / 255);
//optimizeEndPoints4(set, block);
//optimizeEndPoints4(set, block);
}
void QuickCompress::outputBlock3(const ColorSet & set, const Vector3 & start, const Vector3 & end, BlockDXT1 * block)
{
Vector3 minColor = start * 255;
Vector3 maxColor = end * 255;
uint16 color0 = roundAndExpand(&minColor);
uint16 color1 = roundAndExpand(&maxColor);
uint16 color0 = roundAndExpand(&minColor);
uint16 color1 = roundAndExpand(&maxColor);
if (color0 > color1)
{
swap(maxColor, minColor);
swap(color0, color1);
}
if (color0 > color1)
{
swap(maxColor, minColor);
swap(color0, color1);
}
block->col0 = Color16(color0);
block->col1 = Color16(color1);
block->col0 = Color16(color0);
block->col1 = Color16(color1);
block->indices = computeIndices3(set, maxColor / 255, minColor / 255);
//optimizeEndPoints3(set, block);
}
//optimizeEndPoints3(set, block);
}

@ -93,6 +93,11 @@ namespace
}
return 0;
}
/*static int translateMask(int input) {
if (input > 0) return 1 << input;
return ~input;
}*/
}
uint nv::countMipmaps(uint w)
@ -372,19 +377,22 @@ void Surface::histogram(int channel, float rangeMin, float rangeMax, int binCoun
}
}
void Surface::range(int channel, float * rangeMin, float * rangeMax)
void Surface::range(int channel, float * rangeMin, float * rangeMax) const
{
Vector2 range(FLT_MAX, -FLT_MAX);
FloatImage * img = m->image;
float * c = img->channel(channel);
const uint count = img->pixelCount();
for (uint p = 0; p < count; p++) {
float f = c[p];
if (f < range.x) range.x = f;
if (f > range.y)
range.y = f;
if (m->image != NULL)
{
float * c = img->channel(channel);
const uint count = img->pixelCount();
for (uint p = 0; p < count; p++) {
float f = c[p];
if (f < range.x) range.x = f;
if (f > range.y) range.y = f;
}
}
*rangeMin = range.x;
@ -1863,9 +1871,9 @@ void Surface::toneMap(ToneMapper tm, float * parameters)
}
else if (tm == ToneMapper_Halo) {
for (uint i = 0; i < count; i++) {
r[i] = 1 - expf(-r[i]);
g[i] = 1 - expf(-g[i]);
b[i] = 1 - expf(-b[i]);
r[i] = 1 - exp2f(-r[i]);
g[i] = 1 - exp2f(-g[i]);
b[i] = 1 - exp2f(-b[i]);
}
}
else if (tm == ToneMapper_Lightmap) {
@ -1884,6 +1892,39 @@ void Surface::toneMap(ToneMapper tm, float * parameters)
}
}
void Surface::toLogScale(int channel, float base) {
if (isNull()) return;
detach();
FloatImage * img = m->image;
float * c = img->channel(channel);
float scale = 1.0f / log2f(base);
const uint count = img->pixelCount();
for (uint i = 0; i < count; i++) {
c[i] = log2f(c[i]) * scale;
}
}
void Surface::fromLogScale(int channel, float base) {
if (isNull()) return;
detach();
FloatImage * img = m->image;
float * c = img->channel(channel);
float scale = log2f(base);
const uint count = img->pixelCount();
for (uint i = 0; i < count; i++) {
c[i] = exp2f(c[i] * scale);
}
}
/*
void Surface::blockLuminanceScale(float scale)

@ -420,6 +420,12 @@ namespace nvtt
ToneMapper_Lightmap,
};
/*enum ChannelMask {
R = 0x70000001,
G = 0x70000002,
B = 0x70000004,
A = 0x70000008,
};*/
// A surface is one level of a 2D or 3D texture.
// @@ It would be nice to add support for texture borders for correct resizing of tiled textures and constrained DXT compression.
@ -450,7 +456,7 @@ namespace nvtt
NVTT_API float average(int channel, int alpha_channel = -1, float gamma = 2.2f) const;
NVTT_API const float * data() const;
NVTT_API void histogram(int channel, float rangeMin, float rangeMax, int binCount, int * binPtr) const;
NVTT_API void range(int channel, float * rangeMin, float * rangeMax);
NVTT_API void range(int channel, float * rangeMin, float * rangeMax) const;
// Texture data.
NVTT_API bool load(const char * fileName, bool * hasAlpha = 0);
@ -500,6 +506,8 @@ namespace nvtt
NVTT_API void fromLUVW(float range = 1.0f);
NVTT_API void abs(int channel);
NVTT_API void convolve(int channel, int kernelSize, float * kernelData);
NVTT_API void toLogScale(int channel, float base);
NVTT_API void fromLogScale(int channel, float base);
NVTT_API void toneMap(ToneMapper tm, float * parameters);

@ -25,7 +25,10 @@ TARGET_LINK_LIBRARIES(process_alpha_map nvcore nvmath nvimage nvtt)
ADD_EXECUTABLE(cubemaptest cubemaptest.cpp)
TARGET_LINK_LIBRARIES(cubemaptest nvcore nvmath nvimage nvtt)
INSTALL(TARGETS nvtestsuite DESTINATION bin)
ADD_EXECUTABLE(nvhdrtest hdrtest.cpp)
TARGET_LINK_LIBRARIES(nvhdrtest nvcore nvmath nvimage nvtt)
INSTALL(TARGETS nvtestsuite nvhdrtest DESTINATION bin)
#include_directories("/usr/include/ffmpeg/")
#ADD_EXECUTABLE(nvmpegenc tools/mpegenc.cpp tools/cmdline.h)

@ -0,0 +1,164 @@
#include "nvmath/Vector.inl"
#include "nvcore/StrLib.h"
namespace nv {
struct GooglePointSet {
GooglePointSet();
Vector2 min, max;
Array<Vector2> points;
const char * legend;
Vector3 lineColor;
int lineWidth;
bool dashed;
int lineSegmentLength;
int blankSegmentLength;
};
struct GoogleLineChart {
GoogleLineChart();
void autoScale();
void build(nv::StringBuilder & builder) const;
const char * title;
int width;
int height;
int leftMargin;
int rightMargin;
int topMargin;
int bottomMargin;
int legendPosition;
Array<GooglePointSet> pointSetArray;
};
GooglePointSet::GooglePointSet()
{
min.x = 0;
min.y = 0;
max.x = 1;
max.x = 1;
legend = NULL;
lineColor = Vector3(1, 0, 0);
lineWidth = 2;
dashed = false;
lineSegmentLength = 4;
blankSegmentLength = 1;
}
GoogleLineChart::GoogleLineChart()
{
title = NULL;
width = 440;
height = 220;
leftMargin = 5;
rightMargin = 5;
topMargin = 5;
bottomMargin = 25;
legendPosition = 3; // bottom
}
void GoogleLineChart::autoScale()
{
Vector2 minimum, maximum;
foreach(i, pointSetArray) {
foreach(p, pointSetArray[i].points) {
Vector2 point = pointSetArray[i].points[p];
minimum = min(minimum, point);
maximum = max(maximum, point);
}
}
foreach(i, pointSetArray) {
pointSetArray[i].min = minimum;
pointSetArray[i].max = maximum;
}
}
void GoogleLineChart::build(nv::StringBuilder & builder) const
{
const uint lineCount = pointSetArray.count();
builder.reset();
// Start LineChartXY.
builder.copy("http://chart.apis.google.com/chart?cht=lxy");
// Size.
builder.appendFormat("&chs=%dx%d", width, height);
// Title.
if (title != NULL) builder.appendFormat("&chtt=%s", title);
// Margins.
builder.appendFormat("&chma=%d,%d,%d,%d", leftMargin, rightMargin, topMargin, bottomMargin);
// Legend position.
builder.appendFormat("&chdlp=%c", "lrtb"[legendPosition]);
// Line colors.
builder.append("&chco=");
for (uint i = 0; i < lineCount; i++) {
const GooglePointSet & set = pointSetArray[i];
builder.appendFormat("%.2X%.2X%.2X", int(255 * set.lineColor.x), int(255 * set.lineColor.y), int(255 * set.lineColor.z));
if (i != lineCount-1) builder.append(",");
}
// Legends.
builder.append("&chdl=");
for (uint i = 0; i < lineCount; i++) {
const GooglePointSet & set = pointSetArray[i];
if (set.legend != NULL) builder.append(set.legend);
if (i != lineCount-1) builder.append("|");
}
// Line format.
builder.append("&chls=");
for (uint i = 0; i < lineCount; i++) {
const GooglePointSet & set = pointSetArray[i];
builder.appendFormat("%d", set.lineWidth);
if (set.dashed) builder.appendFormat(",%d,%d", set.lineSegmentLength, set.blankSegmentLength);
if (i != lineCount-1) builder.append("|");
}
// Scaling.
builder.append("&chds=");
for (uint i = 0; i < lineCount; i++) {
const GooglePointSet & set = pointSetArray[i];
builder.appendFormat("%f,%f,%f,%f", set.min.x, set.max.x, set.min.y, set.max.y);
if (i != lineCount-1) builder.append(",");
}
// Data.
builder.append("&chd=t:");
for (uint i = 0; i < lineCount; i++) {
const GooglePointSet & set = pointSetArray[i];
const uint pointCount = set.points.count();
/*for (uint p = 0; p < pointCount; p++) {
builder.appendFormat("%f", set.points[p].x);
if (p != pointCount-1) builder.append(",");
}*/
builder.append("-1");
builder.append("|");
for (uint p = 0; p < pointCount; p++) {
builder.appendFormat("%f", set.points[p].y);
if (p != pointCount-1) builder.append(",");
}
if (i != lineCount-1) builder.append("|");
}
}
} // nv namespace

@ -0,0 +1,359 @@
// Copyright (c) 2009-2011 Ignacio Castano <castano@gmail.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 <nvtt/nvtt.h>
#include <nvimage/Image.h>
#include <nvimage/ImageIO.h>
#include <nvimage/BlockDXT.h>
#include <nvimage/ColorBlock.h>
#include <nvcore/Ptr.h>
#include <nvcore/Debug.h>
#include <nvcore/StrLib.h>
#include <nvcore/StdStream.h>
#include <nvcore/TextWriter.h>
#include <nvcore/FileSystem.h>
#include <nvcore/Timer.h>
#include <stdlib.h> // free
#include <string.h> // memcpy
#include <float.h> // FLT_MAX
#include "../tools/cmdline.h"
#include "GoogleCharts.h"
using namespace nv;
using namespace nvtt;
static const char * s_hdrImageSet[] = {
"specruin.dds",
"cottage.dds",
"tower.dds",
};
struct MyOutputHandler : public nvtt::OutputHandler
{
MyOutputHandler() : m_data(NULL), m_ptr(NULL) {}
~MyOutputHandler()
{
free(m_data);
}
virtual void beginImage(int size, int width, int height, int depth, int face, int miplevel)
{
m_size = size;
m_width = width;
m_height = height;
free(m_data);
m_data = (unsigned char *)malloc(size);
m_ptr = m_data;
}
virtual void endImage()
{
}
virtual bool writeData(const void * data, int size)
{
memcpy(m_ptr, data, size);
m_ptr += size;
return true;
}
nvtt::Surface decompress(nvtt::Format format, nvtt::Decoder decoder)
{
nvtt::Surface img;
img.setImage2D(format, decoder, m_width, m_height, m_data);
return img;
}
int m_size;
int m_width;
int m_height;
unsigned char * m_data;
unsigned char * m_ptr;
};
// Compare two HDR surfaces tone mapped at the given exposure.
float compare(const Surface & hdr0, const Surface & hdr1, float exposure)
{
Surface ldr0 = hdr0;
ldr0.scaleBias(0, exposure, 0);
ldr0.scaleBias(1, exposure, 0);
ldr0.scaleBias(2, exposure, 0);
ldr0.toneMap(nvtt::ToneMapper_Halo, NULL);
ldr0.toSrgb();
Surface ldr1 = hdr1;
ldr1.scaleBias(0, exposure, 0);
ldr1.scaleBias(1, exposure, 0);
ldr1.scaleBias(2, exposure, 0);
ldr1.toneMap(nvtt::ToneMapper_Halo, NULL);
ldr1.toSrgb();
return nvtt::rmsError(ldr0, ldr1);
}
// Compare two HDR images at different exposures.
void compare(const Surface & hdr0, const Surface & hdr1, const Array<float> & exposures, Array<float> & errors)
{
const uint exposureCount = exposures.count();
errors.resize(exposureCount);
for (uint i = 0; i < exposureCount; i++) {
errors[i] = compare(hdr0, hdr1, exposures[i]);
}
}
void updatePointSet(const Array<float> & exposures, Array<float> & errors, GooglePointSet & pointSet)
{
uint pointCount = exposures.count();
nvDebugCheck(pointCount == errors.count());
pointSet.points.resize(pointCount);
for (uint i = 0; i < pointCount; i++) {
pointSet.points[i].x = exposures[i];
pointSet.points[i].y = errors[i];
}
}
Surface loadInput(const char * fileName) {
Surface src;
src.load(fileName);
src.clamp(0, 0, FLT_MAX);
src.clamp(1, 0, FLT_MAX);
src.clamp(2, 0, FLT_MAX);
return src;
}
Surface process(const Surface & src, int method) {
Surface dst;
float rMin, rMax, gMin, gMax, bMin, bMax;
src.range(0, &rMin, &rMax);
src.range(1, &gMin, &gMax);
src.range(2, &bMin, &bMax);
if (method == 0) {
// Only clamp.
dst = src;
dst.scaleBias(0, 1.0f / 4, 0);
dst.scaleBias(1, 1.0f / 4, 0);
dst.scaleBias(2, 1.0f / 4, 0);
dst.clamp(0, 0, 1);
dst.clamp(1, 0, 1);
dst.clamp(2, 0, 1);
dst.toGamma(0, 2);
dst.toGamma(1, 2);
dst.toGamma(2, 2);
dst.quantize(0, 10, /*exactEndPoints*/true, false);
dst.quantize(1, 10, /*exactEndPoints*/true, false);
dst.quantize(2, 10, /*exactEndPoints*/true, false);
dst.toLinear(0, 2);
dst.toLinear(1, 2);
dst.toLinear(2, 2);
dst.scaleBias(0, 4, 0);
dst.scaleBias(1, 4, 0);
dst.scaleBias(2, 4, 0);
}
else if (method == 1) {
// Scale and bias. Use full range.
dst = src;
float gamma = 3;
dst.scaleBias(0, 1.0f / rMax, 0);
dst.scaleBias(1, 1.0f / gMax, 0);
dst.scaleBias(2, 1.0f / bMax, 0);
dst.clamp(0, 0, 1);
dst.clamp(1, 0, 1);
dst.clamp(2, 0, 1);
dst.toGamma(0, gamma);
dst.toGamma(1, gamma);
dst.toGamma(2, gamma);
dst.quantize(0, 10, /*exactEndPoints*/true, false);
dst.quantize(1, 10, /*exactEndPoints*/true, false);
dst.quantize(2, 10, /*exactEndPoints*/true, false);
dst.toLinear(0, gamma);
dst.toLinear(1, gamma);
dst.toLinear(2, gamma);
dst.scaleBias(0, rMax, 0);
dst.scaleBias(1, gMax, 0);
dst.scaleBias(2, bMax, 0);
}
else if (method == 2) {
// Scale and bias. Use full range.
dst = src;
// @@ Experiment with log/exp transform!
float gamma = 2.2;
dst.scaleBias(0, 1.0f / rMax, 0);
dst.scaleBias(1, 1.0f / gMax, 0);
dst.scaleBias(2, 1.0f / bMax, 0);
dst.clamp(0, 0, 1);
dst.clamp(1, 0, 1);
dst.clamp(2, 0, 1);
//dst.toGamma(0, gamma);
//dst.toGamma(1, gamma);
//dst.toGamma(2, gamma);
dst.toLogScale(0, 2);
dst.toLogScale(1, 2);
dst.toLogScale(2, 2);
dst.quantize(0, 10, /*exactEndPoints*/true, false);
dst.quantize(1, 10, /*exactEndPoints*/true, false);
dst.quantize(2, 10, /*exactEndPoints*/true, false);
dst.fromLogScale(0, 2);
dst.fromLogScale(1, 2);
dst.fromLogScale(2, 2);
//dst.toLinear(0, gamma);
//dst.toLinear(1, gamma);
//dst.toLinear(2, gamma);
dst.scaleBias(0, rMax, 0);
dst.scaleBias(1, gMax, 0);
dst.scaleBias(2, bMax, 0);
}
else if (method == 3) {
// Scale and bias. Use full range.
dst = src;
// @@ Experiment with log/exp transform!
float gamma = 0.5;
dst.scaleBias(0, 1.0f / rMax, 0);
dst.scaleBias(1, 1.0f / gMax, 0);
dst.scaleBias(2, 1.0f / bMax, 0);
dst.clamp(0, 0, 1);
dst.clamp(1, 0, 1);
dst.clamp(2, 0, 1);
dst.toGamma(0, gamma);
dst.toGamma(1, gamma);
dst.toGamma(2, gamma);
dst.toLogScale(0, 2);
dst.toLogScale(1, 2);
dst.toLogScale(2, 2);
dst.quantize(0, 8, /*exactEndPoints*/true, false);
dst.quantize(1, 8, /*exactEndPoints*/true, false);
dst.quantize(2, 8, /*exactEndPoints*/true, false);
dst.fromLogScale(0, 2);
dst.fromLogScale(1, 2);
dst.fromLogScale(2, 2);
dst.toLinear(0, gamma);
dst.toLinear(1, gamma);
dst.toLinear(2, gamma);
dst.scaleBias(0, rMax, 0);
dst.scaleBias(1, gMax, 0);
dst.scaleBias(2, bMax, 0);
}
return dst;
}
void printImageInfo(const Surface & img) {
float rMin, rMax, gMin, gMax, bMin, bMax;
img.range(0, &rMin, &rMax);
img.range(1, &gMin, &gMax);
img.range(2, &bMin, &bMax);
printf("R: %f %f\n", rMin, rMax);
printf("G: %f %f\n", gMin, gMax);
printf("B: %f %f\n", bMin, bMax);
}
int main(int argc, char *argv[])
{
MyAssertHandler assertHandler;
MyMessageHandler messageHandler;
GoogleLineChart chart;
chart.pointSetArray.resize(2);
Array<float> errors;
Array<float> exposures;
for (int i = 0; i < 48; i++) {
//exposures.append(8 * float(i)/63);
exposures.append(lerp(0.22, 22, float(i)/47));
}
Surface src = loadInput("hdr/34017_03.dds");
//Surface src = loadInput("hdr/49002_1F.dds");
if (src.isNull()) {
printf("Error loading image.\n");
return EXIT_FAILURE;
}
printImageInfo(src);
//compare(src, process(src, 0), exposures, errors);
//updatePointSet(exposures, errors, chart.pointSetArray[0]);
//chart.pointSetArray[0].legend = "Clamp";
compare(src, process(src, 0), exposures, errors);
updatePointSet(exposures, errors, chart.pointSetArray[0]);
chart.pointSetArray[0].legend = "Default";
compare(src, process(src, 3), exposures, errors);
updatePointSet(exposures, errors, chart.pointSetArray[1]);
chart.pointSetArray[1].legend = "Log + Gamma 2.2";
chart.pointSetArray[1].lineColor = Vector3(0.19, 0.45, 0.95);
chart.autoScale();
StringBuilder builder;
chart.build(builder);
printf("%s\n", builder.str());
return EXIT_SUCCESS;
}

@ -51,6 +51,7 @@ struct MyMessageHandler : public nv::MessageHandler {
struct MyAssertHandler : public nv::AssertHandler {
MyAssertHandler() {
nv::debug::setAssertHandler( this );
nv::debug::enableSigHandler();
}
~MyAssertHandler() {
nv::debug::resetAssertHandler();

Loading…
Cancel
Save