summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorKrzysztof Kosi??ski <tweenk.pl@gmail.com>2010-07-23 21:58:44 +0000
committerKrzysztof KosiƄski <tweenk.pl@gmail.com>2010-07-23 21:58:44 +0000
commitf146c69978df15996df79962ee8110e10fc1617d (patch)
tree046b9902578f4021e4e55a772181fc83dd703f1d /src
parentSpecular lighting filter (diff)
downloadinkscape-f146c69978df15996df79962ee8110e10fc1617d.tar.gz
inkscape-f146c69978df15996df79962ee8110e10fc1617d.zip
Displacement map filter
(bzr r9508.1.30)
Diffstat (limited to 'src')
-rw-r--r--src/display/cairo-templates.h68
-rw-r--r--src/display/nr-filter-convolve-matrix.cpp9
-rw-r--r--src/display/nr-filter-displacement-map.cpp91
-rw-r--r--src/display/nr-filter-displacement-map.h6
-rw-r--r--src/display/nr-filter-specularlighting.cpp15
-rw-r--r--src/display/nr-filter-specularlighting.h5
6 files changed, 161 insertions, 33 deletions
diff --git a/src/display/cairo-templates.h b/src/display/cairo-templates.h
index 9c2a8c782..8855c65fc 100644
--- a/src/display/cairo-templates.h
+++ b/src/display/cairo-templates.h
@@ -22,6 +22,7 @@
#include <algorithm>
#include <cairo.h>
#include <glib.h>
+#include <math.h>
#include "display/nr-3dutils.h"
/**
@@ -356,7 +357,7 @@ struct SurfaceSynth {
{
cairo_surface_flush(surface);
}
-protected:
+
guint32 pixelAt(int x, int y) {
if (_alpha) {
unsigned char *px = _px + y*_stride + x;
@@ -376,9 +377,74 @@ protected:
return (p & 0xff000000) >> 24;
}
}
+
+ // retrieve a pixel value with bilinear interpolation
+ guint32 pixelAt(double x, double y) {
+ if (_alpha) {
+ return alphaAt(x, y) << 24;
+ }
+
+ double xf = floor(x), yf = floor(y);
+ int xi = xf, yi = yf;
+ guint32 xif = round((x - xf) * 255), yif = round((y - yf) * 255);
+ guint32 p00, p01, p10, p11;
+
+ unsigned char *pxi = _px + yi*_stride + xi*4;
+ guint32 *pxu = reinterpret_cast<guint32*>(pxi);
+ guint32 *pxl = reinterpret_cast<guint32*>(pxi + _stride);
+ p00 = *pxu; p10 = *(pxu + 1);
+ p01 = *pxl; p11 = *(pxl + 1);
+
+ guint32 comp[4];
+
+ for (unsigned i = 0; i < 4; ++i) {
+ guint32 shift = i*8;
+ guint32 mask = 0xff << shift;
+ guint32 c00 = (p00 & mask) >> shift;
+ guint32 c10 = (p10 & mask) >> shift;
+ guint32 c01 = (p01 & mask) >> shift;
+ guint32 c11 = (p11 & mask) >> shift;
+
+ guint32 iu = (255-xif) * c00 + xif * c10;
+ guint32 il = (255-xif) * c01 + xif * c11;
+ comp[i] = (255-yif) * iu + yif * il;
+ comp[i] = (comp[i] + (255*255/2)) / (255*255);
+ }
+
+ guint32 result = comp[0] | (comp[1] << 8) | (comp[2] << 16) | (comp[3] << 24);
+ return result;
+ }
+
+ // retrieve an alpha value with bilinear interpolation
+ guint32 alphaAt(double x, double y) {
+ double xf = floor(x), yf = floor(y);
+ int xi = xf, yi = yf;
+ guint32 xif = round((x - xf) * 255), yif = round((y - yf) * 255);
+ guint32 p00, p01, p10, p11;
+ if (_alpha) {
+ unsigned char *pxu = _px + yi*_stride + xi;
+ unsigned char *pxl = pxu + _stride;
+ p00 = *pxu; p10 = *(pxu + 1);
+ p01 = *pxl; p11 = *(pxl + 1);
+ } else {
+ unsigned char *pxi = _px + yi*_stride + xi*4;
+ guint32 *pxu = reinterpret_cast<guint32*>(pxi);
+ guint32 *pxl = reinterpret_cast<guint32*>(pxi + _stride);
+ p00 = (*pxu & 0xff000000) >> 24; p10 = (*(pxu + 1) & 0xff000000) >> 24;
+ p01 = (*pxl & 0xff000000) >> 24; p11 = (*(pxl + 1) & 0xff000000) >> 24;
+ }
+ guint32 iu = (255-xif) * p00 + xif * p10;
+ guint32 il = (255-xif) * p01 + xif * p11;
+ guint32 result = (255-yif) * iu + yif * il;
+ result = (result + (255*255/2)) / (255*255);
+ return result;
+ }
+
+ // compute surface normal at given coordinates using 3x3 Sobel gradient filter
NR::Fvector surfaceNormalAt(int x, int y, double scale) {
// Below there are some multiplies by zero. They will be optimized out.
// Do not remove them, because they improve readability.
+ // NOTE: fetching using alphaAt is slightly lazy.
NR::Fvector normal;
double fx = -scale/255.0, fy = -scale/255.0;
normal[Z_3D] = 1.0;
diff --git a/src/display/nr-filter-convolve-matrix.cpp b/src/display/nr-filter-convolve-matrix.cpp
index fcb15ee98..6647c6273 100644
--- a/src/display/nr-filter-convolve-matrix.cpp
+++ b/src/display/nr-filter-convolve-matrix.cpp
@@ -191,6 +191,9 @@ private:
void FilterConvolveMatrix::render_cairo(FilterSlot &slot)
{
+ static bool bias_warning = false;
+ static bool edge_warning = false;
+
cairo_surface_t *input = slot.getcairo(_input);
if (orderX<=0 || orderY<=0) {
@@ -208,9 +211,10 @@ void FilterConvolveMatrix::render_cairo(FilterSlot &slot)
cairo_surface_t *out = ink_cairo_surface_create_identical(input);
- if (bias!=0) {
+ if (bias!=0 && !bias_warning) {
g_warning("It is unknown whether Inkscape's implementation of bias in feConvolveMatrix "
"is correct!");
+ bias_warning = true;
// The SVG specification implies that feConvolveMatrix is defined for premultiplied
// colors (which makes sense). It also says that bias should simply be added to the result
// for each color (without taking the alpha into account). However, it also says that one
@@ -219,8 +223,9 @@ void FilterConvolveMatrix::render_cairo(FilterSlot &slot)
// but this does appear to go against the standard.
// Note that Batik simply does not support bias!=0
}
- if (edgeMode!=CONVOLVEMATRIX_EDGEMODE_NONE) {
+ if (edgeMode!=CONVOLVEMATRIX_EDGEMODE_NONE && !edge_warning) {
g_warning("Inkscape only supports edgeMode=\"none\" (and a filter uses a different one)!");
+ edge_warning = true;
}
guint32 *in_data = reinterpret_cast<guint32*>(cairo_image_surface_get_data(input));
diff --git a/src/display/nr-filter-displacement-map.cpp b/src/display/nr-filter-displacement-map.cpp
index a983fb840..15d590444 100644
--- a/src/display/nr-filter-displacement-map.cpp
+++ b/src/display/nr-filter-displacement-map.cpp
@@ -9,11 +9,11 @@
* Released under GNU GPL, read the file 'COPYING' for more information
*/
+#include "display/cairo-templates.h"
+#include "display/cairo-utils.h"
#include "display/nr-filter-displacement-map.h"
#include "display/nr-filter-types.h"
#include "display/nr-filter-units.h"
-#include "libnr/nr-blit.h"
-#include "libnr/nr-pixops.h"
namespace Inkscape {
namespace Filters {
@@ -28,6 +28,7 @@ FilterPrimitive * FilterDisplacementMap::create() {
FilterDisplacementMap::~FilterDisplacementMap()
{}
+#if 0
struct pixel_t {
unsigned char channels[4];
inline unsigned char operator[](int c) const { return channels[c]; }
@@ -147,7 +148,65 @@ static void performDisplacement(NRPixBlock const* texture, NRPixBlock const* map
}
}
}
+#endif
+
+struct Displace {
+ Displace(cairo_surface_t *texture, cairo_surface_t *map,
+ unsigned xch, unsigned ych, double scalex, double scaley)
+ : _texture(texture)
+ , _map(map)
+ , _xch(xch)
+ , _ych(ych)
+ , _scalex(scalex/255.0)
+ , _scaley(scaley/255.0)
+ {}
+ guint32 operator()(int x, int y) {
+ guint32 mappx = _map.pixelAt(x, y);
+ guint32 a = (mappx & 0xff000000) >> 24;
+ guint32 xpx = 0, ypx = 0;
+ double xtex = x, ytex = y;
+ if (a) {
+ guint32 xshift = _xch * 8, yshift = _ych * 8;
+ xpx = (mappx & (0xff << xshift)) >> xshift;
+ ypx = (mappx & (0xff << yshift)) >> yshift;
+ if (_xch != 3) xpx = unpremul_alpha(xpx, a);
+ if (_ych != 3) ypx = unpremul_alpha(ypx, a);
+ xtex += _scalex * (xpx - 127.5);
+ ytex += _scaley * (ypx - 127.5);
+ }
+
+ if (xtex >= 0 && xtex < (_texture._w - 1) &&
+ ytex >= 0 && ytex < (_texture._h - 1))
+ {
+ return _texture.pixelAt(xtex, ytex);
+ } else {
+ return 0;
+ }
+ }
+private:
+ SurfaceSynth _texture;
+ SurfaceSynth _map;
+ unsigned _xch, _ych;
+ double _scalex, _scaley;
+};
+
+void FilterDisplacementMap::render_cairo(FilterSlot &slot)
+{
+ cairo_surface_t *texture = slot.getcairo(_input);
+ cairo_surface_t *map = slot.getcairo(_input2);
+ cairo_surface_t *out = ink_cairo_surface_create_identical(texture);
+
+ Geom::Matrix trans = slot.get_units().get_matrix_primitiveunits2pb();
+ double scalex = scale * trans.expansionX();
+ double scaley = scale * trans.expansionY();
+
+ ink_cairo_surface_synthesize(out, Displace(texture, map, Xchannel, Ychannel, scalex, scaley));
+
+ slot.set(_output, out);
+ cairo_surface_destroy(out);
+}
+/*
int FilterDisplacementMap::render(FilterSlot &slot, FilterUnits const &units) {
NRPixBlock *texture = slot.get(_input);
NRPixBlock *map = slot.get(_input2);
@@ -212,7 +271,7 @@ int FilterDisplacementMap::render(FilterSlot &slot, FilterUnits const &units) {
out->empty = FALSE;
slot.set(_output, out);
return 0;
-}
+}*/
void FilterDisplacementMap::set_input(int slot) {
_input = slot;
@@ -233,8 +292,26 @@ void FilterDisplacementMap::set_channel_selector(int s, FilterDisplacementMapCha
return;
}
- if (s == 0) Xchannel = channel;
- if (s == 1) Ychannel = channel;
+ // channel numbering:
+ // a = 3, r = 2, g = 1, b = 0
+ // this way we can get the component value using:
+ // component = (color & (ch*8)) >> (ch*8)
+ unsigned ch = 4;
+ switch (channel) {
+ case DISPLACEMENTMAP_CHANNEL_ALPHA:
+ ch = 3; break;
+ case DISPLACEMENTMAP_CHANNEL_RED:
+ ch = 2; break;
+ case DISPLACEMENTMAP_CHANNEL_GREEN:
+ ch = 1; break;
+ case DISPLACEMENTMAP_CHANNEL_BLUE:
+ ch = 0; break;
+ default: break;
+ }
+ if (ch == 4) return;
+
+ if (s == 0) Xchannel = ch;
+ if (s == 1) Ychannel = ch;
}
void FilterDisplacementMap::area_enlarge(NRRectL &area, Geom::Matrix const &trans)
@@ -252,10 +329,6 @@ void FilterDisplacementMap::area_enlarge(NRRectL &area, Geom::Matrix const &tran
area.y1 += (int)(scaley)+2;
}
-FilterTraits FilterDisplacementMap::get_input_traits() {
- return TRAIT_PARALLER;
-}
-
} /* namespace Filters */
} /* namespace Inkscape */
diff --git a/src/display/nr-filter-displacement-map.h b/src/display/nr-filter-displacement-map.h
index bb15b77a3..29f38d604 100644
--- a/src/display/nr-filter-displacement-map.h
+++ b/src/display/nr-filter-displacement-map.h
@@ -31,15 +31,13 @@ public:
virtual void set_input(int input, int slot);
virtual void set_scale(double s);
virtual void set_channel_selector(int s, FilterDisplacementMapChannelSelector channel);
- virtual int render(FilterSlot &slot, FilterUnits const &units);
+ virtual void render_cairo(FilterSlot &slot);
virtual void area_enlarge(NRRectL &area, Geom::Matrix const &trans);
- virtual FilterTraits get_input_traits();
private:
double scale;
int _input2;
- FilterDisplacementMapChannelSelector Xchannel;
- FilterDisplacementMapChannelSelector Ychannel;
+ unsigned Xchannel, Ychannel;
};
} /* namespace Filters */
diff --git a/src/display/nr-filter-specularlighting.cpp b/src/display/nr-filter-specularlighting.cpp
index 23b9b20ac..758b28979 100644
--- a/src/display/nr-filter-specularlighting.cpp
+++ b/src/display/nr-filter-specularlighting.cpp
@@ -17,7 +17,6 @@
#include "display/cairo-utils.h"
#include "display/nr-3dutils.h"
#include "display/nr-filter-specularlighting.h"
-#include "display/nr-filter-getalpha.h"
#include "display/nr-filter-slot.h"
#include "display/nr-filter-units.h"
#include "display/nr-filter-utils.h"
@@ -43,20 +42,6 @@ FilterPrimitive * FilterSpecularLighting::create() {
FilterSpecularLighting::~FilterSpecularLighting()
{}
-//Investigating Phong Lighting model we should not take N.H but
-//R.E which equals to 2*N.H^2 - 1
-//replace the second line by
-//gdouble scal = scalar_product((N), (H)); scal = 2 * scal * scal - 1;
-//to get the expected formula
-#define COMPUTE_INTER(inter, H, N, ks, speculaExponent) \
-do {\
- gdouble scal = NR::scalar_product((N), (H)); \
- if (scal <= 0)\
- (inter) = 0;\
- else\
- (inter) = (ks) * std::pow(scal, (specularExponent));\
-}while(0)
-
struct SpecularLight : public SurfaceSynth {
SpecularLight(cairo_surface_t *bumpmap, double scale, double specular_constant,
double specular_exponent)
diff --git a/src/display/nr-filter-specularlighting.h b/src/display/nr-filter-specularlighting.h
index a350c4b29..6622b6add 100644
--- a/src/display/nr-filter-specularlighting.h
+++ b/src/display/nr-filter-specularlighting.h
@@ -16,7 +16,6 @@
#include <gdk/gdktypes.h>
#include "display/nr-light-types.h"
#include "display/nr-filter-primitive.h"
-#include "display/nr-filter-slot.h"
class SPFeDistantLight;
class SPFePointLight;
@@ -24,7 +23,9 @@ class SPFeSpotLight;
namespace Inkscape {
namespace Filters {
-
+
+class FilterSlot;
+
class FilterSpecularLighting : public FilterPrimitive {
public:
FilterSpecularLighting();