Merge private branch.
This commit is contained in:
@ -23,10 +23,10 @@
|
|||||||
|
|
||||||
#include "BlockDXT.h"
|
#include "BlockDXT.h"
|
||||||
|
|
||||||
#include <nvimage/ColorBlock.h>
|
#include "ColorBlock.h"
|
||||||
|
|
||||||
#include <nvcore/Stream.h>
|
#include "nvcore/Stream.h"
|
||||||
#include <nvcore/Containers.h> // swap
|
#include "nvcore/Utils.h" // swap
|
||||||
|
|
||||||
|
|
||||||
using namespace nv;
|
using namespace nv;
|
||||||
|
@ -1,26 +1,28 @@
|
|||||||
// This code is in the public domain -- castanyo@yahoo.es
|
// This code is in the public domain -- castanyo@yahoo.es
|
||||||
|
|
||||||
#include <nvcore/Containers.h> // swap
|
#include "ColorBlock.h"
|
||||||
#include <nvmath/Box.h>
|
#include "Image.h"
|
||||||
#include <nvimage/ColorBlock.h>
|
|
||||||
#include <nvimage/Image.h>
|
#include "nvmath/Box.h"
|
||||||
|
#include "nvcore/Utils.h" // swap
|
||||||
|
|
||||||
|
|
||||||
using namespace nv;
|
using namespace nv;
|
||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
|
|
||||||
// Get approximate luminance.
|
// Get approximate luminance.
|
||||||
inline static uint colorLuminance(Color32 c)
|
inline static uint colorLuminance(Color32 c)
|
||||||
{
|
{
|
||||||
return c.r + c.g + c.b;
|
return c.r + c.g + c.b;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Get the euclidean distance between the given colors.
|
// Get the euclidean distance between the given colors.
|
||||||
inline static uint colorDistance(Color32 c0, Color32 c1)
|
inline static uint colorDistance(Color32 c0, Color32 c1)
|
||||||
{
|
{
|
||||||
return (c0.r - c1.r) * (c0.r - c1.r) + (c0.g - c1.g) * (c0.g - c1.g) + (c0.b - c1.b) * (c0.b - c1.b);
|
return (c0.r - c1.r) * (c0.r - c1.r) + (c0.g - c1.g) * (c0.g - c1.g) + (c0.b - c1.b) * (c0.b - c1.b);
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace`
|
} // namespace`
|
||||||
|
|
||||||
|
|
||||||
@ -32,450 +34,450 @@ ColorBlock::ColorBlock()
|
|||||||
/// Init the color block from an array of colors.
|
/// Init the color block from an array of colors.
|
||||||
ColorBlock::ColorBlock(const uint * linearImage)
|
ColorBlock::ColorBlock(const uint * linearImage)
|
||||||
{
|
{
|
||||||
for(uint i = 0; i < 16; i++) {
|
for(uint i = 0; i < 16; i++) {
|
||||||
color(i) = Color32(linearImage[i]);
|
color(i) = Color32(linearImage[i]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Init the color block with the contents of the given block.
|
/// Init the color block with the contents of the given block.
|
||||||
ColorBlock::ColorBlock(const ColorBlock & block)
|
ColorBlock::ColorBlock(const ColorBlock & block)
|
||||||
{
|
{
|
||||||
for(uint i = 0; i < 16; i++) {
|
for(uint i = 0; i < 16; i++) {
|
||||||
color(i) = block.color(i);
|
color(i) = block.color(i);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/// Initialize this color block.
|
/// Initialize this color block.
|
||||||
ColorBlock::ColorBlock(const Image * img, uint x, uint y)
|
ColorBlock::ColorBlock(const Image * img, uint x, uint y)
|
||||||
{
|
{
|
||||||
init(img, x, y);
|
init(img, x, y);
|
||||||
}
|
}
|
||||||
|
|
||||||
void ColorBlock::init(const Image * img, uint x, uint y)
|
void ColorBlock::init(const Image * img, uint x, uint y)
|
||||||
{
|
{
|
||||||
nvDebugCheck(img != NULL);
|
nvDebugCheck(img != NULL);
|
||||||
|
|
||||||
const uint bw = min(img->width() - x, 4U);
|
|
||||||
const uint bh = min(img->height() - y, 4U);
|
|
||||||
nvDebugCheck(bw != 0 && bh != 0);
|
|
||||||
|
|
||||||
static const int remainder[] = {
|
const uint bw = min(img->width() - x, 4U);
|
||||||
0, 0, 0, 0,
|
const uint bh = min(img->height() - y, 4U);
|
||||||
0, 1, 0, 1,
|
nvDebugCheck(bw != 0 && bh != 0);
|
||||||
0, 1, 2, 0,
|
|
||||||
0, 1, 2, 3,
|
|
||||||
};
|
|
||||||
|
|
||||||
// Blocks that are smaller than 4x4 are handled by repeating the pixels.
|
static const int remainder[] = {
|
||||||
// @@ Thats only correct when block size is 1, 2 or 4, but not with 3. :(
|
0, 0, 0, 0,
|
||||||
|
0, 1, 0, 1,
|
||||||
|
0, 1, 2, 0,
|
||||||
|
0, 1, 2, 3,
|
||||||
|
};
|
||||||
|
|
||||||
for(uint i = 0; i < 4; i++) {
|
// Blocks that are smaller than 4x4 are handled by repeating the pixels.
|
||||||
//const int by = i % bh;
|
// @@ Thats only correct when block size is 1, 2 or 4, but not with 3. :(
|
||||||
const int by = remainder[(bh - 1) * 4 + i];
|
|
||||||
for(uint e = 0; e < 4; e++) {
|
for(uint i = 0; i < 4; i++) {
|
||||||
//const int bx = e % bw;
|
//const int by = i % bh;
|
||||||
const int bx = remainder[(bw - 1) * 4 + e];
|
const int by = remainder[(bh - 1) * 4 + i];
|
||||||
color(e, i) = img->pixel(x + bx, y + by);
|
for(uint e = 0; e < 4; e++) {
|
||||||
}
|
//const int bx = e % bw;
|
||||||
}
|
const int bx = remainder[(bw - 1) * 4 + e];
|
||||||
|
color(e, i) = img->pixel(x + bx, y + by);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void ColorBlock::init(uint w, uint h, uint * data, uint x, uint y)
|
void ColorBlock::init(uint w, uint h, uint * data, uint x, uint y)
|
||||||
{
|
{
|
||||||
nvDebugCheck(data != NULL);
|
nvDebugCheck(data != NULL);
|
||||||
|
|
||||||
const uint bw = min(w - x, 4U);
|
const uint bw = min(w - x, 4U);
|
||||||
const uint bh = min(h - y, 4U);
|
const uint bh = min(h - y, 4U);
|
||||||
nvDebugCheck(bw != 0 && bh != 0);
|
nvDebugCheck(bw != 0 && bh != 0);
|
||||||
|
|
||||||
// Blocks that are smaller than 4x4 are handled by repeating the pixels.
|
// Blocks that are smaller than 4x4 are handled by repeating the pixels.
|
||||||
// @@ Thats only correct when block size is 1, 2 or 4, but not with 3. :(
|
// @@ Thats only correct when block size is 1, 2 or 4, but not with 3. :(
|
||||||
|
|
||||||
for (uint i = 0; i < 4; i++)
|
for (uint i = 0; i < 4; i++)
|
||||||
{
|
{
|
||||||
const int by = i % bh;
|
const int by = i % bh;
|
||||||
|
|
||||||
for (uint e = 0; e < 4; e++)
|
|
||||||
{
|
|
||||||
const int bx = e % bw;
|
|
||||||
const uint idx = (y + by) * w + x + bx;
|
|
||||||
|
|
||||||
color(e, i).u = data[idx];
|
for (uint e = 0; e < 4; e++)
|
||||||
}
|
{
|
||||||
}
|
const int bx = e % bw;
|
||||||
|
const uint idx = (y + by) * w + x + bx;
|
||||||
|
|
||||||
|
color(e, i).u = data[idx];
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void ColorBlock::init(uint w, uint h, float * data, uint x, uint y)
|
void ColorBlock::init(uint w, uint h, float * data, uint x, uint y)
|
||||||
{
|
{
|
||||||
nvDebugCheck(data != NULL);
|
nvDebugCheck(data != NULL);
|
||||||
|
|
||||||
const uint bw = min(w - x, 4U);
|
const uint bw = min(w - x, 4U);
|
||||||
const uint bh = min(h - y, 4U);
|
const uint bh = min(h - y, 4U);
|
||||||
nvDebugCheck(bw != 0 && bh != 0);
|
nvDebugCheck(bw != 0 && bh != 0);
|
||||||
|
|
||||||
// Blocks that are smaller than 4x4 are handled by repeating the pixels.
|
// Blocks that are smaller than 4x4 are handled by repeating the pixels.
|
||||||
// @@ Thats only correct when block size is 1, 2 or 4, but not with 3. :(
|
// @@ Thats only correct when block size is 1, 2 or 4, but not with 3. :(
|
||||||
|
|
||||||
for (uint i = 0; i < 4; i++)
|
for (uint i = 0; i < 4; i++)
|
||||||
{
|
{
|
||||||
const uint by = i % bh;
|
const uint by = i % bh;
|
||||||
|
|
||||||
for (uint e = 0; e < 4; e++)
|
for (uint e = 0; e < 4; e++)
|
||||||
{
|
{
|
||||||
const uint bx = e % bw;
|
const uint bx = e % bw;
|
||||||
const uint idx = ((y + by) * w + x + bx) * 4;
|
const uint idx = ((y + by) * w + x + bx) * 4;
|
||||||
|
|
||||||
Color32 & c = color(e, i);
|
Color32 & c = color(e, i);
|
||||||
c.r = uint8(255 * clamp(data[idx + 0], 0.0f, 1.0f));
|
c.r = uint8(255 * clamp(data[idx + 0], 0.0f, 1.0f));
|
||||||
c.g = uint8(255 * clamp(data[idx + 1], 0.0f, 1.0f));
|
c.g = uint8(255 * clamp(data[idx + 1], 0.0f, 1.0f));
|
||||||
c.b = uint8(255 * clamp(data[idx + 2], 0.0f, 1.0f));
|
c.b = uint8(255 * clamp(data[idx + 2], 0.0f, 1.0f));
|
||||||
c.a = uint8(255 * clamp(data[idx + 3], 0.0f, 1.0f));
|
c.a = uint8(255 * clamp(data[idx + 3], 0.0f, 1.0f));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline uint8 component(Color32 c, uint i)
|
static inline uint8 component(Color32 c, uint i)
|
||||||
{
|
{
|
||||||
if (i == 0) return c.r;
|
if (i == 0) return c.r;
|
||||||
if (i == 1) return c.g;
|
if (i == 1) return c.g;
|
||||||
if (i == 2) return c.b;
|
if (i == 2) return c.b;
|
||||||
if (i == 3) return c.a;
|
if (i == 3) return c.a;
|
||||||
if (i == 4) return 0xFF;
|
if (i == 4) return 0xFF;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
void ColorBlock::swizzle(uint x, uint y, uint z, uint w)
|
void ColorBlock::swizzle(uint x, uint y, uint z, uint w)
|
||||||
{
|
{
|
||||||
for (int i = 0; i < 16; i++)
|
for (int i = 0; i < 16; i++)
|
||||||
{
|
{
|
||||||
Color32 c = m_color[i];
|
Color32 c = m_color[i];
|
||||||
m_color[i].r = component(c, x);
|
m_color[i].r = component(c, x);
|
||||||
m_color[i].g = component(c, y);
|
m_color[i].g = component(c, y);
|
||||||
m_color[i].b = component(c, z);
|
m_color[i].b = component(c, z);
|
||||||
m_color[i].a = component(c, w);
|
m_color[i].a = component(c, w);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/// Returns true if the block has a single color.
|
/// Returns true if the block has a single color.
|
||||||
bool ColorBlock::isSingleColor() const
|
bool ColorBlock::isSingleColor() const
|
||||||
{
|
{
|
||||||
Color32 mask(0xFF, 0xFF, 0xFF, 0x00);
|
Color32 mask(0xFF, 0xFF, 0xFF, 0x00);
|
||||||
uint u = m_color[0].u & mask.u;
|
uint u = m_color[0].u & mask.u;
|
||||||
|
|
||||||
for (int i = 1; i < 16; i++)
|
for (int i = 1; i < 16; i++)
|
||||||
{
|
{
|
||||||
if (u != (m_color[i].u & mask.u))
|
if (u != (m_color[i].u & mask.u))
|
||||||
{
|
{
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
/// Returns true if the block has a single color, ignoring transparent pixels.
|
/// Returns true if the block has a single color, ignoring transparent pixels.
|
||||||
bool ColorBlock::isSingleColorNoAlpha() const
|
bool ColorBlock::isSingleColorNoAlpha() const
|
||||||
{
|
{
|
||||||
Color32 c;
|
Color32 c;
|
||||||
int i;
|
int i;
|
||||||
for(i = 0; i < 16; i++)
|
for(i = 0; i < 16; i++)
|
||||||
{
|
{
|
||||||
if (m_color[i].a != 0) {
|
if (m_color[i].a != 0) {
|
||||||
c = m_color[i];
|
c = m_color[i];
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Color32 mask(0xFF, 0xFF, 0xFF, 0x00);
|
Color32 mask(0xFF, 0xFF, 0xFF, 0x00);
|
||||||
uint u = c.u & mask.u;
|
uint u = c.u & mask.u;
|
||||||
|
|
||||||
for(; i < 16; i++)
|
for(; i < 16; i++)
|
||||||
{
|
{
|
||||||
if (u != (m_color[i].u & mask.u))
|
if (u != (m_color[i].u & mask.u))
|
||||||
{
|
{
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/// Count number of unique colors in this color block.
|
/// Count number of unique colors in this color block.
|
||||||
uint ColorBlock::countUniqueColors() const
|
uint ColorBlock::countUniqueColors() const
|
||||||
{
|
{
|
||||||
uint count = 0;
|
uint count = 0;
|
||||||
|
|
||||||
// @@ This does not have to be o(n^2)
|
// @@ This does not have to be o(n^2)
|
||||||
for(int i = 0; i < 16; i++)
|
for(int i = 0; i < 16; i++)
|
||||||
{
|
{
|
||||||
bool unique = true;
|
bool unique = true;
|
||||||
for(int j = 0; j < i; j++) {
|
for(int j = 0; j < i; j++) {
|
||||||
if( m_color[i] != m_color[j] ) {
|
if( m_color[i] != m_color[j] ) {
|
||||||
unique = false;
|
unique = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if( unique ) {
|
if( unique ) {
|
||||||
count++;
|
count++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return count;
|
return count;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Get average color of the block.
|
/// Get average color of the block.
|
||||||
Color32 ColorBlock::averageColor() const
|
Color32 ColorBlock::averageColor() const
|
||||||
{
|
{
|
||||||
uint r, g, b, a;
|
uint r, g, b, a;
|
||||||
r = g = b = a = 0;
|
r = g = b = a = 0;
|
||||||
|
|
||||||
for(uint i = 0; i < 16; i++) {
|
for(uint i = 0; i < 16; i++) {
|
||||||
r += m_color[i].r;
|
r += m_color[i].r;
|
||||||
g += m_color[i].g;
|
g += m_color[i].g;
|
||||||
b += m_color[i].b;
|
b += m_color[i].b;
|
||||||
a += m_color[i].a;
|
a += m_color[i].a;
|
||||||
}
|
}
|
||||||
|
|
||||||
return Color32(uint8(r / 16), uint8(g / 16), uint8(b / 16), uint8(a / 16));
|
return Color32(uint8(r / 16), uint8(g / 16), uint8(b / 16), uint8(a / 16));
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Return true if the block is not fully opaque.
|
/// Return true if the block is not fully opaque.
|
||||||
bool ColorBlock::hasAlpha() const
|
bool ColorBlock::hasAlpha() const
|
||||||
{
|
{
|
||||||
for (uint i = 0; i < 16; i++)
|
for (uint i = 0; i < 16; i++)
|
||||||
{
|
{
|
||||||
if (m_color[i].a != 255) return true;
|
if (m_color[i].a != 255) return true;
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/// Get diameter color range.
|
/// Get diameter color range.
|
||||||
void ColorBlock::diameterRange(Color32 * start, Color32 * end) const
|
void ColorBlock::diameterRange(Color32 * start, Color32 * end) const
|
||||||
{
|
{
|
||||||
nvDebugCheck(start != NULL);
|
nvDebugCheck(start != NULL);
|
||||||
nvDebugCheck(end != NULL);
|
nvDebugCheck(end != NULL);
|
||||||
|
|
||||||
Color32 c0, c1;
|
Color32 c0, c1;
|
||||||
uint best_dist = 0;
|
uint best_dist = 0;
|
||||||
|
|
||||||
for(int i = 0; i < 16; i++) {
|
for(int i = 0; i < 16; i++) {
|
||||||
for (int j = i+1; j < 16; j++) {
|
for (int j = i+1; j < 16; j++) {
|
||||||
uint dist = colorDistance(m_color[i], m_color[j]);
|
uint dist = colorDistance(m_color[i], m_color[j]);
|
||||||
if( dist > best_dist ) {
|
if( dist > best_dist ) {
|
||||||
best_dist = dist;
|
best_dist = dist;
|
||||||
c0 = m_color[i];
|
c0 = m_color[i];
|
||||||
c1 = m_color[j];
|
c1 = m_color[j];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
*start = c0;
|
*start = c0;
|
||||||
*end = c1;
|
*end = c1;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Get luminance color range.
|
/// Get luminance color range.
|
||||||
void ColorBlock::luminanceRange(Color32 * start, Color32 * end) const
|
void ColorBlock::luminanceRange(Color32 * start, Color32 * end) const
|
||||||
{
|
{
|
||||||
nvDebugCheck(start != NULL);
|
nvDebugCheck(start != NULL);
|
||||||
nvDebugCheck(end != NULL);
|
nvDebugCheck(end != NULL);
|
||||||
|
|
||||||
Color32 minColor, maxColor;
|
|
||||||
uint minLuminance, maxLuminance;
|
|
||||||
|
|
||||||
maxLuminance = minLuminance = colorLuminance(m_color[0]);
|
|
||||||
|
|
||||||
for(uint i = 1; i < 16; i++)
|
|
||||||
{
|
|
||||||
uint luminance = colorLuminance(m_color[i]);
|
|
||||||
|
|
||||||
if (luminance > maxLuminance) {
|
|
||||||
maxLuminance = luminance;
|
|
||||||
maxColor = m_color[i];
|
|
||||||
}
|
|
||||||
else if (luminance < minLuminance) {
|
|
||||||
minLuminance = luminance;
|
|
||||||
minColor = m_color[i];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
*start = minColor;
|
Color32 minColor, maxColor;
|
||||||
*end = maxColor;
|
uint minLuminance, maxLuminance;
|
||||||
|
|
||||||
|
maxLuminance = minLuminance = colorLuminance(m_color[0]);
|
||||||
|
|
||||||
|
for(uint i = 1; i < 16; i++)
|
||||||
|
{
|
||||||
|
uint luminance = colorLuminance(m_color[i]);
|
||||||
|
|
||||||
|
if (luminance > maxLuminance) {
|
||||||
|
maxLuminance = luminance;
|
||||||
|
maxColor = m_color[i];
|
||||||
|
}
|
||||||
|
else if (luminance < minLuminance) {
|
||||||
|
minLuminance = luminance;
|
||||||
|
minColor = m_color[i];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
*start = minColor;
|
||||||
|
*end = maxColor;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Get color range based on the bounding box.
|
/// Get color range based on the bounding box.
|
||||||
void ColorBlock::boundsRange(Color32 * start, Color32 * end) const
|
void ColorBlock::boundsRange(Color32 * start, Color32 * end) const
|
||||||
{
|
{
|
||||||
nvDebugCheck(start != NULL);
|
nvDebugCheck(start != NULL);
|
||||||
nvDebugCheck(end != NULL);
|
nvDebugCheck(end != NULL);
|
||||||
|
|
||||||
Color32 minColor(255, 255, 255);
|
Color32 minColor(255, 255, 255);
|
||||||
Color32 maxColor(0, 0, 0);
|
Color32 maxColor(0, 0, 0);
|
||||||
|
|
||||||
for(uint i = 0; i < 16; i++)
|
for(uint i = 0; i < 16; i++)
|
||||||
{
|
{
|
||||||
if (m_color[i].r < minColor.r) { minColor.r = m_color[i].r; }
|
if (m_color[i].r < minColor.r) { minColor.r = m_color[i].r; }
|
||||||
if (m_color[i].g < minColor.g) { minColor.g = m_color[i].g; }
|
if (m_color[i].g < minColor.g) { minColor.g = m_color[i].g; }
|
||||||
if (m_color[i].b < minColor.b) { minColor.b = m_color[i].b; }
|
if (m_color[i].b < minColor.b) { minColor.b = m_color[i].b; }
|
||||||
if (m_color[i].r > maxColor.r) { maxColor.r = m_color[i].r; }
|
if (m_color[i].r > maxColor.r) { maxColor.r = m_color[i].r; }
|
||||||
if (m_color[i].g > maxColor.g) { maxColor.g = m_color[i].g; }
|
if (m_color[i].g > maxColor.g) { maxColor.g = m_color[i].g; }
|
||||||
if (m_color[i].b > maxColor.b) { maxColor.b = m_color[i].b; }
|
if (m_color[i].b > maxColor.b) { maxColor.b = m_color[i].b; }
|
||||||
}
|
}
|
||||||
|
|
||||||
// Offset range by 1/16 of the extents
|
// Offset range by 1/16 of the extents
|
||||||
Color32 inset;
|
Color32 inset;
|
||||||
inset.r = (maxColor.r - minColor.r) >> 4;
|
inset.r = (maxColor.r - minColor.r) >> 4;
|
||||||
inset.g = (maxColor.g - minColor.g) >> 4;
|
inset.g = (maxColor.g - minColor.g) >> 4;
|
||||||
inset.b = (maxColor.b - minColor.b) >> 4;
|
inset.b = (maxColor.b - minColor.b) >> 4;
|
||||||
|
|
||||||
minColor.r = (minColor.r + inset.r <= 255) ? minColor.r + inset.r : 255;
|
minColor.r = (minColor.r + inset.r <= 255) ? minColor.r + inset.r : 255;
|
||||||
minColor.g = (minColor.g + inset.g <= 255) ? minColor.g + inset.g : 255;
|
minColor.g = (minColor.g + inset.g <= 255) ? minColor.g + inset.g : 255;
|
||||||
minColor.b = (minColor.b + inset.b <= 255) ? minColor.b + inset.b : 255;
|
minColor.b = (minColor.b + inset.b <= 255) ? minColor.b + inset.b : 255;
|
||||||
|
|
||||||
maxColor.r = (maxColor.r >= inset.r) ? maxColor.r - inset.r : 0;
|
maxColor.r = (maxColor.r >= inset.r) ? maxColor.r - inset.r : 0;
|
||||||
maxColor.g = (maxColor.g >= inset.g) ? maxColor.g - inset.g : 0;
|
maxColor.g = (maxColor.g >= inset.g) ? maxColor.g - inset.g : 0;
|
||||||
maxColor.b = (maxColor.b >= inset.b) ? maxColor.b - inset.b : 0;
|
maxColor.b = (maxColor.b >= inset.b) ? maxColor.b - inset.b : 0;
|
||||||
|
|
||||||
*start = minColor;
|
*start = minColor;
|
||||||
*end = maxColor;
|
*end = maxColor;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Get color range based on the bounding box.
|
/// Get color range based on the bounding box.
|
||||||
void ColorBlock::boundsRangeAlpha(Color32 * start, Color32 * end) const
|
void ColorBlock::boundsRangeAlpha(Color32 * start, Color32 * end) const
|
||||||
{
|
{
|
||||||
nvDebugCheck(start != NULL);
|
nvDebugCheck(start != NULL);
|
||||||
nvDebugCheck(end != NULL);
|
nvDebugCheck(end != NULL);
|
||||||
|
|
||||||
Color32 minColor(255, 255, 255, 255);
|
Color32 minColor(255, 255, 255, 255);
|
||||||
Color32 maxColor(0, 0, 0, 0);
|
Color32 maxColor(0, 0, 0, 0);
|
||||||
|
|
||||||
for(uint i = 0; i < 16; i++)
|
for(uint i = 0; i < 16; i++)
|
||||||
{
|
{
|
||||||
if (m_color[i].r < minColor.r) { minColor.r = m_color[i].r; }
|
if (m_color[i].r < minColor.r) { minColor.r = m_color[i].r; }
|
||||||
if (m_color[i].g < minColor.g) { minColor.g = m_color[i].g; }
|
if (m_color[i].g < minColor.g) { minColor.g = m_color[i].g; }
|
||||||
if (m_color[i].b < minColor.b) { minColor.b = m_color[i].b; }
|
if (m_color[i].b < minColor.b) { minColor.b = m_color[i].b; }
|
||||||
if (m_color[i].a < minColor.a) { minColor.a = m_color[i].a; }
|
if (m_color[i].a < minColor.a) { minColor.a = m_color[i].a; }
|
||||||
if (m_color[i].r > maxColor.r) { maxColor.r = m_color[i].r; }
|
if (m_color[i].r > maxColor.r) { maxColor.r = m_color[i].r; }
|
||||||
if (m_color[i].g > maxColor.g) { maxColor.g = m_color[i].g; }
|
if (m_color[i].g > maxColor.g) { maxColor.g = m_color[i].g; }
|
||||||
if (m_color[i].b > maxColor.b) { maxColor.b = m_color[i].b; }
|
if (m_color[i].b > maxColor.b) { maxColor.b = m_color[i].b; }
|
||||||
if (m_color[i].a > maxColor.a) { maxColor.a = m_color[i].a; }
|
if (m_color[i].a > maxColor.a) { maxColor.a = m_color[i].a; }
|
||||||
}
|
}
|
||||||
|
|
||||||
// Offset range by 1/16 of the extents
|
// Offset range by 1/16 of the extents
|
||||||
Color32 inset;
|
Color32 inset;
|
||||||
inset.r = (maxColor.r - minColor.r) >> 4;
|
inset.r = (maxColor.r - minColor.r) >> 4;
|
||||||
inset.g = (maxColor.g - minColor.g) >> 4;
|
inset.g = (maxColor.g - minColor.g) >> 4;
|
||||||
inset.b = (maxColor.b - minColor.b) >> 4;
|
inset.b = (maxColor.b - minColor.b) >> 4;
|
||||||
inset.a = (maxColor.a - minColor.a) >> 4;
|
inset.a = (maxColor.a - minColor.a) >> 4;
|
||||||
|
|
||||||
minColor.r = (minColor.r + inset.r <= 255) ? minColor.r + inset.r : 255;
|
minColor.r = (minColor.r + inset.r <= 255) ? minColor.r + inset.r : 255;
|
||||||
minColor.g = (minColor.g + inset.g <= 255) ? minColor.g + inset.g : 255;
|
minColor.g = (minColor.g + inset.g <= 255) ? minColor.g + inset.g : 255;
|
||||||
minColor.b = (minColor.b + inset.b <= 255) ? minColor.b + inset.b : 255;
|
minColor.b = (minColor.b + inset.b <= 255) ? minColor.b + inset.b : 255;
|
||||||
minColor.a = (minColor.a + inset.a <= 255) ? minColor.a + inset.a : 255;
|
minColor.a = (minColor.a + inset.a <= 255) ? minColor.a + inset.a : 255;
|
||||||
|
|
||||||
maxColor.r = (maxColor.r >= inset.r) ? maxColor.r - inset.r : 0;
|
maxColor.r = (maxColor.r >= inset.r) ? maxColor.r - inset.r : 0;
|
||||||
maxColor.g = (maxColor.g >= inset.g) ? maxColor.g - inset.g : 0;
|
maxColor.g = (maxColor.g >= inset.g) ? maxColor.g - inset.g : 0;
|
||||||
maxColor.b = (maxColor.b >= inset.b) ? maxColor.b - inset.b : 0;
|
maxColor.b = (maxColor.b >= inset.b) ? maxColor.b - inset.b : 0;
|
||||||
maxColor.a = (maxColor.a >= inset.a) ? maxColor.a - inset.a : 0;
|
maxColor.a = (maxColor.a >= inset.a) ? maxColor.a - inset.a : 0;
|
||||||
|
|
||||||
*start = minColor;
|
*start = minColor;
|
||||||
*end = maxColor;
|
*end = maxColor;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/// Sort colors by abosolute value in their 16 bit representation.
|
/// Sort colors by abosolute value in their 16 bit representation.
|
||||||
void ColorBlock::sortColorsByAbsoluteValue()
|
void ColorBlock::sortColorsByAbsoluteValue()
|
||||||
{
|
{
|
||||||
// Dummy selection sort.
|
// Dummy selection sort.
|
||||||
for( uint a = 0; a < 16; a++ ) {
|
for( uint a = 0; a < 16; a++ ) {
|
||||||
uint max = a;
|
uint max = a;
|
||||||
Color16 cmax(m_color[a]);
|
Color16 cmax(m_color[a]);
|
||||||
|
|
||||||
for( uint b = a+1; b < 16; b++ ) {
|
for( uint b = a+1; b < 16; b++ ) {
|
||||||
Color16 cb(m_color[b]);
|
Color16 cb(m_color[b]);
|
||||||
|
|
||||||
if( cb.u > cmax.u ) {
|
if( cb.u > cmax.u ) {
|
||||||
max = b;
|
max = b;
|
||||||
cmax = cb;
|
cmax = cb;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
swap( m_color[a], m_color[max] );
|
swap( m_color[a], m_color[max] );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/// Find extreme colors in the given axis.
|
/// Find extreme colors in the given axis.
|
||||||
void ColorBlock::computeRange(Vector3::Arg axis, Color32 * start, Color32 * end) const
|
void ColorBlock::computeRange(Vector3::Arg axis, Color32 * start, Color32 * end) const
|
||||||
{
|
{
|
||||||
nvDebugCheck(start != NULL);
|
nvDebugCheck(start != NULL);
|
||||||
nvDebugCheck(end != NULL);
|
nvDebugCheck(end != NULL);
|
||||||
|
|
||||||
int mini, maxi;
|
|
||||||
mini = maxi = 0;
|
|
||||||
|
|
||||||
float min, max;
|
|
||||||
min = max = dot(Vector3(m_color[0].r, m_color[0].g, m_color[0].b), axis);
|
|
||||||
|
|
||||||
for(uint i = 1; i < 16; i++)
|
int mini, maxi;
|
||||||
{
|
mini = maxi = 0;
|
||||||
const Vector3 vec(m_color[i].r, m_color[i].g, m_color[i].b);
|
|
||||||
|
float min, max;
|
||||||
float val = dot(vec, axis);
|
min = max = dot(Vector3(m_color[0].r, m_color[0].g, m_color[0].b), axis);
|
||||||
if( val < min ) {
|
|
||||||
mini = i;
|
for(uint i = 1; i < 16; i++)
|
||||||
min = val;
|
{
|
||||||
}
|
const Vector3 vec(m_color[i].r, m_color[i].g, m_color[i].b);
|
||||||
else if( val > max ) {
|
|
||||||
maxi = i;
|
float val = dot(vec, axis);
|
||||||
max = val;
|
if( val < min ) {
|
||||||
}
|
mini = i;
|
||||||
}
|
min = val;
|
||||||
|
}
|
||||||
*start = m_color[mini];
|
else if( val > max ) {
|
||||||
*end = m_color[maxi];
|
maxi = i;
|
||||||
|
max = val;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
*start = m_color[mini];
|
||||||
|
*end = m_color[maxi];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/// Sort colors in the given axis.
|
/// Sort colors in the given axis.
|
||||||
void ColorBlock::sortColors(const Vector3 & axis)
|
void ColorBlock::sortColors(const Vector3 & axis)
|
||||||
{
|
{
|
||||||
float luma_array[16];
|
float luma_array[16];
|
||||||
|
|
||||||
for(uint i = 0; i < 16; i++) {
|
for(uint i = 0; i < 16; i++) {
|
||||||
const Vector3 vec(m_color[i].r, m_color[i].g, m_color[i].b);
|
const Vector3 vec(m_color[i].r, m_color[i].g, m_color[i].b);
|
||||||
luma_array[i] = dot(vec, axis);
|
luma_array[i] = dot(vec, axis);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Dummy selection sort.
|
// Dummy selection sort.
|
||||||
for( uint a = 0; a < 16; a++ ) {
|
for( uint a = 0; a < 16; a++ ) {
|
||||||
uint min = a;
|
uint min = a;
|
||||||
for( uint b = a+1; b < 16; b++ ) {
|
for( uint b = a+1; b < 16; b++ ) {
|
||||||
if( luma_array[b] < luma_array[min] ) {
|
if( luma_array[b] < luma_array[min] ) {
|
||||||
min = b;
|
min = b;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
swap( luma_array[a], luma_array[min] );
|
swap( luma_array[a], luma_array[min] );
|
||||||
swap( m_color[a], m_color[min] );
|
swap( m_color[a], m_color[min] );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/// Get the volume of the color block.
|
/// Get the volume of the color block.
|
||||||
float ColorBlock::volume() const
|
float ColorBlock::volume() const
|
||||||
{
|
{
|
||||||
Box bounds;
|
Box bounds;
|
||||||
bounds.clearBounds();
|
bounds.clearBounds();
|
||||||
|
|
||||||
for(int i = 0; i < 16; i++) {
|
for(int i = 0; i < 16; i++) {
|
||||||
const Vector3 point(m_color[i].r, m_color[i].g, m_color[i].b);
|
const Vector3 point(m_color[i].r, m_color[i].g, m_color[i].b);
|
||||||
bounds.addPointToBounds(point);
|
bounds.addPointToBounds(point);
|
||||||
}
|
}
|
||||||
|
|
||||||
return bounds.volume();
|
return bounds.volume();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -1,96 +1,97 @@
|
|||||||
// This code is in the public domain -- castanyo@yahoo.es
|
// This code is in the public domain -- castanyo@yahoo.es
|
||||||
|
|
||||||
|
#pragma once
|
||||||
#ifndef NV_IMAGE_COLORBLOCK_H
|
#ifndef NV_IMAGE_COLORBLOCK_H
|
||||||
#define NV_IMAGE_COLORBLOCK_H
|
#define NV_IMAGE_COLORBLOCK_H
|
||||||
|
|
||||||
#include <nvmath/Color.h>
|
#include "nvmath/Color.h"
|
||||||
|
|
||||||
namespace nv
|
namespace nv
|
||||||
{
|
{
|
||||||
class Image;
|
class Image;
|
||||||
|
|
||||||
/// Uncompressed 4x4 color block.
|
/// Uncompressed 4x4 color block.
|
||||||
struct ColorBlock
|
struct ColorBlock
|
||||||
{
|
{
|
||||||
ColorBlock();
|
ColorBlock();
|
||||||
ColorBlock(const uint * linearImage);
|
ColorBlock(const uint * linearImage);
|
||||||
ColorBlock(const ColorBlock & block);
|
ColorBlock(const ColorBlock & block);
|
||||||
ColorBlock(const Image * img, uint x, uint y);
|
ColorBlock(const Image * img, uint x, uint y);
|
||||||
|
|
||||||
void init(const Image * img, uint x, uint y);
|
|
||||||
void init(uint w, uint h, uint * data, uint x, uint y);
|
|
||||||
void init(uint w, uint h, float * data, uint x, uint y);
|
|
||||||
|
|
||||||
void swizzle(uint x, uint y, uint z, uint w); // 0=r, 1=g, 2=b, 3=a, 4=0xFF, 5=0
|
|
||||||
|
|
||||||
bool isSingleColor() const;
|
|
||||||
//bool isSingleColorNoAlpha() const;
|
|
||||||
uint countUniqueColors() const;
|
|
||||||
Color32 averageColor() const;
|
|
||||||
bool hasAlpha() const;
|
|
||||||
|
|
||||||
void diameterRange(Color32 * start, Color32 * end) const;
|
|
||||||
void luminanceRange(Color32 * start, Color32 * end) const;
|
|
||||||
void boundsRange(Color32 * start, Color32 * end) const;
|
|
||||||
void boundsRangeAlpha(Color32 * start, Color32 * end) const;
|
|
||||||
|
|
||||||
void sortColorsByAbsoluteValue();
|
|
||||||
|
|
||||||
void computeRange(const Vector3 & axis, Color32 * start, Color32 * end) const;
|
|
||||||
void sortColors(const Vector3 & axis);
|
|
||||||
|
|
||||||
float volume() const;
|
|
||||||
|
|
||||||
// Accessors
|
|
||||||
const Color32 * colors() const;
|
|
||||||
|
|
||||||
Color32 color(uint i) const;
|
void init(const Image * img, uint x, uint y);
|
||||||
Color32 & color(uint i);
|
void init(uint w, uint h, uint * data, uint x, uint y);
|
||||||
|
void init(uint w, uint h, float * data, uint x, uint y);
|
||||||
Color32 color(uint x, uint y) const;
|
|
||||||
Color32 & color(uint x, uint y);
|
void swizzle(uint x, uint y, uint z, uint w); // 0=r, 1=g, 2=b, 3=a, 4=0xFF, 5=0
|
||||||
|
|
||||||
private:
|
bool isSingleColor() const;
|
||||||
|
//bool isSingleColorNoAlpha() const;
|
||||||
Color32 m_color[4*4];
|
uint countUniqueColors() const;
|
||||||
|
Color32 averageColor() const;
|
||||||
};
|
bool hasAlpha() const;
|
||||||
|
|
||||||
|
void diameterRange(Color32 * start, Color32 * end) const;
|
||||||
|
void luminanceRange(Color32 * start, Color32 * end) const;
|
||||||
|
void boundsRange(Color32 * start, Color32 * end) const;
|
||||||
|
void boundsRangeAlpha(Color32 * start, Color32 * end) const;
|
||||||
|
|
||||||
|
void sortColorsByAbsoluteValue();
|
||||||
|
|
||||||
|
void computeRange(const Vector3 & axis, Color32 * start, Color32 * end) const;
|
||||||
|
void sortColors(const Vector3 & axis);
|
||||||
|
|
||||||
|
float volume() const;
|
||||||
|
|
||||||
|
// Accessors
|
||||||
|
const Color32 * colors() const;
|
||||||
|
|
||||||
|
Color32 color(uint i) const;
|
||||||
|
Color32 & color(uint i);
|
||||||
|
|
||||||
|
Color32 color(uint x, uint y) const;
|
||||||
|
Color32 & color(uint x, uint y);
|
||||||
|
|
||||||
|
private:
|
||||||
|
|
||||||
|
Color32 m_color[4*4];
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
/// Get pointer to block colors.
|
||||||
|
inline const Color32 * ColorBlock::colors() const
|
||||||
|
{
|
||||||
|
return m_color;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Get block color.
|
||||||
|
inline Color32 ColorBlock::color(uint i) const
|
||||||
|
{
|
||||||
|
nvDebugCheck(i < 16);
|
||||||
|
return m_color[i];
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Get block color.
|
||||||
|
inline Color32 & ColorBlock::color(uint i)
|
||||||
|
{
|
||||||
|
nvDebugCheck(i < 16);
|
||||||
|
return m_color[i];
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Get block color.
|
||||||
|
inline Color32 ColorBlock::color(uint x, uint y) const
|
||||||
|
{
|
||||||
|
nvDebugCheck(x < 4 && y < 4);
|
||||||
|
return m_color[y * 4 + x];
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Get block color.
|
||||||
|
inline Color32 & ColorBlock::color(uint x, uint y)
|
||||||
|
{
|
||||||
|
nvDebugCheck(x < 4 && y < 4);
|
||||||
|
return m_color[y * 4 + x];
|
||||||
|
}
|
||||||
|
|
||||||
/// Get pointer to block colors.
|
|
||||||
inline const Color32 * ColorBlock::colors() const
|
|
||||||
{
|
|
||||||
return m_color;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Get block color.
|
|
||||||
inline Color32 ColorBlock::color(uint i) const
|
|
||||||
{
|
|
||||||
nvDebugCheck(i < 16);
|
|
||||||
return m_color[i];
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Get block color.
|
|
||||||
inline Color32 & ColorBlock::color(uint i)
|
|
||||||
{
|
|
||||||
nvDebugCheck(i < 16);
|
|
||||||
return m_color[i];
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Get block color.
|
|
||||||
inline Color32 ColorBlock::color(uint x, uint y) const
|
|
||||||
{
|
|
||||||
nvDebugCheck(x < 4 && y < 4);
|
|
||||||
return m_color[y * 4 + x];
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Get block color.
|
|
||||||
inline Color32 & ColorBlock::color(uint x, uint y)
|
|
||||||
{
|
|
||||||
nvDebugCheck(x < 4 && y < 4);
|
|
||||||
return m_color[y * 4 + x];
|
|
||||||
}
|
|
||||||
|
|
||||||
} // nv namespace
|
} // nv namespace
|
||||||
|
|
||||||
#endif // NV_IMAGE_COLORBLOCK_H
|
#endif // NV_IMAGE_COLORBLOCK_H
|
||||||
|
File diff suppressed because it is too large
Load Diff
@ -21,6 +21,7 @@
|
|||||||
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
|
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
|
||||||
// OTHER DEALINGS IN THE SOFTWARE.
|
// OTHER DEALINGS IN THE SOFTWARE.
|
||||||
|
|
||||||
|
#pragma once
|
||||||
#ifndef NV_IMAGE_DIRECTDRAWSURFACE_H
|
#ifndef NV_IMAGE_DIRECTDRAWSURFACE_H
|
||||||
#define NV_IMAGE_DIRECTDRAWSURFACE_H
|
#define NV_IMAGE_DIRECTDRAWSURFACE_H
|
||||||
|
|
||||||
@ -28,134 +29,134 @@
|
|||||||
|
|
||||||
namespace nv
|
namespace nv
|
||||||
{
|
{
|
||||||
class Image;
|
class Image;
|
||||||
class Stream;
|
class Stream;
|
||||||
struct ColorBlock;
|
struct ColorBlock;
|
||||||
|
|
||||||
struct NVIMAGE_CLASS DDSPixelFormat
|
struct NVIMAGE_CLASS DDSPixelFormat
|
||||||
{
|
{
|
||||||
uint size;
|
uint size;
|
||||||
uint flags;
|
uint flags;
|
||||||
uint fourcc;
|
uint fourcc;
|
||||||
uint bitcount;
|
uint bitcount;
|
||||||
uint rmask;
|
uint rmask;
|
||||||
uint gmask;
|
uint gmask;
|
||||||
uint bmask;
|
uint bmask;
|
||||||
uint amask;
|
uint amask;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct NVIMAGE_CLASS DDSCaps
|
struct NVIMAGE_CLASS DDSCaps
|
||||||
{
|
{
|
||||||
uint caps1;
|
uint caps1;
|
||||||
uint caps2;
|
uint caps2;
|
||||||
uint caps3;
|
uint caps3;
|
||||||
uint caps4;
|
uint caps4;
|
||||||
};
|
};
|
||||||
|
|
||||||
/// DDS file header for DX10.
|
/// DDS file header for DX10.
|
||||||
struct NVIMAGE_CLASS DDSHeader10
|
struct NVIMAGE_CLASS DDSHeader10
|
||||||
{
|
{
|
||||||
uint dxgiFormat;
|
uint dxgiFormat;
|
||||||
uint resourceDimension;
|
uint resourceDimension;
|
||||||
uint miscFlag;
|
uint miscFlag;
|
||||||
uint arraySize;
|
uint arraySize;
|
||||||
uint reserved;
|
uint reserved;
|
||||||
};
|
};
|
||||||
|
|
||||||
/// DDS file header.
|
/// DDS file header.
|
||||||
struct NVIMAGE_CLASS DDSHeader
|
struct NVIMAGE_CLASS DDSHeader
|
||||||
{
|
{
|
||||||
uint fourcc;
|
uint fourcc;
|
||||||
uint size;
|
uint size;
|
||||||
uint flags;
|
uint flags;
|
||||||
uint height;
|
uint height;
|
||||||
uint width;
|
uint width;
|
||||||
uint pitch;
|
uint pitch;
|
||||||
uint depth;
|
uint depth;
|
||||||
uint mipmapcount;
|
uint mipmapcount;
|
||||||
uint reserved[11];
|
uint reserved[11];
|
||||||
DDSPixelFormat pf;
|
DDSPixelFormat pf;
|
||||||
DDSCaps caps;
|
DDSCaps caps;
|
||||||
uint notused;
|
uint notused;
|
||||||
DDSHeader10 header10;
|
DDSHeader10 header10;
|
||||||
|
|
||||||
|
|
||||||
// Helper methods.
|
|
||||||
DDSHeader();
|
|
||||||
|
|
||||||
void setWidth(uint w);
|
|
||||||
void setHeight(uint h);
|
|
||||||
void setDepth(uint d);
|
|
||||||
void setMipmapCount(uint count);
|
|
||||||
void setTexture2D();
|
|
||||||
void setTexture3D();
|
|
||||||
void setTextureCube();
|
|
||||||
void setLinearSize(uint size);
|
|
||||||
void setPitch(uint pitch);
|
|
||||||
void setFourCC(uint8 c0, uint8 c1, uint8 c2, uint8 c3);
|
|
||||||
void setFormatCode(uint code);
|
|
||||||
void setSwizzleCode(uint8 c0, uint8 c1, uint8 c2, uint8 c3);
|
|
||||||
void setPixelFormat(uint bitcount, uint rmask, uint gmask, uint bmask, uint amask);
|
|
||||||
void setDX10Format(uint format);
|
|
||||||
void setNormalFlag(bool b);
|
|
||||||
void setHasAlphaFlag(bool b);
|
|
||||||
|
|
||||||
void swapBytes();
|
|
||||||
|
|
||||||
bool hasDX10Header() const;
|
|
||||||
};
|
|
||||||
|
|
||||||
NVIMAGE_API Stream & operator<< (Stream & s, DDSHeader & header);
|
|
||||||
|
|
||||||
|
|
||||||
/// DirectDraw Surface. (DDS)
|
// Helper methods.
|
||||||
class NVIMAGE_CLASS DirectDrawSurface
|
DDSHeader();
|
||||||
{
|
|
||||||
public:
|
|
||||||
DirectDrawSurface(const char * file);
|
|
||||||
DirectDrawSurface(Stream * stream);
|
|
||||||
~DirectDrawSurface();
|
|
||||||
|
|
||||||
bool isValid() const;
|
|
||||||
bool isSupported() const;
|
|
||||||
|
|
||||||
bool hasAlpha() const;
|
void setWidth(uint w);
|
||||||
|
void setHeight(uint h);
|
||||||
uint mipmapCount() const;
|
void setDepth(uint d);
|
||||||
uint width() const;
|
void setMipmapCount(uint count);
|
||||||
uint height() const;
|
void setTexture2D();
|
||||||
uint depth() const;
|
void setTexture3D();
|
||||||
bool isTexture1D() const;
|
void setTextureCube();
|
||||||
bool isTexture2D() const;
|
void setLinearSize(uint size);
|
||||||
bool isTexture3D() const;
|
void setPitch(uint pitch);
|
||||||
bool isTextureCube() const;
|
void setFourCC(uint8 c0, uint8 c1, uint8 c2, uint8 c3);
|
||||||
|
void setFormatCode(uint code);
|
||||||
|
void setSwizzleCode(uint8 c0, uint8 c1, uint8 c2, uint8 c3);
|
||||||
|
void setPixelFormat(uint bitcount, uint rmask, uint gmask, uint bmask, uint amask);
|
||||||
|
void setDX10Format(uint format);
|
||||||
|
void setNormalFlag(bool b);
|
||||||
|
void setHasAlphaFlag(bool b);
|
||||||
|
|
||||||
void setNormalFlag(bool b);
|
void swapBytes();
|
||||||
void setHasAlphaFlag(bool b);
|
|
||||||
|
|
||||||
void mipmap(Image * img, uint f, uint m);
|
|
||||||
// void mipmap(FloatImage * img, uint f, uint m);
|
|
||||||
|
|
||||||
void printInfo() const;
|
|
||||||
|
|
||||||
private:
|
bool hasDX10Header() const;
|
||||||
|
};
|
||||||
uint blockSize() const;
|
|
||||||
uint faceSize() const;
|
NVIMAGE_API Stream & operator<< (Stream & s, DDSHeader & header);
|
||||||
uint mipmapSize(uint m) const;
|
|
||||||
|
|
||||||
uint offset(uint f, uint m);
|
/// DirectDraw Surface. (DDS)
|
||||||
|
class NVIMAGE_CLASS DirectDrawSurface
|
||||||
void readLinearImage(Image * img);
|
{
|
||||||
void readBlockImage(Image * img);
|
public:
|
||||||
void readBlock(ColorBlock * rgba);
|
DirectDrawSurface(const char * file);
|
||||||
|
DirectDrawSurface(Stream * stream);
|
||||||
|
~DirectDrawSurface();
|
||||||
private:
|
|
||||||
Stream * const stream;
|
bool isValid() const;
|
||||||
DDSHeader header;
|
bool isSupported() const;
|
||||||
DDSHeader10 header10;
|
|
||||||
};
|
bool hasAlpha() const;
|
||||||
|
|
||||||
|
uint mipmapCount() const;
|
||||||
|
uint width() const;
|
||||||
|
uint height() const;
|
||||||
|
uint depth() const;
|
||||||
|
bool isTexture1D() const;
|
||||||
|
bool isTexture2D() const;
|
||||||
|
bool isTexture3D() const;
|
||||||
|
bool isTextureCube() const;
|
||||||
|
|
||||||
|
void setNormalFlag(bool b);
|
||||||
|
void setHasAlphaFlag(bool b);
|
||||||
|
|
||||||
|
void mipmap(Image * img, uint f, uint m);
|
||||||
|
// void mipmap(FloatImage * img, uint f, uint m);
|
||||||
|
|
||||||
|
void printInfo() const;
|
||||||
|
|
||||||
|
private:
|
||||||
|
|
||||||
|
uint blockSize() const;
|
||||||
|
uint faceSize() const;
|
||||||
|
uint mipmapSize(uint m) const;
|
||||||
|
|
||||||
|
uint offset(uint f, uint m);
|
||||||
|
|
||||||
|
void readLinearImage(Image * img);
|
||||||
|
void readBlockImage(Image * img);
|
||||||
|
void readBlock(ColorBlock * rgba);
|
||||||
|
|
||||||
|
|
||||||
|
private:
|
||||||
|
Stream * const stream;
|
||||||
|
DDSHeader header;
|
||||||
|
DDSHeader10 header10;
|
||||||
|
};
|
||||||
|
|
||||||
} // nv namespace
|
} // nv namespace
|
||||||
|
|
||||||
|
@ -35,62 +35,64 @@
|
|||||||
|
|
||||||
#include "Filter.h"
|
#include "Filter.h"
|
||||||
|
|
||||||
#include <nvmath/Vector.h> // Vector4
|
#include "nvmath/Vector.h" // Vector4
|
||||||
#include <nvcore/Containers.h> // swap
|
#include "nvcore/Utils.h" // swap
|
||||||
|
|
||||||
|
#include <string.h> // memset
|
||||||
|
|
||||||
using namespace nv;
|
using namespace nv;
|
||||||
|
|
||||||
namespace
|
namespace
|
||||||
{
|
{
|
||||||
// Sinc function.
|
// Sinc function.
|
||||||
inline static float sincf(const float x)
|
inline static float sincf(const float x)
|
||||||
{
|
{
|
||||||
if (fabs(x) < NV_EPSILON) {
|
if (fabs(x) < NV_EPSILON) {
|
||||||
//return 1.0;
|
//return 1.0;
|
||||||
return 1.0f + x*x*(-1.0f/6.0f + x*x*1.0f/120.0f);
|
return 1.0f + x*x*(-1.0f/6.0f + x*x*1.0f/120.0f);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
return sin(x) / x;
|
return sin(x) / x;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Bessel function of the first kind from Jon Blow's article.
|
// Bessel function of the first kind from Jon Blow's article.
|
||||||
// http://mathworld.wolfram.com/BesselFunctionoftheFirstKind.html
|
// http://mathworld.wolfram.com/BesselFunctionoftheFirstKind.html
|
||||||
// http://en.wikipedia.org/wiki/Bessel_function
|
// http://en.wikipedia.org/wiki/Bessel_function
|
||||||
inline static float bessel0(float x)
|
inline static float bessel0(float x)
|
||||||
{
|
{
|
||||||
const float EPSILON_RATIO = 1e-6f;
|
const float EPSILON_RATIO = 1e-6f;
|
||||||
float xh, sum, pow, ds;
|
float xh, sum, pow, ds;
|
||||||
int k;
|
int k;
|
||||||
|
|
||||||
xh = 0.5f * x;
|
xh = 0.5f * x;
|
||||||
sum = 1.0f;
|
sum = 1.0f;
|
||||||
pow = 1.0f;
|
pow = 1.0f;
|
||||||
k = 0;
|
k = 0;
|
||||||
ds = 1.0;
|
ds = 1.0;
|
||||||
while (ds > sum * EPSILON_RATIO) {
|
while (ds > sum * EPSILON_RATIO) {
|
||||||
++k;
|
++k;
|
||||||
pow = pow * (xh / k);
|
pow = pow * (xh / k);
|
||||||
ds = pow * pow;
|
ds = pow * pow;
|
||||||
sum = sum + ds;
|
sum = sum + ds;
|
||||||
}
|
}
|
||||||
|
|
||||||
return sum;
|
return sum;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*// Alternative bessel function from Paul Heckbert.
|
/*// Alternative bessel function from Paul Heckbert.
|
||||||
static float _bessel0(float x)
|
static float _bessel0(float x)
|
||||||
{
|
{
|
||||||
const float EPSILON_RATIO = 1E-6;
|
const float EPSILON_RATIO = 1E-6;
|
||||||
float sum = 1.0f;
|
float sum = 1.0f;
|
||||||
float y = x * x / 4.0f;
|
float y = x * x / 4.0f;
|
||||||
float t = y;
|
float t = y;
|
||||||
for(int i = 2; t > EPSILON_RATIO; i++) {
|
for(int i = 2; t > EPSILON_RATIO; i++) {
|
||||||
sum += t;
|
sum += t;
|
||||||
t *= y / float(i * i);
|
t *= y / float(i * i);
|
||||||
}
|
}
|
||||||
return sum;
|
return sum;
|
||||||
}*/
|
}*/
|
||||||
|
|
||||||
} // namespace
|
} // namespace
|
||||||
|
|
||||||
@ -105,42 +107,42 @@ Filter::Filter(float width) : m_width(width)
|
|||||||
|
|
||||||
float Filter::sampleDelta(float x, float scale) const
|
float Filter::sampleDelta(float x, float scale) const
|
||||||
{
|
{
|
||||||
return evaluate((x + 0.5f)* scale);
|
return evaluate((x + 0.5f)* scale);
|
||||||
}
|
}
|
||||||
|
|
||||||
float Filter::sampleBox(float x, float scale, int samples) const
|
float Filter::sampleBox(float x, float scale, int samples) const
|
||||||
{
|
{
|
||||||
float sum = 0;
|
float sum = 0;
|
||||||
float isamples = 1.0f / float(samples);
|
float isamples = 1.0f / float(samples);
|
||||||
|
|
||||||
for(int s = 0; s < samples; s++)
|
for(int s = 0; s < samples; s++)
|
||||||
{
|
{
|
||||||
float p = (x + (float(s) + 0.5f) * isamples) * scale;
|
float p = (x + (float(s) + 0.5f) * isamples) * scale;
|
||||||
float value = evaluate(p);
|
float value = evaluate(p);
|
||||||
sum += value;
|
sum += value;
|
||||||
}
|
}
|
||||||
|
|
||||||
return sum * isamples;
|
return sum * isamples;
|
||||||
}
|
}
|
||||||
|
|
||||||
float Filter::sampleTriangle(float x, float scale, int samples) const
|
float Filter::sampleTriangle(float x, float scale, int samples) const
|
||||||
{
|
{
|
||||||
float sum = 0;
|
float sum = 0;
|
||||||
float isamples = 1.0f / float(samples);
|
float isamples = 1.0f / float(samples);
|
||||||
|
|
||||||
for(int s = 0; s < samples; s++)
|
for(int s = 0; s < samples; s++)
|
||||||
{
|
{
|
||||||
float offset = (2 * float(s) + 1.0f) * isamples;
|
float offset = (2 * float(s) + 1.0f) * isamples;
|
||||||
float p = (x + offset - 0.5f) * scale;
|
float p = (x + offset - 0.5f) * scale;
|
||||||
float value = evaluate(p);
|
float value = evaluate(p);
|
||||||
|
|
||||||
float weight = offset;
|
float weight = offset;
|
||||||
if (weight > 1.0f) weight = 2.0f - weight;
|
if (weight > 1.0f) weight = 2.0f - weight;
|
||||||
|
|
||||||
sum += value * weight;
|
sum += value * weight;
|
||||||
}
|
}
|
||||||
|
|
||||||
return 2 * sum * isamples;
|
return 2 * sum * isamples;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -152,8 +154,8 @@ BoxFilter::BoxFilter(float width) : Filter(width) {}
|
|||||||
|
|
||||||
float BoxFilter::evaluate(float x) const
|
float BoxFilter::evaluate(float x) const
|
||||||
{
|
{
|
||||||
if (fabs(x) <= m_width) return 1.0f;
|
if (fabs(x) <= m_width) return 1.0f;
|
||||||
else return 0.0f;
|
else return 0.0f;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -162,7 +164,7 @@ TriangleFilter::TriangleFilter(float width) : Filter(width) {}
|
|||||||
|
|
||||||
float TriangleFilter::evaluate(float x) const
|
float TriangleFilter::evaluate(float x) const
|
||||||
{
|
{
|
||||||
x = fabs(x);
|
x = fabs(x);
|
||||||
if( x < m_width ) return m_width - x;
|
if( x < m_width ) return m_width - x;
|
||||||
return 0.0f;
|
return 0.0f;
|
||||||
}
|
}
|
||||||
@ -172,11 +174,11 @@ QuadraticFilter::QuadraticFilter() : Filter(1.5f) {}
|
|||||||
|
|
||||||
float QuadraticFilter::evaluate(float x) const
|
float QuadraticFilter::evaluate(float x) const
|
||||||
{
|
{
|
||||||
x = fabs(x);
|
x = fabs(x);
|
||||||
if( x < 0.5f ) return 0.75f - x * x;
|
if( x < 0.5f ) return 0.75f - x * x;
|
||||||
if( x < 1.5f ) {
|
if( x < 1.5f ) {
|
||||||
float t = x - 1.5f;
|
float t = x - 1.5f;
|
||||||
return 0.5f * t * t;
|
return 0.5f * t * t;
|
||||||
}
|
}
|
||||||
return 0.0f;
|
return 0.0f;
|
||||||
}
|
}
|
||||||
@ -186,10 +188,10 @@ CubicFilter::CubicFilter() : Filter(1.0f) {}
|
|||||||
|
|
||||||
float CubicFilter::evaluate(float x) const
|
float CubicFilter::evaluate(float x) const
|
||||||
{
|
{
|
||||||
// f(t) = 2|t|^3 - 3|t|^2 + 1, -1 <= t <= 1
|
// f(t) = 2|t|^3 - 3|t|^2 + 1, -1 <= t <= 1
|
||||||
x = fabs(x);
|
x = fabs(x);
|
||||||
if( x < 1.0f ) return((2.0f * x - 3.0f) * x * x + 1.0f);
|
if( x < 1.0f ) return((2.0f * x - 3.0f) * x * x + 1.0f);
|
||||||
return 0.0f;
|
return 0.0f;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -197,11 +199,11 @@ BSplineFilter::BSplineFilter() : Filter(2.0f) {}
|
|||||||
|
|
||||||
float BSplineFilter::evaluate(float x) const
|
float BSplineFilter::evaluate(float x) const
|
||||||
{
|
{
|
||||||
x = fabs(x);
|
x = fabs(x);
|
||||||
if( x < 1.0f ) return (4.0f + x * x * (-6.0f + x * 3.0f)) / 6.0f;
|
if( x < 1.0f ) return (4.0f + x * x * (-6.0f + x * 3.0f)) / 6.0f;
|
||||||
if( x < 2.0f ) {
|
if( x < 2.0f ) {
|
||||||
float t = 2.0f - x;
|
float t = 2.0f - x;
|
||||||
return t * t * t / 6.0f;
|
return t * t * t / 6.0f;
|
||||||
}
|
}
|
||||||
return 0.0f;
|
return 0.0f;
|
||||||
}
|
}
|
||||||
@ -211,21 +213,21 @@ MitchellFilter::MitchellFilter() : Filter(2.0f) { setParameters(1.0f/3.0f, 1.0f/
|
|||||||
|
|
||||||
float MitchellFilter::evaluate(float x) const
|
float MitchellFilter::evaluate(float x) const
|
||||||
{
|
{
|
||||||
x = fabs(x);
|
x = fabs(x);
|
||||||
if( x < 1.0f ) return p0 + x * x * (p2 + x * p3);
|
if( x < 1.0f ) return p0 + x * x * (p2 + x * p3);
|
||||||
if( x < 2.0f ) return q0 + x * (q1 + x * (q2 + x * q3));
|
if( x < 2.0f ) return q0 + x * (q1 + x * (q2 + x * q3));
|
||||||
return 0.0f;
|
return 0.0f;
|
||||||
}
|
}
|
||||||
|
|
||||||
void MitchellFilter::setParameters(float b, float c)
|
void MitchellFilter::setParameters(float b, float c)
|
||||||
{
|
{
|
||||||
p0 = (6.0f - 2.0f * b) / 6.0f;
|
p0 = (6.0f - 2.0f * b) / 6.0f;
|
||||||
p2 = (-18.0f + 12.0f * b + 6.0f * c) / 6.0f;
|
p2 = (-18.0f + 12.0f * b + 6.0f * c) / 6.0f;
|
||||||
p3 = (12.0f - 9.0f * b - 6.0f * c) / 6.0f;
|
p3 = (12.0f - 9.0f * b - 6.0f * c) / 6.0f;
|
||||||
q0 = (8.0f * b + 24.0f * c) / 6.0f;
|
q0 = (8.0f * b + 24.0f * c) / 6.0f;
|
||||||
q1 = (-12.0f * b - 48.0f * c) / 6.0f;
|
q1 = (-12.0f * b - 48.0f * c) / 6.0f;
|
||||||
q2 = (6.0f * b + 30.0f * c) / 6.0f;
|
q2 = (6.0f * b + 30.0f * c) / 6.0f;
|
||||||
q3 = (-b - 6.0f * c) / 6.0f;
|
q3 = (-b - 6.0f * c) / 6.0f;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -233,9 +235,9 @@ LanczosFilter::LanczosFilter() : Filter(3.0f) {}
|
|||||||
|
|
||||||
float LanczosFilter::evaluate(float x) const
|
float LanczosFilter::evaluate(float x) const
|
||||||
{
|
{
|
||||||
x = fabs(x);
|
x = fabs(x);
|
||||||
if( x < 3.0f ) return sincf(PI * x) * sincf(PI * x / 3.0f);
|
if( x < 3.0f ) return sincf(PI * x) * sincf(PI * x / 3.0f);
|
||||||
return 0.0f;
|
return 0.0f;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -243,7 +245,7 @@ SincFilter::SincFilter(float w) : Filter(w) {}
|
|||||||
|
|
||||||
float SincFilter::evaluate(float x) const
|
float SincFilter::evaluate(float x) const
|
||||||
{
|
{
|
||||||
return sincf(PI * x);
|
return sincf(PI * x);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -251,16 +253,16 @@ KaiserFilter::KaiserFilter(float w) : Filter(w) { setParameters(4.0f, 1.0f); }
|
|||||||
|
|
||||||
float KaiserFilter::evaluate(float x) const
|
float KaiserFilter::evaluate(float x) const
|
||||||
{
|
{
|
||||||
const float sinc_value = sincf(PI * x * stretch);
|
const float sinc_value = sincf(PI * x * stretch);
|
||||||
const float t = x / m_width;
|
const float t = x / m_width;
|
||||||
if ((1 - t * t) >= 0) return sinc_value * bessel0(alpha * sqrtf(1 - t * t)) / bessel0(alpha);
|
if ((1 - t * t) >= 0) return sinc_value * bessel0(alpha * sqrtf(1 - t * t)) / bessel0(alpha);
|
||||||
else return 0;
|
else return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
void KaiserFilter::setParameters(float alpha, float stretch)
|
void KaiserFilter::setParameters(float alpha, float stretch)
|
||||||
{
|
{
|
||||||
this->alpha = alpha;
|
this->alpha = alpha;
|
||||||
this->stretch = stretch;
|
this->stretch = stretch;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -268,44 +270,44 @@ void KaiserFilter::setParameters(float alpha, float stretch)
|
|||||||
/// Ctor.
|
/// Ctor.
|
||||||
Kernel1::Kernel1(const Filter & f, int iscale, int samples/*= 32*/)
|
Kernel1::Kernel1(const Filter & f, int iscale, int samples/*= 32*/)
|
||||||
{
|
{
|
||||||
nvDebugCheck(iscale > 1);
|
nvDebugCheck(iscale > 1);
|
||||||
nvDebugCheck(samples > 0);
|
nvDebugCheck(samples > 0);
|
||||||
|
|
||||||
const float scale = 1.0f / iscale;
|
const float scale = 1.0f / iscale;
|
||||||
|
|
||||||
m_width = f.width() * iscale;
|
m_width = f.width() * iscale;
|
||||||
m_windowSize = (int)ceilf(2 * m_width);
|
m_windowSize = (int)ceilf(2 * m_width);
|
||||||
m_data = new float[m_windowSize];
|
m_data = new float[m_windowSize];
|
||||||
|
|
||||||
const float offset = float(m_windowSize) / 2;
|
const float offset = float(m_windowSize) / 2;
|
||||||
|
|
||||||
float total = 0.0f;
|
float total = 0.0f;
|
||||||
for (int i = 0; i < m_windowSize; i++)
|
for (int i = 0; i < m_windowSize; i++)
|
||||||
{
|
{
|
||||||
const float sample = f.sampleBox(i - offset, scale, samples);
|
const float sample = f.sampleBox(i - offset, scale, samples);
|
||||||
m_data[i] = sample;
|
m_data[i] = sample;
|
||||||
total += sample;
|
total += sample;
|
||||||
}
|
}
|
||||||
|
|
||||||
const float inv = 1.0f / total;
|
const float inv = 1.0f / total;
|
||||||
for (int i = 0; i < m_windowSize; i++)
|
for (int i = 0; i < m_windowSize; i++)
|
||||||
{
|
{
|
||||||
m_data[i] *= inv;
|
m_data[i] *= inv;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Dtor.
|
/// Dtor.
|
||||||
Kernel1::~Kernel1()
|
Kernel1::~Kernel1()
|
||||||
{
|
{
|
||||||
delete m_data;
|
delete m_data;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Print the kernel for debugging purposes.
|
/// Print the kernel for debugging purposes.
|
||||||
void Kernel1::debugPrint()
|
void Kernel1::debugPrint()
|
||||||
{
|
{
|
||||||
for (int i = 0; i < m_windowSize; i++) {
|
for (int i = 0; i < m_windowSize; i++) {
|
||||||
nvDebug("%d: %f\n", i, m_data[i]);
|
nvDebug("%d: %f\n", i, m_data[i]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -313,102 +315,102 @@ void Kernel1::debugPrint()
|
|||||||
/// Ctor.
|
/// Ctor.
|
||||||
Kernel2::Kernel2(uint ws) : m_windowSize(ws)
|
Kernel2::Kernel2(uint ws) : m_windowSize(ws)
|
||||||
{
|
{
|
||||||
m_data = new float[m_windowSize * m_windowSize];
|
m_data = new float[m_windowSize * m_windowSize];
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Copy ctor.
|
/// Copy ctor.
|
||||||
Kernel2::Kernel2(const Kernel2 & k) : m_windowSize(k.m_windowSize)
|
Kernel2::Kernel2(const Kernel2 & k) : m_windowSize(k.m_windowSize)
|
||||||
{
|
{
|
||||||
m_data = new float[m_windowSize * m_windowSize];
|
m_data = new float[m_windowSize * m_windowSize];
|
||||||
for (uint i = 0; i < m_windowSize * m_windowSize; i++) {
|
for (uint i = 0; i < m_windowSize * m_windowSize; i++) {
|
||||||
m_data[i] = k.m_data[i];
|
m_data[i] = k.m_data[i];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/// Dtor.
|
/// Dtor.
|
||||||
Kernel2::~Kernel2()
|
Kernel2::~Kernel2()
|
||||||
{
|
{
|
||||||
delete m_data;
|
delete m_data;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Normalize the filter.
|
/// Normalize the filter.
|
||||||
void Kernel2::normalize()
|
void Kernel2::normalize()
|
||||||
{
|
{
|
||||||
float total = 0.0f;
|
float total = 0.0f;
|
||||||
for(uint i = 0; i < m_windowSize*m_windowSize; i++) {
|
for(uint i = 0; i < m_windowSize*m_windowSize; i++) {
|
||||||
total += fabs(m_data[i]);
|
total += fabs(m_data[i]);
|
||||||
}
|
}
|
||||||
|
|
||||||
float inv = 1.0f / total;
|
float inv = 1.0f / total;
|
||||||
for(uint i = 0; i < m_windowSize*m_windowSize; i++) {
|
for(uint i = 0; i < m_windowSize*m_windowSize; i++) {
|
||||||
m_data[i] *= inv;
|
m_data[i] *= inv;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Transpose the kernel.
|
/// Transpose the kernel.
|
||||||
void Kernel2::transpose()
|
void Kernel2::transpose()
|
||||||
{
|
{
|
||||||
for(uint i = 0; i < m_windowSize; i++) {
|
for(uint i = 0; i < m_windowSize; i++) {
|
||||||
for(uint j = i+1; j < m_windowSize; j++) {
|
for(uint j = i+1; j < m_windowSize; j++) {
|
||||||
swap(m_data[i*m_windowSize + j], m_data[j*m_windowSize + i]);
|
swap(m_data[i*m_windowSize + j], m_data[j*m_windowSize + i]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Init laplacian filter, usually used for sharpening.
|
/// Init laplacian filter, usually used for sharpening.
|
||||||
void Kernel2::initLaplacian()
|
void Kernel2::initLaplacian()
|
||||||
{
|
{
|
||||||
nvDebugCheck(m_windowSize == 3);
|
nvDebugCheck(m_windowSize == 3);
|
||||||
// m_data[0] = -1; m_data[1] = -1; m_data[2] = -1;
|
// m_data[0] = -1; m_data[1] = -1; m_data[2] = -1;
|
||||||
// m_data[3] = -1; m_data[4] = +8; m_data[5] = -1;
|
// m_data[3] = -1; m_data[4] = +8; m_data[5] = -1;
|
||||||
// m_data[6] = -1; m_data[7] = -1; m_data[8] = -1;
|
// m_data[6] = -1; m_data[7] = -1; m_data[8] = -1;
|
||||||
|
|
||||||
m_data[0] = +0; m_data[1] = -1; m_data[2] = +0;
|
m_data[0] = +0; m_data[1] = -1; m_data[2] = +0;
|
||||||
m_data[3] = -1; m_data[4] = +4; m_data[5] = -1;
|
m_data[3] = -1; m_data[4] = +4; m_data[5] = -1;
|
||||||
m_data[6] = +0; m_data[7] = -1; m_data[8] = +0;
|
m_data[6] = +0; m_data[7] = -1; m_data[8] = +0;
|
||||||
|
|
||||||
// m_data[0] = +1; m_data[1] = -2; m_data[2] = +1;
|
// m_data[0] = +1; m_data[1] = -2; m_data[2] = +1;
|
||||||
// m_data[3] = -2; m_data[4] = +4; m_data[5] = -2;
|
// m_data[3] = -2; m_data[4] = +4; m_data[5] = -2;
|
||||||
// m_data[6] = +1; m_data[7] = -2; m_data[8] = +1;
|
// m_data[6] = +1; m_data[7] = -2; m_data[8] = +1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/// Init simple edge detection filter.
|
/// Init simple edge detection filter.
|
||||||
void Kernel2::initEdgeDetection()
|
void Kernel2::initEdgeDetection()
|
||||||
{
|
{
|
||||||
nvCheck(m_windowSize == 3);
|
nvCheck(m_windowSize == 3);
|
||||||
m_data[0] = 0; m_data[1] = 0; m_data[2] = 0;
|
m_data[0] = 0; m_data[1] = 0; m_data[2] = 0;
|
||||||
m_data[3] =-1; m_data[4] = 0; m_data[5] = 1;
|
m_data[3] =-1; m_data[4] = 0; m_data[5] = 1;
|
||||||
m_data[6] = 0; m_data[7] = 0; m_data[8] = 0;
|
m_data[6] = 0; m_data[7] = 0; m_data[8] = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Init sobel filter.
|
/// Init sobel filter.
|
||||||
void Kernel2::initSobel()
|
void Kernel2::initSobel()
|
||||||
{
|
{
|
||||||
if (m_windowSize == 3)
|
if (m_windowSize == 3)
|
||||||
{
|
{
|
||||||
m_data[0] = -1; m_data[1] = 0; m_data[2] = 1;
|
m_data[0] = -1; m_data[1] = 0; m_data[2] = 1;
|
||||||
m_data[3] = -2; m_data[4] = 0; m_data[5] = 2;
|
m_data[3] = -2; m_data[4] = 0; m_data[5] = 2;
|
||||||
m_data[6] = -1; m_data[7] = 0; m_data[8] = 1;
|
m_data[6] = -1; m_data[7] = 0; m_data[8] = 1;
|
||||||
}
|
}
|
||||||
else if (m_windowSize == 5)
|
else if (m_windowSize == 5)
|
||||||
{
|
{
|
||||||
float elements[] = {
|
float elements[] = {
|
||||||
-1, -2, 0, 2, 1,
|
-1, -2, 0, 2, 1,
|
||||||
-2, -3, 0, 3, 2,
|
-2, -3, 0, 3, 2,
|
||||||
-3, -4, 0, 4, 3,
|
-3, -4, 0, 4, 3,
|
||||||
-2, -3, 0, 3, 2,
|
-2, -3, 0, 3, 2,
|
||||||
-1, -2, 0, 2, 1
|
-1, -2, 0, 2, 1
|
||||||
};
|
};
|
||||||
|
|
||||||
for (int i = 0; i < 5*5; i++) {
|
for (int i = 0; i < 5*5; i++) {
|
||||||
m_data[i] = elements[i];
|
m_data[i] = elements[i];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (m_windowSize == 7)
|
else if (m_windowSize == 7)
|
||||||
{
|
{
|
||||||
float elements[] = {
|
float elements[] = {
|
||||||
-1, -2, -3, 0, 3, 2, 1,
|
-1, -2, -3, 0, 3, 2, 1,
|
||||||
-2, -3, -4, 0, 4, 3, 2,
|
-2, -3, -4, 0, 4, 3, 2,
|
||||||
-3, -4, -5, 0, 5, 4, 3,
|
-3, -4, -5, 0, 5, 4, 3,
|
||||||
@ -416,15 +418,15 @@ void Kernel2::initSobel()
|
|||||||
-3, -4, -5, 0, 5, 4, 3,
|
-3, -4, -5, 0, 5, 4, 3,
|
||||||
-2, -3, -4, 0, 4, 3, 2,
|
-2, -3, -4, 0, 4, 3, 2,
|
||||||
-1, -2, -3, 0, 3, 2, 1
|
-1, -2, -3, 0, 3, 2, 1
|
||||||
};
|
};
|
||||||
|
|
||||||
for (int i = 0; i < 7*7; i++) {
|
for (int i = 0; i < 7*7; i++) {
|
||||||
m_data[i] = elements[i];
|
m_data[i] = elements[i];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (m_windowSize == 9)
|
else if (m_windowSize == 9)
|
||||||
{
|
{
|
||||||
float elements[] = {
|
float elements[] = {
|
||||||
-1, -2, -3, -4, 0, 4, 3, 2, 1,
|
-1, -2, -3, -4, 0, 4, 3, 2, 1,
|
||||||
-2, -3, -4, -5, 0, 5, 4, 3, 2,
|
-2, -3, -4, -5, 0, 5, 4, 3, 2,
|
||||||
-3, -4, -5, -6, 0, 6, 5, 4, 3,
|
-3, -4, -5, -6, 0, 6, 5, 4, 3,
|
||||||
@ -434,47 +436,47 @@ void Kernel2::initSobel()
|
|||||||
-3, -4, -5, -6, 0, 6, 5, 4, 3,
|
-3, -4, -5, -6, 0, 6, 5, 4, 3,
|
||||||
-2, -3, -4, -5, 0, 5, 4, 3, 2,
|
-2, -3, -4, -5, 0, 5, 4, 3, 2,
|
||||||
-1, -2, -3, -4, 0, 4, 3, 2, 1
|
-1, -2, -3, -4, 0, 4, 3, 2, 1
|
||||||
};
|
};
|
||||||
|
|
||||||
for (int i = 0; i < 9*9; i++) {
|
for (int i = 0; i < 9*9; i++) {
|
||||||
m_data[i] = elements[i];
|
m_data[i] = elements[i];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Init prewitt filter.
|
/// Init prewitt filter.
|
||||||
void Kernel2::initPrewitt()
|
void Kernel2::initPrewitt()
|
||||||
{
|
{
|
||||||
if (m_windowSize == 3)
|
if (m_windowSize == 3)
|
||||||
{
|
{
|
||||||
m_data[0] = -1; m_data[1] = 0; m_data[2] = -1;
|
m_data[0] = -1; m_data[1] = 0; m_data[2] = -1;
|
||||||
m_data[3] = -1; m_data[4] = 0; m_data[5] = -1;
|
m_data[3] = -1; m_data[4] = 0; m_data[5] = -1;
|
||||||
m_data[6] = -1; m_data[7] = 0; m_data[8] = -1;
|
m_data[6] = -1; m_data[7] = 0; m_data[8] = -1;
|
||||||
}
|
}
|
||||||
else if (m_windowSize == 5)
|
else if (m_windowSize == 5)
|
||||||
{
|
{
|
||||||
// @@ Is this correct?
|
// @@ Is this correct?
|
||||||
float elements[] = {
|
float elements[] = {
|
||||||
-2, -1, 0, 1, 2,
|
-2, -1, 0, 1, 2,
|
||||||
-2, -1, 0, 1, 2,
|
-2, -1, 0, 1, 2,
|
||||||
-2, -1, 0, 1, 2,
|
-2, -1, 0, 1, 2,
|
||||||
-2, -1, 0, 1, 2,
|
-2, -1, 0, 1, 2,
|
||||||
-2, -1, 0, 1, 2
|
-2, -1, 0, 1, 2
|
||||||
};
|
};
|
||||||
|
|
||||||
for (int i = 0; i < 5*5; i++) {
|
for (int i = 0; i < 5*5; i++) {
|
||||||
m_data[i] = elements[i];
|
m_data[i] = elements[i];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Init blended sobel filter.
|
/// Init blended sobel filter.
|
||||||
void Kernel2::initBlendedSobel(const Vector4 & scale)
|
void Kernel2::initBlendedSobel(const Vector4 & scale)
|
||||||
{
|
{
|
||||||
nvCheck(m_windowSize == 9);
|
nvCheck(m_windowSize == 9);
|
||||||
|
|
||||||
{
|
{
|
||||||
const float elements[] = {
|
const float elements[] = {
|
||||||
-1, -2, -3, -4, 0, 4, 3, 2, 1,
|
-1, -2, -3, -4, 0, 4, 3, 2, 1,
|
||||||
-2, -3, -4, -5, 0, 5, 4, 3, 2,
|
-2, -3, -4, -5, 0, 5, 4, 3, 2,
|
||||||
-3, -4, -5, -6, 0, 6, 5, 4, 3,
|
-3, -4, -5, -6, 0, 6, 5, 4, 3,
|
||||||
@ -484,14 +486,14 @@ void Kernel2::initBlendedSobel(const Vector4 & scale)
|
|||||||
-3, -4, -5, -6, 0, 6, 5, 4, 3,
|
-3, -4, -5, -6, 0, 6, 5, 4, 3,
|
||||||
-2, -3, -4, -5, 0, 5, 4, 3, 2,
|
-2, -3, -4, -5, 0, 5, 4, 3, 2,
|
||||||
-1, -2, -3, -4, 0, 4, 3, 2, 1
|
-1, -2, -3, -4, 0, 4, 3, 2, 1
|
||||||
};
|
};
|
||||||
|
|
||||||
for (int i = 0; i < 9*9; i++) {
|
for (int i = 0; i < 9*9; i++) {
|
||||||
m_data[i] = elements[i] * scale.w();
|
m_data[i] = elements[i] * scale.w;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
{
|
{
|
||||||
const float elements[] = {
|
const float elements[] = {
|
||||||
-1, -2, -3, 0, 3, 2, 1,
|
-1, -2, -3, 0, 3, 2, 1,
|
||||||
-2, -3, -4, 0, 4, 3, 2,
|
-2, -3, -4, 0, 4, 3, 2,
|
||||||
-3, -4, -5, 0, 5, 4, 3,
|
-3, -4, -5, 0, 5, 4, 3,
|
||||||
@ -499,107 +501,107 @@ void Kernel2::initBlendedSobel(const Vector4 & scale)
|
|||||||
-3, -4, -5, 0, 5, 4, 3,
|
-3, -4, -5, 0, 5, 4, 3,
|
||||||
-2, -3, -4, 0, 4, 3, 2,
|
-2, -3, -4, 0, 4, 3, 2,
|
||||||
-1, -2, -3, 0, 3, 2, 1,
|
-1, -2, -3, 0, 3, 2, 1,
|
||||||
};
|
};
|
||||||
|
|
||||||
for (int i = 0; i < 7; i++) {
|
for (int i = 0; i < 7; i++) {
|
||||||
for (int e = 0; e < 7; e++) {
|
for (int e = 0; e < 7; e++) {
|
||||||
m_data[(i + 1) * 9 + e + 1] += elements[i * 7 + e] * scale.z();
|
m_data[(i + 1) * 9 + e + 1] += elements[i * 7 + e] * scale.z;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
{
|
{
|
||||||
const float elements[] = {
|
const float elements[] = {
|
||||||
-1, -2, 0, 2, 1,
|
-1, -2, 0, 2, 1,
|
||||||
-2, -3, 0, 3, 2,
|
-2, -3, 0, 3, 2,
|
||||||
-3, -4, 0, 4, 3,
|
-3, -4, 0, 4, 3,
|
||||||
-2, -3, 0, 3, 2,
|
-2, -3, 0, 3, 2,
|
||||||
-1, -2, 0, 2, 1
|
-1, -2, 0, 2, 1
|
||||||
};
|
};
|
||||||
|
|
||||||
for (int i = 0; i < 5; i++) {
|
for (int i = 0; i < 5; i++) {
|
||||||
for (int e = 0; e < 5; e++) {
|
for (int e = 0; e < 5; e++) {
|
||||||
m_data[(i + 2) * 9 + e + 2] += elements[i * 5 + e] * scale.y();
|
m_data[(i + 2) * 9 + e + 2] += elements[i * 5 + e] * scale.y;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
{
|
{
|
||||||
const float elements[] = {
|
const float elements[] = {
|
||||||
-1, 0, 1,
|
-1, 0, 1,
|
||||||
-2, 0, 2,
|
-2, 0, 2,
|
||||||
-1, 0, 1,
|
-1, 0, 1,
|
||||||
};
|
};
|
||||||
|
|
||||||
for (int i = 0; i < 3; i++) {
|
for (int i = 0; i < 3; i++) {
|
||||||
for (int e = 0; e < 3; e++) {
|
for (int e = 0; e < 3; e++) {
|
||||||
m_data[(i + 3) * 9 + e + 3] += elements[i * 3 + e] * scale.x();
|
m_data[(i + 3) * 9 + e + 3] += elements[i * 3 + e] * scale.x;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
PolyphaseKernel::PolyphaseKernel(const Filter & f, uint srcLength, uint dstLength, int samples/*= 32*/)
|
PolyphaseKernel::PolyphaseKernel(const Filter & f, uint srcLength, uint dstLength, int samples/*= 32*/)
|
||||||
{
|
{
|
||||||
nvDebugCheck(samples > 0);
|
nvDebugCheck(samples > 0);
|
||||||
|
|
||||||
float scale = float(dstLength) / float(srcLength);
|
float scale = float(dstLength) / float(srcLength);
|
||||||
const float iscale = 1.0f / scale;
|
const float iscale = 1.0f / scale;
|
||||||
|
|
||||||
if (scale > 1) {
|
if (scale > 1) {
|
||||||
// Upsampling.
|
// Upsampling.
|
||||||
samples = 1;
|
samples = 1;
|
||||||
scale = 1;
|
scale = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
m_length = dstLength;
|
m_length = dstLength;
|
||||||
m_width = f.width() * iscale;
|
m_width = f.width() * iscale;
|
||||||
m_windowSize = (int)ceilf(m_width * 2) + 1;
|
m_windowSize = (int)ceilf(m_width * 2) + 1;
|
||||||
|
|
||||||
m_data = new float[m_windowSize * m_length];
|
m_data = new float[m_windowSize * m_length];
|
||||||
memset(m_data, 0, sizeof(float) * m_windowSize * m_length);
|
memset(m_data, 0, sizeof(float) * m_windowSize * m_length);
|
||||||
|
|
||||||
for (uint i = 0; i < m_length; i++)
|
for (uint i = 0; i < m_length; i++)
|
||||||
{
|
{
|
||||||
const float center = (0.5f + i) * iscale;
|
const float center = (0.5f + i) * iscale;
|
||||||
|
|
||||||
const int left = (int)floorf(center - m_width);
|
const int left = (int)floorf(center - m_width);
|
||||||
const int right = (int)ceilf(center + m_width);
|
const int right = (int)ceilf(center + m_width);
|
||||||
nvDebugCheck(right - left <= m_windowSize);
|
nvDebugCheck(right - left <= m_windowSize);
|
||||||
|
|
||||||
float total = 0.0f;
|
float total = 0.0f;
|
||||||
for (int j = 0; j < m_windowSize; j++)
|
for (int j = 0; j < m_windowSize; j++)
|
||||||
{
|
{
|
||||||
const float sample = f.sampleBox(left + j - center, scale, samples);
|
const float sample = f.sampleBox(left + j - center, scale, samples);
|
||||||
|
|
||||||
m_data[i * m_windowSize + j] = sample;
|
m_data[i * m_windowSize + j] = sample;
|
||||||
total += sample;
|
total += sample;
|
||||||
}
|
}
|
||||||
|
|
||||||
// normalize weights.
|
// normalize weights.
|
||||||
for (int j = 0; j < m_windowSize; j++)
|
for (int j = 0; j < m_windowSize; j++)
|
||||||
{
|
{
|
||||||
m_data[i * m_windowSize + j] /= total;
|
m_data[i * m_windowSize + j] /= total;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
PolyphaseKernel::~PolyphaseKernel()
|
PolyphaseKernel::~PolyphaseKernel()
|
||||||
{
|
{
|
||||||
delete [] m_data;
|
delete [] m_data;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/// Print the kernel for debugging purposes.
|
/// Print the kernel for debugging purposes.
|
||||||
void PolyphaseKernel::debugPrint() const
|
void PolyphaseKernel::debugPrint() const
|
||||||
{
|
{
|
||||||
for (uint i = 0; i < m_length; i++)
|
for (uint i = 0; i < m_length; i++)
|
||||||
{
|
{
|
||||||
nvDebug("%d: ", i);
|
nvDebug("%d: ", i);
|
||||||
for (int j = 0; j < m_windowSize; j++)
|
for (int j = 0; j < m_windowSize; j++)
|
||||||
{
|
{
|
||||||
nvDebug(" %6.4f", m_data[i * m_windowSize + j]);
|
nvDebug(" %6.4f", m_data[i * m_windowSize + j]);
|
||||||
}
|
}
|
||||||
nvDebug("\n");
|
nvDebug("\n");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,218 +1,219 @@
|
|||||||
// This code is in the public domain -- castanyo@yahoo.es
|
// This code is in the public domain -- castanyo@yahoo.es
|
||||||
|
|
||||||
|
#pragma once
|
||||||
#ifndef NV_IMAGE_FILTER_H
|
#ifndef NV_IMAGE_FILTER_H
|
||||||
#define NV_IMAGE_FILTER_H
|
#define NV_IMAGE_FILTER_H
|
||||||
|
|
||||||
#include <nvimage/nvimage.h>
|
#include "nvimage.h"
|
||||||
#include <nvcore/Debug.h>
|
#include "nvcore/Debug.h"
|
||||||
|
|
||||||
namespace nv
|
namespace nv
|
||||||
{
|
{
|
||||||
class Vector4;
|
class Vector4;
|
||||||
|
|
||||||
/// Base filter class.
|
/// Base filter class.
|
||||||
class NVIMAGE_CLASS Filter
|
class NVIMAGE_CLASS Filter
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
Filter(float width);
|
Filter(float width);
|
||||||
virtual ~Filter();
|
virtual ~Filter();
|
||||||
|
|
||||||
float width() const { return m_width; }
|
float width() const { return m_width; }
|
||||||
float sampleDelta(float x, float scale) const;
|
float sampleDelta(float x, float scale) const;
|
||||||
float sampleBox(float x, float scale, int samples) const;
|
float sampleBox(float x, float scale, int samples) const;
|
||||||
float sampleTriangle(float x, float scale, int samples) const;
|
float sampleTriangle(float x, float scale, int samples) const;
|
||||||
|
|
||||||
virtual float evaluate(float x) const = 0;
|
virtual float evaluate(float x) const = 0;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
const float m_width;
|
const float m_width;
|
||||||
};
|
};
|
||||||
|
|
||||||
// Box filter.
|
// Box filter.
|
||||||
class NVIMAGE_CLASS BoxFilter : public Filter
|
class NVIMAGE_CLASS BoxFilter : public Filter
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
BoxFilter();
|
BoxFilter();
|
||||||
BoxFilter(float width);
|
BoxFilter(float width);
|
||||||
virtual float evaluate(float x) const;
|
virtual float evaluate(float x) const;
|
||||||
};
|
};
|
||||||
|
|
||||||
// Triangle (bilinear/tent) filter.
|
// Triangle (bilinear/tent) filter.
|
||||||
class NVIMAGE_CLASS TriangleFilter : public Filter
|
class NVIMAGE_CLASS TriangleFilter : public Filter
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
TriangleFilter();
|
TriangleFilter();
|
||||||
TriangleFilter(float width);
|
TriangleFilter(float width);
|
||||||
virtual float evaluate(float x) const;
|
virtual float evaluate(float x) const;
|
||||||
};
|
};
|
||||||
|
|
||||||
// Quadratic (bell) filter.
|
// Quadratic (bell) filter.
|
||||||
class NVIMAGE_CLASS QuadraticFilter : public Filter
|
class NVIMAGE_CLASS QuadraticFilter : public Filter
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
QuadraticFilter();
|
QuadraticFilter();
|
||||||
virtual float evaluate(float x) const;
|
virtual float evaluate(float x) const;
|
||||||
};
|
};
|
||||||
|
|
||||||
// Cubic filter from Thatcher Ulrich.
|
// Cubic filter from Thatcher Ulrich.
|
||||||
class NVIMAGE_CLASS CubicFilter : public Filter
|
class NVIMAGE_CLASS CubicFilter : public Filter
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
CubicFilter();
|
CubicFilter();
|
||||||
virtual float evaluate(float x) const;
|
virtual float evaluate(float x) const;
|
||||||
};
|
};
|
||||||
|
|
||||||
// Cubic b-spline filter from Paul Heckbert.
|
// Cubic b-spline filter from Paul Heckbert.
|
||||||
class NVIMAGE_CLASS BSplineFilter : public Filter
|
class NVIMAGE_CLASS BSplineFilter : public Filter
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
BSplineFilter();
|
BSplineFilter();
|
||||||
virtual float evaluate(float x) const;
|
virtual float evaluate(float x) const;
|
||||||
};
|
};
|
||||||
|
|
||||||
/// Mitchell & Netravali's two-param cubic
|
/// Mitchell & Netravali's two-param cubic
|
||||||
/// @see "Reconstruction Filters in Computer Graphics", SIGGRAPH 88
|
/// @see "Reconstruction Filters in Computer Graphics", SIGGRAPH 88
|
||||||
class NVIMAGE_CLASS MitchellFilter : public Filter
|
class NVIMAGE_CLASS MitchellFilter : public Filter
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
MitchellFilter();
|
MitchellFilter();
|
||||||
virtual float evaluate(float x) const;
|
virtual float evaluate(float x) const;
|
||||||
|
|
||||||
void setParameters(float b, float c);
|
void setParameters(float b, float c);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
float p0, p2, p3;
|
float p0, p2, p3;
|
||||||
float q0, q1, q2, q3;
|
float q0, q1, q2, q3;
|
||||||
};
|
};
|
||||||
|
|
||||||
// Lanczos3 filter.
|
// Lanczos3 filter.
|
||||||
class NVIMAGE_CLASS LanczosFilter : public Filter
|
class NVIMAGE_CLASS LanczosFilter : public Filter
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
LanczosFilter();
|
LanczosFilter();
|
||||||
virtual float evaluate(float x) const;
|
virtual float evaluate(float x) const;
|
||||||
};
|
};
|
||||||
|
|
||||||
// Sinc filter.
|
// Sinc filter.
|
||||||
class NVIMAGE_CLASS SincFilter : public Filter
|
class NVIMAGE_CLASS SincFilter : public Filter
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
SincFilter(float w);
|
SincFilter(float w);
|
||||||
virtual float evaluate(float x) const;
|
virtual float evaluate(float x) const;
|
||||||
};
|
};
|
||||||
|
|
||||||
// Kaiser filter.
|
// Kaiser filter.
|
||||||
class NVIMAGE_CLASS KaiserFilter : public Filter
|
class NVIMAGE_CLASS KaiserFilter : public Filter
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
KaiserFilter(float w);
|
KaiserFilter(float w);
|
||||||
virtual float evaluate(float x) const;
|
virtual float evaluate(float x) const;
|
||||||
|
|
||||||
void setParameters(float a, float stretch);
|
|
||||||
|
|
||||||
private:
|
void setParameters(float a, float stretch);
|
||||||
float alpha;
|
|
||||||
float stretch;
|
private:
|
||||||
};
|
float alpha;
|
||||||
|
float stretch;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/// A 1D kernel. Used to precompute filter weights.
|
/// A 1D kernel. Used to precompute filter weights.
|
||||||
class NVIMAGE_CLASS Kernel1
|
class NVIMAGE_CLASS Kernel1
|
||||||
{
|
{
|
||||||
NV_FORBID_COPY(Kernel1);
|
NV_FORBID_COPY(Kernel1);
|
||||||
public:
|
public:
|
||||||
Kernel1(const Filter & f, int iscale, int samples = 32);
|
Kernel1(const Filter & f, int iscale, int samples = 32);
|
||||||
~Kernel1();
|
~Kernel1();
|
||||||
|
|
||||||
float valueAt(uint x) const {
|
float valueAt(uint x) const {
|
||||||
nvDebugCheck(x < (uint)m_windowSize);
|
nvDebugCheck(x < (uint)m_windowSize);
|
||||||
return m_data[x];
|
return m_data[x];
|
||||||
}
|
}
|
||||||
|
|
||||||
int windowSize() const {
|
int windowSize() const {
|
||||||
return m_windowSize;
|
return m_windowSize;
|
||||||
}
|
}
|
||||||
|
|
||||||
float width() const {
|
float width() const {
|
||||||
return m_width;
|
return m_width;
|
||||||
}
|
}
|
||||||
|
|
||||||
void debugPrint();
|
void debugPrint();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
int m_windowSize;
|
int m_windowSize;
|
||||||
float m_width;
|
float m_width;
|
||||||
float * m_data;
|
float * m_data;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
/// A 2D kernel.
|
/// A 2D kernel.
|
||||||
class NVIMAGE_CLASS Kernel2
|
class NVIMAGE_CLASS Kernel2
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
Kernel2(uint width);
|
Kernel2(uint width);
|
||||||
Kernel2(const Kernel2 & k);
|
Kernel2(const Kernel2 & k);
|
||||||
~Kernel2();
|
~Kernel2();
|
||||||
|
|
||||||
void normalize();
|
void normalize();
|
||||||
void transpose();
|
void transpose();
|
||||||
|
|
||||||
float valueAt(uint x, uint y) const {
|
float valueAt(uint x, uint y) const {
|
||||||
return m_data[y * m_windowSize + x];
|
return m_data[y * m_windowSize + x];
|
||||||
}
|
}
|
||||||
|
|
||||||
uint windowSize() const {
|
uint windowSize() const {
|
||||||
return m_windowSize;
|
return m_windowSize;
|
||||||
}
|
}
|
||||||
|
|
||||||
void initLaplacian();
|
void initLaplacian();
|
||||||
void initEdgeDetection();
|
void initEdgeDetection();
|
||||||
void initSobel();
|
void initSobel();
|
||||||
void initPrewitt();
|
void initPrewitt();
|
||||||
|
|
||||||
void initBlendedSobel(const Vector4 & scale);
|
void initBlendedSobel(const Vector4 & scale);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
const uint m_windowSize;
|
const uint m_windowSize;
|
||||||
float * m_data;
|
float * m_data;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
/// A 1D polyphase kernel
|
/// A 1D polyphase kernel
|
||||||
class NVIMAGE_CLASS PolyphaseKernel
|
class NVIMAGE_CLASS PolyphaseKernel
|
||||||
{
|
{
|
||||||
NV_FORBID_COPY(PolyphaseKernel);
|
NV_FORBID_COPY(PolyphaseKernel);
|
||||||
public:
|
public:
|
||||||
PolyphaseKernel(const Filter & f, uint srcLength, uint dstLength, int samples = 32);
|
PolyphaseKernel(const Filter & f, uint srcLength, uint dstLength, int samples = 32);
|
||||||
~PolyphaseKernel();
|
~PolyphaseKernel();
|
||||||
|
|
||||||
int windowSize() const {
|
|
||||||
return m_windowSize;
|
|
||||||
}
|
|
||||||
|
|
||||||
uint length() const {
|
|
||||||
return m_length;
|
|
||||||
}
|
|
||||||
|
|
||||||
float width() const {
|
int windowSize() const {
|
||||||
return m_width;
|
return m_windowSize;
|
||||||
}
|
}
|
||||||
|
|
||||||
float valueAt(uint column, uint x) const {
|
uint length() const {
|
||||||
nvDebugCheck(column < m_length);
|
return m_length;
|
||||||
nvDebugCheck(x < (uint)m_windowSize);
|
}
|
||||||
return m_data[column * m_windowSize + x];
|
|
||||||
}
|
|
||||||
|
|
||||||
void debugPrint() const;
|
float width() const {
|
||||||
|
return m_width;
|
||||||
private:
|
}
|
||||||
int m_windowSize;
|
|
||||||
uint m_length;
|
float valueAt(uint column, uint x) const {
|
||||||
float m_width;
|
nvDebugCheck(column < m_length);
|
||||||
float * m_data;
|
nvDebugCheck(x < (uint)m_windowSize);
|
||||||
};
|
return m_data[column * m_windowSize + x];
|
||||||
|
}
|
||||||
|
|
||||||
|
void debugPrint() const;
|
||||||
|
|
||||||
|
private:
|
||||||
|
int m_windowSize;
|
||||||
|
uint m_length;
|
||||||
|
float m_width;
|
||||||
|
float * m_data;
|
||||||
|
};
|
||||||
|
|
||||||
} // nv namespace
|
} // nv namespace
|
||||||
|
|
||||||
|
File diff suppressed because it is too large
Load Diff
@ -1,275 +1,267 @@
|
|||||||
// This code is in the public domain -- castanyo@yahoo.es
|
// This code is in the public domain -- castanyo@yahoo.es
|
||||||
|
|
||||||
|
#ifndef NV_IMAGE_FLOATIMAGE_H
|
||||||
|
#define NV_IMAGE_FLOATIMAGE_H
|
||||||
|
|
||||||
|
#include "nvimage.h"
|
||||||
|
|
||||||
|
#include "nvcore/Debug.h"
|
||||||
|
#include "nvcore/Utils.h" // clamp
|
||||||
|
|
||||||
|
#include <stdlib.h> // abs
|
||||||
|
|
||||||
|
|
||||||
|
namespace nv
|
||||||
|
{
|
||||||
|
class Vector4;
|
||||||
|
class Matrix;
|
||||||
|
class Image;
|
||||||
|
class Filter;
|
||||||
|
class Kernel1;
|
||||||
|
class Kernel2;
|
||||||
|
class PolyphaseKernel;
|
||||||
|
|
||||||
|
/// Multicomponent floating point image class.
|
||||||
|
class FloatImage
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
|
||||||
|
enum WrapMode {
|
||||||
|
WrapMode_Clamp,
|
||||||
|
WrapMode_Repeat,
|
||||||
|
WrapMode_Mirror
|
||||||
|
};
|
||||||
|
|
||||||
|
NVIMAGE_API FloatImage();
|
||||||
|
NVIMAGE_API FloatImage(const Image * img);
|
||||||
|
NVIMAGE_API virtual ~FloatImage();
|
||||||
|
|
||||||
|
/** @name Conversion. */
|
||||||
|
//@{
|
||||||
|
NVIMAGE_API void initFrom(const Image * img);
|
||||||
|
NVIMAGE_API Image * createImage(uint base_component = 0, uint num = 4) const;
|
||||||
|
NVIMAGE_API Image * createImageGammaCorrect(float gamma = 2.2f) const;
|
||||||
|
//@}
|
||||||
|
|
||||||
|
/** @name Allocation. */
|
||||||
|
//@{
|
||||||
|
NVIMAGE_API void allocate(uint c, uint w, uint h);
|
||||||
|
NVIMAGE_API void free(); // Does not clear members.
|
||||||
|
//@}
|
||||||
|
|
||||||
|
/** @name Manipulation. */
|
||||||
|
//@{
|
||||||
|
NVIMAGE_API void clear(float f = 0.0f);
|
||||||
|
NVIMAGE_API void clear(uint component, float f = 0.0f);
|
||||||
|
|
||||||
|
NVIMAGE_API void normalize(uint base_component);
|
||||||
|
|
||||||
|
NVIMAGE_API void packNormals(uint base_component);
|
||||||
|
NVIMAGE_API void expandNormals(uint base_component);
|
||||||
|
NVIMAGE_API void scaleBias(uint base_component, uint num, float scale, float add);
|
||||||
|
|
||||||
|
//NVIMAGE_API void clamp(uint base_component, uint num);
|
||||||
|
NVIMAGE_API void clamp(float low, float high);
|
||||||
|
|
||||||
|
NVIMAGE_API void toLinear(uint base_component, uint num, float gamma = 2.2f);
|
||||||
|
NVIMAGE_API void toGamma(uint base_component, uint num, float gamma = 2.2f);
|
||||||
|
NVIMAGE_API void exponentiate(uint base_component, uint num, float power);
|
||||||
|
|
||||||
|
NVIMAGE_API void transform(uint base_component, const Matrix & m, const Vector4 & offset);
|
||||||
|
NVIMAGE_API void swizzle(uint base_component, uint r, uint g, uint b, uint a);
|
||||||
|
|
||||||
|
NVIMAGE_API FloatImage * fastDownSample() const;
|
||||||
|
NVIMAGE_API FloatImage * downSample(const Filter & filter, WrapMode wm) const;
|
||||||
|
NVIMAGE_API FloatImage * downSample(const Filter & filter, WrapMode wm, uint alpha) const;
|
||||||
|
NVIMAGE_API FloatImage * resize(const Filter & filter, uint w, uint h, WrapMode wm) const;
|
||||||
|
NVIMAGE_API FloatImage * resize(const Filter & filter, uint w, uint h, WrapMode wm, uint alpha) const;
|
||||||
|
|
||||||
|
//NVIMAGE_API FloatImage * downSample(const Kernel1 & filter, WrapMode wm) const;
|
||||||
|
//NVIMAGE_API FloatImage * downSample(const Kernel1 & filter, uint w, uint h, WrapMode wm) const;
|
||||||
|
//@}
|
||||||
|
|
||||||
|
NVIMAGE_API float applyKernel(const Kernel2 * k, int x, int y, uint c, WrapMode wm) const;
|
||||||
|
NVIMAGE_API float applyKernelVertical(const Kernel1 * k, int x, int y, uint c, WrapMode wm) const;
|
||||||
|
NVIMAGE_API float applyKernelHorizontal(const Kernel1 * k, int x, int y, uint c, WrapMode wm) const;
|
||||||
|
NVIMAGE_API void applyKernelVertical(const PolyphaseKernel & k, int x, uint c, WrapMode wm, float * output) const;
|
||||||
|
NVIMAGE_API void applyKernelHorizontal(const PolyphaseKernel & k, int y, uint c, WrapMode wm, float * output) const;
|
||||||
|
NVIMAGE_API void applyKernelVertical(const PolyphaseKernel & k, int x, uint c, uint a, WrapMode wm, float * output) const;
|
||||||
|
NVIMAGE_API void applyKernelHorizontal(const PolyphaseKernel & k, int y, uint c, uint a, WrapMode wm, float * output) const;
|
||||||
|
|
||||||
|
NVIMAGE_API void flip();
|
||||||
|
|
||||||
#ifndef NV_IMAGE_FLOATIMAGE_H
|
NVIMAGE_API float alphaTestCoverage(float alphaRef, int alphaChannel) const;
|
||||||
#define NV_IMAGE_FLOATIMAGE_H
|
NVIMAGE_API void scaleAlphaToCoverage(float coverage, float alphaRef, int alphaChannel);
|
||||||
|
|
||||||
#include <nvimage/nvimage.h>
|
|
||||||
|
uint width() const { return m_width; }
|
||||||
#include <nvmath/Vector.h>
|
uint height() const { return m_height; }
|
||||||
|
uint componentNum() const { return m_componentNum; }
|
||||||
#include <nvcore/Debug.h>
|
uint count() const { return m_count; }
|
||||||
#include <nvcore/Algorithms.h> // clamp
|
|
||||||
|
|
||||||
#include <stdlib.h> // abs
|
/** @name Pixel access. */
|
||||||
|
//@{
|
||||||
|
const float * channel(uint c) const;
|
||||||
namespace nv
|
float * channel(uint c);
|
||||||
{
|
|
||||||
class Vector4;
|
const float * scanline(uint y, uint c) const;
|
||||||
class Matrix;
|
float * scanline(uint y, uint c);
|
||||||
class Image;
|
|
||||||
class Filter;
|
float pixel(uint x, uint y, uint c) const;
|
||||||
class Kernel1;
|
float & pixel(uint x, uint y, uint c);
|
||||||
class Kernel2;
|
|
||||||
class PolyphaseKernel;
|
float pixel(uint idx) const;
|
||||||
|
float & pixel(uint idx);
|
||||||
/// Multicomponent floating point image class.
|
|
||||||
class FloatImage
|
float sampleNearest(float x, float y, int c, WrapMode wm) const;
|
||||||
{
|
float sampleLinear(float x, float y, int c, WrapMode wm) const;
|
||||||
public:
|
|
||||||
|
float sampleNearestClamp(float x, float y, int c) const;
|
||||||
enum WrapMode {
|
float sampleNearestRepeat(float x, float y, int c) const;
|
||||||
WrapMode_Clamp,
|
float sampleNearestMirror(float x, float y, int c) const;
|
||||||
WrapMode_Repeat,
|
|
||||||
WrapMode_Mirror
|
float sampleLinearClamp(float x, float y, int c) const;
|
||||||
};
|
float sampleLinearRepeat(float x, float y, int c) const;
|
||||||
|
float sampleLinearMirror(float x, float y, int c) const;
|
||||||
NVIMAGE_API FloatImage();
|
//@}
|
||||||
NVIMAGE_API FloatImage(const Image * img);
|
|
||||||
NVIMAGE_API virtual ~FloatImage();
|
|
||||||
|
FloatImage* clone() const;
|
||||||
/** @name Conversion. */
|
|
||||||
//@{
|
public:
|
||||||
NVIMAGE_API void initFrom(const Image * img);
|
|
||||||
NVIMAGE_API Image * createImage(uint base_component = 0, uint num = 4) const;
|
uint index(uint x, uint y) const;
|
||||||
NVIMAGE_API Image * createImageGammaCorrect(float gamma = 2.2f) const;
|
uint indexClamp(int x, int y) const;
|
||||||
//@}
|
uint indexRepeat(int x, int y) const;
|
||||||
|
uint indexMirror(int x, int y) const;
|
||||||
/** @name Allocation. */
|
uint index(int x, int y, WrapMode wm) const;
|
||||||
//@{
|
|
||||||
NVIMAGE_API void allocate(uint c, uint w, uint h);
|
public:
|
||||||
NVIMAGE_API void free(); // Does not clear members.
|
|
||||||
//@}
|
uint16 m_width; ///< Width of the texture.
|
||||||
|
uint16 m_height; ///< Height of the texture.
|
||||||
/** @name Manipulation. */
|
uint32 m_componentNum; ///< Number of components.
|
||||||
//@{
|
uint32 m_count; ///< Image pixel count.
|
||||||
NVIMAGE_API void clear(float f=0.0f);
|
float * m_mem;
|
||||||
|
|
||||||
NVIMAGE_API void normalize(uint base_component);
|
};
|
||||||
|
|
||||||
NVIMAGE_API void packNormals(uint base_component);
|
|
||||||
NVIMAGE_API void expandNormals(uint base_component);
|
/// Get const channel pointer.
|
||||||
NVIMAGE_API void scaleBias(uint base_component, uint num, float scale, float bias);
|
inline const float * FloatImage::channel(uint c) const
|
||||||
|
{
|
||||||
NVIMAGE_API void clamp(uint base_component, uint num, float low, float high);
|
nvDebugCheck(m_mem != NULL);
|
||||||
|
nvDebugCheck(c < m_componentNum);
|
||||||
NVIMAGE_API void toLinear(uint base_component, uint num, float gamma = 2.2f);
|
return m_mem + c * m_width * m_height;
|
||||||
NVIMAGE_API void toGamma(uint base_component, uint num, float gamma = 2.2f);
|
}
|
||||||
NVIMAGE_API void exponentiate(uint base_component, uint num, float power);
|
|
||||||
|
/// Get channel pointer.
|
||||||
NVIMAGE_API void transform(uint base_component, const Matrix & m, const Vector4 & offset);
|
inline float * FloatImage::channel(uint c) {
|
||||||
NVIMAGE_API void swizzle(uint base_component, uint r, uint g, uint b, uint a);
|
nvDebugCheck(m_mem != NULL);
|
||||||
|
nvDebugCheck(c < m_componentNum);
|
||||||
NVIMAGE_API FloatImage * fastDownSample() const;
|
return m_mem + c * m_width * m_height;
|
||||||
NVIMAGE_API FloatImage * downSample(const Filter & filter, WrapMode wm) const;
|
}
|
||||||
NVIMAGE_API FloatImage * downSample(const Filter & filter, WrapMode wm, uint alpha) const;
|
|
||||||
NVIMAGE_API FloatImage * resize(const Filter & filter, uint w, uint h, WrapMode wm) const;
|
/// Get const scanline pointer.
|
||||||
|
inline const float * FloatImage::scanline(uint y, uint c) const
|
||||||
NVIMAGE_API FloatImage * resize(const Filter & filter, uint w, uint h, WrapMode wm, uint alpha) const;
|
{
|
||||||
|
nvDebugCheck(y < m_height);
|
||||||
NVIMAGE_API float applyKernel(const Kernel2 * k, int x, int y, uint c, WrapMode wm) const;
|
return channel(c) + y * m_width;
|
||||||
NVIMAGE_API float applyKernelVertical(const Kernel1 * k, int x, int y, uint c, WrapMode wm) const;
|
}
|
||||||
NVIMAGE_API float applyKernelHorizontal(const Kernel1 * k, int x, int y, uint c, WrapMode wm) const;
|
|
||||||
NVIMAGE_API void applyKernelVertical(const PolyphaseKernel & k, int x, uint c, WrapMode wm, float * output) const;
|
/// Get scanline pointer.
|
||||||
NVIMAGE_API void applyKernelHorizontal(const PolyphaseKernel & k, int y, uint c, WrapMode wm, float * output) const;
|
inline float * FloatImage::scanline(uint y, uint c)
|
||||||
NVIMAGE_API void applyKernelVertical(const PolyphaseKernel & k, int x, uint c, uint a, WrapMode wm, float * output) const;
|
{
|
||||||
NVIMAGE_API void applyKernelHorizontal(const PolyphaseKernel & k, int y, uint c, uint a, WrapMode wm, float * output) const;
|
nvDebugCheck(y < m_height);
|
||||||
|
return channel(c) + y * m_width;
|
||||||
NVIMAGE_API void flip();
|
}
|
||||||
|
|
||||||
NVIMAGE_API float alphaTestCoverage(float alphaRef, int alphaChannel) const;
|
/// Get pixel component.
|
||||||
NVIMAGE_API void scaleAlphaToCoverage(float coverage, float alphaRef, int alphaChannel);
|
inline float FloatImage::pixel(uint x, uint y, uint c) const
|
||||||
//@}
|
{
|
||||||
|
nvDebugCheck(m_mem != NULL);
|
||||||
uint width() const { return m_width; }
|
nvDebugCheck(x < m_width);
|
||||||
uint height() const { return m_height; }
|
nvDebugCheck(y < m_height);
|
||||||
uint componentNum() const { return m_componentNum; }
|
nvDebugCheck(c < m_componentNum);
|
||||||
uint count() const { return m_count; }
|
return m_mem[(c * m_height + y) * m_width + x];
|
||||||
|
}
|
||||||
|
|
||||||
/** @name Pixel access. */
|
/// Get pixel component.
|
||||||
//@{
|
inline float & FloatImage::pixel(uint x, uint y, uint c)
|
||||||
const float * channel(uint c) const;
|
{
|
||||||
float * channel(uint c);
|
nvDebugCheck(m_mem != NULL);
|
||||||
|
nvDebugCheck(x < m_width);
|
||||||
const float * scanline(uint y, uint c) const;
|
nvDebugCheck(y < m_height);
|
||||||
float * scanline(uint y, uint c);
|
nvDebugCheck(c < m_componentNum);
|
||||||
|
return m_mem[(c * m_height + y) * m_width + x];
|
||||||
void setPixel(float f, uint x, uint y, uint c);
|
}
|
||||||
void addPixel(float f, uint x, uint y, uint c);
|
|
||||||
float pixel(uint x, uint y, uint c) const;
|
/// Get pixel component.
|
||||||
|
inline float FloatImage::pixel(uint idx) const
|
||||||
void setPixel(float f, uint idx);
|
{
|
||||||
float pixel(uint idx) const;
|
nvDebugCheck(idx < m_count);
|
||||||
|
return m_mem[idx];
|
||||||
float sampleNearest(float x, float y, int c, WrapMode wm) const;
|
}
|
||||||
float sampleLinear(float x, float y, int c, WrapMode wm) const;
|
|
||||||
|
/// Get pixel component.
|
||||||
float sampleNearestClamp(float x, float y, int c) const;
|
inline float & FloatImage::pixel(uint idx)
|
||||||
float sampleNearestRepeat(float x, float y, int c) const;
|
{
|
||||||
float sampleNearestMirror(float x, float y, int c) const;
|
nvDebugCheck(idx < m_count);
|
||||||
|
return m_mem[idx];
|
||||||
float sampleLinearClamp(float x, float y, int c) const;
|
}
|
||||||
float sampleLinearRepeat(float x, float y, int c) const;
|
|
||||||
float sampleLinearMirror(float x, float y, int c) const;
|
inline uint FloatImage::index(uint x, uint y) const
|
||||||
//@}
|
{
|
||||||
|
nvDebugCheck(x < m_width);
|
||||||
|
nvDebugCheck(y < m_height);
|
||||||
FloatImage* clone() const;
|
return y * m_width + x;
|
||||||
|
}
|
||||||
public:
|
|
||||||
|
inline uint FloatImage::indexClamp(int x, int y) const
|
||||||
uint index(uint x, uint y) const;
|
{
|
||||||
uint indexClamp(int x, int y) const;
|
return nv::clamp(y, int(0), int(m_height-1)) * m_width + nv::clamp(x, int(0), int(m_width-1));
|
||||||
uint indexRepeat(int x, int y) const;
|
}
|
||||||
uint indexMirror(int x, int y) const;
|
|
||||||
uint index(int x, int y, WrapMode wm) const;
|
inline int repeat_remainder(int a, int b)
|
||||||
|
{
|
||||||
public:
|
if (a >= 0) return a % b;
|
||||||
|
else return (a + 1) % b + b - 1;
|
||||||
uint16 m_width; ///< Width of the texture.
|
}
|
||||||
uint16 m_height; ///< Height of the texture.
|
|
||||||
uint32 m_componentNum; ///< Number of components.
|
inline uint FloatImage::indexRepeat(int x, int y) const
|
||||||
uint32 m_count; ///< Image pixel count.
|
{
|
||||||
float * m_mem;
|
return repeat_remainder(y, m_height) * m_width + repeat_remainder(x, m_width);
|
||||||
|
}
|
||||||
};
|
|
||||||
|
inline uint FloatImage::indexMirror(int x, int y) const
|
||||||
|
{
|
||||||
/// Get const channel pointer.
|
if (m_width == 1) x = 0;
|
||||||
inline const float * FloatImage::channel(uint c) const
|
|
||||||
{
|
x = abs(x);
|
||||||
nvDebugCheck(m_mem != NULL);
|
while (x >= m_width) {
|
||||||
nvDebugCheck(c < m_componentNum);
|
x = abs(m_width + m_width - x - 2);
|
||||||
return m_mem + c * m_width * m_height;
|
}
|
||||||
}
|
|
||||||
|
if (m_height == 1) y = 0;
|
||||||
/// Get channel pointer.
|
|
||||||
inline float * FloatImage::channel(uint c) {
|
y = abs(y);
|
||||||
nvDebugCheck(m_mem != NULL);
|
while (y >= m_height) {
|
||||||
nvDebugCheck(c < m_componentNum);
|
y = abs(m_height + m_height - y - 2);
|
||||||
return m_mem + c * m_width * m_height;
|
}
|
||||||
}
|
|
||||||
|
return index(x, y);
|
||||||
/// Get const scanline pointer.
|
}
|
||||||
inline const float * FloatImage::scanline(uint y, uint c) const
|
|
||||||
{
|
inline uint FloatImage::index(int x, int y, WrapMode wm) const
|
||||||
nvDebugCheck(y < m_height);
|
{
|
||||||
return channel(c) + y * m_width;
|
if (wm == WrapMode_Clamp) return indexClamp(x, y);
|
||||||
}
|
if (wm == WrapMode_Repeat) return indexRepeat(x, y);
|
||||||
|
/*if (wm == WrapMode_Mirror)*/ return indexMirror(x, y);
|
||||||
/// Get scanline pointer.
|
}
|
||||||
inline float * FloatImage::scanline(uint y, uint c)
|
|
||||||
{
|
} // nv namespace
|
||||||
nvDebugCheck(y < m_height);
|
|
||||||
return channel(c) + y * m_width;
|
|
||||||
}
|
|
||||||
|
#endif // NV_IMAGE_FLOATIMAGE_H
|
||||||
/// Set pixel component.
|
|
||||||
inline void FloatImage::setPixel(float f, uint x, uint y, uint c)
|
|
||||||
{
|
|
||||||
nvDebugCheck(m_mem != NULL);
|
|
||||||
nvDebugCheck(x < m_width);
|
|
||||||
nvDebugCheck(y < m_height);
|
|
||||||
nvDebugCheck(c < m_componentNum);
|
|
||||||
m_mem[(c * m_height + y) * m_width + x] = f;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Add to pixel component.
|
|
||||||
inline void FloatImage::addPixel(float f, uint x, uint y, uint c)
|
|
||||||
{
|
|
||||||
nvDebugCheck(m_mem != NULL);
|
|
||||||
nvDebugCheck(x < m_width);
|
|
||||||
nvDebugCheck(y < m_height);
|
|
||||||
nvDebugCheck(c < m_componentNum);
|
|
||||||
m_mem[(c * m_height + y) * m_width + x] += f;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Get pixel component.
|
|
||||||
inline float FloatImage::pixel(uint x, uint y, uint c) const
|
|
||||||
{
|
|
||||||
nvDebugCheck(m_mem != NULL);
|
|
||||||
nvDebugCheck(x < m_width);
|
|
||||||
nvDebugCheck(y < m_height);
|
|
||||||
nvDebugCheck(c < m_componentNum);
|
|
||||||
return m_mem[(c * m_height + y) * m_width + x];
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Set pixel component.
|
|
||||||
inline void FloatImage::setPixel(float f, uint idx)
|
|
||||||
{
|
|
||||||
nvDebugCheck(idx < m_count);
|
|
||||||
m_mem[idx] = f;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Get pixel component.
|
|
||||||
inline float FloatImage::pixel(uint idx) const
|
|
||||||
{
|
|
||||||
nvDebugCheck(idx < m_count);
|
|
||||||
return m_mem[idx];
|
|
||||||
}
|
|
||||||
|
|
||||||
inline uint FloatImage::index(uint x, uint y) const
|
|
||||||
{
|
|
||||||
nvDebugCheck(x < m_width);
|
|
||||||
nvDebugCheck(y < m_height);
|
|
||||||
return y * m_width + x;
|
|
||||||
}
|
|
||||||
|
|
||||||
inline uint FloatImage::indexClamp(int x, int y) const
|
|
||||||
{
|
|
||||||
return nv::clamp(y, int(0), int(m_height-1)) * m_width + nv::clamp(x, int(0), int(m_width-1));
|
|
||||||
}
|
|
||||||
|
|
||||||
inline int repeat_remainder(int a, int b)
|
|
||||||
{
|
|
||||||
if (a >= 0) return a % b;
|
|
||||||
else return (a + 1) % b + b - 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
inline uint FloatImage::indexRepeat(int x, int y) const
|
|
||||||
{
|
|
||||||
return repeat_remainder(y, m_height) * m_width + repeat_remainder(x, m_width);
|
|
||||||
}
|
|
||||||
|
|
||||||
inline uint FloatImage::indexMirror(int x, int y) const
|
|
||||||
{
|
|
||||||
if (m_width == 1) x = 0;
|
|
||||||
|
|
||||||
x = abs(x);
|
|
||||||
while (x >= m_width) {
|
|
||||||
x = abs(m_width + m_width - x - 2);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (m_height == 1) y = 0;
|
|
||||||
|
|
||||||
y = abs(y);
|
|
||||||
while (y >= m_height) {
|
|
||||||
y = abs(m_height + m_height - y - 2);
|
|
||||||
}
|
|
||||||
|
|
||||||
return index(x, y);
|
|
||||||
}
|
|
||||||
|
|
||||||
inline uint FloatImage::index(int x, int y, WrapMode wm) const
|
|
||||||
{
|
|
||||||
if (wm == WrapMode_Clamp) return indexClamp(x, y);
|
|
||||||
if (wm == WrapMode_Repeat) return indexRepeat(x, y);
|
|
||||||
/*if (wm == WrapMode_Mirror)*/ return indexMirror(x, y);
|
|
||||||
}
|
|
||||||
|
|
||||||
} // nv namespace
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
#endif // NV_IMAGE_FLOATIMAGE_H
|
|
||||||
|
@ -1,13 +1,13 @@
|
|||||||
// This code is in the public domain -- castanyo@yahoo.es
|
// This code is in the public domain -- castanyo@yahoo.es
|
||||||
|
|
||||||
#include <nvimage/Image.h>
|
#include "Image.h"
|
||||||
#include <nvimage/ImageIO.h>
|
#include "ImageIO.h"
|
||||||
|
|
||||||
#include <nvmath/Color.h>
|
#include "nvmath/Color.h"
|
||||||
|
|
||||||
#include <nvcore/Debug.h>
|
#include "nvcore/Debug.h"
|
||||||
#include <nvcore/Ptr.h>
|
#include "nvcore/Ptr.h"
|
||||||
#include <nvcore/Containers.h> // swap
|
#include "nvcore/Utils.h" // swap
|
||||||
|
|
||||||
|
|
||||||
using namespace nv;
|
using namespace nv;
|
||||||
@ -18,133 +18,133 @@ Image::Image() : m_width(0), m_height(0), m_format(Format_RGB), m_data(NULL)
|
|||||||
|
|
||||||
Image::Image(const Image & img) : m_data(NULL)
|
Image::Image(const Image & img) : m_data(NULL)
|
||||||
{
|
{
|
||||||
allocate(img.m_width, img.m_height);
|
allocate(img.m_width, img.m_height);
|
||||||
m_format = img.m_format;
|
m_format = img.m_format;
|
||||||
memcpy(m_data, img.m_data, sizeof(Color32) * m_width * m_height);
|
memcpy(m_data, img.m_data, sizeof(Color32) * m_width * m_height);
|
||||||
}
|
}
|
||||||
|
|
||||||
Image::~Image()
|
Image::~Image()
|
||||||
{
|
{
|
||||||
free();
|
free();
|
||||||
}
|
}
|
||||||
|
|
||||||
const Image & Image::operator=(const Image & img)
|
const Image & Image::operator=(const Image & img)
|
||||||
{
|
{
|
||||||
allocate(img.m_width, img.m_height);
|
allocate(img.m_width, img.m_height);
|
||||||
m_format = img.m_format;
|
m_format = img.m_format;
|
||||||
memcpy(m_data, img.m_data, sizeof(Color32) * m_width * m_height);
|
memcpy(m_data, img.m_data, sizeof(Color32) * m_width * m_height);
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void Image::allocate(uint w, uint h)
|
void Image::allocate(uint w, uint h)
|
||||||
{
|
{
|
||||||
m_width = w;
|
m_width = w;
|
||||||
m_height = h;
|
m_height = h;
|
||||||
m_data = (Color32 *)nv::mem::realloc(m_data, w * h * sizeof(Color32));
|
m_data = (Color32 *)nv::mem::realloc(m_data, w * h * sizeof(Color32));
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Image::load(const char * name)
|
bool Image::load(const char * name)
|
||||||
{
|
{
|
||||||
free();
|
free();
|
||||||
|
|
||||||
AutoPtr<Image> img(ImageIO::load(name));
|
AutoPtr<Image> img(ImageIO::load(name));
|
||||||
if (img == NULL) {
|
if (img == NULL) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
swap(m_width, img->m_width);
|
swap(m_width, img->m_width);
|
||||||
swap(m_height, img->m_height);
|
swap(m_height, img->m_height);
|
||||||
swap(m_format, img->m_format);
|
swap(m_format, img->m_format);
|
||||||
swap(m_data, img->m_data);
|
swap(m_data, img->m_data);
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Image::wrap(void * data, uint w, uint h)
|
void Image::wrap(void * data, uint w, uint h)
|
||||||
{
|
{
|
||||||
free();
|
free();
|
||||||
m_data = (Color32 *)data;
|
m_data = (Color32 *)data;
|
||||||
m_width = w;
|
m_width = w;
|
||||||
m_height = h;
|
m_height = h;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Image::unwrap()
|
void Image::unwrap()
|
||||||
{
|
{
|
||||||
m_data = NULL;
|
m_data = NULL;
|
||||||
m_width = 0;
|
m_width = 0;
|
||||||
m_height = 0;
|
m_height = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void Image::free()
|
void Image::free()
|
||||||
{
|
{
|
||||||
nv::mem::free(m_data);
|
nv::mem::free(m_data);
|
||||||
m_data = NULL;
|
m_data = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
uint Image::width() const
|
uint Image::width() const
|
||||||
{
|
{
|
||||||
return m_width;
|
return m_width;
|
||||||
}
|
}
|
||||||
|
|
||||||
uint Image::height() const
|
uint Image::height() const
|
||||||
{
|
{
|
||||||
return m_height;
|
return m_height;
|
||||||
}
|
}
|
||||||
|
|
||||||
const Color32 * Image::scanline(uint h) const
|
const Color32 * Image::scanline(uint h) const
|
||||||
{
|
{
|
||||||
nvDebugCheck(h < m_height);
|
nvDebugCheck(h < m_height);
|
||||||
return m_data + h * m_width;
|
return m_data + h * m_width;
|
||||||
}
|
}
|
||||||
|
|
||||||
Color32 * Image::scanline(uint h)
|
Color32 * Image::scanline(uint h)
|
||||||
{
|
{
|
||||||
nvDebugCheck(h < m_height);
|
nvDebugCheck(h < m_height);
|
||||||
return m_data + h * m_width;
|
return m_data + h * m_width;
|
||||||
}
|
}
|
||||||
|
|
||||||
const Color32 * Image::pixels() const
|
const Color32 * Image::pixels() const
|
||||||
{
|
{
|
||||||
return m_data;
|
return m_data;
|
||||||
}
|
}
|
||||||
|
|
||||||
Color32 * Image::pixels()
|
Color32 * Image::pixels()
|
||||||
{
|
{
|
||||||
return m_data;
|
return m_data;
|
||||||
}
|
}
|
||||||
|
|
||||||
const Color32 & Image::pixel(uint idx) const
|
const Color32 & Image::pixel(uint idx) const
|
||||||
{
|
{
|
||||||
nvDebugCheck(idx < m_width * m_height);
|
nvDebugCheck(idx < m_width * m_height);
|
||||||
return m_data[idx];
|
return m_data[idx];
|
||||||
}
|
}
|
||||||
|
|
||||||
Color32 & Image::pixel(uint idx)
|
Color32 & Image::pixel(uint idx)
|
||||||
{
|
{
|
||||||
nvDebugCheck(idx < m_width * m_height);
|
nvDebugCheck(idx < m_width * m_height);
|
||||||
return m_data[idx];
|
return m_data[idx];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
Image::Format Image::format() const
|
Image::Format Image::format() const
|
||||||
{
|
{
|
||||||
return m_format;
|
return m_format;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Image::setFormat(Image::Format f)
|
void Image::setFormat(Image::Format f)
|
||||||
{
|
{
|
||||||
m_format = f;
|
m_format = f;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Image::fill(Color32 c)
|
void Image::fill(Color32 c)
|
||||||
{
|
{
|
||||||
const uint size = m_width * m_height;
|
const uint size = m_width * m_height;
|
||||||
for (uint i = 0; i < size; ++i)
|
for (uint i = 0; i < size; ++i)
|
||||||
{
|
{
|
||||||
m_data[i] = c;
|
m_data[i] = c;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,81 +1,82 @@
|
|||||||
// This code is in the public domain -- castanyo@yahoo.es
|
// This code is in the public domain -- castanyo@yahoo.es
|
||||||
|
|
||||||
|
#pragma once
|
||||||
#ifndef NV_IMAGE_IMAGE_H
|
#ifndef NV_IMAGE_IMAGE_H
|
||||||
#define NV_IMAGE_IMAGE_H
|
#define NV_IMAGE_IMAGE_H
|
||||||
|
|
||||||
#include <nvcore/Debug.h>
|
#include "nvimage.h"
|
||||||
#include <nvimage/nvimage.h>
|
#include "nvcore/Debug.h"
|
||||||
|
|
||||||
namespace nv
|
namespace nv
|
||||||
{
|
{
|
||||||
class Color32;
|
class Color32;
|
||||||
|
|
||||||
/// 32 bit RGBA image.
|
|
||||||
class NVIMAGE_CLASS Image
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
|
|
||||||
enum Format
|
|
||||||
{
|
|
||||||
Format_RGB,
|
|
||||||
Format_ARGB,
|
|
||||||
};
|
|
||||||
|
|
||||||
Image();
|
|
||||||
Image(const Image & img);
|
|
||||||
~Image();
|
|
||||||
|
|
||||||
const Image & operator=(const Image & img);
|
/// 32 bit RGBA image.
|
||||||
|
class NVIMAGE_CLASS Image
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
|
||||||
|
enum Format
|
||||||
|
{
|
||||||
|
Format_RGB,
|
||||||
|
Format_ARGB,
|
||||||
|
};
|
||||||
|
|
||||||
|
Image();
|
||||||
|
Image(const Image & img);
|
||||||
|
~Image();
|
||||||
|
|
||||||
|
const Image & operator=(const Image & img);
|
||||||
|
|
||||||
|
|
||||||
void allocate(uint w, uint h);
|
void allocate(uint w, uint h);
|
||||||
bool load(const char * name);
|
bool load(const char * name);
|
||||||
|
|
||||||
void wrap(void * data, uint w, uint h);
|
|
||||||
void unwrap();
|
|
||||||
|
|
||||||
uint width() const;
|
|
||||||
uint height() const;
|
|
||||||
|
|
||||||
const Color32 * scanline(uint h) const;
|
|
||||||
Color32 * scanline(uint h);
|
|
||||||
|
|
||||||
const Color32 * pixels() const;
|
|
||||||
Color32 * pixels();
|
|
||||||
|
|
||||||
const Color32 & pixel(uint idx) const;
|
|
||||||
Color32 & pixel(uint idx);
|
|
||||||
|
|
||||||
const Color32 & pixel(uint x, uint y) const;
|
|
||||||
Color32 & pixel(uint x, uint y);
|
|
||||||
|
|
||||||
Format format() const;
|
|
||||||
void setFormat(Format f);
|
|
||||||
|
|
||||||
void fill(Color32 c);
|
|
||||||
|
|
||||||
private:
|
void wrap(void * data, uint w, uint h);
|
||||||
void free();
|
void unwrap();
|
||||||
|
|
||||||
private:
|
uint width() const;
|
||||||
uint m_width;
|
uint height() const;
|
||||||
uint m_height;
|
|
||||||
Format m_format;
|
const Color32 * scanline(uint h) const;
|
||||||
Color32 * m_data;
|
Color32 * scanline(uint h);
|
||||||
};
|
|
||||||
|
const Color32 * pixels() const;
|
||||||
|
Color32 * pixels();
|
||||||
|
|
||||||
|
const Color32 & pixel(uint idx) const;
|
||||||
|
Color32 & pixel(uint idx);
|
||||||
|
|
||||||
|
const Color32 & pixel(uint x, uint y) const;
|
||||||
|
Color32 & pixel(uint x, uint y);
|
||||||
|
|
||||||
|
Format format() const;
|
||||||
|
void setFormat(Format f);
|
||||||
|
|
||||||
|
void fill(Color32 c);
|
||||||
|
|
||||||
|
private:
|
||||||
|
void free();
|
||||||
|
|
||||||
|
private:
|
||||||
|
uint m_width;
|
||||||
|
uint m_height;
|
||||||
|
Format m_format;
|
||||||
|
Color32 * m_data;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
inline const Color32 & Image::pixel(uint x, uint y) const
|
inline const Color32 & Image::pixel(uint x, uint y) const
|
||||||
{
|
{
|
||||||
nvDebugCheck(x < width() && y < height());
|
nvDebugCheck(x < width() && y < height());
|
||||||
return pixel(y * width() + x);
|
return pixel(y * width() + x);
|
||||||
}
|
}
|
||||||
|
|
||||||
inline Color32 & Image::pixel(uint x, uint y)
|
inline Color32 & Image::pixel(uint x, uint y)
|
||||||
{
|
{
|
||||||
nvDebugCheck(x < width() && y < height());
|
nvDebugCheck(x < width() && y < height());
|
||||||
return pixel(y * width() + x);
|
return pixel(y * width() + x);
|
||||||
}
|
}
|
||||||
|
|
||||||
} // nv namespace
|
} // nv namespace
|
||||||
|
|
||||||
|
@ -6,12 +6,13 @@
|
|||||||
#include "TgaFile.h"
|
#include "TgaFile.h"
|
||||||
#include "PsdFile.h"
|
#include "PsdFile.h"
|
||||||
|
|
||||||
#include <nvmath/Color.h>
|
#include "nvmath/Color.h"
|
||||||
|
|
||||||
#include <nvcore/Ptr.h>
|
#include "nvcore/Ptr.h"
|
||||||
#include <nvcore/Containers.h>
|
#include "nvcore/Utils.h"
|
||||||
#include <nvcore/StrLib.h>
|
#include "nvcore/Array.h"
|
||||||
#include <nvcore/StdStream.h>
|
#include "nvcore/StrLib.h"
|
||||||
|
#include "nvcore/StdStream.h"
|
||||||
|
|
||||||
// Extern
|
// Extern
|
||||||
#if defined(HAVE_FREEIMAGE)
|
#if defined(HAVE_FREEIMAGE)
|
||||||
|
@ -1,40 +1,42 @@
|
|||||||
// This code is in the public domain -- castanyo@yahoo.es
|
// This code is in the public domain -- castanyo@yahoo.es
|
||||||
|
|
||||||
|
#pragma once
|
||||||
#ifndef NV_IMAGE_IMAGEIO_H
|
#ifndef NV_IMAGE_IMAGEIO_H
|
||||||
#define NV_IMAGE_IMAGEIO_H
|
#define NV_IMAGE_IMAGEIO_H
|
||||||
|
|
||||||
#include <nvimage/nvimage.h>
|
#include "nvimage.h"
|
||||||
|
|
||||||
#include <nvcore/StrLib.h>
|
#include "nvcore/StrLib.h"
|
||||||
|
#include "nvcore/HashMap.h"
|
||||||
|
|
||||||
|
|
||||||
namespace nv
|
namespace nv
|
||||||
{
|
{
|
||||||
class Image;
|
class Image;
|
||||||
class FloatImage;
|
class FloatImage;
|
||||||
class Stream;
|
class Stream;
|
||||||
|
|
||||||
namespace ImageIO
|
namespace ImageIO
|
||||||
{
|
{
|
||||||
struct ImageMetaData
|
struct ImageMetaData
|
||||||
{
|
{
|
||||||
HashMap<String, String> tagMap;
|
HashMap<String, String> tagMap;
|
||||||
};
|
};
|
||||||
|
|
||||||
NVIMAGE_API Image * load(const char * fileName);
|
NVIMAGE_API Image * load(const char * fileName);
|
||||||
NVIMAGE_API Image * load(const char * fileName, Stream & s);
|
NVIMAGE_API Image * load(const char * fileName, Stream & s);
|
||||||
|
|
||||||
NVIMAGE_API FloatImage * loadFloat(const char * fileName);
|
NVIMAGE_API FloatImage * loadFloat(const char * fileName);
|
||||||
NVIMAGE_API FloatImage * loadFloat(const char * fileName, Stream & s);
|
NVIMAGE_API FloatImage * loadFloat(const char * fileName, Stream & s);
|
||||||
|
|
||||||
NVIMAGE_API bool save(const char * fileName, const Image * img, const ImageMetaData * tags=NULL);
|
|
||||||
NVIMAGE_API bool save(const char * fileName, Stream & s, const Image * img, const ImageMetaData * tags=NULL);
|
|
||||||
|
|
||||||
NVIMAGE_API bool saveFloat(const char * fileName, const FloatImage * fimage, uint baseComponent, uint componentCount);
|
NVIMAGE_API bool save(const char * fileName, const Image * img, const ImageMetaData * tags=NULL);
|
||||||
NVIMAGE_API bool saveFloat(const char * fileName, Stream & s, const FloatImage * fimage, uint baseComponent, uint componentCount);
|
NVIMAGE_API bool save(const char * fileName, Stream & s, const Image * img, const ImageMetaData * tags=NULL);
|
||||||
|
|
||||||
|
NVIMAGE_API bool saveFloat(const char * fileName, const FloatImage * fimage, uint baseComponent, uint componentCount);
|
||||||
|
NVIMAGE_API bool saveFloat(const char * fileName, Stream & s, const FloatImage * fimage, uint baseComponent, uint componentCount);
|
||||||
|
|
||||||
|
} // ImageIO namespace
|
||||||
|
|
||||||
} // ImageIO namespace
|
|
||||||
|
|
||||||
} // nv namespace
|
} // nv namespace
|
||||||
|
|
||||||
|
|
||||||
|
@ -65,9 +65,9 @@ static FloatImage * createNormalMap(const Image * img, FloatImage::WrapMode wm,
|
|||||||
|
|
||||||
Vector3 n = normalize(Vector3(du, dv, heightScale));
|
Vector3 n = normalize(Vector3(du, dv, heightScale));
|
||||||
|
|
||||||
fimage->setPixel(0.5f * n.x() + 0.5f, x, y, 0);
|
fimage->pixel(x, y, 0) = 0.5f * n.x + 0.5f;
|
||||||
fimage->setPixel(0.5f * n.y() + 0.5f, x, y, 1);
|
fimage->pixel(x, y, 1) = 0.5f * n.y + 0.5f;
|
||||||
fimage->setPixel(0.5f * n.z() + 0.5f, x, y, 2);
|
fimage->pixel(x, y, 2) = 0.5f * n.z + 0.5f;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -100,9 +100,9 @@ static FloatImage * createNormalMap(const FloatImage * img, FloatImage::WrapMode
|
|||||||
|
|
||||||
Vector3 n = normalize(Vector3(du, dv, heightScale));
|
Vector3 n = normalize(Vector3(du, dv, heightScale));
|
||||||
|
|
||||||
img_out->setPixel(n.x(), x, y, 0);
|
img_out->pixel(x, y, 0) = n.x;
|
||||||
img_out->setPixel(n.y(), x, y, 1);
|
img_out->pixel(x, y, 1) = n.y;
|
||||||
img_out->setPixel(n.z(), x, y, 2);
|
img_out->pixel(x, y, 2) = n.z;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -111,7 +111,7 @@ static FloatImage * createNormalMap(const FloatImage * img, FloatImage::WrapMode
|
|||||||
{
|
{
|
||||||
for (uint x = 0; x < w; x++)
|
for (uint x = 0; x < w; x++)
|
||||||
{
|
{
|
||||||
img_out->setPixel(img->pixel(x, y, 3), x, y, 3);
|
img_out->pixel(x, y, 3) = img->pixel(x, y, 3);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -12,13 +12,15 @@ http://www.efg2.com/Lab/Library/ImageProcessing/DHALF.TXT
|
|||||||
@@ This code needs to be reviewed, I'm not sure it's correct.
|
@@ This code needs to be reviewed, I'm not sure it's correct.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include <nvimage/Quantize.h>
|
#include "Quantize.h"
|
||||||
#include <nvimage/Image.h>
|
#include "Image.h"
|
||||||
#include <nvimage/PixelFormat.h>
|
#include "PixelFormat.h"
|
||||||
|
|
||||||
#include <nvmath/Color.h>
|
#include "nvmath/Color.h"
|
||||||
|
|
||||||
#include <nvcore/Containers.h> // swap
|
#include "nvcore/Utils.h" // swap
|
||||||
|
|
||||||
|
#include <string.h> // memset
|
||||||
|
|
||||||
|
|
||||||
using namespace nv;
|
using namespace nv;
|
||||||
@ -174,10 +176,10 @@ void nv::Quantize::FloydSteinberg(Image * image, uint rsize, uint gsize, uint bs
|
|||||||
Color32 pixel = image->pixel(x, y);
|
Color32 pixel = image->pixel(x, y);
|
||||||
|
|
||||||
// Add error.
|
// Add error.
|
||||||
pixel.r = clamp(int(pixel.r) + int(row0[1+x].x()), 0, 255);
|
pixel.r = clamp(int(pixel.r) + int(row0[1+x].x), 0, 255);
|
||||||
pixel.g = clamp(int(pixel.g) + int(row0[1+x].y()), 0, 255);
|
pixel.g = clamp(int(pixel.g) + int(row0[1+x].y), 0, 255);
|
||||||
pixel.b = clamp(int(pixel.b) + int(row0[1+x].z()), 0, 255);
|
pixel.b = clamp(int(pixel.b) + int(row0[1+x].z), 0, 255);
|
||||||
pixel.a = clamp(int(pixel.a) + int(row0[1+x].w()), 0, 255);
|
pixel.a = clamp(int(pixel.a) + int(row0[1+x].w), 0, 255);
|
||||||
|
|
||||||
int r = pixel.r;
|
int r = pixel.r;
|
||||||
int g = pixel.g;
|
int g = pixel.g;
|
||||||
|
Reference in New Issue
Block a user