2009-01-05 10:17:06 +00:00
|
|
|
// Copyright NVIDIA Corporation 2007 -- Ignacio Castano <icastano@nvidia.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.
|
|
|
|
|
2009-10-11 23:51:22 +00:00
|
|
|
#include "TexImage.h"
|
2009-01-05 10:17:06 +00:00
|
|
|
|
2009-03-07 07:14:00 +00:00
|
|
|
#include <nvmath/Vector.h>
|
|
|
|
#include <nvmath/Matrix.h>
|
2009-03-16 08:37:07 +00:00
|
|
|
#include <nvmath/Color.h>
|
2009-03-07 07:14:00 +00:00
|
|
|
|
|
|
|
#include <nvimage/Filter.h>
|
2009-03-15 10:18:54 +00:00
|
|
|
#include <nvimage/ImageIO.h>
|
2009-03-16 08:37:07 +00:00
|
|
|
#include <nvimage/NormalMap.h>
|
2009-07-06 09:02:20 +00:00
|
|
|
#include <nvimage/BlockDXT.h>
|
|
|
|
#include <nvimage/ColorBlock.h>
|
2009-03-07 07:14:00 +00:00
|
|
|
|
2009-10-11 23:51:22 +00:00
|
|
|
#include <float.h>
|
|
|
|
|
2009-03-07 07:14:00 +00:00
|
|
|
using namespace nv;
|
2009-01-05 10:17:06 +00:00
|
|
|
using namespace nvtt;
|
|
|
|
|
2009-03-07 07:14:00 +00:00
|
|
|
namespace
|
|
|
|
{
|
|
|
|
// 1 -> 1, 2 -> 2, 3 -> 2, 4 -> 4, 5 -> 4, ...
|
|
|
|
static uint previousPowerOfTwo(const uint v)
|
|
|
|
{
|
|
|
|
return nextPowerOfTwo(v + 1) / 2;
|
|
|
|
}
|
|
|
|
|
|
|
|
static uint nearestPowerOfTwo(const uint v)
|
|
|
|
{
|
|
|
|
const uint np2 = nextPowerOfTwo(v);
|
|
|
|
const uint pp2 = previousPowerOfTwo(v);
|
|
|
|
|
|
|
|
if (np2 - v <= v - pp2)
|
|
|
|
{
|
|
|
|
return np2;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
return pp2;
|
|
|
|
}
|
|
|
|
}
|
2009-10-12 07:56:02 +00:00
|
|
|
|
|
|
|
#pragma message(NV_FILE_LINE "Move these functions to a common location")
|
|
|
|
static int blockSize(Format format)
|
|
|
|
{
|
|
|
|
if (format == Format_DXT1 || format == Format_DXT1a || format == Format_DXT1n) {
|
|
|
|
return 8;
|
|
|
|
}
|
|
|
|
else if (format == Format_DXT3) {
|
|
|
|
return 16;
|
|
|
|
}
|
|
|
|
else if (format == Format_DXT5 || format == Format_DXT5n) {
|
|
|
|
return 16;
|
|
|
|
}
|
|
|
|
else if (format == Format_BC4) {
|
|
|
|
return 8;
|
|
|
|
}
|
|
|
|
else if (format == Format_BC5) {
|
|
|
|
return 16;
|
|
|
|
}
|
|
|
|
else if (format == Format_CTX1) {
|
|
|
|
return 8;
|
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static uint countMipmaps(int w, int h, int d)
|
|
|
|
{
|
|
|
|
uint mipmap = 0;
|
|
|
|
|
|
|
|
while (w != 1 || h != 1 || d != 1) {
|
|
|
|
w = max(1, w / 2);
|
|
|
|
h = max(1, h / 2);
|
|
|
|
d = max(1, d / 2);
|
|
|
|
mipmap++;
|
|
|
|
}
|
|
|
|
|
|
|
|
return mipmap + 1;
|
|
|
|
}
|
2009-03-07 07:14:00 +00:00
|
|
|
}
|
|
|
|
|
2009-01-05 10:17:06 +00:00
|
|
|
|
2009-03-16 08:37:07 +00:00
|
|
|
TexImage::TexImage() : m(new TexImage::Private())
|
2009-01-05 10:17:06 +00:00
|
|
|
{
|
|
|
|
}
|
|
|
|
|
2009-03-16 08:37:07 +00:00
|
|
|
TexImage::TexImage(const TexImage & tex) : m(tex.m)
|
2009-01-05 10:17:06 +00:00
|
|
|
{
|
2009-03-07 07:14:00 +00:00
|
|
|
m->addRef();
|
2009-01-05 10:17:06 +00:00
|
|
|
}
|
|
|
|
|
2009-03-16 08:37:07 +00:00
|
|
|
TexImage::~TexImage()
|
2009-01-05 10:17:06 +00:00
|
|
|
{
|
2009-03-07 07:14:00 +00:00
|
|
|
m->release();
|
|
|
|
m = NULL;
|
2009-01-05 10:17:06 +00:00
|
|
|
}
|
|
|
|
|
2009-03-16 08:37:07 +00:00
|
|
|
void TexImage::operator=(const TexImage & tex)
|
2009-01-05 10:17:06 +00:00
|
|
|
{
|
2009-03-05 05:34:28 +00:00
|
|
|
tex.m->addRef();
|
|
|
|
m = tex.m;
|
|
|
|
m->release();
|
2009-01-05 10:17:06 +00:00
|
|
|
}
|
|
|
|
|
2009-03-16 08:37:07 +00:00
|
|
|
void TexImage::detach()
|
2009-01-05 10:17:06 +00:00
|
|
|
{
|
2009-03-07 07:14:00 +00:00
|
|
|
if (m->refCount() > 1)
|
|
|
|
{
|
2009-03-16 08:37:07 +00:00
|
|
|
m = new TexImage::Private(*m);
|
2009-03-07 07:14:00 +00:00
|
|
|
m->addRef();
|
|
|
|
nvDebugCheck(m->refCount() == 1);
|
|
|
|
}
|
2009-01-05 10:17:06 +00:00
|
|
|
}
|
|
|
|
|
2009-03-16 08:37:07 +00:00
|
|
|
void TexImage::setTextureType(TextureType type)
|
2009-01-05 10:17:06 +00:00
|
|
|
{
|
2009-03-07 07:14:00 +00:00
|
|
|
if (m->type != type)
|
|
|
|
{
|
|
|
|
detach();
|
2009-03-16 08:37:07 +00:00
|
|
|
|
2009-03-07 07:14:00 +00:00
|
|
|
m->type = type;
|
2009-03-16 08:37:07 +00:00
|
|
|
|
|
|
|
if (type == TextureType_2D)
|
|
|
|
{
|
|
|
|
// @@ Free images.
|
|
|
|
m->imageArray.resize(1, NULL);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
nvCheck (type == TextureType_Cube);
|
|
|
|
m->imageArray.resize(6, NULL);
|
|
|
|
}
|
2009-03-07 07:14:00 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2009-03-16 08:37:07 +00:00
|
|
|
void TexImage::setWrapMode(WrapMode wrapMode)
|
2009-03-07 07:14:00 +00:00
|
|
|
{
|
|
|
|
if (m->wrapMode != wrapMode)
|
|
|
|
{
|
|
|
|
detach();
|
|
|
|
m->wrapMode = wrapMode;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2009-03-16 08:37:07 +00:00
|
|
|
void TexImage::setAlphaMode(AlphaMode alphaMode)
|
2009-03-07 07:14:00 +00:00
|
|
|
{
|
|
|
|
if (m->alphaMode != alphaMode)
|
|
|
|
{
|
|
|
|
detach();
|
|
|
|
m->alphaMode = alphaMode;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2009-03-16 08:37:07 +00:00
|
|
|
void TexImage::setNormalMap(bool isNormalMap)
|
2009-03-07 07:14:00 +00:00
|
|
|
{
|
|
|
|
if (m->isNormalMap != isNormalMap)
|
|
|
|
{
|
|
|
|
detach();
|
|
|
|
m->isNormalMap = isNormalMap;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2009-03-16 08:37:07 +00:00
|
|
|
int TexImage::width() const
|
|
|
|
{
|
|
|
|
if (m->imageArray.count() > 0)
|
|
|
|
{
|
|
|
|
return m->imageArray[0]->width();
|
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
int TexImage::height() const
|
|
|
|
{
|
|
|
|
if (m->imageArray.count() > 0)
|
|
|
|
{
|
|
|
|
return m->imageArray[0]->height();
|
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
int TexImage::depth() const
|
|
|
|
{
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
int TexImage::faceCount() const
|
|
|
|
{
|
|
|
|
return m->imageArray.count();
|
|
|
|
}
|
|
|
|
|
|
|
|
TextureType TexImage::textureType() const
|
|
|
|
{
|
|
|
|
return m->type;
|
|
|
|
}
|
|
|
|
|
|
|
|
WrapMode TexImage::wrapMode() const
|
|
|
|
{
|
|
|
|
return m->wrapMode;
|
|
|
|
}
|
|
|
|
|
|
|
|
AlphaMode TexImage::alphaMode() const
|
|
|
|
{
|
|
|
|
return m->alphaMode;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool TexImage::isNormalMap() const
|
|
|
|
{
|
|
|
|
return m->isNormalMap;
|
|
|
|
}
|
|
|
|
|
2009-10-12 07:56:02 +00:00
|
|
|
int TexImage::countMipmaps() const
|
|
|
|
{
|
|
|
|
return ::countMipmaps(width(), height(), depth());
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2009-03-16 08:37:07 +00:00
|
|
|
bool TexImage::load(const char * fileName)
|
2009-03-07 07:14:00 +00:00
|
|
|
{
|
2009-10-12 07:56:02 +00:00
|
|
|
#pragma message(NV_FILE_LINE "Add support for DDS textures in TexImage::load")
|
2009-03-15 10:18:54 +00:00
|
|
|
|
|
|
|
AutoPtr<FloatImage> img(ImageIO::loadFloat(fileName));
|
|
|
|
|
|
|
|
if (img == NULL)
|
|
|
|
{
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2009-03-16 08:37:07 +00:00
|
|
|
detach();
|
|
|
|
|
2009-03-15 10:18:54 +00:00
|
|
|
m->imageArray.resize(1);
|
|
|
|
m->imageArray[0] = img.release();
|
|
|
|
|
|
|
|
return true;
|
2009-01-05 10:17:06 +00:00
|
|
|
}
|
|
|
|
|
2009-07-06 09:02:20 +00:00
|
|
|
bool TexImage::save(const char * fileName) const
|
|
|
|
{
|
|
|
|
// @@ Add support for DDS textures?
|
|
|
|
|
|
|
|
if (m->imageArray.count() == 0)
|
|
|
|
{
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
return ImageIO::saveFloat(fileName, m->imageArray[0], 0, 4);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2009-03-16 08:37:07 +00:00
|
|
|
bool TexImage::setImage2D(InputFormat format, int w, int h, int idx, const void * restrict data)
|
2009-01-05 10:17:06 +00:00
|
|
|
{
|
2009-04-01 07:17:25 +00:00
|
|
|
if (idx < 0 || uint(idx) >= m->imageArray.count())
|
2009-03-16 08:37:07 +00:00
|
|
|
{
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
FloatImage * img = m->imageArray[idx];
|
|
|
|
if (img->width() != w || img->height() != h)
|
|
|
|
{
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
detach();
|
|
|
|
|
|
|
|
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);
|
|
|
|
|
|
|
|
if (format == InputFormat_BGRA_8UB)
|
|
|
|
{
|
|
|
|
const Color32 * src = (const Color32 *)data;
|
|
|
|
|
|
|
|
try {
|
|
|
|
for (int i = 0; i < count; i++)
|
|
|
|
{
|
|
|
|
rdst[i] = src[i].r;
|
|
|
|
gdst[i] = src[i].g;
|
|
|
|
bdst[i] = src[i].b;
|
|
|
|
adst[i] = src[i].a;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
catch(...) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else if (format == InputFormat_RGBA_32F)
|
|
|
|
{
|
|
|
|
const float * src = (const float *)data;
|
|
|
|
|
|
|
|
try {
|
|
|
|
for (int i = 0; i < count; i++)
|
|
|
|
{
|
|
|
|
rdst[i] = src[4 * i + 0];
|
|
|
|
gdst[i] = src[4 * i + 1];
|
|
|
|
bdst[i] = src[4 * i + 2];
|
|
|
|
adst[i] = src[4 * i + 3];
|
|
|
|
}
|
|
|
|
}
|
|
|
|
catch(...) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return true;
|
2009-01-05 10:17:06 +00:00
|
|
|
}
|
|
|
|
|
2009-03-16 08:37:07 +00:00
|
|
|
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)
|
|
|
|
{
|
2009-04-01 07:17:25 +00:00
|
|
|
if (idx < 0 || uint(idx) >= m->imageArray.count())
|
2009-03-16 08:37:07 +00:00
|
|
|
{
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
FloatImage * img = m->imageArray[idx];
|
|
|
|
if (img->width() != w || img->height() != h)
|
|
|
|
{
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
detach();
|
2009-03-07 07:14:00 +00:00
|
|
|
|
2009-03-16 08:37:07 +00:00
|
|
|
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);
|
|
|
|
|
|
|
|
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;
|
|
|
|
|
|
|
|
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(...) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else if (format == InputFormat_RGBA_32F)
|
|
|
|
{
|
|
|
|
const float * rsrc = (const float *)r;
|
|
|
|
const float * gsrc = (const float *)g;
|
|
|
|
const float * bsrc = (const float *)b;
|
|
|
|
const float * asrc = (const float *)a;
|
|
|
|
|
|
|
|
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(...) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2009-07-06 09:02:20 +00:00
|
|
|
bool TexImage::setImage2D(Format format, Decoder decoder, int w, int h, int idx, const void * data)
|
|
|
|
{
|
|
|
|
if (idx < 0 || uint(idx) >= m->imageArray.count())
|
|
|
|
{
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2009-10-12 07:56:02 +00:00
|
|
|
if (format != nvtt::Format_BC1 && format != nvtt::Format_BC2 && format != nvtt::Format_BC3)
|
2009-07-06 09:02:20 +00:00
|
|
|
{
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
FloatImage * img = m->imageArray[idx];
|
|
|
|
if (img->width() != w || img->height() != h)
|
|
|
|
{
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
detach();
|
|
|
|
|
|
|
|
const int count = w * h;
|
|
|
|
|
2009-10-12 07:56:02 +00:00
|
|
|
const int bw = (w + 3) / 4;
|
|
|
|
const int bh = (h + 3) / 4;
|
2009-07-06 09:02:20 +00:00
|
|
|
|
2009-10-12 07:56:02 +00:00
|
|
|
const uint bs = blockSize(format);
|
|
|
|
|
|
|
|
const uint8 * ptr = (const uint8 *)data;
|
2009-07-06 09:02:20 +00:00
|
|
|
|
|
|
|
try {
|
2009-10-12 07:56:02 +00:00
|
|
|
for (int y = 0; y < bh; y++)
|
2009-07-06 09:02:20 +00:00
|
|
|
{
|
2009-10-12 07:56:02 +00:00
|
|
|
for (int x = 0; x < bw; x++)
|
2009-07-06 09:02:20 +00:00
|
|
|
{
|
2009-10-12 07:56:02 +00:00
|
|
|
ColorBlock colors;
|
|
|
|
|
|
|
|
if (format == nvtt::Format_BC1)
|
2009-07-06 09:02:20 +00:00
|
|
|
{
|
2009-10-12 07:56:02 +00:00
|
|
|
const BlockDXT1 * block = (const BlockDXT1 *)ptr;
|
|
|
|
|
2009-07-06 09:02:20 +00:00
|
|
|
if (decoder == Decoder_Reference) {
|
|
|
|
block->decodeBlock(&colors);
|
|
|
|
}
|
|
|
|
else if (decoder == Decoder_NV5x) {
|
|
|
|
block->decodeBlockNV5x(&colors);
|
|
|
|
}
|
|
|
|
}
|
2009-10-12 07:56:02 +00:00
|
|
|
else if (format == nvtt::Format_BC2)
|
|
|
|
{
|
|
|
|
const BlockDXT3 * block = (const BlockDXT3 *)ptr;
|
2009-07-06 09:02:20 +00:00
|
|
|
|
2009-10-12 07:56:02 +00:00
|
|
|
#pragma message(NV_FILE_LINE "Add NV5x decoder to DXT3 block")
|
|
|
|
//if (decoder == Decoder_Reference) {
|
|
|
|
block->decodeBlock(&colors);
|
|
|
|
//}
|
|
|
|
//else if (decoder == Decoder_NV5x) {
|
|
|
|
// block->decodeBlockNV5x(&colors);
|
|
|
|
//}
|
|
|
|
}
|
|
|
|
else if (format == nvtt::Format_BC3)
|
2009-07-06 09:02:20 +00:00
|
|
|
{
|
2009-10-12 07:56:02 +00:00
|
|
|
const BlockDXT5 * block = (const BlockDXT5 *)ptr;
|
|
|
|
|
2009-07-06 09:02:20 +00:00
|
|
|
if (decoder == Decoder_Reference) {
|
|
|
|
block->decodeBlock(&colors);
|
|
|
|
}
|
|
|
|
else if (decoder == Decoder_NV5x) {
|
|
|
|
block->decodeBlockNV5x(&colors);
|
|
|
|
}
|
2009-10-12 07:56:02 +00:00
|
|
|
}
|
2009-07-06 09:02:20 +00:00
|
|
|
|
2009-10-12 07:56:02 +00:00
|
|
|
for (int yy = 0; yy < 4; yy++)
|
|
|
|
{
|
|
|
|
for (int xx = 0; xx < 4; xx++)
|
2009-07-06 09:02:20 +00:00
|
|
|
{
|
2009-10-12 07:56:02 +00:00
|
|
|
Color32 c = colors.color(xx, yy);
|
|
|
|
|
|
|
|
if (x * 4 + xx < w && y * 4 + yy < h)
|
2009-07-06 09:02:20 +00:00
|
|
|
{
|
2009-10-12 07:56:02 +00:00
|
|
|
img->setPixel(float(c.r) * 1.0f/255.0f, x*4 + xx, y*4 + yy, 0);
|
|
|
|
img->setPixel(float(c.g) * 1.0f/255.0f, x*4 + xx, y*4 + yy, 1);
|
|
|
|
img->setPixel(float(c.b) * 1.0f/255.0f, x*4 + xx, y*4 + yy, 2);
|
|
|
|
img->setPixel(float(c.a) * 1.0f/255.0f, x*4 + xx, y*4 + yy, 3);
|
2009-07-06 09:02:20 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2009-10-12 07:56:02 +00:00
|
|
|
|
|
|
|
ptr += bs;
|
2009-07-06 09:02:20 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
catch(...) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2009-03-16 08:37:07 +00:00
|
|
|
void TexImage::resize(int w, int h, ResizeFilter filter)
|
2009-01-05 10:17:06 +00:00
|
|
|
{
|
2009-03-07 07:14:00 +00:00
|
|
|
if (m->imageArray.count() > 0)
|
|
|
|
{
|
2009-03-15 10:18:54 +00:00
|
|
|
if (w == m->imageArray[0]->width() && h == m->imageArray[0]->height()) return;
|
2009-03-07 07:14:00 +00:00
|
|
|
}
|
|
|
|
|
2009-03-16 08:37:07 +00:00
|
|
|
// @@ TODO: if cubemap, make sure w == h.
|
2009-03-07 07:14:00 +00:00
|
|
|
|
|
|
|
detach();
|
|
|
|
|
2009-03-16 08:47:20 +00:00
|
|
|
FloatImage::WrapMode wrapMode = (FloatImage::WrapMode)m->wrapMode;
|
|
|
|
|
2009-03-16 09:05:32 +00:00
|
|
|
foreach (i, m->imageArray)
|
2009-03-07 07:14:00 +00:00
|
|
|
{
|
2009-03-16 08:47:20 +00:00
|
|
|
if (m->imageArray[i] == NULL) continue;
|
2009-03-07 07:14:00 +00:00
|
|
|
|
|
|
|
if (m->alphaMode == AlphaMode_Transparency)
|
|
|
|
{
|
|
|
|
if (filter == ResizeFilter_Box)
|
|
|
|
{
|
|
|
|
BoxFilter filter;
|
2009-03-15 10:18:54 +00:00
|
|
|
m->imageArray[i]->resize(filter, w, h, wrapMode, 3);
|
2009-03-07 07:14:00 +00:00
|
|
|
}
|
|
|
|
else if (filter == ResizeFilter_Triangle)
|
|
|
|
{
|
|
|
|
TriangleFilter filter;
|
2009-03-15 10:18:54 +00:00
|
|
|
m->imageArray[i]->resize(filter, w, h, wrapMode, 3);
|
2009-03-07 07:14:00 +00:00
|
|
|
}
|
|
|
|
else if (filter == ResizeFilter_Kaiser)
|
|
|
|
{
|
|
|
|
//KaiserFilter filter(inputOptions.kaiserWidth);
|
|
|
|
//filter.setParameters(inputOptions.kaiserAlpha, inputOptions.kaiserStretch);
|
|
|
|
KaiserFilter filter(3);
|
2009-03-15 10:18:54 +00:00
|
|
|
m->imageArray[i]->resize(filter, w, h, wrapMode, 3);
|
2009-03-07 07:14:00 +00:00
|
|
|
}
|
|
|
|
else //if (filter == ResizeFilter_Mitchell)
|
|
|
|
{
|
|
|
|
nvDebugCheck(filter == ResizeFilter_Mitchell);
|
|
|
|
MitchellFilter filter;
|
2009-03-15 10:18:54 +00:00
|
|
|
m->imageArray[i]->resize(filter, w, h, wrapMode, 3);
|
2009-03-07 07:14:00 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
if (filter == ResizeFilter_Box)
|
|
|
|
{
|
|
|
|
BoxFilter filter;
|
2009-03-15 10:18:54 +00:00
|
|
|
m->imageArray[i]->resize(filter, w, h, wrapMode);
|
2009-03-07 07:14:00 +00:00
|
|
|
}
|
|
|
|
else if (filter == ResizeFilter_Triangle)
|
|
|
|
{
|
|
|
|
TriangleFilter filter;
|
2009-03-15 10:18:54 +00:00
|
|
|
m->imageArray[i]->resize(filter, w, h, wrapMode);
|
2009-03-07 07:14:00 +00:00
|
|
|
}
|
|
|
|
else if (filter == ResizeFilter_Kaiser)
|
|
|
|
{
|
|
|
|
//KaiserFilter filter(inputOptions.kaiserWidth);
|
|
|
|
//filter.setParameters(inputOptions.kaiserAlpha, inputOptions.kaiserStretch);
|
|
|
|
KaiserFilter filter(3);
|
2009-03-15 10:18:54 +00:00
|
|
|
m->imageArray[i]->resize(filter, w, h, wrapMode);
|
2009-03-07 07:14:00 +00:00
|
|
|
}
|
|
|
|
else //if (filter == ResizeFilter_Mitchell)
|
|
|
|
{
|
|
|
|
nvDebugCheck(filter == ResizeFilter_Mitchell);
|
|
|
|
MitchellFilter filter;
|
2009-03-15 10:18:54 +00:00
|
|
|
m->imageArray[i]->resize(filter, w, h, wrapMode);
|
2009-03-07 07:14:00 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2009-03-16 08:37:07 +00:00
|
|
|
void TexImage::resize(int maxExtent, RoundMode roundMode, ResizeFilter filter)
|
2009-03-07 07:14:00 +00:00
|
|
|
{
|
|
|
|
if (m->imageArray.count() > 0)
|
|
|
|
{
|
2009-03-15 10:18:54 +00:00
|
|
|
int w = m->imageArray[0]->width();
|
|
|
|
int h = m->imageArray[0]->height();
|
2009-03-07 07:14:00 +00:00
|
|
|
|
|
|
|
nvDebugCheck(w > 0);
|
|
|
|
nvDebugCheck(h > 0);
|
|
|
|
|
|
|
|
if (roundMode != RoundMode_None)
|
|
|
|
{
|
|
|
|
// rounded max extent should never be higher than original max extent.
|
|
|
|
maxExtent = previousPowerOfTwo(maxExtent);
|
|
|
|
}
|
|
|
|
|
|
|
|
// Scale extents without changing aspect ratio.
|
2009-03-14 03:29:43 +00:00
|
|
|
int maxwh = max(w, h);
|
2009-03-07 07:14:00 +00:00
|
|
|
if (maxExtent != 0 && maxwh > maxExtent)
|
|
|
|
{
|
2009-03-14 03:29:43 +00:00
|
|
|
w = max((w * maxExtent) / maxwh, 1);
|
|
|
|
h = max((h * maxExtent) / maxwh, 1);
|
2009-03-07 07:14:00 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// Round to power of two.
|
|
|
|
if (roundMode == RoundMode_ToNextPowerOfTwo)
|
|
|
|
{
|
|
|
|
w = nextPowerOfTwo(w);
|
|
|
|
h = nextPowerOfTwo(h);
|
|
|
|
}
|
|
|
|
else if (roundMode == RoundMode_ToNearestPowerOfTwo)
|
|
|
|
{
|
|
|
|
w = nearestPowerOfTwo(w);
|
|
|
|
h = nearestPowerOfTwo(h);
|
|
|
|
}
|
|
|
|
else if (roundMode == RoundMode_ToPreviousPowerOfTwo)
|
|
|
|
{
|
|
|
|
w = previousPowerOfTwo(w);
|
|
|
|
h = previousPowerOfTwo(h);
|
|
|
|
}
|
|
|
|
|
|
|
|
resize(w, h, filter);
|
|
|
|
}
|
2009-01-05 10:17:06 +00:00
|
|
|
}
|
|
|
|
|
2009-03-16 08:37:07 +00:00
|
|
|
bool TexImage::buildNextMipmap(MipmapFilter filter)
|
2009-01-05 10:17:06 +00:00
|
|
|
{
|
2009-03-14 03:29:43 +00:00
|
|
|
if (m->imageArray.count() > 0)
|
|
|
|
{
|
2009-03-15 10:18:54 +00:00
|
|
|
int w = m->imageArray[0]->width();
|
|
|
|
int h = m->imageArray[0]->height();
|
2009-03-07 07:14:00 +00:00
|
|
|
|
2009-03-14 03:29:43 +00:00
|
|
|
nvDebugCheck(w > 0);
|
|
|
|
nvDebugCheck(h > 0);
|
|
|
|
|
2009-07-06 09:02:20 +00:00
|
|
|
if (w == 1 && h == 1)
|
|
|
|
{
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
}
|
2009-03-14 03:29:43 +00:00
|
|
|
|
2009-07-06 09:02:20 +00:00
|
|
|
detach();
|
2009-03-07 07:14:00 +00:00
|
|
|
|
2009-03-16 08:47:20 +00:00
|
|
|
FloatImage::WrapMode wrapMode = (FloatImage::WrapMode)m->wrapMode;
|
|
|
|
|
2009-03-16 09:05:32 +00:00
|
|
|
foreach (i, m->imageArray)
|
2009-03-07 07:14:00 +00:00
|
|
|
{
|
2009-03-16 08:47:20 +00:00
|
|
|
if (m->imageArray[i] == NULL) continue;
|
2009-03-07 07:14:00 +00:00
|
|
|
|
|
|
|
if (m->alphaMode == AlphaMode_Transparency)
|
|
|
|
{
|
|
|
|
if (filter == MipmapFilter_Box)
|
|
|
|
{
|
|
|
|
BoxFilter filter;
|
2009-03-15 10:18:54 +00:00
|
|
|
m->imageArray[i]->downSample(filter, wrapMode, 3);
|
2009-03-07 07:14:00 +00:00
|
|
|
}
|
|
|
|
else if (filter == MipmapFilter_Triangle)
|
|
|
|
{
|
|
|
|
TriangleFilter filter;
|
2009-03-15 10:18:54 +00:00
|
|
|
m->imageArray[i]->downSample(filter, wrapMode, 3);
|
2009-03-07 07:14:00 +00:00
|
|
|
}
|
|
|
|
else if (filter == MipmapFilter_Kaiser)
|
|
|
|
{
|
|
|
|
nvDebugCheck(filter == MipmapFilter_Kaiser);
|
|
|
|
//KaiserFilter filter(inputOptions.kaiserWidth);
|
|
|
|
//filter.setParameters(inputOptions.kaiserAlpha, inputOptions.kaiserStretch);
|
|
|
|
KaiserFilter filter(3);
|
2009-03-15 10:18:54 +00:00
|
|
|
m->imageArray[i]->downSample(filter, wrapMode, 3);
|
2009-03-07 07:14:00 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
if (filter == MipmapFilter_Box)
|
|
|
|
{
|
2009-03-15 10:18:54 +00:00
|
|
|
m->imageArray[i]->fastDownSample();
|
2009-03-07 07:14:00 +00:00
|
|
|
}
|
|
|
|
else if (filter == MipmapFilter_Triangle)
|
|
|
|
{
|
|
|
|
TriangleFilter filter;
|
2009-03-15 10:18:54 +00:00
|
|
|
m->imageArray[i]->downSample(filter, wrapMode);
|
2009-03-07 07:14:00 +00:00
|
|
|
}
|
|
|
|
else //if (filter == MipmapFilter_Kaiser)
|
|
|
|
{
|
|
|
|
nvDebugCheck(filter == MipmapFilter_Kaiser);
|
|
|
|
//KaiserFilter filter(inputOptions.kaiserWidth);
|
|
|
|
//filter.setParameters(inputOptions.kaiserAlpha, inputOptions.kaiserStretch);
|
|
|
|
KaiserFilter filter(3);
|
2009-03-15 10:18:54 +00:00
|
|
|
m->imageArray[i]->downSample(filter, wrapMode);
|
2009-03-07 07:14:00 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2009-03-14 03:29:43 +00:00
|
|
|
|
2009-07-06 09:02:20 +00:00
|
|
|
return true;
|
2009-01-05 10:17:06 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// Color transforms.
|
2009-03-16 08:37:07 +00:00
|
|
|
void TexImage::toLinear(float gamma)
|
2009-01-05 10:17:06 +00:00
|
|
|
{
|
2009-03-07 07:14:00 +00:00
|
|
|
if (equal(gamma, 1.0f)) return;
|
|
|
|
|
|
|
|
detach();
|
|
|
|
|
2009-03-16 09:05:32 +00:00
|
|
|
foreach (i, m->imageArray)
|
2009-01-05 10:17:06 +00:00
|
|
|
{
|
2009-03-16 08:47:20 +00:00
|
|
|
if (m->imageArray[i] == NULL) continue;
|
|
|
|
|
2009-03-15 10:18:54 +00:00
|
|
|
m->imageArray[i]->toLinear(0, 3, gamma);
|
2009-01-05 10:17:06 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2009-03-16 08:37:07 +00:00
|
|
|
void TexImage::toGamma(float gamma)
|
2009-01-05 10:17:06 +00:00
|
|
|
{
|
2009-03-07 07:14:00 +00:00
|
|
|
if (equal(gamma, 1.0f)) return;
|
|
|
|
|
|
|
|
detach();
|
|
|
|
|
2009-03-16 09:05:32 +00:00
|
|
|
foreach (i, m->imageArray)
|
2009-01-05 10:17:06 +00:00
|
|
|
{
|
2009-03-16 08:47:20 +00:00
|
|
|
if (m->imageArray[i] == NULL) continue;
|
|
|
|
|
2009-03-15 10:18:54 +00:00
|
|
|
m->imageArray[i]->toGamma(0, 3, gamma);
|
2009-01-05 10:17:06 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2009-03-16 08:37:07 +00:00
|
|
|
void TexImage::transform(const float w0[4], const float w1[4], const float w2[4], const float w3[4], const float offset[4])
|
2009-01-05 10:17:06 +00:00
|
|
|
{
|
2009-03-07 07:14:00 +00:00
|
|
|
detach();
|
|
|
|
|
|
|
|
Matrix xform(
|
|
|
|
Vector4(w0[0], w0[1], w0[2], w0[3]),
|
|
|
|
Vector4(w1[0], w1[1], w1[2], w1[3]),
|
|
|
|
Vector4(w2[0], w2[1], w2[2], w2[3]),
|
|
|
|
Vector4(w3[0], w3[1], w3[2], w3[3]));
|
|
|
|
|
|
|
|
Vector4 voffset(offset[0], offset[1], offset[2], offset[3]);
|
|
|
|
|
2009-03-16 09:05:32 +00:00
|
|
|
foreach (i, m->imageArray)
|
2009-03-07 07:14:00 +00:00
|
|
|
{
|
2009-03-16 08:47:20 +00:00
|
|
|
if (m->imageArray[i] == NULL) continue;
|
|
|
|
|
2009-03-15 10:18:54 +00:00
|
|
|
m->imageArray[i]->transform(0, xform, voffset);
|
2009-03-07 07:14:00 +00:00
|
|
|
}
|
2009-01-05 10:17:06 +00:00
|
|
|
}
|
|
|
|
|
2009-03-16 08:37:07 +00:00
|
|
|
void TexImage::swizzle(int r, int g, int b, int a)
|
2009-01-05 10:17:06 +00:00
|
|
|
{
|
2009-03-07 07:14:00 +00:00
|
|
|
if (r == 0 && g == 1 && b == 2 && a == 3) return;
|
|
|
|
|
|
|
|
detach();
|
|
|
|
|
2009-03-16 09:05:32 +00:00
|
|
|
foreach (i, m->imageArray)
|
2009-01-05 10:17:06 +00:00
|
|
|
{
|
2009-03-16 08:47:20 +00:00
|
|
|
if (m->imageArray[i] == NULL) continue;
|
|
|
|
|
2009-03-15 10:18:54 +00:00
|
|
|
m->imageArray[i]->swizzle(0, r, g, b, a);
|
2009-01-05 10:17:06 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2009-03-16 08:37:07 +00:00
|
|
|
void TexImage::scaleBias(int channel, float scale, float bias)
|
2009-01-05 10:17:06 +00:00
|
|
|
{
|
2009-03-07 07:14:00 +00:00
|
|
|
if (equal(scale, 1.0f) && equal(bias, 0.0f)) return;
|
|
|
|
|
|
|
|
detach();
|
|
|
|
|
2009-03-16 09:05:32 +00:00
|
|
|
foreach (i, m->imageArray)
|
2009-01-05 10:17:06 +00:00
|
|
|
{
|
2009-03-16 08:47:20 +00:00
|
|
|
if (m->imageArray[i] == NULL) continue;
|
|
|
|
|
2009-03-15 10:18:54 +00:00
|
|
|
m->imageArray[i]->scaleBias(channel, 1, scale, bias);
|
2009-01-05 10:17:06 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2009-03-16 09:05:32 +00:00
|
|
|
void TexImage::blend(float red, float green, float blue, float alpha, float t)
|
2009-01-05 10:17:06 +00:00
|
|
|
{
|
2009-03-07 07:14:00 +00:00
|
|
|
detach();
|
|
|
|
|
2009-03-16 09:05:32 +00:00
|
|
|
foreach (i, m->imageArray)
|
2009-01-05 10:17:06 +00:00
|
|
|
{
|
2009-03-16 08:54:43 +00:00
|
|
|
FloatImage * img = m->imageArray[i];
|
|
|
|
if (img == NULL) continue;
|
|
|
|
|
|
|
|
float * restrict r = img->channel(0);
|
2009-03-16 09:05:32 +00:00
|
|
|
float * restrict g = img->channel(1);
|
|
|
|
float * restrict b = img->channel(2);
|
|
|
|
float * restrict a = img->channel(3);
|
2009-03-16 08:47:20 +00:00
|
|
|
|
2009-03-16 08:54:43 +00:00
|
|
|
const int count = img->width() * img->height();
|
|
|
|
for (int i = 0; i < count; i++)
|
|
|
|
{
|
2009-03-16 09:05:32 +00:00
|
|
|
r[i] = lerp(r[i], red, t);
|
|
|
|
g[i] = lerp(g[i], green, t);
|
|
|
|
b[i] = lerp(b[i], blue, t);
|
|
|
|
a[i] = lerp(a[i], alpha, t);
|
2009-03-16 08:54:43 +00:00
|
|
|
}
|
2009-01-05 10:17:06 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2009-03-16 08:37:07 +00:00
|
|
|
void TexImage::premultiplyAlpha()
|
2009-01-05 10:17:06 +00:00
|
|
|
{
|
2009-03-07 07:14:00 +00:00
|
|
|
detach();
|
|
|
|
|
2009-03-16 09:05:32 +00:00
|
|
|
foreach (i, m->imageArray)
|
2009-03-16 08:47:20 +00:00
|
|
|
{
|
2009-03-16 08:54:43 +00:00
|
|
|
FloatImage * img = m->imageArray[i];
|
|
|
|
if (img == NULL) continue;
|
|
|
|
|
|
|
|
float * restrict r = img->channel(0);
|
2009-03-16 09:05:32 +00:00
|
|
|
float * restrict g = img->channel(1);
|
|
|
|
float * restrict b = img->channel(2);
|
|
|
|
float * restrict a = img->channel(3);
|
2009-03-16 08:47:20 +00:00
|
|
|
|
2009-03-16 08:54:43 +00:00
|
|
|
const int count = img->width() * img->height();
|
|
|
|
for (int i = 0; i < count; i++)
|
|
|
|
{
|
|
|
|
r[i] *= a[i];
|
|
|
|
g[i] *= a[i];
|
|
|
|
b[i] *= a[i];
|
|
|
|
}
|
2009-03-16 08:47:20 +00:00
|
|
|
}
|
2009-03-16 08:37:07 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void TexImage::toGreyScale(float redScale, float greenScale, float blueScale, float alphaScale)
|
|
|
|
{
|
|
|
|
detach();
|
|
|
|
|
2009-03-16 09:05:32 +00:00
|
|
|
foreach (i, m->imageArray)
|
2009-03-16 08:47:20 +00:00
|
|
|
{
|
|
|
|
FloatImage * img = m->imageArray[i];
|
|
|
|
if (img == NULL) continue;
|
|
|
|
|
|
|
|
float sum = redScale + greenScale + blueScale + alphaScale;
|
|
|
|
redScale /= sum;
|
|
|
|
greenScale /= sum;
|
|
|
|
blueScale /= sum;
|
|
|
|
alphaScale /= sum;
|
|
|
|
|
|
|
|
float * restrict r = img->channel(0);
|
2009-03-16 09:05:32 +00:00
|
|
|
float * restrict g = img->channel(1);
|
|
|
|
float * restrict b = img->channel(2);
|
|
|
|
float * restrict a = img->channel(3);
|
2009-03-16 08:47:20 +00:00
|
|
|
|
|
|
|
const int count = img->width() * img->height();
|
|
|
|
for (int i = 0; i < count; i++)
|
|
|
|
{
|
|
|
|
float grey = r[i] * redScale + g[i] * greenScale + b[i] * blueScale + a[i] * alphaScale;
|
|
|
|
a[i] = b[i] = g[i] = r[i] = grey;
|
|
|
|
}
|
|
|
|
}
|
2009-03-16 08:37:07 +00:00
|
|
|
}
|
|
|
|
|
2009-03-16 09:05:32 +00:00
|
|
|
// Draw colored border.
|
|
|
|
void TexImage::setBorder(float r, float g, float b, float a)
|
|
|
|
{
|
|
|
|
detach();
|
|
|
|
|
|
|
|
foreach (i, m->imageArray)
|
|
|
|
{
|
|
|
|
FloatImage * img = m->imageArray[i];
|
|
|
|
if (img == NULL) continue;
|
|
|
|
|
|
|
|
const int w = img->width();
|
|
|
|
const int h = img->height();
|
|
|
|
|
|
|
|
for (int i = 0; i < w; i++)
|
|
|
|
{
|
|
|
|
img->setPixel(r, i, 0, 0);
|
|
|
|
img->setPixel(g, i, 0, 1);
|
|
|
|
img->setPixel(b, i, 0, 2);
|
|
|
|
img->setPixel(a, i, 0, 3);
|
|
|
|
|
|
|
|
img->setPixel(r, i, h-1, 0);
|
|
|
|
img->setPixel(g, i, h-1, 1);
|
|
|
|
img->setPixel(b, i, h-1, 2);
|
|
|
|
img->setPixel(a, i, h-1, 3);
|
|
|
|
}
|
|
|
|
|
|
|
|
for (int i = 0; i < h; i++)
|
|
|
|
{
|
|
|
|
img->setPixel(r, 0, i, 0);
|
|
|
|
img->setPixel(g, 0, i, 1);
|
|
|
|
img->setPixel(b, 0, i, 2);
|
|
|
|
img->setPixel(a, 0, i, 3);
|
|
|
|
|
|
|
|
img->setPixel(r, w-1, i, 0);
|
|
|
|
img->setPixel(g, w-1, i, 1);
|
|
|
|
img->setPixel(b, w-1, i, 2);
|
|
|
|
img->setPixel(a, w-1, i, 3);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Fill image with the given color.
|
|
|
|
void TexImage::fill(float red, float green, float blue, float alpha)
|
|
|
|
{
|
|
|
|
detach();
|
|
|
|
|
|
|
|
foreach (i, m->imageArray)
|
|
|
|
{
|
|
|
|
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);
|
|
|
|
|
|
|
|
const int count = img->width() * img->height();
|
|
|
|
for (int i = 0; i < count; i++)
|
|
|
|
{
|
|
|
|
r[i] = red;
|
|
|
|
g[i] = green;
|
|
|
|
b[i] = blue;
|
|
|
|
a[i] = alpha;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2009-03-16 08:37:07 +00:00
|
|
|
// Set normal map options.
|
|
|
|
void TexImage::toNormalMap(float sm, float medium, float big, float large)
|
|
|
|
{
|
|
|
|
detach();
|
|
|
|
|
2009-03-16 09:05:32 +00:00
|
|
|
foreach (i, m->imageArray)
|
2009-03-16 08:47:20 +00:00
|
|
|
{
|
|
|
|
if (m->imageArray[i] == NULL) continue;
|
2009-03-16 08:37:07 +00:00
|
|
|
|
2009-03-16 08:47:20 +00:00
|
|
|
// @@ Not implemented.
|
|
|
|
}
|
2009-01-05 10:17:06 +00:00
|
|
|
}
|
|
|
|
|
2009-03-16 08:37:07 +00:00
|
|
|
void TexImage::toHeightMap()
|
2009-01-05 10:17:06 +00:00
|
|
|
{
|
2009-03-07 07:14:00 +00:00
|
|
|
detach();
|
|
|
|
|
2009-03-16 09:05:32 +00:00
|
|
|
foreach (i, m->imageArray)
|
2009-03-16 08:47:20 +00:00
|
|
|
{
|
|
|
|
if (m->imageArray[i] == NULL) continue;
|
|
|
|
|
|
|
|
// @@ Not implemented.
|
|
|
|
}
|
2009-01-05 10:17:06 +00:00
|
|
|
}
|
|
|
|
|
2009-03-16 08:37:07 +00:00
|
|
|
void TexImage::normalizeNormalMap()
|
|
|
|
{
|
|
|
|
//nvCheck(m->isNormalMap);
|
|
|
|
|
|
|
|
detach();
|
2009-01-05 10:17:06 +00:00
|
|
|
|
2009-03-16 09:05:32 +00:00
|
|
|
foreach (i, m->imageArray)
|
2009-03-16 08:37:07 +00:00
|
|
|
{
|
2009-03-16 08:47:20 +00:00
|
|
|
if (m->imageArray[i] == NULL) continue;
|
|
|
|
|
2009-03-16 08:37:07 +00:00
|
|
|
nv::normalizeNormalMap(m->imageArray[i]);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Compress.
|
2009-07-06 09:02:20 +00:00
|
|
|
/*void TexImage::outputCompressed(const CompressionOptions & compressionOptions, const OutputOptions & outputOptions)
|
2009-03-16 08:37:07 +00:00
|
|
|
{
|
2009-03-16 09:05:32 +00:00
|
|
|
foreach (i, m->imageArray)
|
2009-03-16 08:47:20 +00:00
|
|
|
{
|
|
|
|
if (m->imageArray[i] == NULL) continue;
|
|
|
|
|
|
|
|
// @@ Not implemented.
|
|
|
|
}
|
2009-07-06 09:02:20 +00:00
|
|
|
}*/
|
|
|
|
|
|
|
|
float TexImage::rootMeanSquaredError_rgb(const TexImage & reference) const
|
|
|
|
{
|
|
|
|
int totalCount = 0;
|
|
|
|
double mse = 0;
|
|
|
|
|
|
|
|
const int faceCount = this->faceCount();
|
|
|
|
if (faceCount != reference.faceCount()) {
|
|
|
|
return FLT_MAX;
|
|
|
|
}
|
|
|
|
|
|
|
|
for (int f = 0; f < faceCount; f++)
|
|
|
|
{
|
|
|
|
const FloatImage * img = m->imageArray[f];
|
|
|
|
const FloatImage * ref = reference.m->imageArray[f];
|
|
|
|
|
|
|
|
if (img == NULL || ref == NULL) {
|
|
|
|
return FLT_MAX;
|
|
|
|
}
|
|
|
|
|
|
|
|
nvCheck(img->componentNum() == 4);
|
|
|
|
nvCheck(ref->componentNum() == 4);
|
|
|
|
|
|
|
|
const uint count = img->width() * img->height();
|
|
|
|
totalCount += count;
|
|
|
|
|
|
|
|
for (uint i = 0; i < count; i++)
|
|
|
|
{
|
|
|
|
float r0 = img->pixel(4 * i + count * 0);
|
|
|
|
float g0 = img->pixel(4 * i + count * 1);
|
|
|
|
float b0 = img->pixel(4 * i + count * 2);
|
|
|
|
float a0 = img->pixel(4 * i + count * 3);
|
|
|
|
float r1 = ref->pixel(4 * i + count * 0);
|
|
|
|
float g1 = ref->pixel(4 * i + count * 1);
|
|
|
|
float b1 = ref->pixel(4 * i + count * 2);
|
|
|
|
float a1 = ref->pixel(4 * i + count * 3);
|
|
|
|
|
|
|
|
float r = r0 - r1;
|
|
|
|
float g = g0 - g1;
|
|
|
|
float b = b0 - b1;
|
|
|
|
float a = a0 - a1;
|
|
|
|
|
|
|
|
if (reference.alphaMode() == nvtt::AlphaMode_Transparency)
|
|
|
|
{
|
|
|
|
mse += double(r * r * a1) / 255.0;
|
|
|
|
mse += double(g * g * a1) / 255.0;
|
|
|
|
mse += double(b * b * a1) / 255.0;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
mse += r * r;
|
|
|
|
mse += g * g;
|
|
|
|
mse += b * b;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return float(sqrt(mse / totalCount));
|
2009-03-16 08:37:07 +00:00
|
|
|
}
|
2009-07-06 09:02:20 +00:00
|
|
|
|
|
|
|
float TexImage::rootMeanSquaredError_alpha(const TexImage & reference) const
|
|
|
|
{
|
|
|
|
int totalCount = 0;
|
|
|
|
double mse = 0;
|
|
|
|
|
|
|
|
const int faceCount = this->faceCount();
|
|
|
|
if (faceCount != reference.faceCount()) {
|
|
|
|
return FLT_MAX;
|
|
|
|
}
|
|
|
|
|
|
|
|
for (int f = 0; f < faceCount; f++)
|
|
|
|
{
|
|
|
|
const FloatImage * img = m->imageArray[f];
|
|
|
|
const FloatImage * ref = reference.m->imageArray[f];
|
|
|
|
|
|
|
|
if (img == NULL || ref == NULL) {
|
|
|
|
return FLT_MAX;
|
|
|
|
}
|
|
|
|
|
|
|
|
nvCheck(img->componentNum() == 4);
|
|
|
|
nvCheck(ref->componentNum() == 4);
|
|
|
|
|
|
|
|
const uint count = img->width() * img->height();
|
|
|
|
totalCount += count;
|
|
|
|
|
|
|
|
for (uint i = 0; i < count; i++)
|
|
|
|
{
|
|
|
|
float a0 = img->pixel(4 * i + count * 3);
|
|
|
|
float a1 = ref->pixel(4 * i + count * 3);
|
|
|
|
|
|
|
|
float a = a0 - a1;
|
|
|
|
|
|
|
|
mse += a * a;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return float(sqrt(mse / totalCount));
|
|
|
|
}
|
|
|
|
|