Merge private branch.

This commit is contained in:
castano
2010-05-27 23:18:39 +00:00
parent e7f2d1e2bc
commit 51a4fe7e2d
15 changed files with 3558 additions and 3549 deletions

View File

@ -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;

View File

@ -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();
} }

View File

@ -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

View File

@ -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

View File

@ -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");
} }
} }

View File

@ -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

View File

@ -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

View File

@ -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;
} }
} }

View File

@ -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

View File

@ -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)

View File

@ -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

View File

@ -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);
} }
} }

View File

@ -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;