diff options
| author | Krzysztof Kosi??ski <tweenk.pl@gmail.com> | 2010-07-23 21:58:44 +0000 |
|---|---|---|
| committer | Krzysztof KosiĆski <tweenk.pl@gmail.com> | 2010-07-23 21:58:44 +0000 |
| commit | f146c69978df15996df79962ee8110e10fc1617d (patch) | |
| tree | 046b9902578f4021e4e55a772181fc83dd703f1d /src | |
| parent | Specular lighting filter (diff) | |
| download | inkscape-f146c69978df15996df79962ee8110e10fc1617d.tar.gz inkscape-f146c69978df15996df79962ee8110e10fc1617d.zip | |
Displacement map filter
(bzr r9508.1.30)
Diffstat (limited to 'src')
| -rw-r--r-- | src/display/cairo-templates.h | 68 | ||||
| -rw-r--r-- | src/display/nr-filter-convolve-matrix.cpp | 9 | ||||
| -rw-r--r-- | src/display/nr-filter-displacement-map.cpp | 91 | ||||
| -rw-r--r-- | src/display/nr-filter-displacement-map.h | 6 | ||||
| -rw-r--r-- | src/display/nr-filter-specularlighting.cpp | 15 | ||||
| -rw-r--r-- | src/display/nr-filter-specularlighting.h | 5 |
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(); |
