|
|
|
@ -26,6 +26,7 @@
|
|
|
|
|
#include "nvmath/Vector.h"
|
|
|
|
|
#include "nvmath/Matrix.h"
|
|
|
|
|
#include "nvmath/Color.h"
|
|
|
|
|
#include "nvmath/Half.h"
|
|
|
|
|
|
|
|
|
|
#include "nvimage/Filter.h"
|
|
|
|
|
#include "nvimage/ImageIO.h"
|
|
|
|
@ -104,6 +105,7 @@ namespace
|
|
|
|
|
|
|
|
|
|
TexImage::TexImage() : m(new TexImage::Private())
|
|
|
|
|
{
|
|
|
|
|
m->addRef();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
TexImage::TexImage(const TexImage & tex) : m(tex.m)
|
|
|
|
@ -300,7 +302,7 @@ bool TexImage::save(const char * fileName) const
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool TexImage::setImage2D(nvtt::InputFormat format, int w, int h, int idx, const void * restrict data)
|
|
|
|
|
bool TexImage::setImage2D(nvtt::InputFormat format, int w, int h, int idx, const void * data)
|
|
|
|
|
{
|
|
|
|
|
if (idx < 0 || uint(idx) >= m->imageArray.count())
|
|
|
|
|
{
|
|
|
|
@ -323,10 +325,10 @@ bool TexImage::setImage2D(nvtt::InputFormat format, int w, int h, int idx, const
|
|
|
|
|
|
|
|
|
|
const int count = w * h;
|
|
|
|
|
|
|
|
|
|
float * restrict rdst = img->channel(0);
|
|
|
|
|
float * restrict gdst = img->channel(1);
|
|
|
|
|
float * restrict bdst = img->channel(2);
|
|
|
|
|
float * restrict adst = img->channel(3);
|
|
|
|
|
float * rdst = img->channel(0);
|
|
|
|
|
float * gdst = img->channel(1);
|
|
|
|
|
float * bdst = img->channel(2);
|
|
|
|
|
float * adst = img->channel(3);
|
|
|
|
|
|
|
|
|
|
if (format == InputFormat_BGRA_8UB)
|
|
|
|
|
{
|
|
|
|
@ -345,6 +347,23 @@ bool TexImage::setImage2D(nvtt::InputFormat format, int w, int h, int idx, const
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else if (format == InputFormat_RGBA_16F)
|
|
|
|
|
{
|
|
|
|
|
const uint16 * src = (const uint16 *)data;
|
|
|
|
|
|
|
|
|
|
try {
|
|
|
|
|
for (int i = 0; i < count; i++)
|
|
|
|
|
{
|
|
|
|
|
((uint32 *)rdst)[i] = half_to_float(src[4*i+0]);
|
|
|
|
|
((uint32 *)gdst)[i] = half_to_float(src[4*i+1]);
|
|
|
|
|
((uint32 *)bdst)[i] = half_to_float(src[4*i+2]);
|
|
|
|
|
((uint32 *)adst)[i] = half_to_float(src[4*i+3]);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
catch(...) {
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else if (format == InputFormat_RGBA_32F)
|
|
|
|
|
{
|
|
|
|
|
const float * src = (const float *)data;
|
|
|
|
@ -366,7 +385,7 @@ bool TexImage::setImage2D(nvtt::InputFormat format, int w, int h, int idx, const
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool TexImage::setImage2D(InputFormat format, int w, int h, int idx, const void * restrict r, const void * restrict g, const void * restrict b, const void * restrict a)
|
|
|
|
|
bool TexImage::setImage2D(InputFormat format, int w, int h, int idx, const void * r, const void * g, const void * b, const void * a)
|
|
|
|
|
{
|
|
|
|
|
if (idx < 0 || uint(idx) >= m->imageArray.count())
|
|
|
|
|
{
|
|
|
|
@ -383,17 +402,17 @@ bool TexImage::setImage2D(InputFormat format, int w, int h, int idx, const void
|
|
|
|
|
|
|
|
|
|
const int count = w * h;
|
|
|
|
|
|
|
|
|
|
float * restrict rdst = img->channel(0);
|
|
|
|
|
float * restrict gdst = img->channel(1);
|
|
|
|
|
float * restrict bdst = img->channel(2);
|
|
|
|
|
float * restrict adst = img->channel(3);
|
|
|
|
|
float * rdst = img->channel(0);
|
|
|
|
|
float * gdst = img->channel(1);
|
|
|
|
|
float * bdst = img->channel(2);
|
|
|
|
|
float * adst = img->channel(3);
|
|
|
|
|
|
|
|
|
|
if (format == InputFormat_BGRA_8UB)
|
|
|
|
|
{
|
|
|
|
|
const uint8 * restrict rsrc = (const uint8 *)r;
|
|
|
|
|
const uint8 * restrict gsrc = (const uint8 *)g;
|
|
|
|
|
const uint8 * restrict bsrc = (const uint8 *)b;
|
|
|
|
|
const uint8 * restrict asrc = (const uint8 *)a;
|
|
|
|
|
const uint8 * rsrc = (const uint8 *)r;
|
|
|
|
|
const uint8 * gsrc = (const uint8 *)g;
|
|
|
|
|
const uint8 * bsrc = (const uint8 *)b;
|
|
|
|
|
const uint8 * asrc = (const uint8 *)a;
|
|
|
|
|
|
|
|
|
|
try {
|
|
|
|
|
for (int i = 0; i < count; i++) rdst[i] = float(rsrc[i]) / 255.0f;
|
|
|
|
@ -405,6 +424,23 @@ bool TexImage::setImage2D(InputFormat format, int w, int h, int idx, const void
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else if (format == InputFormat_RGBA_16F)
|
|
|
|
|
{
|
|
|
|
|
const uint16 * rsrc = (const uint16 *)r;
|
|
|
|
|
const uint16 * gsrc = (const uint16 *)g;
|
|
|
|
|
const uint16 * bsrc = (const uint16 *)b;
|
|
|
|
|
const uint16 * asrc = (const uint16 *)a;
|
|
|
|
|
|
|
|
|
|
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(...) {
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else if (format == InputFormat_RGBA_32F)
|
|
|
|
|
{
|
|
|
|
|
const float * rsrc = (const float *)r;
|
|
|
|
@ -526,9 +562,38 @@ bool TexImage::setImage2D(Format format, Decoder decoder, int w, int h, int idx,
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
#pragma NV_MESSAGE("TODO: provide a TexImage::resize that can override filter width and parameters.")
|
|
|
|
|
static void getDefaultFilterWidthAndParams(int filter, float * filterWidth, float params[2])
|
|
|
|
|
{
|
|
|
|
|
if (filter == ResizeFilter_Box) {
|
|
|
|
|
*filterWidth = 0.5f;
|
|
|
|
|
}
|
|
|
|
|
else if (filter == ResizeFilter_Triangle) {
|
|
|
|
|
*filterWidth = 1.0f;
|
|
|
|
|
}
|
|
|
|
|
else if (filter == ResizeFilter_Kaiser)
|
|
|
|
|
{
|
|
|
|
|
*filterWidth = 3.0f;
|
|
|
|
|
params[0] = 4.0f;
|
|
|
|
|
params[1] = 1.0f;
|
|
|
|
|
}
|
|
|
|
|
else //if (filter == ResizeFilter_Mitchell)
|
|
|
|
|
{
|
|
|
|
|
*filterWidth = 2.0f;
|
|
|
|
|
params[0] = 1.0f / 3.0f;
|
|
|
|
|
params[1] = 1.0f / 3.0f;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void TexImage::resize(int w, int h, ResizeFilter filter)
|
|
|
|
|
{
|
|
|
|
|
float filterWidth;
|
|
|
|
|
float params[2];
|
|
|
|
|
getDefaultFilterWidthAndParams(filter, &filterWidth, params);
|
|
|
|
|
|
|
|
|
|
resize(w, h, filter, filterWidth, params);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void TexImage::resize(int w, int h, ResizeFilter filter, float filterWidth, const float * params)
|
|
|
|
|
{
|
|
|
|
|
if (m->imageArray.count() > 0)
|
|
|
|
|
{
|
|
|
|
@ -555,25 +620,25 @@ void TexImage::resize(int w, int h, ResizeFilter filter)
|
|
|
|
|
{
|
|
|
|
|
if (filter == ResizeFilter_Box)
|
|
|
|
|
{
|
|
|
|
|
BoxFilter filter;
|
|
|
|
|
BoxFilter filter(filterWidth);
|
|
|
|
|
img = img->resize(filter, w, h, wrapMode, 3);
|
|
|
|
|
}
|
|
|
|
|
else if (filter == ResizeFilter_Triangle)
|
|
|
|
|
{
|
|
|
|
|
TriangleFilter filter;
|
|
|
|
|
TriangleFilter filter(filterWidth);
|
|
|
|
|
img = img->resize(filter, w, h, wrapMode, 3);
|
|
|
|
|
}
|
|
|
|
|
else if (filter == ResizeFilter_Kaiser)
|
|
|
|
|
{
|
|
|
|
|
//KaiserFilter filter(inputOptions.kaiserWidth);
|
|
|
|
|
//filter.setParameters(inputOptions.kaiserAlpha, inputOptions.kaiserStretch);
|
|
|
|
|
KaiserFilter filter(3);
|
|
|
|
|
KaiserFilter filter(filterWidth);
|
|
|
|
|
if (params != NULL) filter.setParameters(params[0], params[1]);
|
|
|
|
|
img = img->resize(filter, w, h, wrapMode, 3);
|
|
|
|
|
}
|
|
|
|
|
else //if (filter == ResizeFilter_Mitchell)
|
|
|
|
|
{
|
|
|
|
|
nvDebugCheck(filter == ResizeFilter_Mitchell);
|
|
|
|
|
MitchellFilter filter;
|
|
|
|
|
if (params != NULL) filter.setParameters(params[0], params[1]);
|
|
|
|
|
img = img->resize(filter, w, h, wrapMode, 3);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
@ -581,25 +646,25 @@ void TexImage::resize(int w, int h, ResizeFilter filter)
|
|
|
|
|
{
|
|
|
|
|
if (filter == ResizeFilter_Box)
|
|
|
|
|
{
|
|
|
|
|
BoxFilter filter;
|
|
|
|
|
BoxFilter filter(filterWidth);
|
|
|
|
|
img = img->resize(filter, w, h, wrapMode);
|
|
|
|
|
}
|
|
|
|
|
else if (filter == ResizeFilter_Triangle)
|
|
|
|
|
{
|
|
|
|
|
TriangleFilter filter;
|
|
|
|
|
TriangleFilter filter(filterWidth);
|
|
|
|
|
img = img->resize(filter, w, h, wrapMode);
|
|
|
|
|
}
|
|
|
|
|
else if (filter == ResizeFilter_Kaiser)
|
|
|
|
|
{
|
|
|
|
|
//KaiserFilter filter(inputOptions.kaiserWidth);
|
|
|
|
|
//filter.setParameters(inputOptions.kaiserAlpha, inputOptions.kaiserStretch);
|
|
|
|
|
KaiserFilter filter(3);
|
|
|
|
|
KaiserFilter filter(filterWidth);
|
|
|
|
|
if (params != NULL) filter.setParameters(params[0], params[1]);
|
|
|
|
|
img = img->resize(filter, w, h, wrapMode);
|
|
|
|
|
}
|
|
|
|
|
else //if (filter == ResizeFilter_Mitchell)
|
|
|
|
|
{
|
|
|
|
|
nvDebugCheck(filter == ResizeFilter_Mitchell);
|
|
|
|
|
MitchellFilter filter;
|
|
|
|
|
if (params != NULL) filter.setParameters(params[0], params[1]);
|
|
|
|
|
img = img->resize(filter, w, h, wrapMode);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
@ -610,6 +675,16 @@ void TexImage::resize(int w, int h, ResizeFilter filter)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void TexImage::resize(int maxExtent, RoundMode roundMode, ResizeFilter filter)
|
|
|
|
|
{
|
|
|
|
|
float filterWidth;
|
|
|
|
|
float params[2];
|
|
|
|
|
getDefaultFilterWidthAndParams(filter, &filterWidth, params);
|
|
|
|
|
|
|
|
|
|
resize(maxExtent, roundMode, filter, filterWidth, params);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
void TexImage::resize(int maxExtent, RoundMode roundMode, ResizeFilter filter, float filterWidth, const float * params)
|
|
|
|
|
{
|
|
|
|
|
if (m->imageArray.count() > 0)
|
|
|
|
|
{
|
|
|
|
@ -619,7 +694,7 @@ void TexImage::resize(int maxExtent, RoundMode roundMode, ResizeFilter filter)
|
|
|
|
|
nvDebugCheck(w > 0);
|
|
|
|
|
nvDebugCheck(h > 0);
|
|
|
|
|
|
|
|
|
|
if (roundMode != RoundMode_None)
|
|
|
|
|
if (roundMode != RoundMode_None && maxExtent > 0)
|
|
|
|
|
{
|
|
|
|
|
// rounded max extent should never be higher than original max extent.
|
|
|
|
|
maxExtent = previousPowerOfTwo(maxExtent);
|
|
|
|
@ -627,7 +702,7 @@ void TexImage::resize(int maxExtent, RoundMode roundMode, ResizeFilter filter)
|
|
|
|
|
|
|
|
|
|
// Scale extents without changing aspect ratio.
|
|
|
|
|
int maxwh = max(w, h);
|
|
|
|
|
if (maxExtent != 0 && maxwh > maxExtent)
|
|
|
|
|
if (maxExtent > 0 && maxwh > maxExtent)
|
|
|
|
|
{
|
|
|
|
|
w = max((w * maxExtent) / maxwh, 1);
|
|
|
|
|
h = max((h * maxExtent) / maxwh, 1);
|
|
|
|
@ -656,11 +731,20 @@ void TexImage::resize(int maxExtent, RoundMode roundMode, ResizeFilter filter)
|
|
|
|
|
w = h = max(w, h);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
resize(w, h, filter);
|
|
|
|
|
resize(w, h, filter, filterWidth, params);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool TexImage::buildNextMipmap(MipmapFilter filter)
|
|
|
|
|
{
|
|
|
|
|
float filterWidth;
|
|
|
|
|
float params[2];
|
|
|
|
|
getDefaultFilterWidthAndParams(filter, &filterWidth, params);
|
|
|
|
|
|
|
|
|
|
buildNextMipmap(filter, filterWidth, params);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool TexImage::buildNextMipmap(MipmapFilter filter, float filterWidth, const float * params)
|
|
|
|
|
{
|
|
|
|
|
if (m->imageArray.count() > 0)
|
|
|
|
|
{
|
|
|
|
@ -690,20 +774,19 @@ bool TexImage::buildNextMipmap(MipmapFilter filter)
|
|
|
|
|
{
|
|
|
|
|
if (filter == MipmapFilter_Box)
|
|
|
|
|
{
|
|
|
|
|
BoxFilter filter;
|
|
|
|
|
BoxFilter filter(filterWidth);
|
|
|
|
|
img = img->downSample(filter, wrapMode, 3);
|
|
|
|
|
}
|
|
|
|
|
else if (filter == MipmapFilter_Triangle)
|
|
|
|
|
{
|
|
|
|
|
TriangleFilter filter;
|
|
|
|
|
TriangleFilter filter(filterWidth);
|
|
|
|
|
img = img->downSample(filter, wrapMode, 3);
|
|
|
|
|
}
|
|
|
|
|
else if (filter == MipmapFilter_Kaiser)
|
|
|
|
|
{
|
|
|
|
|
nvDebugCheck(filter == MipmapFilter_Kaiser);
|
|
|
|
|
//KaiserFilter filter(inputOptions.kaiserWidth);
|
|
|
|
|
//filter.setParameters(inputOptions.kaiserAlpha, inputOptions.kaiserStretch);
|
|
|
|
|
KaiserFilter filter(3);
|
|
|
|
|
KaiserFilter filter(filterWidth);
|
|
|
|
|
if (params != NULL) filter.setParameters(params[0], params[1]);
|
|
|
|
|
img = img->downSample(filter, wrapMode, 3);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
@ -711,19 +794,24 @@ bool TexImage::buildNextMipmap(MipmapFilter filter)
|
|
|
|
|
{
|
|
|
|
|
if (filter == MipmapFilter_Box)
|
|
|
|
|
{
|
|
|
|
|
if (filterWidth == 0.5f) {
|
|
|
|
|
img = img->fastDownSample();
|
|
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
BoxFilter filter(filterWidth);
|
|
|
|
|
img = img->downSample(filter, wrapMode);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else if (filter == MipmapFilter_Triangle)
|
|
|
|
|
{
|
|
|
|
|
TriangleFilter filter;
|
|
|
|
|
TriangleFilter filter(filterWidth);
|
|
|
|
|
img = img->downSample(filter, wrapMode);
|
|
|
|
|
}
|
|
|
|
|
else //if (filter == MipmapFilter_Kaiser)
|
|
|
|
|
{
|
|
|
|
|
nvDebugCheck(filter == MipmapFilter_Kaiser);
|
|
|
|
|
//KaiserFilter filter(inputOptions.kaiserWidth);
|
|
|
|
|
//filter.setParameters(inputOptions.kaiserAlpha, inputOptions.kaiserStretch);
|
|
|
|
|
KaiserFilter filter(3);
|
|
|
|
|
KaiserFilter filter(filterWidth);
|
|
|
|
|
if (params != NULL) filter.setParameters(params[0], params[1]);
|
|
|
|
|
img = img->downSample(filter, wrapMode);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
@ -848,10 +936,10 @@ void TexImage::blend(float red, float green, float blue, float alpha, float t)
|
|
|
|
|
FloatImage * img = m->imageArray[i];
|
|
|
|
|
if (img == NULL) continue;
|
|
|
|
|
|
|
|
|
|
float * restrict r = img->channel(0);
|
|
|
|
|
float * restrict g = img->channel(1);
|
|
|
|
|
float * restrict b = img->channel(2);
|
|
|
|
|
float * restrict a = img->channel(3);
|
|
|
|
|
float * r = img->channel(0);
|
|
|
|
|
float * g = img->channel(1);
|
|
|
|
|
float * b = img->channel(2);
|
|
|
|
|
float * a = img->channel(3);
|
|
|
|
|
|
|
|
|
|
const int count = img->width() * img->height();
|
|
|
|
|
for (int i = 0; i < count; i++)
|
|
|
|
@ -873,10 +961,10 @@ void TexImage::premultiplyAlpha()
|
|
|
|
|
FloatImage * img = m->imageArray[i];
|
|
|
|
|
if (img == NULL) continue;
|
|
|
|
|
|
|
|
|
|
float * restrict r = img->channel(0);
|
|
|
|
|
float * restrict g = img->channel(1);
|
|
|
|
|
float * restrict b = img->channel(2);
|
|
|
|
|
float * restrict a = img->channel(3);
|
|
|
|
|
float * r = img->channel(0);
|
|
|
|
|
float * g = img->channel(1);
|
|
|
|
|
float * b = img->channel(2);
|
|
|
|
|
float * a = img->channel(3);
|
|
|
|
|
|
|
|
|
|
const int count = img->width() * img->height();
|
|
|
|
|
for (int i = 0; i < count; i++)
|
|
|
|
@ -904,10 +992,10 @@ void TexImage::toGreyScale(float redScale, float greenScale, float blueScale, fl
|
|
|
|
|
blueScale /= sum;
|
|
|
|
|
alphaScale /= sum;
|
|
|
|
|
|
|
|
|
|
float * restrict r = img->channel(0);
|
|
|
|
|
float * restrict g = img->channel(1);
|
|
|
|
|
float * restrict b = img->channel(2);
|
|
|
|
|
float * restrict a = img->channel(3);
|
|
|
|
|
float * r = img->channel(0);
|
|
|
|
|
float * g = img->channel(1);
|
|
|
|
|
float * b = img->channel(2);
|
|
|
|
|
float * a = img->channel(3);
|
|
|
|
|
|
|
|
|
|
const int count = img->width() * img->height();
|
|
|
|
|
for (int i = 0; i < count; i++)
|
|
|
|
@ -1047,6 +1135,139 @@ bool TexImage::normalizeRange(float * rangeMin, float * rangeMax)
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Ideally you should compress/quantize the RGB and M portions independently.
|
|
|
|
|
// Once you have M quantized, you would compute the corresponding RGB and quantize that.
|
|
|
|
|
void TexImage::toRGBM(float range/*= 1*/, float threshold/*= 0.25*/)
|
|
|
|
|
{
|
|
|
|
|
detach();
|
|
|
|
|
|
|
|
|
|
float irange = 1.0f / range;
|
|
|
|
|
|
|
|
|
|
foreach (idx, m->imageArray) {
|
|
|
|
|
FloatImage * img = m->imageArray[idx];
|
|
|
|
|
if (img == NULL) continue;
|
|
|
|
|
|
|
|
|
|
float * r = img->channel(0);
|
|
|
|
|
float * g = img->channel(1);
|
|
|
|
|
float * b = img->channel(2);
|
|
|
|
|
float * a = img->channel(3);
|
|
|
|
|
|
|
|
|
|
const uint count = img->width() * img->height();
|
|
|
|
|
for (uint i = 0; i < count; i++) {
|
|
|
|
|
float ri = nv::clamp(r[i] * irange, 0.0f, 1.0f);
|
|
|
|
|
float gi = nv::clamp(g[i] * irange, 0.0f, 1.0f);
|
|
|
|
|
float bi = nv::clamp(b[i] * irange, 0.0f, 1.0f);
|
|
|
|
|
|
|
|
|
|
float m = max(max(ri, gi), max(bi, 1e-6f)); // Avoid division by zero.
|
|
|
|
|
//m = quantizeCeil(m, 8);
|
|
|
|
|
float im = 1.0f / m;
|
|
|
|
|
|
|
|
|
|
r[i] = ri * im;
|
|
|
|
|
g[i] = gi * im;
|
|
|
|
|
b[i] = bi * im;
|
|
|
|
|
a[i] = m;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Y is in the [0, 1] range, while CoCg are in the [-1, 1] range.
|
|
|
|
|
void TexImage::toYCoCg()
|
|
|
|
|
{
|
|
|
|
|
detach();
|
|
|
|
|
|
|
|
|
|
foreach (idx, m->imageArray) {
|
|
|
|
|
FloatImage * img = m->imageArray[idx];
|
|
|
|
|
if (img == NULL) continue;
|
|
|
|
|
|
|
|
|
|
float * r = img->channel(0);
|
|
|
|
|
float * g = img->channel(1);
|
|
|
|
|
float * b = img->channel(2);
|
|
|
|
|
float * a = img->channel(3);
|
|
|
|
|
|
|
|
|
|
const uint count = img->width() * img->height();
|
|
|
|
|
for (uint i = 0; i < count; i++) {
|
|
|
|
|
float ri = r[i];
|
|
|
|
|
float gi = g[i];
|
|
|
|
|
float bi = b[i];
|
|
|
|
|
|
|
|
|
|
float Y = (2*gi + ri + bi) * 0.25f;
|
|
|
|
|
float Co = (ri - bi);
|
|
|
|
|
float Cg = (2*gi - ri - bi) * 0.5f;
|
|
|
|
|
|
|
|
|
|
r[i] = Co;
|
|
|
|
|
g[i] = Cg;
|
|
|
|
|
b[i] = 0.0f;
|
|
|
|
|
a[i] = Y;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// img.toYCoCg();
|
|
|
|
|
// img.blockScaleCoCg();
|
|
|
|
|
// img.scaleBias(0, 0.5, 0.5);
|
|
|
|
|
// img.scaleBias(1, 0.5, 0.5);
|
|
|
|
|
|
|
|
|
|
// @@ Add support for threshold.
|
|
|
|
|
// We could do something to prevent scale values from adjacent blocks from being too different to each other
|
|
|
|
|
// and minimize bilinear interpolation artifacts.
|
|
|
|
|
void TexImage::blockScaleCoCg(int bits/*= 5*/, float threshold/*= 0.0*/)
|
|
|
|
|
{
|
|
|
|
|
detach();
|
|
|
|
|
|
|
|
|
|
foreach (idx, m->imageArray) {
|
|
|
|
|
FloatImage * img = m->imageArray[idx];
|
|
|
|
|
if (img == NULL) continue;
|
|
|
|
|
|
|
|
|
|
const uint w = img->width();
|
|
|
|
|
const uint h = img->height();
|
|
|
|
|
const uint bw = max(1U, w/4);
|
|
|
|
|
const uint bh = max(1U, h/4);
|
|
|
|
|
|
|
|
|
|
for (uint bj = 0; bj < bh; bj++) {
|
|
|
|
|
for (uint bi = 0; bi < bw; bi++) {
|
|
|
|
|
|
|
|
|
|
// Compute per block scale.
|
|
|
|
|
float m = 1.0f / 256.0f;
|
|
|
|
|
for (uint j = 0; j < 4; j++) {
|
|
|
|
|
for (uint i = 0; i < 4; i++) {
|
|
|
|
|
uint x = min(bi*4 + i, w);
|
|
|
|
|
uint y = min(bj*4 + j, h);
|
|
|
|
|
|
|
|
|
|
float Co = img->pixel(x, y, 0);
|
|
|
|
|
float Cg = img->pixel(x, y, 1);
|
|
|
|
|
|
|
|
|
|
m = max(m, fabsf(Co));
|
|
|
|
|
m = max(m, fabsf(Cg));
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
float scale = quantizeCeil(m, bits);
|
|
|
|
|
nvDebugCheck(scale >= m);
|
|
|
|
|
|
|
|
|
|
// Store block scale in blue channel and scale CoCg.
|
|
|
|
|
for (uint j = 0; j < 4; j++) {
|
|
|
|
|
for (uint i = 0; i < 4; i++) {
|
|
|
|
|
uint x = min(bi*4 + i, w);
|
|
|
|
|
uint y = min(bj*4 + j, h);
|
|
|
|
|
|
|
|
|
|
float & Co = img->pixel(x, y, 0);
|
|
|
|
|
float & Cg = img->pixel(x, y, 1);
|
|
|
|
|
|
|
|
|
|
Co /= scale;
|
|
|
|
|
nvDebugCheck(fabsf(Co) <= 1.0f);
|
|
|
|
|
|
|
|
|
|
Cg /= scale;
|
|
|
|
|
nvDebugCheck(fabsf(Cg) <= 1.0f);
|
|
|
|
|
|
|
|
|
|
img->pixel(x, y, 2) = scale;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// Set normal map options.
|
|
|
|
|
void TexImage::toNormalMap(float sm, float medium, float big, float large)
|
|
|
|
@ -1071,20 +1292,6 @@ void TexImage::toNormalMap(float sm, float medium, float big, float large)
|
|
|
|
|
m->isNormalMap = true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*void TexImage::toHeightMap()
|
|
|
|
|
{
|
|
|
|
|
detach();
|
|
|
|
|
|
|
|
|
|
foreach (i, m->imageArray)
|
|
|
|
|
{
|
|
|
|
|
if (m->imageArray[i] == NULL) continue;
|
|
|
|
|
|
|
|
|
|
#pragma message(NV_FILE_LINE "TODO: Implement TexImage::toHeightMap")
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
m->isNormalMap = false;
|
|
|
|
|
}*/
|
|
|
|
|
|
|
|
|
|
void TexImage::normalizeNormalMap()
|
|
|
|
|
{
|
|
|
|
|
//nvCheck(m->isNormalMap);
|
|
|
|
|