Merge changes from the Witness.
This commit is contained in:
@ -40,6 +40,10 @@
|
||||
#include <float.h>
|
||||
#include <string.h> // memset, memcpy
|
||||
|
||||
#if NV_CC_GNUC
|
||||
#include <math.h> // exp2f and log2f
|
||||
#endif
|
||||
|
||||
using namespace nv;
|
||||
using namespace nvtt;
|
||||
|
||||
@ -101,6 +105,20 @@ namespace
|
||||
}*/
|
||||
}
|
||||
|
||||
bool nv::canMakeNextMipmap(uint w, uint h, uint d, uint min_size)
|
||||
{
|
||||
if (min_size==1u) {
|
||||
if(w==1u && h==1u && d==1u) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
else if (((w <= min_size || h <= min_size) && d == 1u)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
uint nv::countMipmaps(uint w)
|
||||
{
|
||||
uint mipmap = 0;
|
||||
@ -127,6 +145,21 @@ uint nv::countMipmaps(uint w, uint h, uint d)
|
||||
return mipmap + 1;
|
||||
}
|
||||
|
||||
uint nv::countMipmapsWithMinSize(uint w, uint h, uint d, uint min_size)
|
||||
{
|
||||
uint mipmap = 0;
|
||||
|
||||
while (canMakeNextMipmap(w, h, d, min_size)) {
|
||||
w = max(1U, w / 2);
|
||||
h = max(1U, h / 2);
|
||||
d = max(1U, d / 2);
|
||||
mipmap++;
|
||||
}
|
||||
|
||||
return mipmap + 1;
|
||||
}
|
||||
|
||||
|
||||
uint nv::computeImageSize(uint w, uint h, uint d, uint bitCount, uint pitchAlignmentInBytes, Format format)
|
||||
{
|
||||
if (format == Format_RGBA) {
|
||||
@ -308,10 +341,18 @@ int Surface::countMipmaps() const
|
||||
return ::countMipmaps(m->image->width(), m->image->height(), 1);
|
||||
}
|
||||
|
||||
int Surface::countMipmaps(int min_size) const
|
||||
{
|
||||
if (m->image == NULL) return 0;
|
||||
return ::countMipmapsWithMinSize(m->image->width(), m->image->height(), 1, min_size);
|
||||
}
|
||||
|
||||
float Surface::alphaTestCoverage(float alphaRef/*= 0.5*/) const
|
||||
{
|
||||
if (m->image == NULL) return 0.0f;
|
||||
|
||||
alphaRef = nv::clamp(alphaRef, 1.0f/256, 255.0f/256);
|
||||
|
||||
return m->image->alphaTestCoverage(alphaRef, 3);
|
||||
}
|
||||
|
||||
@ -348,7 +389,7 @@ float Surface::average(int channel, int alpha_channel/*= -1*/, float gamma /*= 2
|
||||
// Avoid division by zero.
|
||||
if (denom == 0.0f) return 0.0f;
|
||||
|
||||
return sum / denom;
|
||||
return powf(sum / denom, 1.0f/gamma);
|
||||
}
|
||||
|
||||
const float * Surface::data() const
|
||||
@ -356,6 +397,13 @@ const float * Surface::data() const
|
||||
return m->image->channel(0);
|
||||
}
|
||||
|
||||
const float * Surface::channel(int i) const
|
||||
{
|
||||
if (i < 0 || i > 3) return NULL;
|
||||
return m->image->channel(i);
|
||||
}
|
||||
|
||||
|
||||
void Surface::histogram(int channel, float rangeMin, float rangeMax, int binCount, int * binPtr) const
|
||||
{
|
||||
// We assume it's clear in case we want to accumulate multiple histograms.
|
||||
@ -378,12 +426,14 @@ void Surface::histogram(int channel, float rangeMin, float rangeMax, int binCoun
|
||||
}
|
||||
}
|
||||
|
||||
void Surface::range(int channel, float * rangeMin, float * rangeMax) const
|
||||
void Surface::range(int channel, float * rangeMin, float * rangeMax, int alpha_channel/*= -1*/, float alpha_ref/*= 0.f*/) const
|
||||
{
|
||||
Vector2 range(FLT_MAX, -FLT_MAX);
|
||||
|
||||
FloatImage * img = m->image;
|
||||
|
||||
if (alpha_channel == -1) { // no alpha channel; just like the original range function
|
||||
|
||||
if (m->image != NULL)
|
||||
{
|
||||
float * c = img->channel(channel);
|
||||
@ -395,6 +445,25 @@ void Surface::range(int channel, float * rangeMin, float * rangeMax) const
|
||||
if (f > range.y) range.y = f;
|
||||
}
|
||||
}
|
||||
}
|
||||
else { // use alpha test to ignore some pixels
|
||||
//note, it's quite possible to get FLT_MAX,-FLT_MAX back if all pixels fail the test
|
||||
|
||||
if (m->image != NULL)
|
||||
{
|
||||
const float * c = img->channel(channel);
|
||||
const float * a = img->channel(alpha_channel);
|
||||
|
||||
const uint count = img->pixelCount();
|
||||
for (uint p = 0; p < count; p++) {
|
||||
if(a[p]>alpha_ref) {
|
||||
float f = c[p];
|
||||
if (f < range.x) range.x = f;
|
||||
if (f > range.y) range.y = f;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
*rangeMin = range.x;
|
||||
*rangeMax = range.y;
|
||||
@ -423,16 +492,44 @@ bool Surface::load(const char * fileName, bool * hasAlpha/*= NULL*/)
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Surface::save(const char * fileName) const
|
||||
bool Surface::save(const char * fileName, bool hasAlpha/*=0*/, bool hdr/*=0*/) const
|
||||
{
|
||||
if (m->image != NULL)
|
||||
{
|
||||
return ImageIO::saveFloat(fileName, m->image, 0, 4);
|
||||
if (m->image == NULL) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return false;
|
||||
if (hdr) {
|
||||
return ImageIO::saveFloat(fileName, m->image, 0, 4);
|
||||
}
|
||||
else {
|
||||
AutoPtr<Image> image(m->image->createImage(0, 4));
|
||||
nvCheck(image != NULL);
|
||||
|
||||
if (hasAlpha) {
|
||||
image->setFormat(Image::Format_ARGB);
|
||||
}
|
||||
|
||||
return ImageIO::save(fileName, image.ptr());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
bool Surface::setImage(int w, int h, int d)
|
||||
{
|
||||
detach();
|
||||
|
||||
if (m->image == NULL) {
|
||||
m->image = new FloatImage();
|
||||
}
|
||||
m->image->allocate(4, w, h, d);
|
||||
m->type = (d == 1) ? TextureType_2D : TextureType_3D;
|
||||
|
||||
m->image->clear();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
#if 0 //NV_OS_WIN32
|
||||
|
||||
#include <windows.h>
|
||||
@ -449,13 +546,14 @@ static int filter(unsigned int code, struct _EXCEPTION_POINTERS *ep) {
|
||||
}
|
||||
|
||||
#define TRY __try
|
||||
|
||||
#define CATCH __except (filter(GetExceptionCode(), GetExceptionInformation()))
|
||||
#else
|
||||
|
||||
#else // 0
|
||||
|
||||
#define TRY if (true)
|
||||
#define CATCH else
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
bool Surface::setImage(nvtt::InputFormat format, int w, int h, int d, const void * data)
|
||||
{
|
||||
@ -553,13 +651,13 @@ bool Surface::setImage(InputFormat format, int w, int h, int d, const void * r,
|
||||
const uint8 * bsrc = (const uint8 *)b;
|
||||
const uint8 * asrc = (const uint8 *)a;
|
||||
|
||||
try {
|
||||
TRY {
|
||||
for (int i = 0; i < count; i++) rdst[i] = float(rsrc[i]) / 255.0f;
|
||||
for (int i = 0; i < count; i++) gdst[i] = float(gsrc[i]) / 255.0f;
|
||||
for (int i = 0; i < count; i++) bdst[i] = float(bsrc[i]) / 255.0f;
|
||||
for (int i = 0; i < count; i++) adst[i] = float(asrc[i]) / 255.0f;
|
||||
}
|
||||
catch(...) {
|
||||
CATCH {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@ -570,13 +668,13 @@ bool Surface::setImage(InputFormat format, int w, int h, int d, const void * r,
|
||||
const uint16 * bsrc = (const uint16 *)b;
|
||||
const uint16 * asrc = (const uint16 *)a;
|
||||
|
||||
try {
|
||||
TRY {
|
||||
for (int i = 0; i < count; i++) ((uint32 *)rdst)[i] = half_to_float(rsrc[i]);
|
||||
for (int i = 0; i < count; i++) ((uint32 *)gdst)[i] = half_to_float(gsrc[i]);
|
||||
for (int i = 0; i < count; i++) ((uint32 *)bdst)[i] = half_to_float(bsrc[i]);
|
||||
for (int i = 0; i < count; i++) ((uint32 *)adst)[i] = half_to_float(asrc[i]);
|
||||
}
|
||||
catch(...) {
|
||||
CATCH {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@ -587,13 +685,13 @@ bool Surface::setImage(InputFormat format, int w, int h, int d, const void * r,
|
||||
const float * bsrc = (const float *)b;
|
||||
const float * asrc = (const float *)a;
|
||||
|
||||
try {
|
||||
TRY {
|
||||
memcpy(rdst, rsrc, count * sizeof(float));
|
||||
memcpy(gdst, gsrc, count * sizeof(float));
|
||||
memcpy(bdst, bsrc, count * sizeof(float));
|
||||
memcpy(adst, asrc, count * sizeof(float));
|
||||
}
|
||||
catch(...) {
|
||||
CATCH {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@ -624,87 +722,87 @@ bool Surface::setImage2D(Format format, Decoder decoder, int w, int h, const voi
|
||||
|
||||
const uint8 * ptr = (const uint8 *)data;
|
||||
|
||||
try {
|
||||
TRY {
|
||||
for (int y = 0; y < bh; y++)
|
||||
{
|
||||
for (int x = 0; x < bw; x++)
|
||||
{
|
||||
ColorBlock colors;
|
||||
|
||||
if (format == nvtt::Format_BC1)
|
||||
{
|
||||
const BlockDXT1 * block = (const BlockDXT1 *)ptr;
|
||||
if (format == nvtt::Format_BC1)
|
||||
{
|
||||
const BlockDXT1 * block = (const BlockDXT1 *)ptr;
|
||||
|
||||
if (decoder == Decoder_D3D10) {
|
||||
block->decodeBlock(&colors, false);
|
||||
}
|
||||
else if (decoder == Decoder_D3D9) {
|
||||
block->decodeBlock(&colors, false);
|
||||
}
|
||||
else if (decoder == Decoder_NV5x) {
|
||||
block->decodeBlockNV5x(&colors);
|
||||
}
|
||||
}
|
||||
else if (format == nvtt::Format_BC2)
|
||||
{
|
||||
const BlockDXT3 * block = (const BlockDXT3 *)ptr;
|
||||
if (decoder == Decoder_D3D10) {
|
||||
block->decodeBlock(&colors, false);
|
||||
}
|
||||
else if (decoder == Decoder_D3D9) {
|
||||
block->decodeBlock(&colors, false);
|
||||
}
|
||||
else if (decoder == Decoder_NV5x) {
|
||||
block->decodeBlockNV5x(&colors);
|
||||
}
|
||||
}
|
||||
else if (format == nvtt::Format_BC2)
|
||||
{
|
||||
const BlockDXT3 * block = (const BlockDXT3 *)ptr;
|
||||
|
||||
if (decoder == Decoder_D3D10) {
|
||||
block->decodeBlock(&colors, false);
|
||||
}
|
||||
else if (decoder == Decoder_D3D9) {
|
||||
block->decodeBlock(&colors, false);
|
||||
}
|
||||
else if (decoder == Decoder_NV5x) {
|
||||
block->decodeBlockNV5x(&colors);
|
||||
}
|
||||
}
|
||||
else if (format == nvtt::Format_BC3)
|
||||
{
|
||||
const BlockDXT5 * block = (const BlockDXT5 *)ptr;
|
||||
if (decoder == Decoder_D3D10) {
|
||||
block->decodeBlock(&colors, false);
|
||||
}
|
||||
else if (decoder == Decoder_D3D9) {
|
||||
block->decodeBlock(&colors, false);
|
||||
}
|
||||
else if (decoder == Decoder_NV5x) {
|
||||
block->decodeBlockNV5x(&colors);
|
||||
}
|
||||
}
|
||||
else if (format == nvtt::Format_BC3)
|
||||
{
|
||||
const BlockDXT5 * block = (const BlockDXT5 *)ptr;
|
||||
|
||||
if (decoder == Decoder_D3D10) {
|
||||
block->decodeBlock(&colors, false);
|
||||
}
|
||||
else if (decoder == Decoder_D3D9) {
|
||||
block->decodeBlock(&colors, false);
|
||||
}
|
||||
else if (decoder == Decoder_NV5x) {
|
||||
block->decodeBlockNV5x(&colors);
|
||||
}
|
||||
}
|
||||
else if (format == nvtt::Format_BC4)
|
||||
{
|
||||
const BlockATI1 * block = (const BlockATI1 *)ptr;
|
||||
block->decodeBlock(&colors, decoder == Decoder_D3D9);
|
||||
if (decoder == Decoder_D3D10) {
|
||||
block->decodeBlock(&colors, false);
|
||||
}
|
||||
else if (decoder == Decoder_D3D9) {
|
||||
block->decodeBlock(&colors, false);
|
||||
}
|
||||
else if (decoder == Decoder_NV5x) {
|
||||
block->decodeBlockNV5x(&colors);
|
||||
}
|
||||
}
|
||||
else if (format == nvtt::Format_BC4)
|
||||
{
|
||||
const BlockATI1 * block = (const BlockATI1 *)ptr;
|
||||
block->decodeBlock(&colors, decoder == Decoder_D3D9);
|
||||
}
|
||||
else if (format == nvtt::Format_BC5)
|
||||
{
|
||||
const BlockATI2 * block = (const BlockATI2 *)ptr;
|
||||
block->decodeBlock(&colors, decoder == Decoder_D3D9);
|
||||
}
|
||||
|
||||
for (int yy = 0; yy < 4; yy++)
|
||||
{
|
||||
for (int xx = 0; xx < 4; xx++)
|
||||
{
|
||||
Color32 c = colors.color(xx, yy);
|
||||
|
||||
if (x * 4 + xx < w && y * 4 + yy < h)
|
||||
{
|
||||
m->image->pixel(0, x*4 + xx, y*4 + yy, 0) = float(c.r) * 1.0f/255.0f;
|
||||
m->image->pixel(1, x*4 + xx, y*4 + yy, 0) = float(c.g) * 1.0f/255.0f;
|
||||
m->image->pixel(2, x*4 + xx, y*4 + yy, 0) = float(c.b) * 1.0f/255.0f;
|
||||
m->image->pixel(3, x*4 + xx, y*4 + yy, 0) = float(c.a) * 1.0f/255.0f;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ptr += bs;
|
||||
}
|
||||
}
|
||||
else if (format == nvtt::Format_BC5)
|
||||
{
|
||||
const BlockATI2 * block = (const BlockATI2 *)ptr;
|
||||
block->decodeBlock(&colors, decoder == Decoder_D3D9);
|
||||
}
|
||||
|
||||
for (int yy = 0; yy < 4; yy++)
|
||||
{
|
||||
for (int xx = 0; xx < 4; xx++)
|
||||
{
|
||||
Color32 c = colors.color(xx, yy);
|
||||
|
||||
if (x * 4 + xx < w && y * 4 + yy < h)
|
||||
{
|
||||
m->image->pixel(0, x*4 + xx, y*4 + yy, 0) = float(c.r) * 1.0f/255.0f;
|
||||
m->image->pixel(1, x*4 + xx, y*4 + yy, 0) = float(c.g) * 1.0f/255.0f;
|
||||
m->image->pixel(2, x*4 + xx, y*4 + yy, 0) = float(c.b) * 1.0f/255.0f;
|
||||
m->image->pixel(3, x*4 + xx, y*4 + yy, 0) = float(c.a) * 1.0f/255.0f;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ptr += bs;
|
||||
}
|
||||
}
|
||||
}
|
||||
catch(...) {
|
||||
CATCH {
|
||||
return false;
|
||||
}
|
||||
|
||||
@ -812,6 +910,43 @@ void Surface::resize(int w, int h, int d, ResizeFilter filter, float filterWidth
|
||||
m->image = img;
|
||||
}
|
||||
|
||||
void Surface::resize_make_square(int maxExtent, RoundMode roundMode, ResizeFilter filter)
|
||||
{
|
||||
if (isNull()) return;
|
||||
|
||||
float filterWidth;
|
||||
float params[2];
|
||||
getDefaultFilterWidthAndParams(filter, &filterWidth, params);
|
||||
|
||||
int w = m->image->width();
|
||||
int h = m->image->height();
|
||||
int d = m->image->depth();
|
||||
|
||||
getTargetExtent(&w, &h, &d, maxExtent, roundMode, m->type);
|
||||
|
||||
if (m->type == TextureType_2D)
|
||||
{
|
||||
nvDebugCheck(d==1);
|
||||
int md = nv::min(w,h);
|
||||
w = md;
|
||||
h = md;
|
||||
}
|
||||
else if (m->type == TextureType_Cube)
|
||||
{
|
||||
nvDebugCheck(d==1);
|
||||
nvDebugCheck(w==h);
|
||||
}
|
||||
else if (m->type == TextureType_3D)
|
||||
{
|
||||
int md = nv::min(nv::min(w,h),d);
|
||||
w = md;
|
||||
h = md;
|
||||
d = md;
|
||||
}
|
||||
|
||||
resize(w, h, d, filter, filterWidth, params);
|
||||
}
|
||||
|
||||
void Surface::resize(int maxExtent, RoundMode roundMode, ResizeFilter filter)
|
||||
{
|
||||
float filterWidth;
|
||||
@ -834,18 +969,26 @@ void Surface::resize(int maxExtent, RoundMode roundMode, ResizeFilter filter, fl
|
||||
resize(w, h, d, filter, filterWidth, params);
|
||||
}
|
||||
|
||||
bool Surface::buildNextMipmap(MipmapFilter filter)
|
||||
bool Surface::canMakeNextMipmap(int min_size /*= 1*/)
|
||||
{
|
||||
if (isNull()) return false;
|
||||
|
||||
return nv::canMakeNextMipmap(width(), height(), depth(), min_size);
|
||||
}
|
||||
|
||||
|
||||
bool Surface::buildNextMipmap(MipmapFilter filter, int min_size /*= 1*/)
|
||||
{
|
||||
float filterWidth;
|
||||
float params[2];
|
||||
getDefaultFilterWidthAndParams(filter, &filterWidth, params);
|
||||
|
||||
return buildNextMipmap(filter, filterWidth, params);
|
||||
return buildNextMipmap(filter, filterWidth, params, min_size);
|
||||
}
|
||||
|
||||
bool Surface::buildNextMipmap(MipmapFilter filter, float filterWidth, const float * params)
|
||||
bool Surface::buildNextMipmap(MipmapFilter filter, float filterWidth, const float * params, int min_size /*= 1*/)
|
||||
{
|
||||
if (isNull() || (width() == 1 && height() == 1 && depth() == 1)) {
|
||||
if (!canMakeNextMipmap(min_size)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@ -907,6 +1050,30 @@ bool Surface::buildNextMipmap(MipmapFilter filter, float filterWidth, const floa
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Surface::buildNextMipmapSolidColor(const float * const color_components)
|
||||
{
|
||||
if (isNull() || (width() == 1 && height() == 1 && depth() == 1)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
detach();
|
||||
|
||||
FloatImage * img = new FloatImage();
|
||||
const uint w = max(1, m->image->m_width / 2);
|
||||
const uint h = max(1, m->image->m_height / 2);
|
||||
img->allocate(m->image->m_componentCount, w, h);
|
||||
|
||||
for(uint c = 0; c < img->m_componentCount; c++)
|
||||
{
|
||||
img->clear(c, color_components[c]);
|
||||
}
|
||||
|
||||
delete m->image;
|
||||
m->image = img;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void Surface::canvasSize(int w, int h, int d)
|
||||
{
|
||||
nvDebugCheck(w > 0 && h > 0 && d > 0);
|
||||
@ -1083,6 +1250,7 @@ void Surface::transform(const float w0[4], const float w1[4], const float w2[4],
|
||||
m->image->transform(0, xform, voffset);
|
||||
}
|
||||
|
||||
// R, G, B, A, 1, 0, -1
|
||||
void Surface::swizzle(int r, int g, int b, int a)
|
||||
{
|
||||
if (isNull()) return;
|
||||
@ -1113,52 +1281,6 @@ void Surface::clamp(int channel, float low, float high)
|
||||
m->image->clamp(channel, 1, low, high);
|
||||
}
|
||||
|
||||
void Surface::packNormal()
|
||||
{
|
||||
if (isNull()) return;
|
||||
|
||||
detach();
|
||||
|
||||
m->image->scaleBias(0, 3, 0.5f, 0.5f);
|
||||
}
|
||||
|
||||
void Surface::expandNormal()
|
||||
{
|
||||
if (isNull()) return;
|
||||
|
||||
detach();
|
||||
|
||||
m->image->scaleBias(0, 3, 2.0f, -1.0f);
|
||||
}
|
||||
|
||||
// Create a Toksvig map for this normal map.
|
||||
// http://blog.selfshadow.com/2011/07/22/specular-showdown/
|
||||
// @@ Assumes this is a normal map expanded in the [-1, 1] range.
|
||||
Surface Surface::createToksvigMap(float power) const
|
||||
{
|
||||
if (isNull()) return Surface();
|
||||
|
||||
// @@ TODO
|
||||
|
||||
return Surface();
|
||||
}
|
||||
|
||||
// @@ Should I add support for LEAN maps? That requires 5 terms, which would have to be encoded in two textures.
|
||||
// There's nothing stopping us from having 5 channels in a surface, and then, let the user swizzle them as they wish.
|
||||
// CLEAN maps are probably more practical, though.
|
||||
// http://www.cs.umbc.edu/~olano/papers/lean/
|
||||
// http://gaim.umbc.edu/2011/07/24/shiny-and-clean/
|
||||
// http://gaim.umbc.edu/2011/07/26/on-error/
|
||||
NVTT_API Surface Surface::createCleanMap() const
|
||||
{
|
||||
if (isNull()) return Surface();
|
||||
|
||||
// @@ TODO
|
||||
|
||||
return Surface();
|
||||
}
|
||||
|
||||
|
||||
void Surface::blend(float red, float green, float blue, float alpha, float t)
|
||||
{
|
||||
if (isNull()) return;
|
||||
@ -1285,13 +1407,10 @@ void Surface::fill(float red, float green, float blue, float alpha)
|
||||
float * a = img->channel(3);
|
||||
|
||||
const uint count = img->pixelCount();
|
||||
for (uint i = 0; i < count; i++)
|
||||
{
|
||||
r[i] = red;
|
||||
g[i] = green;
|
||||
b[i] = blue;
|
||||
a[i] = alpha;
|
||||
}
|
||||
for (uint i = 0; i < count; i++) r[i] = red;
|
||||
for (uint i = 0; i < count; i++) g[i] = green;
|
||||
for (uint i = 0; i < count; i++) b[i] = blue;
|
||||
for (uint i = 0; i < count; i++) a[i] = alpha;
|
||||
}
|
||||
|
||||
|
||||
@ -1301,6 +1420,8 @@ void Surface::scaleAlphaToCoverage(float coverage, float alphaRef/*= 0.5f*/)
|
||||
|
||||
detach();
|
||||
|
||||
alphaRef = nv::clamp(alphaRef, 1.0f/256, 255.0f/256);
|
||||
|
||||
m->image->scaleAlphaToCoverage(coverage, alphaRef, 3);
|
||||
}
|
||||
|
||||
@ -1341,7 +1462,6 @@ void Surface::toRGBM(float range/*= 1*/, float threshold/*= 0.25*/)
|
||||
detach();
|
||||
|
||||
threshold = ::clamp(threshold, 1e-6f, 1.0f);
|
||||
float irange = 1.0f / range;
|
||||
|
||||
FloatImage * img = m->image;
|
||||
float * r = img->channel(0);
|
||||
@ -1360,6 +1480,7 @@ void Surface::toRGBM(float range/*= 1*/, float threshold/*= 0.25*/)
|
||||
r[i] = R / M;
|
||||
g[i] = G / M;
|
||||
b[i] = B / M;
|
||||
|
||||
a[i] = (M - threshold) / (1 - threshold);
|
||||
|
||||
#else
|
||||
@ -1402,6 +1523,7 @@ void Surface::toRGBM(float range/*= 1*/, float threshold/*= 0.25*/)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void Surface::fromRGBM(float range/*= 1*/)
|
||||
{
|
||||
if (isNull()) return;
|
||||
@ -1425,6 +1547,37 @@ void Surface::fromRGBM(float range/*= 1*/)
|
||||
}
|
||||
}
|
||||
|
||||
// This is dumb way to encode luminance only values.
|
||||
void Surface::toLM(float range/*= 1*/, float threshold/*= 0.25*/)
|
||||
{
|
||||
if (isNull()) return;
|
||||
|
||||
detach();
|
||||
|
||||
threshold = ::clamp(threshold, 1e-6f, 1.0f);
|
||||
|
||||
FloatImage * img = m->image;
|
||||
float * r = img->channel(0);
|
||||
float * g = img->channel(1);
|
||||
float * b = img->channel(2);
|
||||
float * a = img->channel(3);
|
||||
|
||||
const uint count = img->pixelCount();
|
||||
for (uint i = 0; i < count; i++) {
|
||||
float R = nv::clamp(r[i], 0.0f, 1.0f);
|
||||
float G = nv::clamp(g[i], 0.0f, 1.0f);
|
||||
float B = nv::clamp(b[i], 0.0f, 1.0f);
|
||||
|
||||
float M = max(max(R, G), max(B, threshold));
|
||||
|
||||
float L = (R + G + B) / 3;
|
||||
r[i] = L / M;
|
||||
b[i] = L / M;
|
||||
g[i] = L / M;
|
||||
a[i] = (M - threshold) / (1 - threshold);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static Color32 toRgbe8(float r, float g, float b)
|
||||
{
|
||||
@ -2147,21 +2300,25 @@ void Surface::quantize(int channel, int bits, bool exactEndPoints, bool dither)
|
||||
|
||||
FloatImage * img = m->image;
|
||||
|
||||
float scale, offset;
|
||||
float scale, offset0, offset1;
|
||||
if (exactEndPoints) {
|
||||
// floor(x*(range-1) + 0.5) / (range-1)
|
||||
scale = float((1 << bits) - 1);
|
||||
offset = 0.0f;
|
||||
offset0 = 0.5f;
|
||||
offset1 = 0.0f;
|
||||
}
|
||||
else {
|
||||
// (floor(x*range) + 0.5) / range
|
||||
scale = float(1 << bits);
|
||||
offset = 0.5f;
|
||||
offset0 = 0.0f;
|
||||
offset1 = 0.5f;
|
||||
}
|
||||
|
||||
if (!dither) {
|
||||
float * c = img->channel(channel);
|
||||
const uint count = img->pixelCount();
|
||||
for (uint i = 0; i < count; i++) {
|
||||
c[i] = floorf(c[i] * scale + offset) / scale;
|
||||
c[i] = saturate((floorf(c[i] * scale + offset0) + offset1) / scale);
|
||||
}
|
||||
}
|
||||
else {
|
||||
@ -2182,7 +2339,7 @@ void Surface::quantize(int channel, int bits, bool exactEndPoints, bool dither)
|
||||
float & f = img->pixel(channel, x, y, 0);
|
||||
|
||||
// Add error and quantize.
|
||||
float qf = floorf((f + row0[1+x]) * scale + offset) / scale;
|
||||
float qf = saturate((floorf((f + row0[1+x]) * scale + offset0) + offset1) / scale);
|
||||
|
||||
// Compute new error:
|
||||
float diff = f - qf;
|
||||
@ -2221,9 +2378,6 @@ void Surface::toNormalMap(float sm, float medium, float big, float large)
|
||||
const FloatImage * img = m->image;
|
||||
m->image = nv::createNormalMap(img, (FloatImage::WrapMode)m->wrapMode, filterWeights);
|
||||
|
||||
#pragma NV_MESSAGE("TODO: Pack and expand normals explicitly?")
|
||||
m->image->packNormals(0);
|
||||
|
||||
delete img;
|
||||
|
||||
m->isNormalMap = true;
|
||||
@ -2246,7 +2400,6 @@ void Surface::transformNormals(NormalTransform xform)
|
||||
detach();
|
||||
|
||||
FloatImage * img = m->image;
|
||||
img->expandNormals(0);
|
||||
|
||||
const uint count = img->pixelCount();
|
||||
for (uint i = 0; i < count; i++) {
|
||||
@ -2308,8 +2461,6 @@ void Surface::transformNormals(NormalTransform xform)
|
||||
y = n.y;
|
||||
z = n.z;
|
||||
}
|
||||
|
||||
img->packNormals(0);
|
||||
}
|
||||
|
||||
void Surface::reconstructNormals(NormalTransform xform)
|
||||
@ -2319,7 +2470,6 @@ void Surface::reconstructNormals(NormalTransform xform)
|
||||
detach();
|
||||
|
||||
FloatImage * img = m->image;
|
||||
img->expandNormals(0);
|
||||
|
||||
const uint count = img->pixelCount();
|
||||
for (uint i = 0; i < count; i++) {
|
||||
@ -2357,8 +2507,6 @@ void Surface::reconstructNormals(NormalTransform xform)
|
||||
y = n.y;
|
||||
z = n.z;
|
||||
}
|
||||
|
||||
img->packNormals(0);
|
||||
}
|
||||
|
||||
void Surface::toCleanNormalMap()
|
||||
@ -2367,8 +2515,6 @@ void Surface::toCleanNormalMap()
|
||||
|
||||
detach();
|
||||
|
||||
m->image->expandNormals(0);
|
||||
|
||||
const uint count = m->image->pixelCount();
|
||||
for (uint i = 0; i < count; i++) {
|
||||
float x = m->image->pixel(0, i);
|
||||
@ -2376,22 +2522,48 @@ void Surface::toCleanNormalMap()
|
||||
|
||||
m->image->pixel(2, i) = x*x + y*y;
|
||||
}
|
||||
|
||||
m->image->packNormals(0);
|
||||
}
|
||||
|
||||
// [-1,1] -> [ 0,1]
|
||||
void Surface::packNormals() {
|
||||
void Surface::packNormals(float scale/*= 0.5f*/, float bias/*= 0.5f*/) {
|
||||
if (isNull()) return;
|
||||
detach();
|
||||
m->image->packNormals(0);
|
||||
m->image->scaleBias(0, 3, scale, bias);
|
||||
}
|
||||
|
||||
// [ 0,1] -> [-1,1]
|
||||
void Surface::expandNormals() {
|
||||
void Surface::expandNormals(float scale/*= 2.0f*/, float bias/*= - 2.0f * 127.0f / 255.0f*/) {
|
||||
if (isNull()) return;
|
||||
detach();
|
||||
m->image->expandNormals(0);
|
||||
m->image->scaleBias(0, 3, scale, bias);
|
||||
}
|
||||
|
||||
|
||||
// Create a Toksvig map for this normal map.
|
||||
// http://blog.selfshadow.com/2011/07/22/specular-showdown/
|
||||
// @@ Assumes this is a normal map expanded in the [-1, 1] range.
|
||||
Surface Surface::createToksvigMap(float power) const
|
||||
{
|
||||
if (isNull()) return Surface();
|
||||
|
||||
// @@ TODO
|
||||
|
||||
return Surface();
|
||||
}
|
||||
|
||||
// @@ Should I add support for LEAN maps? That requires 5 terms, which would have to be encoded in two textures.
|
||||
// There's nothing stopping us from having 5 channels in a surface, and then, let the user swizzle them as they wish.
|
||||
// CLEAN maps are probably more practical, though.
|
||||
// http://www.cs.umbc.edu/~olano/papers/lean/
|
||||
// http://gaim.umbc.edu/2011/07/24/shiny-and-clean/
|
||||
// http://gaim.umbc.edu/2011/07/26/on-error/
|
||||
NVTT_API Surface Surface::createCleanMap() const
|
||||
{
|
||||
if (isNull()) return Surface();
|
||||
|
||||
// @@ TODO
|
||||
|
||||
return Surface();
|
||||
}
|
||||
|
||||
|
||||
@ -2422,7 +2594,7 @@ void Surface::flipZ()
|
||||
m->image->flipZ();
|
||||
}
|
||||
|
||||
Surface Surface::subImage(int x0, int x1, int y0, int y1, int z0, int z1) const
|
||||
Surface Surface::createSubImage(int x0, int x1, int y0, int y1, int z0, int z1) const
|
||||
{
|
||||
Surface s;
|
||||
|
||||
@ -2495,9 +2667,6 @@ bool Surface::addChannel(const Surface & srcImage, int srcChannel, int dstChanne
|
||||
|
||||
dst = m->image;
|
||||
|
||||
const uint w = src->width();
|
||||
const uint h = src->height();
|
||||
|
||||
float * d = dst->channel(dstChannel);
|
||||
const float * s = src->channel(srcChannel);
|
||||
|
||||
@ -2510,6 +2679,38 @@ bool Surface::addChannel(const Surface & srcImage, int srcChannel, int dstChanne
|
||||
}
|
||||
|
||||
|
||||
bool Surface::copy(const Surface & srcImage, int xsrc, int ysrc, int zsrc, int xsize, int ysize, int zsize, int xdst, int ydst, int zdst)
|
||||
{
|
||||
if (xsrc < 0 || ysrc < 0 || zsrc < 0) return false;
|
||||
if (xdst < 0 || ydst < 0 || zdst < 0) return false;
|
||||
|
||||
FloatImage * dst = m->image;
|
||||
const FloatImage * src = srcImage.m->image;
|
||||
|
||||
if (toU32(xsrc + xsize) > src->width() || toU32(ysrc + ysize) > src->height() || toU32(zsrc + zsize) > src->depth()) return false;
|
||||
if (toU32(xdst + xsize) > dst->width() || toU32(ydst + ysize) > dst->height() || toU32(zdst + zsize) > dst->depth()) return false;
|
||||
|
||||
detach();
|
||||
|
||||
// For each channel.
|
||||
for(int i = 0; i < 4; i++) {
|
||||
float * d = dst->channel(i);
|
||||
const float * s = src->channel(i);
|
||||
|
||||
// Copy region from src to dst.
|
||||
for (int z = 0; z < zsize; z++) {
|
||||
for (int y = 0; y < ysize; y++) {
|
||||
for (int x = 0; x < xsize; x++) {
|
||||
d[dst->index(xdst + x, ydst + y, zdst + z)] = s[src->index(xsrc + x, ysrc + y, zsrc + z)];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
|
||||
float nvtt::rmsError(const Surface & reference, const Surface & image)
|
||||
{
|
||||
|
Reference in New Issue
Block a user