Merge private branch.
This commit is contained in:
parent
e7f2d1e2bc
commit
51a4fe7e2d
@ -23,10 +23,10 @@
|
||||
|
||||
#include "BlockDXT.h"
|
||||
|
||||
#include <nvimage/ColorBlock.h>
|
||||
#include "ColorBlock.h"
|
||||
|
||||
#include <nvcore/Stream.h>
|
||||
#include <nvcore/Containers.h> // swap
|
||||
#include "nvcore/Stream.h"
|
||||
#include "nvcore/Utils.h" // swap
|
||||
|
||||
|
||||
using namespace nv;
|
||||
|
@ -1,26 +1,28 @@
|
||||
// This code is in the public domain -- castanyo@yahoo.es
|
||||
|
||||
#include <nvcore/Containers.h> // swap
|
||||
#include <nvmath/Box.h>
|
||||
#include <nvimage/ColorBlock.h>
|
||||
#include <nvimage/Image.h>
|
||||
#include "ColorBlock.h"
|
||||
#include "Image.h"
|
||||
|
||||
#include "nvmath/Box.h"
|
||||
#include "nvcore/Utils.h" // swap
|
||||
|
||||
|
||||
using namespace nv;
|
||||
|
||||
namespace {
|
||||
|
||||
// Get approximate luminance.
|
||||
inline static uint colorLuminance(Color32 c)
|
||||
{
|
||||
return c.r + c.g + c.b;
|
||||
}
|
||||
|
||||
// Get the euclidean distance between the given colors.
|
||||
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);
|
||||
}
|
||||
|
||||
|
||||
// Get approximate luminance.
|
||||
inline static uint colorLuminance(Color32 c)
|
||||
{
|
||||
return c.r + c.g + c.b;
|
||||
}
|
||||
|
||||
// Get the euclidean distance between the given colors.
|
||||
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);
|
||||
}
|
||||
|
||||
} // namespace`
|
||||
|
||||
|
||||
@ -32,450 +34,450 @@ ColorBlock::ColorBlock()
|
||||
/// Init the color block from an array of colors.
|
||||
ColorBlock::ColorBlock(const uint * linearImage)
|
||||
{
|
||||
for(uint i = 0; i < 16; i++) {
|
||||
color(i) = Color32(linearImage[i]);
|
||||
}
|
||||
for(uint i = 0; i < 16; i++) {
|
||||
color(i) = Color32(linearImage[i]);
|
||||
}
|
||||
}
|
||||
|
||||
/// Init the color block with the contents of the given block.
|
||||
ColorBlock::ColorBlock(const ColorBlock & block)
|
||||
{
|
||||
for(uint i = 0; i < 16; i++) {
|
||||
color(i) = block.color(i);
|
||||
}
|
||||
for(uint i = 0; i < 16; i++) {
|
||||
color(i) = block.color(i);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/// Initialize this color block.
|
||||
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)
|
||||
{
|
||||
nvDebugCheck(img != NULL);
|
||||
|
||||
const uint bw = min(img->width() - x, 4U);
|
||||
const uint bh = min(img->height() - y, 4U);
|
||||
nvDebugCheck(bw != 0 && bh != 0);
|
||||
nvDebugCheck(img != NULL);
|
||||
|
||||
static const int remainder[] = {
|
||||
0, 0, 0, 0,
|
||||
0, 1, 0, 1,
|
||||
0, 1, 2, 0,
|
||||
0, 1, 2, 3,
|
||||
};
|
||||
const uint bw = min(img->width() - x, 4U);
|
||||
const uint bh = min(img->height() - y, 4U);
|
||||
nvDebugCheck(bw != 0 && bh != 0);
|
||||
|
||||
// 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. :(
|
||||
static const int remainder[] = {
|
||||
0, 0, 0, 0,
|
||||
0, 1, 0, 1,
|
||||
0, 1, 2, 0,
|
||||
0, 1, 2, 3,
|
||||
};
|
||||
|
||||
for(uint i = 0; i < 4; i++) {
|
||||
//const int by = i % bh;
|
||||
const int by = remainder[(bh - 1) * 4 + i];
|
||||
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);
|
||||
}
|
||||
}
|
||||
// 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. :(
|
||||
|
||||
for(uint i = 0; i < 4; i++) {
|
||||
//const int by = i % bh;
|
||||
const int by = remainder[(bh - 1) * 4 + i];
|
||||
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)
|
||||
{
|
||||
nvDebugCheck(data != NULL);
|
||||
nvDebugCheck(data != NULL);
|
||||
|
||||
const uint bw = min(w - x, 4U);
|
||||
const uint bh = min(h - y, 4U);
|
||||
nvDebugCheck(bw != 0 && bh != 0);
|
||||
const uint bw = min(w - x, 4U);
|
||||
const uint bh = min(h - y, 4U);
|
||||
nvDebugCheck(bw != 0 && bh != 0);
|
||||
|
||||
// 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. :(
|
||||
// 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. :(
|
||||
|
||||
for (uint i = 0; i < 4; i++)
|
||||
{
|
||||
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;
|
||||
for (uint i = 0; i < 4; i++)
|
||||
{
|
||||
const int by = i % bh;
|
||||
|
||||
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)
|
||||
{
|
||||
nvDebugCheck(data != NULL);
|
||||
nvDebugCheck(data != NULL);
|
||||
|
||||
const uint bw = min(w - x, 4U);
|
||||
const uint bh = min(h - y, 4U);
|
||||
nvDebugCheck(bw != 0 && bh != 0);
|
||||
const uint bw = min(w - x, 4U);
|
||||
const uint bh = min(h - y, 4U);
|
||||
nvDebugCheck(bw != 0 && bh != 0);
|
||||
|
||||
// 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. :(
|
||||
// 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. :(
|
||||
|
||||
for (uint i = 0; i < 4; i++)
|
||||
{
|
||||
const uint by = i % bh;
|
||||
|
||||
for (uint e = 0; e < 4; e++)
|
||||
{
|
||||
const uint bx = e % bw;
|
||||
const uint idx = ((y + by) * w + x + bx) * 4;
|
||||
|
||||
Color32 & c = color(e, i);
|
||||
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.b = uint8(255 * clamp(data[idx + 2], 0.0f, 1.0f));
|
||||
c.a = uint8(255 * clamp(data[idx + 3], 0.0f, 1.0f));
|
||||
}
|
||||
}
|
||||
for (uint i = 0; i < 4; i++)
|
||||
{
|
||||
const uint by = i % bh;
|
||||
|
||||
for (uint e = 0; e < 4; e++)
|
||||
{
|
||||
const uint bx = e % bw;
|
||||
const uint idx = ((y + by) * w + x + bx) * 4;
|
||||
|
||||
Color32 & c = color(e, i);
|
||||
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.b = uint8(255 * clamp(data[idx + 2], 0.0f, 1.0f));
|
||||
c.a = uint8(255 * clamp(data[idx + 3], 0.0f, 1.0f));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static inline uint8 component(Color32 c, uint i)
|
||||
{
|
||||
if (i == 0) return c.r;
|
||||
if (i == 1) return c.g;
|
||||
if (i == 2) return c.b;
|
||||
if (i == 3) return c.a;
|
||||
if (i == 4) return 0xFF;
|
||||
return 0;
|
||||
if (i == 0) return c.r;
|
||||
if (i == 1) return c.g;
|
||||
if (i == 2) return c.b;
|
||||
if (i == 3) return c.a;
|
||||
if (i == 4) return 0xFF;
|
||||
return 0;
|
||||
}
|
||||
|
||||
void ColorBlock::swizzle(uint x, uint y, uint z, uint w)
|
||||
{
|
||||
for (int i = 0; i < 16; i++)
|
||||
{
|
||||
Color32 c = m_color[i];
|
||||
m_color[i].r = component(c, x);
|
||||
m_color[i].g = component(c, y);
|
||||
m_color[i].b = component(c, z);
|
||||
m_color[i].a = component(c, w);
|
||||
}
|
||||
for (int i = 0; i < 16; i++)
|
||||
{
|
||||
Color32 c = m_color[i];
|
||||
m_color[i].r = component(c, x);
|
||||
m_color[i].g = component(c, y);
|
||||
m_color[i].b = component(c, z);
|
||||
m_color[i].a = component(c, w);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/// Returns true if the block has a single color.
|
||||
bool ColorBlock::isSingleColor() const
|
||||
{
|
||||
Color32 mask(0xFF, 0xFF, 0xFF, 0x00);
|
||||
uint u = m_color[0].u & mask.u;
|
||||
|
||||
for (int i = 1; i < 16; i++)
|
||||
{
|
||||
if (u != (m_color[i].u & mask.u))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
Color32 mask(0xFF, 0xFF, 0xFF, 0x00);
|
||||
uint u = m_color[0].u & mask.u;
|
||||
|
||||
for (int i = 1; i < 16; i++)
|
||||
{
|
||||
if (u != (m_color[i].u & mask.u))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/*
|
||||
/// Returns true if the block has a single color, ignoring transparent pixels.
|
||||
bool ColorBlock::isSingleColorNoAlpha() const
|
||||
{
|
||||
Color32 c;
|
||||
int i;
|
||||
for(i = 0; i < 16; i++)
|
||||
{
|
||||
if (m_color[i].a != 0) {
|
||||
c = m_color[i];
|
||||
break;
|
||||
}
|
||||
}
|
||||
Color32 c;
|
||||
int i;
|
||||
for(i = 0; i < 16; i++)
|
||||
{
|
||||
if (m_color[i].a != 0) {
|
||||
c = m_color[i];
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
Color32 mask(0xFF, 0xFF, 0xFF, 0x00);
|
||||
uint u = c.u & mask.u;
|
||||
Color32 mask(0xFF, 0xFF, 0xFF, 0x00);
|
||||
uint u = c.u & mask.u;
|
||||
|
||||
for(; i < 16; i++)
|
||||
{
|
||||
if (u != (m_color[i].u & mask.u))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
for(; i < 16; i++)
|
||||
{
|
||||
if (u != (m_color[i].u & mask.u))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
*/
|
||||
|
||||
/// Count number of unique colors in this color block.
|
||||
uint ColorBlock::countUniqueColors() const
|
||||
{
|
||||
uint count = 0;
|
||||
uint count = 0;
|
||||
|
||||
// @@ This does not have to be o(n^2)
|
||||
for(int i = 0; i < 16; i++)
|
||||
{
|
||||
bool unique = true;
|
||||
for(int j = 0; j < i; j++) {
|
||||
if( m_color[i] != m_color[j] ) {
|
||||
unique = false;
|
||||
}
|
||||
}
|
||||
|
||||
if( unique ) {
|
||||
count++;
|
||||
}
|
||||
}
|
||||
|
||||
return count;
|
||||
// @@ This does not have to be o(n^2)
|
||||
for(int i = 0; i < 16; i++)
|
||||
{
|
||||
bool unique = true;
|
||||
for(int j = 0; j < i; j++) {
|
||||
if( m_color[i] != m_color[j] ) {
|
||||
unique = false;
|
||||
}
|
||||
}
|
||||
|
||||
if( unique ) {
|
||||
count++;
|
||||
}
|
||||
}
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
/// Get average color of the block.
|
||||
Color32 ColorBlock::averageColor() const
|
||||
{
|
||||
uint r, g, b, a;
|
||||
r = g = b = a = 0;
|
||||
uint r, g, b, a;
|
||||
r = g = b = a = 0;
|
||||
|
||||
for(uint i = 0; i < 16; i++) {
|
||||
r += m_color[i].r;
|
||||
g += m_color[i].g;
|
||||
b += m_color[i].b;
|
||||
a += m_color[i].a;
|
||||
}
|
||||
|
||||
return Color32(uint8(r / 16), uint8(g / 16), uint8(b / 16), uint8(a / 16));
|
||||
for(uint i = 0; i < 16; i++) {
|
||||
r += m_color[i].r;
|
||||
g += m_color[i].g;
|
||||
b += m_color[i].b;
|
||||
a += m_color[i].a;
|
||||
}
|
||||
|
||||
return Color32(uint8(r / 16), uint8(g / 16), uint8(b / 16), uint8(a / 16));
|
||||
}
|
||||
|
||||
/// Return true if the block is not fully opaque.
|
||||
bool ColorBlock::hasAlpha() const
|
||||
{
|
||||
for (uint i = 0; i < 16; i++)
|
||||
{
|
||||
if (m_color[i].a != 255) return true;
|
||||
}
|
||||
return false;
|
||||
for (uint i = 0; i < 16; i++)
|
||||
{
|
||||
if (m_color[i].a != 255) return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
/// Get diameter color range.
|
||||
void ColorBlock::diameterRange(Color32 * start, Color32 * end) const
|
||||
{
|
||||
nvDebugCheck(start != NULL);
|
||||
nvDebugCheck(end != NULL);
|
||||
|
||||
Color32 c0, c1;
|
||||
uint best_dist = 0;
|
||||
|
||||
for(int i = 0; i < 16; i++) {
|
||||
for (int j = i+1; j < 16; j++) {
|
||||
uint dist = colorDistance(m_color[i], m_color[j]);
|
||||
if( dist > best_dist ) {
|
||||
best_dist = dist;
|
||||
c0 = m_color[i];
|
||||
c1 = m_color[j];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
*start = c0;
|
||||
*end = c1;
|
||||
nvDebugCheck(start != NULL);
|
||||
nvDebugCheck(end != NULL);
|
||||
|
||||
Color32 c0, c1;
|
||||
uint best_dist = 0;
|
||||
|
||||
for(int i = 0; i < 16; i++) {
|
||||
for (int j = i+1; j < 16; j++) {
|
||||
uint dist = colorDistance(m_color[i], m_color[j]);
|
||||
if( dist > best_dist ) {
|
||||
best_dist = dist;
|
||||
c0 = m_color[i];
|
||||
c1 = m_color[j];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
*start = c0;
|
||||
*end = c1;
|
||||
}
|
||||
|
||||
/// Get luminance color range.
|
||||
void ColorBlock::luminanceRange(Color32 * start, Color32 * end) const
|
||||
{
|
||||
nvDebugCheck(start != 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];
|
||||
}
|
||||
}
|
||||
nvDebugCheck(start != NULL);
|
||||
nvDebugCheck(end != NULL);
|
||||
|
||||
*start = minColor;
|
||||
*end = maxColor;
|
||||
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;
|
||||
*end = maxColor;
|
||||
}
|
||||
|
||||
/// Get color range based on the bounding box.
|
||||
void ColorBlock::boundsRange(Color32 * start, Color32 * end) const
|
||||
{
|
||||
nvDebugCheck(start != NULL);
|
||||
nvDebugCheck(end != NULL);
|
||||
nvDebugCheck(start != NULL);
|
||||
nvDebugCheck(end != NULL);
|
||||
|
||||
Color32 minColor(255, 255, 255);
|
||||
Color32 maxColor(0, 0, 0);
|
||||
Color32 minColor(255, 255, 255);
|
||||
Color32 maxColor(0, 0, 0);
|
||||
|
||||
for(uint i = 0; i < 16; i++)
|
||||
{
|
||||
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].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].g > maxColor.g) { maxColor.g = m_color[i].g; }
|
||||
if (m_color[i].b > maxColor.b) { maxColor.b = m_color[i].b; }
|
||||
}
|
||||
for(uint i = 0; i < 16; i++)
|
||||
{
|
||||
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].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].g > maxColor.g) { maxColor.g = m_color[i].g; }
|
||||
if (m_color[i].b > maxColor.b) { maxColor.b = m_color[i].b; }
|
||||
}
|
||||
|
||||
// Offset range by 1/16 of the extents
|
||||
Color32 inset;
|
||||
inset.r = (maxColor.r - minColor.r) >> 4;
|
||||
inset.g = (maxColor.g - minColor.g) >> 4;
|
||||
inset.b = (maxColor.b - minColor.b) >> 4;
|
||||
// Offset range by 1/16 of the extents
|
||||
Color32 inset;
|
||||
inset.r = (maxColor.r - minColor.r) >> 4;
|
||||
inset.g = (maxColor.g - minColor.g) >> 4;
|
||||
inset.b = (maxColor.b - minColor.b) >> 4;
|
||||
|
||||
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.b = (minColor.b + inset.b <= 255) ? minColor.b + inset.b : 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.b = (minColor.b + inset.b <= 255) ? minColor.b + inset.b : 255;
|
||||
|
||||
maxColor.r = (maxColor.r >= inset.r) ? maxColor.r - inset.r : 0;
|
||||
maxColor.g = (maxColor.g >= inset.g) ? maxColor.g - inset.g : 0;
|
||||
maxColor.b = (maxColor.b >= inset.b) ? maxColor.b - inset.b : 0;
|
||||
maxColor.r = (maxColor.r >= inset.r) ? maxColor.r - inset.r : 0;
|
||||
maxColor.g = (maxColor.g >= inset.g) ? maxColor.g - inset.g : 0;
|
||||
maxColor.b = (maxColor.b >= inset.b) ? maxColor.b - inset.b : 0;
|
||||
|
||||
*start = minColor;
|
||||
*end = maxColor;
|
||||
*start = minColor;
|
||||
*end = maxColor;
|
||||
}
|
||||
|
||||
/// Get color range based on the bounding box.
|
||||
void ColorBlock::boundsRangeAlpha(Color32 * start, Color32 * end) const
|
||||
{
|
||||
nvDebugCheck(start != NULL);
|
||||
nvDebugCheck(end != NULL);
|
||||
nvDebugCheck(start != NULL);
|
||||
nvDebugCheck(end != NULL);
|
||||
|
||||
Color32 minColor(255, 255, 255, 255);
|
||||
Color32 maxColor(0, 0, 0, 0);
|
||||
Color32 minColor(255, 255, 255, 255);
|
||||
Color32 maxColor(0, 0, 0, 0);
|
||||
|
||||
for(uint i = 0; i < 16; i++)
|
||||
{
|
||||
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].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].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].b > maxColor.b) { maxColor.b = m_color[i].b; }
|
||||
if (m_color[i].a > maxColor.a) { maxColor.a = m_color[i].a; }
|
||||
}
|
||||
for(uint i = 0; i < 16; i++)
|
||||
{
|
||||
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].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].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].b > maxColor.b) { maxColor.b = m_color[i].b; }
|
||||
if (m_color[i].a > maxColor.a) { maxColor.a = m_color[i].a; }
|
||||
}
|
||||
|
||||
// Offset range by 1/16 of the extents
|
||||
Color32 inset;
|
||||
inset.r = (maxColor.r - minColor.r) >> 4;
|
||||
inset.g = (maxColor.g - minColor.g) >> 4;
|
||||
inset.b = (maxColor.b - minColor.b) >> 4;
|
||||
inset.a = (maxColor.a - minColor.a) >> 4;
|
||||
// Offset range by 1/16 of the extents
|
||||
Color32 inset;
|
||||
inset.r = (maxColor.r - minColor.r) >> 4;
|
||||
inset.g = (maxColor.g - minColor.g) >> 4;
|
||||
inset.b = (maxColor.b - minColor.b) >> 4;
|
||||
inset.a = (maxColor.a - minColor.a) >> 4;
|
||||
|
||||
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.b = (minColor.b + inset.b <= 255) ? minColor.b + inset.b : 255;
|
||||
minColor.a = (minColor.a + inset.a <= 255) ? minColor.a + inset.a : 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.b = (minColor.b + inset.b <= 255) ? minColor.b + inset.b : 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.g = (maxColor.g >= inset.g) ? maxColor.g - inset.g : 0;
|
||||
maxColor.b = (maxColor.b >= inset.b) ? maxColor.b - inset.b : 0;
|
||||
maxColor.a = (maxColor.a >= inset.a) ? maxColor.a - inset.a : 0;
|
||||
|
||||
*start = minColor;
|
||||
*end = maxColor;
|
||||
maxColor.r = (maxColor.r >= inset.r) ? maxColor.r - inset.r : 0;
|
||||
maxColor.g = (maxColor.g >= inset.g) ? maxColor.g - inset.g : 0;
|
||||
maxColor.b = (maxColor.b >= inset.b) ? maxColor.b - inset.b : 0;
|
||||
maxColor.a = (maxColor.a >= inset.a) ? maxColor.a - inset.a : 0;
|
||||
|
||||
*start = minColor;
|
||||
*end = maxColor;
|
||||
}
|
||||
|
||||
|
||||
/// Sort colors by abosolute value in their 16 bit representation.
|
||||
void ColorBlock::sortColorsByAbsoluteValue()
|
||||
{
|
||||
// Dummy selection sort.
|
||||
for( uint a = 0; a < 16; a++ ) {
|
||||
uint max = a;
|
||||
Color16 cmax(m_color[a]);
|
||||
|
||||
for( uint b = a+1; b < 16; b++ ) {
|
||||
Color16 cb(m_color[b]);
|
||||
|
||||
if( cb.u > cmax.u ) {
|
||||
max = b;
|
||||
cmax = cb;
|
||||
}
|
||||
}
|
||||
swap( m_color[a], m_color[max] );
|
||||
}
|
||||
// Dummy selection sort.
|
||||
for( uint a = 0; a < 16; a++ ) {
|
||||
uint max = a;
|
||||
Color16 cmax(m_color[a]);
|
||||
|
||||
for( uint b = a+1; b < 16; b++ ) {
|
||||
Color16 cb(m_color[b]);
|
||||
|
||||
if( cb.u > cmax.u ) {
|
||||
max = b;
|
||||
cmax = cb;
|
||||
}
|
||||
}
|
||||
swap( m_color[a], m_color[max] );
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/// Find extreme colors in the given axis.
|
||||
void ColorBlock::computeRange(Vector3::Arg axis, Color32 * start, Color32 * end) const
|
||||
{
|
||||
nvDebugCheck(start != 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);
|
||||
nvDebugCheck(start != NULL);
|
||||
nvDebugCheck(end != NULL);
|
||||
|
||||
for(uint i = 1; i < 16; i++)
|
||||
{
|
||||
const Vector3 vec(m_color[i].r, m_color[i].g, m_color[i].b);
|
||||
|
||||
float val = dot(vec, axis);
|
||||
if( val < min ) {
|
||||
mini = i;
|
||||
min = val;
|
||||
}
|
||||
else if( val > max ) {
|
||||
maxi = i;
|
||||
max = val;
|
||||
}
|
||||
}
|
||||
|
||||
*start = m_color[mini];
|
||||
*end = m_color[maxi];
|
||||
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++)
|
||||
{
|
||||
const Vector3 vec(m_color[i].r, m_color[i].g, m_color[i].b);
|
||||
|
||||
float val = dot(vec, axis);
|
||||
if( val < min ) {
|
||||
mini = i;
|
||||
min = val;
|
||||
}
|
||||
else if( val > max ) {
|
||||
maxi = i;
|
||||
max = val;
|
||||
}
|
||||
}
|
||||
|
||||
*start = m_color[mini];
|
||||
*end = m_color[maxi];
|
||||
}
|
||||
|
||||
|
||||
/// Sort colors in the given axis.
|
||||
void ColorBlock::sortColors(const Vector3 & axis)
|
||||
{
|
||||
float luma_array[16];
|
||||
|
||||
for(uint i = 0; i < 16; i++) {
|
||||
const Vector3 vec(m_color[i].r, m_color[i].g, m_color[i].b);
|
||||
luma_array[i] = dot(vec, axis);
|
||||
}
|
||||
|
||||
// Dummy selection sort.
|
||||
for( uint a = 0; a < 16; a++ ) {
|
||||
uint min = a;
|
||||
for( uint b = a+1; b < 16; b++ ) {
|
||||
if( luma_array[b] < luma_array[min] ) {
|
||||
min = b;
|
||||
}
|
||||
}
|
||||
swap( luma_array[a], luma_array[min] );
|
||||
swap( m_color[a], m_color[min] );
|
||||
}
|
||||
float luma_array[16];
|
||||
|
||||
for(uint i = 0; i < 16; i++) {
|
||||
const Vector3 vec(m_color[i].r, m_color[i].g, m_color[i].b);
|
||||
luma_array[i] = dot(vec, axis);
|
||||
}
|
||||
|
||||
// Dummy selection sort.
|
||||
for( uint a = 0; a < 16; a++ ) {
|
||||
uint min = a;
|
||||
for( uint b = a+1; b < 16; b++ ) {
|
||||
if( luma_array[b] < luma_array[min] ) {
|
||||
min = b;
|
||||
}
|
||||
}
|
||||
swap( luma_array[a], luma_array[min] );
|
||||
swap( m_color[a], m_color[min] );
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/// Get the volume of the color block.
|
||||
float ColorBlock::volume() const
|
||||
{
|
||||
Box bounds;
|
||||
bounds.clearBounds();
|
||||
|
||||
for(int i = 0; i < 16; i++) {
|
||||
const Vector3 point(m_color[i].r, m_color[i].g, m_color[i].b);
|
||||
bounds.addPointToBounds(point);
|
||||
}
|
||||
|
||||
return bounds.volume();
|
||||
Box bounds;
|
||||
bounds.clearBounds();
|
||||
|
||||
for(int i = 0; i < 16; i++) {
|
||||
const Vector3 point(m_color[i].r, m_color[i].g, m_color[i].b);
|
||||
bounds.addPointToBounds(point);
|
||||
}
|
||||
|
||||
return bounds.volume();
|
||||
}
|
||||
|
||||
|
||||
|
@ -1,96 +1,97 @@
|
||||
// This code is in the public domain -- castanyo@yahoo.es
|
||||
|
||||
#pragma once
|
||||
#ifndef NV_IMAGE_COLORBLOCK_H
|
||||
#define NV_IMAGE_COLORBLOCK_H
|
||||
|
||||
#include <nvmath/Color.h>
|
||||
#include "nvmath/Color.h"
|
||||
|
||||
namespace nv
|
||||
{
|
||||
class Image;
|
||||
class Image;
|
||||
|
||||
/// Uncompressed 4x4 color block.
|
||||
struct ColorBlock
|
||||
{
|
||||
ColorBlock();
|
||||
ColorBlock(const uint * linearImage);
|
||||
ColorBlock(const ColorBlock & block);
|
||||
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;
|
||||
/// Uncompressed 4x4 color block.
|
||||
struct ColorBlock
|
||||
{
|
||||
ColorBlock();
|
||||
ColorBlock(const uint * linearImage);
|
||||
ColorBlock(const ColorBlock & block);
|
||||
ColorBlock(const Image * img, uint x, uint y);
|
||||
|
||||
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];
|
||||
|
||||
};
|
||||
|
||||
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;
|
||||
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
|
||||
|
||||
#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
|
||||
// OTHER DEALINGS IN THE SOFTWARE.
|
||||
|
||||
#pragma once
|
||||
#ifndef NV_IMAGE_DIRECTDRAWSURFACE_H
|
||||
#define NV_IMAGE_DIRECTDRAWSURFACE_H
|
||||
|
||||
@ -28,134 +29,134 @@
|
||||
|
||||
namespace nv
|
||||
{
|
||||
class Image;
|
||||
class Stream;
|
||||
struct ColorBlock;
|
||||
class Image;
|
||||
class Stream;
|
||||
struct ColorBlock;
|
||||
|
||||
struct NVIMAGE_CLASS DDSPixelFormat
|
||||
{
|
||||
uint size;
|
||||
uint flags;
|
||||
uint fourcc;
|
||||
uint bitcount;
|
||||
uint rmask;
|
||||
uint gmask;
|
||||
uint bmask;
|
||||
uint amask;
|
||||
};
|
||||
struct NVIMAGE_CLASS DDSPixelFormat
|
||||
{
|
||||
uint size;
|
||||
uint flags;
|
||||
uint fourcc;
|
||||
uint bitcount;
|
||||
uint rmask;
|
||||
uint gmask;
|
||||
uint bmask;
|
||||
uint amask;
|
||||
};
|
||||
|
||||
struct NVIMAGE_CLASS DDSCaps
|
||||
{
|
||||
uint caps1;
|
||||
uint caps2;
|
||||
uint caps3;
|
||||
uint caps4;
|
||||
};
|
||||
struct NVIMAGE_CLASS DDSCaps
|
||||
{
|
||||
uint caps1;
|
||||
uint caps2;
|
||||
uint caps3;
|
||||
uint caps4;
|
||||
};
|
||||
|
||||
/// DDS file header for DX10.
|
||||
struct NVIMAGE_CLASS DDSHeader10
|
||||
{
|
||||
uint dxgiFormat;
|
||||
uint resourceDimension;
|
||||
uint miscFlag;
|
||||
uint arraySize;
|
||||
uint reserved;
|
||||
};
|
||||
/// DDS file header for DX10.
|
||||
struct NVIMAGE_CLASS DDSHeader10
|
||||
{
|
||||
uint dxgiFormat;
|
||||
uint resourceDimension;
|
||||
uint miscFlag;
|
||||
uint arraySize;
|
||||
uint reserved;
|
||||
};
|
||||
|
||||
/// DDS file header.
|
||||
struct NVIMAGE_CLASS DDSHeader
|
||||
{
|
||||
uint fourcc;
|
||||
uint size;
|
||||
uint flags;
|
||||
uint height;
|
||||
uint width;
|
||||
uint pitch;
|
||||
uint depth;
|
||||
uint mipmapcount;
|
||||
uint reserved[11];
|
||||
DDSPixelFormat pf;
|
||||
DDSCaps caps;
|
||||
uint notused;
|
||||
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);
|
||||
/// DDS file header.
|
||||
struct NVIMAGE_CLASS DDSHeader
|
||||
{
|
||||
uint fourcc;
|
||||
uint size;
|
||||
uint flags;
|
||||
uint height;
|
||||
uint width;
|
||||
uint pitch;
|
||||
uint depth;
|
||||
uint mipmapcount;
|
||||
uint reserved[11];
|
||||
DDSPixelFormat pf;
|
||||
DDSCaps caps;
|
||||
uint notused;
|
||||
DDSHeader10 header10;
|
||||
|
||||
|
||||
/// DirectDraw Surface. (DDS)
|
||||
class NVIMAGE_CLASS DirectDrawSurface
|
||||
{
|
||||
public:
|
||||
DirectDrawSurface(const char * file);
|
||||
DirectDrawSurface(Stream * stream);
|
||||
~DirectDrawSurface();
|
||||
|
||||
bool isValid() const;
|
||||
bool isSupported() const;
|
||||
// Helper methods.
|
||||
DDSHeader();
|
||||
|
||||
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 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 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;
|
||||
void swapBytes();
|
||||
|
||||
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;
|
||||
};
|
||||
bool hasDX10Header() const;
|
||||
};
|
||||
|
||||
NVIMAGE_API Stream & operator<< (Stream & s, DDSHeader & header);
|
||||
|
||||
|
||||
/// DirectDraw Surface. (DDS)
|
||||
class NVIMAGE_CLASS DirectDrawSurface
|
||||
{
|
||||
public:
|
||||
DirectDrawSurface(const char * file);
|
||||
DirectDrawSurface(Stream * stream);
|
||||
~DirectDrawSurface();
|
||||
|
||||
bool isValid() const;
|
||||
bool isSupported() const;
|
||||
|
||||
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
|
||||
|
||||
|
@ -35,62 +35,64 @@
|
||||
|
||||
#include "Filter.h"
|
||||
|
||||
#include <nvmath/Vector.h> // Vector4
|
||||
#include <nvcore/Containers.h> // swap
|
||||
#include "nvmath/Vector.h" // Vector4
|
||||
#include "nvcore/Utils.h" // swap
|
||||
|
||||
#include <string.h> // memset
|
||||
|
||||
using namespace nv;
|
||||
|
||||
namespace
|
||||
{
|
||||
// Sinc function.
|
||||
inline static float sincf(const float x)
|
||||
{
|
||||
if (fabs(x) < NV_EPSILON) {
|
||||
//return 1.0;
|
||||
return 1.0f + x*x*(-1.0f/6.0f + x*x*1.0f/120.0f);
|
||||
}
|
||||
else {
|
||||
return sin(x) / x;
|
||||
}
|
||||
}
|
||||
// Sinc function.
|
||||
inline static float sincf(const float x)
|
||||
{
|
||||
if (fabs(x) < NV_EPSILON) {
|
||||
//return 1.0;
|
||||
return 1.0f + x*x*(-1.0f/6.0f + x*x*1.0f/120.0f);
|
||||
}
|
||||
else {
|
||||
return sin(x) / x;
|
||||
}
|
||||
}
|
||||
|
||||
// Bessel function of the first kind from Jon Blow's article.
|
||||
// http://mathworld.wolfram.com/BesselFunctionoftheFirstKind.html
|
||||
// http://en.wikipedia.org/wiki/Bessel_function
|
||||
inline static float bessel0(float x)
|
||||
{
|
||||
const float EPSILON_RATIO = 1e-6f;
|
||||
float xh, sum, pow, ds;
|
||||
int k;
|
||||
// Bessel function of the first kind from Jon Blow's article.
|
||||
// http://mathworld.wolfram.com/BesselFunctionoftheFirstKind.html
|
||||
// http://en.wikipedia.org/wiki/Bessel_function
|
||||
inline static float bessel0(float x)
|
||||
{
|
||||
const float EPSILON_RATIO = 1e-6f;
|
||||
float xh, sum, pow, ds;
|
||||
int k;
|
||||
|
||||
xh = 0.5f * x;
|
||||
sum = 1.0f;
|
||||
pow = 1.0f;
|
||||
k = 0;
|
||||
ds = 1.0;
|
||||
while (ds > sum * EPSILON_RATIO) {
|
||||
++k;
|
||||
pow = pow * (xh / k);
|
||||
ds = pow * pow;
|
||||
sum = sum + ds;
|
||||
}
|
||||
xh = 0.5f * x;
|
||||
sum = 1.0f;
|
||||
pow = 1.0f;
|
||||
k = 0;
|
||||
ds = 1.0;
|
||||
while (ds > sum * EPSILON_RATIO) {
|
||||
++k;
|
||||
pow = pow * (xh / k);
|
||||
ds = pow * pow;
|
||||
sum = sum + ds;
|
||||
}
|
||||
|
||||
return sum;
|
||||
}
|
||||
return sum;
|
||||
}
|
||||
|
||||
/*// Alternative bessel function from Paul Heckbert.
|
||||
static float _bessel0(float x)
|
||||
{
|
||||
const float EPSILON_RATIO = 1E-6;
|
||||
float sum = 1.0f;
|
||||
float y = x * x / 4.0f;
|
||||
float t = y;
|
||||
for(int i = 2; t > EPSILON_RATIO; i++) {
|
||||
sum += t;
|
||||
t *= y / float(i * i);
|
||||
}
|
||||
return sum;
|
||||
}*/
|
||||
/*// Alternative bessel function from Paul Heckbert.
|
||||
static float _bessel0(float x)
|
||||
{
|
||||
const float EPSILON_RATIO = 1E-6;
|
||||
float sum = 1.0f;
|
||||
float y = x * x / 4.0f;
|
||||
float t = y;
|
||||
for(int i = 2; t > EPSILON_RATIO; i++) {
|
||||
sum += t;
|
||||
t *= y / float(i * i);
|
||||
}
|
||||
return sum;
|
||||
}*/
|
||||
|
||||
} // namespace
|
||||
|
||||
@ -105,42 +107,42 @@ Filter::Filter(float width) : m_width(width)
|
||||
|
||||
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 sum = 0;
|
||||
float isamples = 1.0f / float(samples);
|
||||
float sum = 0;
|
||||
float isamples = 1.0f / float(samples);
|
||||
|
||||
for(int s = 0; s < samples; s++)
|
||||
{
|
||||
float p = (x + (float(s) + 0.5f) * isamples) * scale;
|
||||
float value = evaluate(p);
|
||||
sum += value;
|
||||
}
|
||||
|
||||
return sum * isamples;
|
||||
for(int s = 0; s < samples; s++)
|
||||
{
|
||||
float p = (x + (float(s) + 0.5f) * isamples) * scale;
|
||||
float value = evaluate(p);
|
||||
sum += value;
|
||||
}
|
||||
|
||||
return sum * isamples;
|
||||
}
|
||||
|
||||
float Filter::sampleTriangle(float x, float scale, int samples) const
|
||||
{
|
||||
float sum = 0;
|
||||
float isamples = 1.0f / float(samples);
|
||||
float sum = 0;
|
||||
float isamples = 1.0f / float(samples);
|
||||
|
||||
for(int s = 0; s < samples; s++)
|
||||
{
|
||||
float offset = (2 * float(s) + 1.0f) * isamples;
|
||||
float p = (x + offset - 0.5f) * scale;
|
||||
float value = evaluate(p);
|
||||
|
||||
float weight = offset;
|
||||
if (weight > 1.0f) weight = 2.0f - weight;
|
||||
|
||||
sum += value * weight;
|
||||
}
|
||||
|
||||
return 2 * sum * isamples;
|
||||
for(int s = 0; s < samples; s++)
|
||||
{
|
||||
float offset = (2 * float(s) + 1.0f) * isamples;
|
||||
float p = (x + offset - 0.5f) * scale;
|
||||
float value = evaluate(p);
|
||||
|
||||
float weight = offset;
|
||||
if (weight > 1.0f) weight = 2.0f - weight;
|
||||
|
||||
sum += value * weight;
|
||||
}
|
||||
|
||||
return 2 * sum * isamples;
|
||||
}
|
||||
|
||||
|
||||
@ -152,8 +154,8 @@ BoxFilter::BoxFilter(float width) : Filter(width) {}
|
||||
|
||||
float BoxFilter::evaluate(float x) const
|
||||
{
|
||||
if (fabs(x) <= m_width) return 1.0f;
|
||||
else return 0.0f;
|
||||
if (fabs(x) <= m_width) return 1.0f;
|
||||
else return 0.0f;
|
||||
}
|
||||
|
||||
|
||||
@ -162,7 +164,7 @@ TriangleFilter::TriangleFilter(float width) : Filter(width) {}
|
||||
|
||||
float TriangleFilter::evaluate(float x) const
|
||||
{
|
||||
x = fabs(x);
|
||||
x = fabs(x);
|
||||
if( x < m_width ) return m_width - x;
|
||||
return 0.0f;
|
||||
}
|
||||
@ -172,11 +174,11 @@ QuadraticFilter::QuadraticFilter() : Filter(1.5f) {}
|
||||
|
||||
float QuadraticFilter::evaluate(float x) const
|
||||
{
|
||||
x = fabs(x);
|
||||
x = fabs(x);
|
||||
if( x < 0.5f ) return 0.75f - x * x;
|
||||
if( x < 1.5f ) {
|
||||
float t = x - 1.5f;
|
||||
return 0.5f * t * t;
|
||||
float t = x - 1.5f;
|
||||
return 0.5f * t * t;
|
||||
}
|
||||
return 0.0f;
|
||||
}
|
||||
@ -186,10 +188,10 @@ CubicFilter::CubicFilter() : Filter(1.0f) {}
|
||||
|
||||
float CubicFilter::evaluate(float x) const
|
||||
{
|
||||
// f(t) = 2|t|^3 - 3|t|^2 + 1, -1 <= t <= 1
|
||||
x = fabs(x);
|
||||
if( x < 1.0f ) return((2.0f * x - 3.0f) * x * x + 1.0f);
|
||||
return 0.0f;
|
||||
// f(t) = 2|t|^3 - 3|t|^2 + 1, -1 <= t <= 1
|
||||
x = fabs(x);
|
||||
if( x < 1.0f ) return((2.0f * x - 3.0f) * x * x + 1.0f);
|
||||
return 0.0f;
|
||||
}
|
||||
|
||||
|
||||
@ -197,11 +199,11 @@ BSplineFilter::BSplineFilter() : Filter(2.0f) {}
|
||||
|
||||
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 < 2.0f ) {
|
||||
float t = 2.0f - x;
|
||||
return t * t * t / 6.0f;
|
||||
float t = 2.0f - x;
|
||||
return t * t * t / 6.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
|
||||
{
|
||||
x = fabs(x);
|
||||
if( x < 1.0f ) return p0 + x * x * (p2 + x * p3);
|
||||
if( x < 2.0f ) return q0 + x * (q1 + x * (q2 + x * q3));
|
||||
return 0.0f;
|
||||
x = fabs(x);
|
||||
if( x < 1.0f ) return p0 + x * x * (p2 + x * p3);
|
||||
if( x < 2.0f ) return q0 + x * (q1 + x * (q2 + x * q3));
|
||||
return 0.0f;
|
||||
}
|
||||
|
||||
void MitchellFilter::setParameters(float b, float c)
|
||||
{
|
||||
p0 = (6.0f - 2.0f * b) / 6.0f;
|
||||
p2 = (-18.0f + 12.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;
|
||||
q1 = (-12.0f * b - 48.0f * c) / 6.0f;
|
||||
q2 = (6.0f * b + 30.0f * c) / 6.0f;
|
||||
q3 = (-b - 6.0f * c) / 6.0f;
|
||||
p0 = (6.0f - 2.0f * b) / 6.0f;
|
||||
p2 = (-18.0f + 12.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;
|
||||
q1 = (-12.0f * b - 48.0f * c) / 6.0f;
|
||||
q2 = (6.0f * b + 30.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
|
||||
{
|
||||
x = fabs(x);
|
||||
if( x < 3.0f ) return sincf(PI * x) * sincf(PI * x / 3.0f);
|
||||
return 0.0f;
|
||||
x = fabs(x);
|
||||
if( x < 3.0f ) return sincf(PI * x) * sincf(PI * x / 3.0f);
|
||||
return 0.0f;
|
||||
}
|
||||
|
||||
|
||||
@ -243,7 +245,7 @@ SincFilter::SincFilter(float w) : Filter(w) {}
|
||||
|
||||
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
|
||||
{
|
||||
const float sinc_value = sincf(PI * x * stretch);
|
||||
const float t = x / m_width;
|
||||
if ((1 - t * t) >= 0) return sinc_value * bessel0(alpha * sqrtf(1 - t * t)) / bessel0(alpha);
|
||||
else return 0;
|
||||
const float sinc_value = sincf(PI * x * stretch);
|
||||
const float t = x / m_width;
|
||||
if ((1 - t * t) >= 0) return sinc_value * bessel0(alpha * sqrtf(1 - t * t)) / bessel0(alpha);
|
||||
else return 0;
|
||||
}
|
||||
|
||||
void KaiserFilter::setParameters(float alpha, float stretch)
|
||||
{
|
||||
this->alpha = alpha;
|
||||
this->stretch = stretch;
|
||||
this->alpha = alpha;
|
||||
this->stretch = stretch;
|
||||
}
|
||||
|
||||
|
||||
@ -268,44 +270,44 @@ void KaiserFilter::setParameters(float alpha, float stretch)
|
||||
/// Ctor.
|
||||
Kernel1::Kernel1(const Filter & f, int iscale, int samples/*= 32*/)
|
||||
{
|
||||
nvDebugCheck(iscale > 1);
|
||||
nvDebugCheck(samples > 0);
|
||||
|
||||
const float scale = 1.0f / iscale;
|
||||
|
||||
m_width = f.width() * iscale;
|
||||
m_windowSize = (int)ceilf(2 * m_width);
|
||||
m_data = new float[m_windowSize];
|
||||
|
||||
const float offset = float(m_windowSize) / 2;
|
||||
|
||||
float total = 0.0f;
|
||||
for (int i = 0; i < m_windowSize; i++)
|
||||
{
|
||||
const float sample = f.sampleBox(i - offset, scale, samples);
|
||||
m_data[i] = sample;
|
||||
total += sample;
|
||||
}
|
||||
|
||||
const float inv = 1.0f / total;
|
||||
for (int i = 0; i < m_windowSize; i++)
|
||||
{
|
||||
m_data[i] *= inv;
|
||||
}
|
||||
nvDebugCheck(iscale > 1);
|
||||
nvDebugCheck(samples > 0);
|
||||
|
||||
const float scale = 1.0f / iscale;
|
||||
|
||||
m_width = f.width() * iscale;
|
||||
m_windowSize = (int)ceilf(2 * m_width);
|
||||
m_data = new float[m_windowSize];
|
||||
|
||||
const float offset = float(m_windowSize) / 2;
|
||||
|
||||
float total = 0.0f;
|
||||
for (int i = 0; i < m_windowSize; i++)
|
||||
{
|
||||
const float sample = f.sampleBox(i - offset, scale, samples);
|
||||
m_data[i] = sample;
|
||||
total += sample;
|
||||
}
|
||||
|
||||
const float inv = 1.0f / total;
|
||||
for (int i = 0; i < m_windowSize; i++)
|
||||
{
|
||||
m_data[i] *= inv;
|
||||
}
|
||||
}
|
||||
|
||||
/// Dtor.
|
||||
Kernel1::~Kernel1()
|
||||
{
|
||||
delete m_data;
|
||||
delete m_data;
|
||||
}
|
||||
|
||||
/// Print the kernel for debugging purposes.
|
||||
void Kernel1::debugPrint()
|
||||
{
|
||||
for (int i = 0; i < m_windowSize; i++) {
|
||||
nvDebug("%d: %f\n", i, m_data[i]);
|
||||
}
|
||||
for (int i = 0; i < m_windowSize; i++) {
|
||||
nvDebug("%d: %f\n", i, m_data[i]);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -313,102 +315,102 @@ void Kernel1::debugPrint()
|
||||
/// Ctor.
|
||||
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.
|
||||
Kernel2::Kernel2(const Kernel2 & k) : m_windowSize(k.m_windowSize)
|
||||
{
|
||||
m_data = new float[m_windowSize * m_windowSize];
|
||||
for (uint i = 0; i < m_windowSize * m_windowSize; i++) {
|
||||
m_data[i] = k.m_data[i];
|
||||
}
|
||||
m_data = new float[m_windowSize * m_windowSize];
|
||||
for (uint i = 0; i < m_windowSize * m_windowSize; i++) {
|
||||
m_data[i] = k.m_data[i];
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/// Dtor.
|
||||
Kernel2::~Kernel2()
|
||||
{
|
||||
delete m_data;
|
||||
delete m_data;
|
||||
}
|
||||
|
||||
/// Normalize the filter.
|
||||
void Kernel2::normalize()
|
||||
{
|
||||
float total = 0.0f;
|
||||
for(uint i = 0; i < m_windowSize*m_windowSize; i++) {
|
||||
total += fabs(m_data[i]);
|
||||
}
|
||||
|
||||
float inv = 1.0f / total;
|
||||
for(uint i = 0; i < m_windowSize*m_windowSize; i++) {
|
||||
m_data[i] *= inv;
|
||||
}
|
||||
float total = 0.0f;
|
||||
for(uint i = 0; i < m_windowSize*m_windowSize; i++) {
|
||||
total += fabs(m_data[i]);
|
||||
}
|
||||
|
||||
float inv = 1.0f / total;
|
||||
for(uint i = 0; i < m_windowSize*m_windowSize; i++) {
|
||||
m_data[i] *= inv;
|
||||
}
|
||||
}
|
||||
|
||||
/// Transpose the kernel.
|
||||
void Kernel2::transpose()
|
||||
{
|
||||
for(uint i = 0; i < m_windowSize; i++) {
|
||||
for(uint j = i+1; j < m_windowSize; j++) {
|
||||
swap(m_data[i*m_windowSize + j], m_data[j*m_windowSize + i]);
|
||||
}
|
||||
}
|
||||
for(uint i = 0; i < m_windowSize; i++) {
|
||||
for(uint j = i+1; j < m_windowSize; j++) {
|
||||
swap(m_data[i*m_windowSize + j], m_data[j*m_windowSize + i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Init laplacian filter, usually used for sharpening.
|
||||
void Kernel2::initLaplacian()
|
||||
{
|
||||
nvDebugCheck(m_windowSize == 3);
|
||||
// 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[6] = -1; m_data[7] = -1; m_data[8] = -1;
|
||||
|
||||
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[6] = +0; m_data[7] = -1; m_data[8] = +0;
|
||||
|
||||
// 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[6] = +1; m_data[7] = -2; m_data[8] = +1;
|
||||
nvDebugCheck(m_windowSize == 3);
|
||||
// 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[6] = -1; m_data[7] = -1; m_data[8] = -1;
|
||||
|
||||
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[6] = +0; m_data[7] = -1; m_data[8] = +0;
|
||||
|
||||
// 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[6] = +1; m_data[7] = -2; m_data[8] = +1;
|
||||
}
|
||||
|
||||
|
||||
/// Init simple edge detection filter.
|
||||
void Kernel2::initEdgeDetection()
|
||||
{
|
||||
nvCheck(m_windowSize == 3);
|
||||
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[6] = 0; m_data[7] = 0; m_data[8] = 0;
|
||||
nvCheck(m_windowSize == 3);
|
||||
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[6] = 0; m_data[7] = 0; m_data[8] = 0;
|
||||
}
|
||||
|
||||
/// Init sobel filter.
|
||||
void Kernel2::initSobel()
|
||||
{
|
||||
if (m_windowSize == 3)
|
||||
{
|
||||
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[6] = -1; m_data[7] = 0; m_data[8] = 1;
|
||||
}
|
||||
else if (m_windowSize == 5)
|
||||
{
|
||||
float elements[] = {
|
||||
if (m_windowSize == 3)
|
||||
{
|
||||
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[6] = -1; m_data[7] = 0; m_data[8] = 1;
|
||||
}
|
||||
else if (m_windowSize == 5)
|
||||
{
|
||||
float elements[] = {
|
||||
-1, -2, 0, 2, 1,
|
||||
-2, -3, 0, 3, 2,
|
||||
-3, -4, 0, 4, 3,
|
||||
-2, -3, 0, 3, 2,
|
||||
-1, -2, 0, 2, 1
|
||||
};
|
||||
};
|
||||
|
||||
for (int i = 0; i < 5*5; i++) {
|
||||
m_data[i] = elements[i];
|
||||
}
|
||||
}
|
||||
else if (m_windowSize == 7)
|
||||
{
|
||||
float elements[] = {
|
||||
for (int i = 0; i < 5*5; i++) {
|
||||
m_data[i] = elements[i];
|
||||
}
|
||||
}
|
||||
else if (m_windowSize == 7)
|
||||
{
|
||||
float elements[] = {
|
||||
-1, -2, -3, 0, 3, 2, 1,
|
||||
-2, -3, -4, 0, 4, 3, 2,
|
||||
-3, -4, -5, 0, 5, 4, 3,
|
||||
@ -416,15 +418,15 @@ void Kernel2::initSobel()
|
||||
-3, -4, -5, 0, 5, 4, 3,
|
||||
-2, -3, -4, 0, 4, 3, 2,
|
||||
-1, -2, -3, 0, 3, 2, 1
|
||||
};
|
||||
};
|
||||
|
||||
for (int i = 0; i < 7*7; i++) {
|
||||
m_data[i] = elements[i];
|
||||
}
|
||||
}
|
||||
else if (m_windowSize == 9)
|
||||
{
|
||||
float elements[] = {
|
||||
for (int i = 0; i < 7*7; i++) {
|
||||
m_data[i] = elements[i];
|
||||
}
|
||||
}
|
||||
else if (m_windowSize == 9)
|
||||
{
|
||||
float elements[] = {
|
||||
-1, -2, -3, -4, 0, 4, 3, 2, 1,
|
||||
-2, -3, -4, -5, 0, 5, 4, 3, 2,
|
||||
-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,
|
||||
-2, -3, -4, -5, 0, 5, 4, 3, 2,
|
||||
-1, -2, -3, -4, 0, 4, 3, 2, 1
|
||||
};
|
||||
|
||||
for (int i = 0; i < 9*9; i++) {
|
||||
m_data[i] = elements[i];
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
for (int i = 0; i < 9*9; i++) {
|
||||
m_data[i] = elements[i];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Init prewitt filter.
|
||||
void Kernel2::initPrewitt()
|
||||
{
|
||||
if (m_windowSize == 3)
|
||||
{
|
||||
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[6] = -1; m_data[7] = 0; m_data[8] = -1;
|
||||
}
|
||||
else if (m_windowSize == 5)
|
||||
{
|
||||
// @@ Is this correct?
|
||||
float elements[] = {
|
||||
if (m_windowSize == 3)
|
||||
{
|
||||
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[6] = -1; m_data[7] = 0; m_data[8] = -1;
|
||||
}
|
||||
else if (m_windowSize == 5)
|
||||
{
|
||||
// @@ Is this correct?
|
||||
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
|
||||
};
|
||||
};
|
||||
|
||||
for (int i = 0; i < 5*5; i++) {
|
||||
m_data[i] = elements[i];
|
||||
}
|
||||
}
|
||||
for (int i = 0; i < 5*5; i++) {
|
||||
m_data[i] = elements[i];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Init blended sobel filter.
|
||||
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,
|
||||
-2, -3, -4, -5, 0, 5, 4, 3, 2,
|
||||
-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,
|
||||
-2, -3, -4, -5, 0, 5, 4, 3, 2,
|
||||
-1, -2, -3, -4, 0, 4, 3, 2, 1
|
||||
};
|
||||
|
||||
for (int i = 0; i < 9*9; i++) {
|
||||
m_data[i] = elements[i] * scale.w();
|
||||
}
|
||||
}
|
||||
{
|
||||
const float elements[] = {
|
||||
};
|
||||
|
||||
for (int i = 0; i < 9*9; i++) {
|
||||
m_data[i] = elements[i] * scale.w;
|
||||
}
|
||||
}
|
||||
{
|
||||
const float elements[] = {
|
||||
-1, -2, -3, 0, 3, 2, 1,
|
||||
-2, -3, -4, 0, 4, 3, 2,
|
||||
-3, -4, -5, 0, 5, 4, 3,
|
||||
@ -499,107 +501,107 @@ void Kernel2::initBlendedSobel(const Vector4 & scale)
|
||||
-3, -4, -5, 0, 5, 4, 3,
|
||||
-2, -3, -4, 0, 4, 3, 2,
|
||||
-1, -2, -3, 0, 3, 2, 1,
|
||||
};
|
||||
};
|
||||
|
||||
for (int i = 0; i < 7; i++) {
|
||||
for (int e = 0; e < 7; e++) {
|
||||
m_data[(i + 1) * 9 + e + 1] += elements[i * 7 + e] * scale.z();
|
||||
}
|
||||
}
|
||||
}
|
||||
{
|
||||
const float elements[] = {
|
||||
for (int i = 0; i < 7; i++) {
|
||||
for (int e = 0; e < 7; e++) {
|
||||
m_data[(i + 1) * 9 + e + 1] += elements[i * 7 + e] * scale.z;
|
||||
}
|
||||
}
|
||||
}
|
||||
{
|
||||
const float elements[] = {
|
||||
-1, -2, 0, 2, 1,
|
||||
-2, -3, 0, 3, 2,
|
||||
-3, -4, 0, 4, 3,
|
||||
-2, -3, 0, 3, 2,
|
||||
-1, -2, 0, 2, 1
|
||||
};
|
||||
};
|
||||
|
||||
for (int i = 0; i < 5; i++) {
|
||||
for (int e = 0; e < 5; e++) {
|
||||
m_data[(i + 2) * 9 + e + 2] += elements[i * 5 + e] * scale.y();
|
||||
}
|
||||
}
|
||||
}
|
||||
{
|
||||
const float elements[] = {
|
||||
for (int i = 0; i < 5; i++) {
|
||||
for (int e = 0; e < 5; e++) {
|
||||
m_data[(i + 2) * 9 + e + 2] += elements[i * 5 + e] * scale.y;
|
||||
}
|
||||
}
|
||||
}
|
||||
{
|
||||
const float elements[] = {
|
||||
-1, 0, 1,
|
||||
-2, 0, 2,
|
||||
-1, 0, 1,
|
||||
};
|
||||
};
|
||||
|
||||
for (int i = 0; i < 3; i++) {
|
||||
for (int e = 0; e < 3; e++) {
|
||||
m_data[(i + 3) * 9 + e + 3] += elements[i * 3 + e] * scale.x();
|
||||
}
|
||||
}
|
||||
}
|
||||
for (int i = 0; i < 3; i++) {
|
||||
for (int e = 0; e < 3; e++) {
|
||||
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*/)
|
||||
{
|
||||
nvDebugCheck(samples > 0);
|
||||
nvDebugCheck(samples > 0);
|
||||
|
||||
float scale = float(dstLength) / float(srcLength);
|
||||
const float iscale = 1.0f / scale;
|
||||
float scale = float(dstLength) / float(srcLength);
|
||||
const float iscale = 1.0f / scale;
|
||||
|
||||
if (scale > 1) {
|
||||
// Upsampling.
|
||||
samples = 1;
|
||||
scale = 1;
|
||||
}
|
||||
if (scale > 1) {
|
||||
// Upsampling.
|
||||
samples = 1;
|
||||
scale = 1;
|
||||
}
|
||||
|
||||
m_length = dstLength;
|
||||
m_width = f.width() * iscale;
|
||||
m_windowSize = (int)ceilf(m_width * 2) + 1;
|
||||
m_length = dstLength;
|
||||
m_width = f.width() * iscale;
|
||||
m_windowSize = (int)ceilf(m_width * 2) + 1;
|
||||
|
||||
m_data = new float[m_windowSize * m_length];
|
||||
memset(m_data, 0, sizeof(float) * m_windowSize * m_length);
|
||||
m_data = new float[m_windowSize * m_length];
|
||||
memset(m_data, 0, sizeof(float) * m_windowSize * m_length);
|
||||
|
||||
for (uint i = 0; i < m_length; i++)
|
||||
{
|
||||
const float center = (0.5f + i) * iscale;
|
||||
|
||||
const int left = (int)floorf(center - m_width);
|
||||
const int right = (int)ceilf(center + m_width);
|
||||
nvDebugCheck(right - left <= m_windowSize);
|
||||
|
||||
float total = 0.0f;
|
||||
for (int j = 0; j < m_windowSize; j++)
|
||||
{
|
||||
const float sample = f.sampleBox(left + j - center, scale, samples);
|
||||
|
||||
m_data[i * m_windowSize + j] = sample;
|
||||
total += sample;
|
||||
}
|
||||
|
||||
// normalize weights.
|
||||
for (int j = 0; j < m_windowSize; j++)
|
||||
{
|
||||
m_data[i * m_windowSize + j] /= total;
|
||||
}
|
||||
}
|
||||
for (uint i = 0; i < m_length; i++)
|
||||
{
|
||||
const float center = (0.5f + i) * iscale;
|
||||
|
||||
const int left = (int)floorf(center - m_width);
|
||||
const int right = (int)ceilf(center + m_width);
|
||||
nvDebugCheck(right - left <= m_windowSize);
|
||||
|
||||
float total = 0.0f;
|
||||
for (int j = 0; j < m_windowSize; j++)
|
||||
{
|
||||
const float sample = f.sampleBox(left + j - center, scale, samples);
|
||||
|
||||
m_data[i * m_windowSize + j] = sample;
|
||||
total += sample;
|
||||
}
|
||||
|
||||
// normalize weights.
|
||||
for (int j = 0; j < m_windowSize; j++)
|
||||
{
|
||||
m_data[i * m_windowSize + j] /= total;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
PolyphaseKernel::~PolyphaseKernel()
|
||||
{
|
||||
delete [] m_data;
|
||||
delete [] m_data;
|
||||
}
|
||||
|
||||
|
||||
/// Print the kernel for debugging purposes.
|
||||
void PolyphaseKernel::debugPrint() const
|
||||
{
|
||||
for (uint i = 0; i < m_length; i++)
|
||||
{
|
||||
nvDebug("%d: ", i);
|
||||
for (int j = 0; j < m_windowSize; j++)
|
||||
{
|
||||
nvDebug(" %6.4f", m_data[i * m_windowSize + j]);
|
||||
}
|
||||
nvDebug("\n");
|
||||
}
|
||||
for (uint i = 0; i < m_length; i++)
|
||||
{
|
||||
nvDebug("%d: ", i);
|
||||
for (int j = 0; j < m_windowSize; j++)
|
||||
{
|
||||
nvDebug(" %6.4f", m_data[i * m_windowSize + j]);
|
||||
}
|
||||
nvDebug("\n");
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1,218 +1,219 @@
|
||||
// This code is in the public domain -- castanyo@yahoo.es
|
||||
|
||||
#pragma once
|
||||
#ifndef NV_IMAGE_FILTER_H
|
||||
#define NV_IMAGE_FILTER_H
|
||||
|
||||
#include <nvimage/nvimage.h>
|
||||
#include <nvcore/Debug.h>
|
||||
#include "nvimage.h"
|
||||
#include "nvcore/Debug.h"
|
||||
|
||||
namespace nv
|
||||
{
|
||||
class Vector4;
|
||||
class Vector4;
|
||||
|
||||
/// Base filter class.
|
||||
class NVIMAGE_CLASS Filter
|
||||
{
|
||||
public:
|
||||
Filter(float width);
|
||||
virtual ~Filter();
|
||||
/// Base filter class.
|
||||
class NVIMAGE_CLASS Filter
|
||||
{
|
||||
public:
|
||||
Filter(float width);
|
||||
virtual ~Filter();
|
||||
|
||||
float width() const { return m_width; }
|
||||
float sampleDelta(float x, float scale) const;
|
||||
float sampleBox(float x, float scale, int samples) const;
|
||||
float sampleTriangle(float x, float scale, int samples) const;
|
||||
float width() const { return m_width; }
|
||||
float sampleDelta(float x, float scale) const;
|
||||
float sampleBox(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:
|
||||
const float m_width;
|
||||
};
|
||||
protected:
|
||||
const float m_width;
|
||||
};
|
||||
|
||||
// Box filter.
|
||||
class NVIMAGE_CLASS BoxFilter : public Filter
|
||||
{
|
||||
public:
|
||||
BoxFilter();
|
||||
BoxFilter(float width);
|
||||
virtual float evaluate(float x) const;
|
||||
};
|
||||
// Box filter.
|
||||
class NVIMAGE_CLASS BoxFilter : public Filter
|
||||
{
|
||||
public:
|
||||
BoxFilter();
|
||||
BoxFilter(float width);
|
||||
virtual float evaluate(float x) const;
|
||||
};
|
||||
|
||||
// Triangle (bilinear/tent) filter.
|
||||
class NVIMAGE_CLASS TriangleFilter : public Filter
|
||||
{
|
||||
public:
|
||||
TriangleFilter();
|
||||
TriangleFilter(float width);
|
||||
virtual float evaluate(float x) const;
|
||||
};
|
||||
// Triangle (bilinear/tent) filter.
|
||||
class NVIMAGE_CLASS TriangleFilter : public Filter
|
||||
{
|
||||
public:
|
||||
TriangleFilter();
|
||||
TriangleFilter(float width);
|
||||
virtual float evaluate(float x) const;
|
||||
};
|
||||
|
||||
// Quadratic (bell) filter.
|
||||
class NVIMAGE_CLASS QuadraticFilter : public Filter
|
||||
{
|
||||
public:
|
||||
QuadraticFilter();
|
||||
virtual float evaluate(float x) const;
|
||||
};
|
||||
// Quadratic (bell) filter.
|
||||
class NVIMAGE_CLASS QuadraticFilter : public Filter
|
||||
{
|
||||
public:
|
||||
QuadraticFilter();
|
||||
virtual float evaluate(float x) const;
|
||||
};
|
||||
|
||||
// Cubic filter from Thatcher Ulrich.
|
||||
class NVIMAGE_CLASS CubicFilter : public Filter
|
||||
{
|
||||
public:
|
||||
CubicFilter();
|
||||
virtual float evaluate(float x) const;
|
||||
};
|
||||
// Cubic filter from Thatcher Ulrich.
|
||||
class NVIMAGE_CLASS CubicFilter : public Filter
|
||||
{
|
||||
public:
|
||||
CubicFilter();
|
||||
virtual float evaluate(float x) const;
|
||||
};
|
||||
|
||||
// Cubic b-spline filter from Paul Heckbert.
|
||||
class NVIMAGE_CLASS BSplineFilter : public Filter
|
||||
{
|
||||
public:
|
||||
BSplineFilter();
|
||||
virtual float evaluate(float x) const;
|
||||
};
|
||||
// Cubic b-spline filter from Paul Heckbert.
|
||||
class NVIMAGE_CLASS BSplineFilter : public Filter
|
||||
{
|
||||
public:
|
||||
BSplineFilter();
|
||||
virtual float evaluate(float x) const;
|
||||
};
|
||||
|
||||
/// Mitchell & Netravali's two-param cubic
|
||||
/// @see "Reconstruction Filters in Computer Graphics", SIGGRAPH 88
|
||||
class NVIMAGE_CLASS MitchellFilter : public Filter
|
||||
{
|
||||
public:
|
||||
MitchellFilter();
|
||||
virtual float evaluate(float x) const;
|
||||
/// Mitchell & Netravali's two-param cubic
|
||||
/// @see "Reconstruction Filters in Computer Graphics", SIGGRAPH 88
|
||||
class NVIMAGE_CLASS MitchellFilter : public Filter
|
||||
{
|
||||
public:
|
||||
MitchellFilter();
|
||||
virtual float evaluate(float x) const;
|
||||
|
||||
void setParameters(float b, float c);
|
||||
void setParameters(float b, float c);
|
||||
|
||||
private:
|
||||
float p0, p2, p3;
|
||||
float q0, q1, q2, q3;
|
||||
};
|
||||
private:
|
||||
float p0, p2, p3;
|
||||
float q0, q1, q2, q3;
|
||||
};
|
||||
|
||||
// Lanczos3 filter.
|
||||
class NVIMAGE_CLASS LanczosFilter : public Filter
|
||||
{
|
||||
public:
|
||||
LanczosFilter();
|
||||
virtual float evaluate(float x) const;
|
||||
};
|
||||
// Lanczos3 filter.
|
||||
class NVIMAGE_CLASS LanczosFilter : public Filter
|
||||
{
|
||||
public:
|
||||
LanczosFilter();
|
||||
virtual float evaluate(float x) const;
|
||||
};
|
||||
|
||||
// Sinc filter.
|
||||
class NVIMAGE_CLASS SincFilter : public Filter
|
||||
{
|
||||
public:
|
||||
SincFilter(float w);
|
||||
virtual float evaluate(float x) const;
|
||||
};
|
||||
// Sinc filter.
|
||||
class NVIMAGE_CLASS SincFilter : public Filter
|
||||
{
|
||||
public:
|
||||
SincFilter(float w);
|
||||
virtual float evaluate(float x) const;
|
||||
};
|
||||
|
||||
// Kaiser filter.
|
||||
class NVIMAGE_CLASS KaiserFilter : public Filter
|
||||
{
|
||||
public:
|
||||
KaiserFilter(float w);
|
||||
virtual float evaluate(float x) const;
|
||||
|
||||
void setParameters(float a, float stretch);
|
||||
// Kaiser filter.
|
||||
class NVIMAGE_CLASS KaiserFilter : public Filter
|
||||
{
|
||||
public:
|
||||
KaiserFilter(float w);
|
||||
virtual float evaluate(float x) const;
|
||||
|
||||
private:
|
||||
float alpha;
|
||||
float stretch;
|
||||
};
|
||||
void setParameters(float a, float stretch);
|
||||
|
||||
private:
|
||||
float alpha;
|
||||
float stretch;
|
||||
};
|
||||
|
||||
|
||||
|
||||
/// A 1D kernel. Used to precompute filter weights.
|
||||
class NVIMAGE_CLASS Kernel1
|
||||
{
|
||||
NV_FORBID_COPY(Kernel1);
|
||||
public:
|
||||
Kernel1(const Filter & f, int iscale, int samples = 32);
|
||||
~Kernel1();
|
||||
|
||||
float valueAt(uint x) const {
|
||||
nvDebugCheck(x < (uint)m_windowSize);
|
||||
return m_data[x];
|
||||
}
|
||||
|
||||
int windowSize() const {
|
||||
return m_windowSize;
|
||||
}
|
||||
|
||||
float width() const {
|
||||
return m_width;
|
||||
}
|
||||
|
||||
void debugPrint();
|
||||
|
||||
private:
|
||||
int m_windowSize;
|
||||
float m_width;
|
||||
float * m_data;
|
||||
};
|
||||
/// A 1D kernel. Used to precompute filter weights.
|
||||
class NVIMAGE_CLASS Kernel1
|
||||
{
|
||||
NV_FORBID_COPY(Kernel1);
|
||||
public:
|
||||
Kernel1(const Filter & f, int iscale, int samples = 32);
|
||||
~Kernel1();
|
||||
|
||||
float valueAt(uint x) const {
|
||||
nvDebugCheck(x < (uint)m_windowSize);
|
||||
return m_data[x];
|
||||
}
|
||||
|
||||
int windowSize() const {
|
||||
return m_windowSize;
|
||||
}
|
||||
|
||||
float width() const {
|
||||
return m_width;
|
||||
}
|
||||
|
||||
void debugPrint();
|
||||
|
||||
private:
|
||||
int m_windowSize;
|
||||
float m_width;
|
||||
float * m_data;
|
||||
};
|
||||
|
||||
|
||||
/// A 2D kernel.
|
||||
class NVIMAGE_CLASS Kernel2
|
||||
{
|
||||
public:
|
||||
Kernel2(uint width);
|
||||
Kernel2(const Kernel2 & k);
|
||||
~Kernel2();
|
||||
|
||||
void normalize();
|
||||
void transpose();
|
||||
|
||||
float valueAt(uint x, uint y) const {
|
||||
return m_data[y * m_windowSize + x];
|
||||
}
|
||||
|
||||
uint windowSize() const {
|
||||
return m_windowSize;
|
||||
}
|
||||
|
||||
void initLaplacian();
|
||||
void initEdgeDetection();
|
||||
void initSobel();
|
||||
void initPrewitt();
|
||||
|
||||
void initBlendedSobel(const Vector4 & scale);
|
||||
|
||||
private:
|
||||
const uint m_windowSize;
|
||||
float * m_data;
|
||||
};
|
||||
/// A 2D kernel.
|
||||
class NVIMAGE_CLASS Kernel2
|
||||
{
|
||||
public:
|
||||
Kernel2(uint width);
|
||||
Kernel2(const Kernel2 & k);
|
||||
~Kernel2();
|
||||
|
||||
void normalize();
|
||||
void transpose();
|
||||
|
||||
float valueAt(uint x, uint y) const {
|
||||
return m_data[y * m_windowSize + x];
|
||||
}
|
||||
|
||||
uint windowSize() const {
|
||||
return m_windowSize;
|
||||
}
|
||||
|
||||
void initLaplacian();
|
||||
void initEdgeDetection();
|
||||
void initSobel();
|
||||
void initPrewitt();
|
||||
|
||||
void initBlendedSobel(const Vector4 & scale);
|
||||
|
||||
private:
|
||||
const uint m_windowSize;
|
||||
float * m_data;
|
||||
};
|
||||
|
||||
|
||||
/// A 1D polyphase kernel
|
||||
class NVIMAGE_CLASS PolyphaseKernel
|
||||
{
|
||||
NV_FORBID_COPY(PolyphaseKernel);
|
||||
public:
|
||||
PolyphaseKernel(const Filter & f, uint srcLength, uint dstLength, int samples = 32);
|
||||
~PolyphaseKernel();
|
||||
|
||||
int windowSize() const {
|
||||
return m_windowSize;
|
||||
}
|
||||
|
||||
uint length() const {
|
||||
return m_length;
|
||||
}
|
||||
/// A 1D polyphase kernel
|
||||
class NVIMAGE_CLASS PolyphaseKernel
|
||||
{
|
||||
NV_FORBID_COPY(PolyphaseKernel);
|
||||
public:
|
||||
PolyphaseKernel(const Filter & f, uint srcLength, uint dstLength, int samples = 32);
|
||||
~PolyphaseKernel();
|
||||
|
||||
float width() const {
|
||||
return m_width;
|
||||
}
|
||||
int windowSize() const {
|
||||
return m_windowSize;
|
||||
}
|
||||
|
||||
float valueAt(uint column, uint x) const {
|
||||
nvDebugCheck(column < m_length);
|
||||
nvDebugCheck(x < (uint)m_windowSize);
|
||||
return m_data[column * m_windowSize + x];
|
||||
}
|
||||
uint length() const {
|
||||
return m_length;
|
||||
}
|
||||
|
||||
void debugPrint() const;
|
||||
|
||||
private:
|
||||
int m_windowSize;
|
||||
uint m_length;
|
||||
float m_width;
|
||||
float * m_data;
|
||||
};
|
||||
float width() const {
|
||||
return m_width;
|
||||
}
|
||||
|
||||
float valueAt(uint column, uint x) const {
|
||||
nvDebugCheck(column < m_length);
|
||||
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
|
||||
|
||||
|
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
|
||||
#define NV_IMAGE_FLOATIMAGE_H
|
||||
|
||||
#include <nvimage/nvimage.h>
|
||||
|
||||
#include <nvmath/Vector.h>
|
||||
|
||||
#include <nvcore/Debug.h>
|
||||
#include <nvcore/Algorithms.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 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 bias);
|
||||
|
||||
NVIMAGE_API void clamp(uint base_component, uint num, 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 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();
|
||||
|
||||
NVIMAGE_API float alphaTestCoverage(float alphaRef, int alphaChannel) const;
|
||||
NVIMAGE_API void scaleAlphaToCoverage(float coverage, float alphaRef, int alphaChannel);
|
||||
//@}
|
||||
|
||||
uint width() const { return m_width; }
|
||||
uint height() const { return m_height; }
|
||||
uint componentNum() const { return m_componentNum; }
|
||||
uint count() const { return m_count; }
|
||||
|
||||
|
||||
/** @name Pixel access. */
|
||||
//@{
|
||||
const float * channel(uint c) const;
|
||||
float * channel(uint c);
|
||||
|
||||
const float * scanline(uint y, uint c) const;
|
||||
float * scanline(uint y, uint c);
|
||||
|
||||
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;
|
||||
|
||||
void setPixel(float f, uint idx);
|
||||
float pixel(uint idx) const;
|
||||
|
||||
float sampleNearest(float x, float y, int c, WrapMode wm) const;
|
||||
float sampleLinear(float x, float y, int c, WrapMode wm) const;
|
||||
|
||||
float sampleNearestClamp(float x, float y, int c) const;
|
||||
float sampleNearestRepeat(float x, float y, int c) const;
|
||||
float sampleNearestMirror(float x, float y, int c) const;
|
||||
|
||||
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;
|
||||
//@}
|
||||
|
||||
|
||||
FloatImage* clone() const;
|
||||
|
||||
public:
|
||||
|
||||
uint index(uint x, uint y) const;
|
||||
uint indexClamp(int x, int y) const;
|
||||
uint indexRepeat(int x, int y) const;
|
||||
uint indexMirror(int x, int y) const;
|
||||
uint index(int x, int y, WrapMode wm) const;
|
||||
|
||||
public:
|
||||
|
||||
uint16 m_width; ///< Width of the texture.
|
||||
uint16 m_height; ///< Height of the texture.
|
||||
uint32 m_componentNum; ///< Number of components.
|
||||
uint32 m_count; ///< Image pixel count.
|
||||
float * m_mem;
|
||||
|
||||
};
|
||||
|
||||
|
||||
/// Get const channel pointer.
|
||||
inline const float * FloatImage::channel(uint c) const
|
||||
{
|
||||
nvDebugCheck(m_mem != NULL);
|
||||
nvDebugCheck(c < m_componentNum);
|
||||
return m_mem + c * m_width * m_height;
|
||||
}
|
||||
|
||||
/// Get channel pointer.
|
||||
inline float * FloatImage::channel(uint c) {
|
||||
nvDebugCheck(m_mem != NULL);
|
||||
nvDebugCheck(c < m_componentNum);
|
||||
return m_mem + c * m_width * m_height;
|
||||
}
|
||||
|
||||
/// Get const scanline pointer.
|
||||
inline const float * FloatImage::scanline(uint y, uint c) const
|
||||
{
|
||||
nvDebugCheck(y < m_height);
|
||||
return channel(c) + y * m_width;
|
||||
}
|
||||
|
||||
/// Get scanline pointer.
|
||||
inline float * FloatImage::scanline(uint y, uint c)
|
||||
{
|
||||
nvDebugCheck(y < m_height);
|
||||
return channel(c) + y * m_width;
|
||||
}
|
||||
|
||||
/// 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
|
||||
NVIMAGE_API float alphaTestCoverage(float alphaRef, int alphaChannel) const;
|
||||
NVIMAGE_API void scaleAlphaToCoverage(float coverage, float alphaRef, int alphaChannel);
|
||||
|
||||
|
||||
uint width() const { return m_width; }
|
||||
uint height() const { return m_height; }
|
||||
uint componentNum() const { return m_componentNum; }
|
||||
uint count() const { return m_count; }
|
||||
|
||||
|
||||
/** @name Pixel access. */
|
||||
//@{
|
||||
const float * channel(uint c) const;
|
||||
float * channel(uint c);
|
||||
|
||||
const float * scanline(uint y, uint c) const;
|
||||
float * scanline(uint y, uint c);
|
||||
|
||||
float pixel(uint x, uint y, uint c) const;
|
||||
float & pixel(uint x, uint y, uint c);
|
||||
|
||||
float pixel(uint idx) const;
|
||||
float & pixel(uint idx);
|
||||
|
||||
float sampleNearest(float x, float y, int c, WrapMode wm) const;
|
||||
float sampleLinear(float x, float y, int c, WrapMode wm) const;
|
||||
|
||||
float sampleNearestClamp(float x, float y, int c) const;
|
||||
float sampleNearestRepeat(float x, float y, int c) const;
|
||||
float sampleNearestMirror(float x, float y, int c) const;
|
||||
|
||||
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;
|
||||
//@}
|
||||
|
||||
|
||||
FloatImage* clone() const;
|
||||
|
||||
public:
|
||||
|
||||
uint index(uint x, uint y) const;
|
||||
uint indexClamp(int x, int y) const;
|
||||
uint indexRepeat(int x, int y) const;
|
||||
uint indexMirror(int x, int y) const;
|
||||
uint index(int x, int y, WrapMode wm) const;
|
||||
|
||||
public:
|
||||
|
||||
uint16 m_width; ///< Width of the texture.
|
||||
uint16 m_height; ///< Height of the texture.
|
||||
uint32 m_componentNum; ///< Number of components.
|
||||
uint32 m_count; ///< Image pixel count.
|
||||
float * m_mem;
|
||||
|
||||
};
|
||||
|
||||
|
||||
/// Get const channel pointer.
|
||||
inline const float * FloatImage::channel(uint c) const
|
||||
{
|
||||
nvDebugCheck(m_mem != NULL);
|
||||
nvDebugCheck(c < m_componentNum);
|
||||
return m_mem + c * m_width * m_height;
|
||||
}
|
||||
|
||||
/// Get channel pointer.
|
||||
inline float * FloatImage::channel(uint c) {
|
||||
nvDebugCheck(m_mem != NULL);
|
||||
nvDebugCheck(c < m_componentNum);
|
||||
return m_mem + c * m_width * m_height;
|
||||
}
|
||||
|
||||
/// Get const scanline pointer.
|
||||
inline const float * FloatImage::scanline(uint y, uint c) const
|
||||
{
|
||||
nvDebugCheck(y < m_height);
|
||||
return channel(c) + y * m_width;
|
||||
}
|
||||
|
||||
/// Get scanline pointer.
|
||||
inline float * FloatImage::scanline(uint y, uint c)
|
||||
{
|
||||
nvDebugCheck(y < m_height);
|
||||
return channel(c) + y * m_width;
|
||||
}
|
||||
|
||||
/// 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];
|
||||
}
|
||||
|
||||
/// Get pixel component.
|
||||
inline float & FloatImage::pixel(uint x, uint y, uint c)
|
||||
{
|
||||
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];
|
||||
}
|
||||
|
||||
/// Get pixel component.
|
||||
inline float FloatImage::pixel(uint idx) const
|
||||
{
|
||||
nvDebugCheck(idx < m_count);
|
||||
return m_mem[idx];
|
||||
}
|
||||
|
||||
/// Get pixel component.
|
||||
inline float & FloatImage::pixel(uint idx)
|
||||
{
|
||||
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
|
||||
|
||||
#include <nvimage/Image.h>
|
||||
#include <nvimage/ImageIO.h>
|
||||
#include "Image.h"
|
||||
#include "ImageIO.h"
|
||||
|
||||
#include <nvmath/Color.h>
|
||||
#include "nvmath/Color.h"
|
||||
|
||||
#include <nvcore/Debug.h>
|
||||
#include <nvcore/Ptr.h>
|
||||
#include <nvcore/Containers.h> // swap
|
||||
#include "nvcore/Debug.h"
|
||||
#include "nvcore/Ptr.h"
|
||||
#include "nvcore/Utils.h" // swap
|
||||
|
||||
|
||||
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)
|
||||
{
|
||||
allocate(img.m_width, img.m_height);
|
||||
m_format = img.m_format;
|
||||
memcpy(m_data, img.m_data, sizeof(Color32) * m_width * m_height);
|
||||
allocate(img.m_width, img.m_height);
|
||||
m_format = img.m_format;
|
||||
memcpy(m_data, img.m_data, sizeof(Color32) * m_width * m_height);
|
||||
}
|
||||
|
||||
Image::~Image()
|
||||
{
|
||||
free();
|
||||
free();
|
||||
}
|
||||
|
||||
const Image & Image::operator=(const Image & img)
|
||||
{
|
||||
allocate(img.m_width, img.m_height);
|
||||
m_format = img.m_format;
|
||||
memcpy(m_data, img.m_data, sizeof(Color32) * m_width * m_height);
|
||||
return *this;
|
||||
allocate(img.m_width, img.m_height);
|
||||
m_format = img.m_format;
|
||||
memcpy(m_data, img.m_data, sizeof(Color32) * m_width * m_height);
|
||||
return *this;
|
||||
}
|
||||
|
||||
|
||||
void Image::allocate(uint w, uint h)
|
||||
{
|
||||
m_width = w;
|
||||
m_height = h;
|
||||
m_data = (Color32 *)nv::mem::realloc(m_data, w * h * sizeof(Color32));
|
||||
m_width = w;
|
||||
m_height = h;
|
||||
m_data = (Color32 *)nv::mem::realloc(m_data, w * h * sizeof(Color32));
|
||||
}
|
||||
|
||||
bool Image::load(const char * name)
|
||||
{
|
||||
free();
|
||||
|
||||
AutoPtr<Image> img(ImageIO::load(name));
|
||||
if (img == NULL) {
|
||||
return false;
|
||||
}
|
||||
|
||||
swap(m_width, img->m_width);
|
||||
swap(m_height, img->m_height);
|
||||
swap(m_format, img->m_format);
|
||||
swap(m_data, img->m_data);
|
||||
|
||||
return true;
|
||||
free();
|
||||
|
||||
AutoPtr<Image> img(ImageIO::load(name));
|
||||
if (img == NULL) {
|
||||
return false;
|
||||
}
|
||||
|
||||
swap(m_width, img->m_width);
|
||||
swap(m_height, img->m_height);
|
||||
swap(m_format, img->m_format);
|
||||
swap(m_data, img->m_data);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void Image::wrap(void * data, uint w, uint h)
|
||||
{
|
||||
free();
|
||||
m_data = (Color32 *)data;
|
||||
m_width = w;
|
||||
m_height = h;
|
||||
free();
|
||||
m_data = (Color32 *)data;
|
||||
m_width = w;
|
||||
m_height = h;
|
||||
}
|
||||
|
||||
void Image::unwrap()
|
||||
{
|
||||
m_data = NULL;
|
||||
m_width = 0;
|
||||
m_height = 0;
|
||||
m_data = NULL;
|
||||
m_width = 0;
|
||||
m_height = 0;
|
||||
}
|
||||
|
||||
|
||||
void Image::free()
|
||||
{
|
||||
nv::mem::free(m_data);
|
||||
m_data = NULL;
|
||||
nv::mem::free(m_data);
|
||||
m_data = NULL;
|
||||
}
|
||||
|
||||
|
||||
uint Image::width() const
|
||||
{
|
||||
return m_width;
|
||||
return m_width;
|
||||
}
|
||||
|
||||
uint Image::height() const
|
||||
{
|
||||
return m_height;
|
||||
return m_height;
|
||||
}
|
||||
|
||||
const Color32 * Image::scanline(uint h) const
|
||||
{
|
||||
nvDebugCheck(h < m_height);
|
||||
return m_data + h * m_width;
|
||||
nvDebugCheck(h < m_height);
|
||||
return m_data + h * m_width;
|
||||
}
|
||||
|
||||
Color32 * Image::scanline(uint h)
|
||||
{
|
||||
nvDebugCheck(h < m_height);
|
||||
return m_data + h * m_width;
|
||||
nvDebugCheck(h < m_height);
|
||||
return m_data + h * m_width;
|
||||
}
|
||||
|
||||
const Color32 * Image::pixels() const
|
||||
{
|
||||
return m_data;
|
||||
return m_data;
|
||||
}
|
||||
|
||||
Color32 * Image::pixels()
|
||||
{
|
||||
return m_data;
|
||||
return m_data;
|
||||
}
|
||||
|
||||
const Color32 & Image::pixel(uint idx) const
|
||||
{
|
||||
nvDebugCheck(idx < m_width * m_height);
|
||||
return m_data[idx];
|
||||
nvDebugCheck(idx < m_width * m_height);
|
||||
return m_data[idx];
|
||||
}
|
||||
|
||||
Color32 & Image::pixel(uint idx)
|
||||
{
|
||||
nvDebugCheck(idx < m_width * m_height);
|
||||
return m_data[idx];
|
||||
nvDebugCheck(idx < m_width * m_height);
|
||||
return m_data[idx];
|
||||
}
|
||||
|
||||
|
||||
Image::Format Image::format() const
|
||||
{
|
||||
return m_format;
|
||||
return m_format;
|
||||
}
|
||||
|
||||
void Image::setFormat(Image::Format f)
|
||||
{
|
||||
m_format = f;
|
||||
m_format = f;
|
||||
}
|
||||
|
||||
void Image::fill(Color32 c)
|
||||
{
|
||||
const uint size = m_width * m_height;
|
||||
for (uint i = 0; i < size; ++i)
|
||||
{
|
||||
m_data[i] = c;
|
||||
}
|
||||
const uint size = m_width * m_height;
|
||||
for (uint i = 0; i < size; ++i)
|
||||
{
|
||||
m_data[i] = c;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1,81 +1,82 @@
|
||||
// This code is in the public domain -- castanyo@yahoo.es
|
||||
|
||||
#pragma once
|
||||
#ifndef NV_IMAGE_IMAGE_H
|
||||
#define NV_IMAGE_IMAGE_H
|
||||
|
||||
#include <nvcore/Debug.h>
|
||||
#include <nvimage/nvimage.h>
|
||||
#include "nvimage.h"
|
||||
#include "nvcore/Debug.h"
|
||||
|
||||
namespace nv
|
||||
{
|
||||
class Color32;
|
||||
|
||||
/// 32 bit RGBA image.
|
||||
class NVIMAGE_CLASS Image
|
||||
{
|
||||
public:
|
||||
|
||||
enum Format
|
||||
{
|
||||
Format_RGB,
|
||||
Format_ARGB,
|
||||
};
|
||||
|
||||
Image();
|
||||
Image(const Image & img);
|
||||
~Image();
|
||||
class Color32;
|
||||
|
||||
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);
|
||||
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);
|
||||
void allocate(uint w, uint h);
|
||||
bool load(const char * name);
|
||||
|
||||
private:
|
||||
void free();
|
||||
|
||||
private:
|
||||
uint m_width;
|
||||
uint m_height;
|
||||
Format m_format;
|
||||
Color32 * m_data;
|
||||
};
|
||||
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 free();
|
||||
|
||||
private:
|
||||
uint m_width;
|
||||
uint m_height;
|
||||
Format m_format;
|
||||
Color32 * m_data;
|
||||
};
|
||||
|
||||
|
||||
inline const Color32 & Image::pixel(uint x, uint y) const
|
||||
{
|
||||
nvDebugCheck(x < width() && y < height());
|
||||
return pixel(y * width() + x);
|
||||
}
|
||||
|
||||
inline Color32 & Image::pixel(uint x, uint y)
|
||||
{
|
||||
nvDebugCheck(x < width() && y < height());
|
||||
return pixel(y * width() + x);
|
||||
}
|
||||
inline const Color32 & Image::pixel(uint x, uint y) const
|
||||
{
|
||||
nvDebugCheck(x < width() && y < height());
|
||||
return pixel(y * width() + x);
|
||||
}
|
||||
|
||||
inline Color32 & Image::pixel(uint x, uint y)
|
||||
{
|
||||
nvDebugCheck(x < width() && y < height());
|
||||
return pixel(y * width() + x);
|
||||
}
|
||||
|
||||
} // nv namespace
|
||||
|
||||
|
@ -6,12 +6,13 @@
|
||||
#include "TgaFile.h"
|
||||
#include "PsdFile.h"
|
||||
|
||||
#include <nvmath/Color.h>
|
||||
#include "nvmath/Color.h"
|
||||
|
||||
#include <nvcore/Ptr.h>
|
||||
#include <nvcore/Containers.h>
|
||||
#include <nvcore/StrLib.h>
|
||||
#include <nvcore/StdStream.h>
|
||||
#include "nvcore/Ptr.h"
|
||||
#include "nvcore/Utils.h"
|
||||
#include "nvcore/Array.h"
|
||||
#include "nvcore/StrLib.h"
|
||||
#include "nvcore/StdStream.h"
|
||||
|
||||
// Extern
|
||||
#if defined(HAVE_FREEIMAGE)
|
||||
|
@ -1,40 +1,42 @@
|
||||
// This code is in the public domain -- castanyo@yahoo.es
|
||||
|
||||
#pragma once
|
||||
#ifndef 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
|
||||
{
|
||||
class Image;
|
||||
class FloatImage;
|
||||
class Stream;
|
||||
class Image;
|
||||
class FloatImage;
|
||||
class Stream;
|
||||
|
||||
namespace ImageIO
|
||||
{
|
||||
struct ImageMetaData
|
||||
{
|
||||
HashMap<String, String> tagMap;
|
||||
};
|
||||
namespace ImageIO
|
||||
{
|
||||
struct ImageMetaData
|
||||
{
|
||||
HashMap<String, String> tagMap;
|
||||
};
|
||||
|
||||
NVIMAGE_API Image * load(const char * fileName);
|
||||
NVIMAGE_API Image * load(const char * fileName, Stream & s);
|
||||
NVIMAGE_API Image * load(const char * fileName);
|
||||
NVIMAGE_API Image * load(const char * fileName, Stream & s);
|
||||
|
||||
NVIMAGE_API FloatImage * loadFloat(const char * fileName);
|
||||
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 FloatImage * loadFloat(const char * fileName);
|
||||
NVIMAGE_API FloatImage * loadFloat(const char * fileName, Stream & s);
|
||||
|
||||
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);
|
||||
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 saveFloat(const char * fileName, Stream & s, const FloatImage * fimage, uint baseComponent, uint componentCount);
|
||||
|
||||
} // ImageIO namespace
|
||||
|
||||
} // ImageIO namespace
|
||||
|
||||
} // nv namespace
|
||||
|
||||
|
||||
|
@ -65,9 +65,9 @@ static FloatImage * createNormalMap(const Image * img, FloatImage::WrapMode wm,
|
||||
|
||||
Vector3 n = normalize(Vector3(du, dv, heightScale));
|
||||
|
||||
fimage->setPixel(0.5f * n.x() + 0.5f, x, y, 0);
|
||||
fimage->setPixel(0.5f * n.y() + 0.5f, x, y, 1);
|
||||
fimage->setPixel(0.5f * n.z() + 0.5f, x, y, 2);
|
||||
fimage->pixel(x, y, 0) = 0.5f * n.x + 0.5f;
|
||||
fimage->pixel(x, y, 1) = 0.5f * n.y + 0.5f;
|
||||
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));
|
||||
|
||||
img_out->setPixel(n.x(), x, y, 0);
|
||||
img_out->setPixel(n.y(), x, y, 1);
|
||||
img_out->setPixel(n.z(), x, y, 2);
|
||||
img_out->pixel(x, y, 0) = n.x;
|
||||
img_out->pixel(x, y, 1) = n.y;
|
||||
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++)
|
||||
{
|
||||
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.
|
||||
*/
|
||||
|
||||
#include <nvimage/Quantize.h>
|
||||
#include <nvimage/Image.h>
|
||||
#include <nvimage/PixelFormat.h>
|
||||
#include "Quantize.h"
|
||||
#include "Image.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;
|
||||
@ -174,10 +176,10 @@ void nv::Quantize::FloydSteinberg(Image * image, uint rsize, uint gsize, uint bs
|
||||
Color32 pixel = image->pixel(x, y);
|
||||
|
||||
// Add error.
|
||||
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.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.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.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);
|
||||
|
||||
int r = pixel.r;
|
||||
int g = pixel.g;
|
||||
|
Loading…
Reference in New Issue
Block a user