diff options
| author | Krzysztof Kosi??ski <tweenk.pl@gmail.com> | 2010-07-23 14:44:54 +0000 |
|---|---|---|
| committer | Krzysztof KosiĆski <tweenk.pl@gmail.com> | 2010-07-23 14:44:54 +0000 |
| commit | 8446900929f553aa8956e2c1b85fdd3d05cd213f (patch) | |
| tree | f2eb2a756656f9af66ba32c73af687ed3a46abad /src | |
| parent | Matrix convolution filter (lazy version) (diff) | |
| download | inkscape-8446900929f553aa8956e2c1b85fdd3d05cd213f.tar.gz inkscape-8446900929f553aa8956e2c1b85fdd3d05cd213f.zip | |
Diffuse lighting filter
(bzr r9508.1.28)
Diffstat (limited to 'src')
| -rw-r--r-- | src/display/cairo-templates.h | 223 | ||||
| -rw-r--r-- | src/display/nr-3dutils.h | 16 | ||||
| -rw-r--r-- | src/display/nr-filter-convolve-matrix.cpp | 5 | ||||
| -rw-r--r-- | src/display/nr-filter-convolve-matrix.h | 1 | ||||
| -rw-r--r-- | src/display/nr-filter-diffuselighting.cpp | 244 | ||||
| -rw-r--r-- | src/display/nr-filter-diffuselighting.h | 21 | ||||
| -rw-r--r-- | src/display/nr-filter-slot.h | 3 | ||||
| -rw-r--r-- | src/filters/diffuselighting.cpp | 3 |
8 files changed, 361 insertions, 155 deletions
diff --git a/src/display/cairo-templates.h b/src/display/cairo-templates.h index fabe62579..8041d0229 100644 --- a/src/display/cairo-templates.h +++ b/src/display/cairo-templates.h @@ -15,12 +15,14 @@ #ifdef HAVE_OPENMP #include <omp.h> #include "preferences.h" +// single-threaded operation if the number of pixels is below this threshold #define OPENMP_THRESHOLD 4096 #endif #include <algorithm> #include <cairo.h> #include <glib.h> +#include "display/nr-3dutils.h" /** * @brief Blend two surfaces using the supplied functor. @@ -271,23 +273,30 @@ void ink_cairo_surface_filter(cairo_surface_t *in, cairo_surface_t *out, Filter cairo_surface_mark_dirty(out); } + +/** + * @brief Synthesize surface pixels based on their position. + * This template accepts a functor that gets called with the x and y coordinates of the pixels, + * given as integers. + * @param out Output surface + * @param out_area The region of the output surface that should be synthesized */ template <typename Synth> -void ink_cairo_surface_synthesize(cairo_surface_t *out, Synth synth) +void ink_cairo_surface_synthesize(cairo_surface_t *out, cairo_rectangle_t const &out_area, Synth synth) { // ASSUMPTIONS // 1. Cairo ARGB32 surface strides are always divisible by 4 // 2. We can only receive CAIRO_FORMAT_ARGB32 or CAIRO_FORMAT_A8 surfaces - int w = cairo_image_surface_get_width(out); - int h = cairo_image_surface_get_height(out); + int w = out_area.width; + int h = out_area.height; int strideout = cairo_image_surface_get_stride(out); int bppout = cairo_image_surface_get_format(out) == CAIRO_FORMAT_A8 ? 1 : 4; - int limit = w * h; // NOTE: fast path is not used, because we would need 2 divisions to get pixel indices - guint32 *const out_data = (guint32*) cairo_image_surface_get_data(out); + unsigned char *out_data = cairo_image_surface_get_data(out); #if HAVE_OPENMP + int limit = w * h; Inkscape::Preferences *prefs = Inkscape::Preferences::get(); int num_threads = prefs->getIntLimited("/options/threading/numthreads", omp_get_num_procs(), 1, 256); if (limit < OPENMP_THRESHOLD) num_threads = 1; // do not spawn threads for very small surfaces @@ -297,9 +306,9 @@ void ink_cairo_surface_synthesize(cairo_surface_t *out, Synth synth) #if HAVE_OPENMP #pragma omp parallel for num_threads(num_threads) #endif - for (int i = 0; i < h; ++i) { - guint32 *out_p = out_data + i * strideout/4; - for (int j = 0; j < w; ++j) { + for (int i = out_area.y; i < h; ++i) { + guint32 *out_p = reinterpret_cast<guint32*>(out_data + i * strideout); + for (int j = out_area.x; j < w; ++j) { *out_p = synth(j, i); ++out_p; } @@ -309,9 +318,9 @@ void ink_cairo_surface_synthesize(cairo_surface_t *out, Synth synth) #if HAVE_OPENMP #pragma omp parallel for num_threads(num_threads) #endif - for (int i = 0; i < h; ++i) { - guint8 *out_p = reinterpret_cast<guint8*>(out_data) + i * strideout; - for (int j = 0; j < w; ++j) { + for (int i = out_area.y; i < h; ++i) { + guint8 *out_p = out_data + i * strideout; + for (int j = out_area.x; j < w; ++j) { guint32 out_px = synth(j, i); *out_p = out_px >> 24; ++out_p; @@ -321,6 +330,196 @@ void ink_cairo_surface_synthesize(cairo_surface_t *out, Synth synth) cairo_surface_mark_dirty(out); } +template <typename Synth> +void ink_cairo_surface_synthesize(cairo_surface_t *out, Synth synth) +{ + int w = cairo_image_surface_get_width(out); + int h = cairo_image_surface_get_height(out); + + cairo_rectangle_t area; + area.x = 0; + area.y = 0; + area.width = w; + area.height = h; + + ink_cairo_surface_synthesize(out, area, synth); +} + +struct SurfaceSynth { + SurfaceSynth(cairo_surface_t *surface) + : _px(cairo_image_surface_get_data(surface)) + , _w(cairo_image_surface_get_width(surface)) + , _h(cairo_image_surface_get_height(surface)) + , _stride(cairo_image_surface_get_stride(surface)) + , _alpha(cairo_surface_get_content(surface) == CAIRO_CONTENT_ALPHA) + { + cairo_surface_flush(surface); + } +protected: + guint32 pixelAt(int x, int y) { + if (_alpha) { + unsigned char *px = _px + y*_stride + x; + return *px << 24; + } else { + unsigned char *px = _px + y*_stride + x*4; + return *reinterpret_cast<guint32*>(px); + } + } + guint32 alphaAt(int x, int y) { + if (_alpha) { + unsigned char *px = _px + y*_stride + x; + return *px; + } else { + unsigned char *px = _px + y*_stride + x*4; + guint32 p = *reinterpret_cast<guint32*>(px); + return (p & 0xff000000) >> 24; + } + } + 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. + NR::Fvector normal; + double fx = -scale/255.0, fy = -scale/255.0; + normal[Z_3D] = 1.0; + if (G_UNLIKELY(x == 0)) { + // leftmost column + if (G_UNLIKELY(y == 0)) { + // upper left corner + fx *= (2.0/3.0); + fy *= (2.0/3.0); + double p00 = alphaAt(x,y), p10 = alphaAt(x+1, y), + p01 = alphaAt(x,y+1), p11 = alphaAt(x+1, y+1); + normal[X_3D] = + -2.0 * p00 +2.0 * p10 + -1.0 * p01 +1.0 * p11; + normal[Y_3D] = + -2.0 * p00 -1.0 * p10 + +2.0 * p01 +1.0 * p11; + } else if (G_UNLIKELY(y == (_h - 1))) { + // lower left corner + fx *= (2.0/3.0); + fy *= (2.0/3.0); + double p00 = alphaAt(x,y-1), p10 = alphaAt(x+1, y-1), + p01 = alphaAt(x,y ), p11 = alphaAt(x+1, y); + normal[X_3D] = + -1.0 * p00 +1.0 * p10 + -2.0 * p01 +2.0 * p11; + normal[Y_3D] = + -2.0 * p00 -1.0 * p10 + +2.0 * p01 +1.0 * p11; + } else { + // leftmost column + fx *= (1.0/2.0); + fy *= (1.0/3.0); + double p00 = alphaAt(x, y-1), p10 = alphaAt(x+1, y-1), + p01 = alphaAt(x, y ), p11 = alphaAt(x+1, y ), + p02 = alphaAt(x, y+1), p12 = alphaAt(x+1, y+1); + normal[X_3D] = + -1.0 * p00 +1.0 * p10 + -2.0 * p01 +2.0 * p11 + -1.0 * p02 +1.0 * p12; + normal[Y_3D] = + -2.0 * p00 -1.0 * p10 + +0.0 * p01 +0.0 * p11 // this will be optimized out + +2.0 * p02 +1.0 * p12; + } + } else if (G_UNLIKELY(x == (_w - 1))) { + // rightmost column + if (G_UNLIKELY(y == 0)) { + // top right corner + fx *= (2.0/3.0); + fy *= (2.0/3.0); + double p00 = alphaAt(x-1,y), p10 = alphaAt(x, y), + p01 = alphaAt(x-1,y+1), p11 = alphaAt(x, y+1); + normal[X_3D] = + -2.0 * p00 +2.0 * p10 + -1.0 * p01 +1.0 * p11; + normal[Y_3D] = + -1.0 * p00 -2.0 * p10 + +1.0 * p01 +2.0 * p11; + } else if (G_UNLIKELY(y == (_h - 1))) { + // bottom right corner + fx *= (2.0/3.0); + fy *= (2.0/3.0); + double p00 = alphaAt(x-1,y-1), p10 = alphaAt(x, y-1), + p01 = alphaAt(x-1,y ), p11 = alphaAt(x, y); + normal[X_3D] = + -1.0 * p00 +1.0 * p10 + -2.0 * p01 +2.0 * p11; + normal[Y_3D] = + -1.0 * p00 -2.0 * p10 + +1.0 * p01 +2.0 * p11; + } else { + // rightmost column + fx *= (1.0/2.0); + fy *= (1.0/3.0); + double p00 = alphaAt(x-1, y-1), p10 = alphaAt(x, y-1), + p01 = alphaAt(x-1, y ), p11 = alphaAt(x, y ), + p02 = alphaAt(x-1, y+1), p12 = alphaAt(x, y+1); + normal[X_3D] = + -1.0 * p00 +1.0 * p10 + -2.0 * p01 +2.0 * p11 + -1.0 * p02 +1.0 * p12; + normal[Y_3D] = + -1.0 * p00 -2.0 * p10 + +0.0 * p01 +0.0 * p11 + +1.0 * p02 +2.0 * p12; + } + } else { + // interior + if (G_UNLIKELY(y == 0)) { + // top row + fx *= (1.0/3.0); + fy *= (1.0/2.0); + double p00 = alphaAt(x-1, y ), p10 = alphaAt(x, y ), p20 = alphaAt(x+1, y ), + p01 = alphaAt(x-1, y+1), p11 = alphaAt(x, y+1), p21 = alphaAt(x+1, y+1); + normal[X_3D] = + -2.0 * p00 +0.0 * p10 +2.0 * p20 + -1.0 * p01 +0.0 * p11 +1.0 * p21; + normal[Y_3D] = + -1.0 * p00 -2.0 * p10 -1.0 * p20 + +1.0 * p01 +2.0 * p11 +1.0 * p21; + } else if (G_UNLIKELY(y == (_h - 1))) { + // bottom row + fx *= (1.0/3.0); + fy *= (1.0/2.0); + double p00 = alphaAt(x-1, y-1), p10 = alphaAt(x, y-1), p20 = alphaAt(x+1, y-1), + p01 = alphaAt(x-1, y ), p11 = alphaAt(x, y ), p21 = alphaAt(x+1, y ); + normal[X_3D] = + -1.0 * p00 +0.0 * p10 +1.0 * p20 + -2.0 * p01 +0.0 * p11 +2.0 * p21; + normal[Y_3D] = + -1.0 * p00 -2.0 * p10 -1.0 * p20 + +1.0 * p01 +2.0 * p11 +1.0 * p21; + } else { + // interior pixels + fx *= (1.0/4.0); + fy *= (1.0/4.0); + double p00 = alphaAt(x-1, y-1), p10 = alphaAt(x, y-1), p20 = alphaAt(x+1, y-1), + p01 = alphaAt(x-1, y ), p11 = alphaAt(x, y ), p21 = alphaAt(x+1, y ), + p02 = alphaAt(x-1, y+1), p12 = alphaAt(x, y+1), p22 = alphaAt(x+1, y+1); + normal[X_3D] = + -1.0 * p00 +0.0 * p10 +1.0 * p20 + -2.0 * p01 +0.0 * p11 +2.0 * p21 + -1.0 * p02 +0.0 * p12 +1.0 * p22; + normal[Y_3D] = + -1.0 * p00 -2.0 * p10 -1.0 * p20 + +0.0 * p01 +0.0 * p11 +0.0 * p21 + +1.0 * p02 +2.0 * p12 +1.0 * p22; + } + } + normal[X_3D] *= fx; + normal[Y_3D] *= fy; + NR::normalize_vector(normal); + return normal; + } + + unsigned char *_px; + int _w, _h, _stride; + bool _alpha; +}; + +/* // simple pixel accessor for image surface that handles different edge wrapping modes class PixelAccessor { public: @@ -374,7 +573,7 @@ private: int _x, _y, _w, _h, _stride; EdgeMode _edge_mode; bool _alpha; -}; +};*/ // Some helpers for pixel manipulation diff --git a/src/display/nr-3dutils.h b/src/display/nr-3dutils.h index dbbc7c9a4..42df36c82 100644 --- a/src/display/nr-3dutils.h +++ b/src/display/nr-3dutils.h @@ -28,12 +28,24 @@ namespace NR { /** * a type of 3 gdouble components vectors */ -typedef gdouble Fvector[3]; +struct Fvector { + Fvector() { + v[0] = v[1] = v[2] = 0.0; + } + Fvector(double x, double y, double z) { + v[0] = x; + v[1] = y; + v[2] = z; + } + double v[3]; + double &operator[](unsigned i) { return v[i]; } + double operator[](unsigned i) const { return v[i]; } +}; /** * The eye vector */ -const static Fvector EYE_VECTOR = {0, 0, 1}; +const static Fvector EYE_VECTOR(0, 0, 1); /** * returns the euclidian norm of the vector v diff --git a/src/display/nr-filter-convolve-matrix.cpp b/src/display/nr-filter-convolve-matrix.cpp index 267aae936..fcb15ee98 100644 --- a/src/display/nr-filter-convolve-matrix.cpp +++ b/src/display/nr-filter-convolve-matrix.cpp @@ -247,11 +247,6 @@ void FilterConvolveMatrix::render_cairo(FilterSlot &slot) cairo_surface_destroy(out); } -bool FilterConvolveMatrix::can_handle_affine(Geom::Matrix const &) -{ - return false; -} - void FilterConvolveMatrix::set_targetX(int coord) { targetX = coord; } diff --git a/src/display/nr-filter-convolve-matrix.h b/src/display/nr-filter-convolve-matrix.h index 904cb30e9..d1fc9c364 100644 --- a/src/display/nr-filter-convolve-matrix.h +++ b/src/display/nr-filter-convolve-matrix.h @@ -35,7 +35,6 @@ public: virtual ~FilterConvolveMatrix(); virtual void render_cairo(FilterSlot &slot); - virtual bool can_handle_affine(Geom::Matrix const &); virtual void area_enlarge(NRRectL &area, Geom::Matrix const &trans); void set_targetY(int coord); diff --git a/src/display/nr-filter-diffuselighting.cpp b/src/display/nr-filter-diffuselighting.cpp index 0fe4c5947..04de6ebf9 100644 --- a/src/display/nr-filter-diffuselighting.cpp +++ b/src/display/nr-filter-diffuselighting.cpp @@ -12,6 +12,8 @@ #include <glib/gmessages.h> +#include "display/cairo-templates.h" +#include "display/cairo-utils.h" #include "display/nr-3dutils.h" #include "display/nr-arena-item.h" #include "display/nr-filter-diffuselighting.h" @@ -43,129 +45,131 @@ FilterPrimitive * FilterDiffuseLighting::create() { FilterDiffuseLighting::~FilterDiffuseLighting() {} -int FilterDiffuseLighting::render(FilterSlot &slot, FilterUnits const &units) { - NRPixBlock *in = slot.get(_input); - if (!in) { - g_warning("Missing source image for feDiffuseLighting (in=%d)", _input); - return 1; +struct DiffuseDistantLight : public SurfaceSynth { + DiffuseDistantLight(cairo_surface_t *bumpmap, SPFeDistantLight *light, guint32 color, + double scale, double diffuse_constant) + : SurfaceSynth(bumpmap) + , _scale(scale) + , _kd(diffuse_constant) + { + DistantLight dl(light, color); + dl.light_vector(_lightv); + dl.light_components(_light_components); } - NRPixBlock *out = new NRPixBlock; - - int w = in->area.x1 - in->area.x0; - int h = in->area.y1 - in->area.y0; - int x0 = in->area.x0; - int y0 = in->area.y0; - int i, j; - //As long as FilterRes and kernel unit is not supported we hardcode the - //default value - int dx = 1; //TODO setup - int dy = 1; //TODO setup - //surface scale - Geom::Matrix trans = units.get_matrix_primitiveunits2pb(); - gdouble ss = surfaceScale * trans[0]; - gdouble kd = diffuseConstant; //diffuse lighting constant - - NR::Fvector L, N, LC; - gdouble inter; - - nr_pixblock_setup_fast(out, in->mode, - in->area.x0, in->area.y0, in->area.x1, in->area.y1, - true); - unsigned char *data_i = NR_PIXBLOCK_PX (in); - unsigned char *data_o = NR_PIXBLOCK_PX (out); - //No light, nothing to do + guint32 operator()(int x, int y) { + NR::Fvector normal = surfaceNormalAt(x, y, _scale); + double k = _kd * NR::scalar_product(normal, _lightv); + + guint32 r = CLAMP_D_TO_U8(k * _light_components[LIGHT_RED]); + guint32 g = CLAMP_D_TO_U8(k * _light_components[LIGHT_GREEN]); + guint32 b = CLAMP_D_TO_U8(k * _light_components[LIGHT_BLUE]); + + ASSEMBLE_ARGB32(pxout, 255,r,g,b) + return pxout; + } +private: + NR::Fvector _lightv, _light_components; + double _scale, _kd; +}; + +struct DiffusePointLight : public SurfaceSynth { + DiffusePointLight(cairo_surface_t *bumpmap, SPFePointLight *light, guint32 color, + Geom::Matrix const &trans, double scale, double diffuse_constant, double x0, double y0) + : SurfaceSynth(bumpmap) + , _light(light, color, trans) + , _scale(scale) + , _kd(diffuse_constant) + , _x0(x0) + , _y0(y0) + { + _light.light_components(_light_components); + } + + guint32 operator()(int x, int y) { + NR::Fvector normal = surfaceNormalAt(x, y, _scale); + NR::Fvector light; + _light.light_vector(light, _x0 + x, _y0 + y, alphaAt(x, y)/255.0); + double k = _kd * NR::scalar_product(normal, light); + + guint32 r = CLAMP_D_TO_U8(k * _light_components[LIGHT_RED]); + guint32 g = CLAMP_D_TO_U8(k * _light_components[LIGHT_GREEN]); + guint32 b = CLAMP_D_TO_U8(k * _light_components[LIGHT_BLUE]); + + ASSEMBLE_ARGB32(pxout, 255,r,g,b) + return pxout; + } +private: + PointLight _light; + NR::Fvector _light_components; + double _scale, _kd, _x0, _y0; +}; + +struct DiffuseSpotLight : public SurfaceSynth { + DiffuseSpotLight(cairo_surface_t *bumpmap, SPFeSpotLight *light, guint32 color, + Geom::Matrix const &trans, double scale, double diffuse_constant, double x0, double y0) + : SurfaceSynth(bumpmap) + , _light(light, color, trans) + , _scale(scale) + , _kd(diffuse_constant) + , _x0(x0) + , _y0(y0) + {} + + guint32 operator()(int x, int y) { + NR::Fvector normal = surfaceNormalAt(x, y, _scale); + NR::Fvector light; + NR::Fvector light_components; + _light.light_vector(light, _x0 + x, _y0 + y, alphaAt(x, y)/255.0); + _light.light_components(light_components, light); + double k = _kd * NR::scalar_product(normal, light); + + guint32 r = CLAMP_D_TO_U8(k * light_components[LIGHT_RED]); + guint32 g = CLAMP_D_TO_U8(k * light_components[LIGHT_GREEN]); + guint32 b = CLAMP_D_TO_U8(k * light_components[LIGHT_BLUE]); + + ASSEMBLE_ARGB32(pxout, 255,r,g,b) + return pxout; + } +private: + SpotLight _light; + double _scale, _kd, _x0, _y0; +}; + +void FilterDiffuseLighting::render_cairo(FilterSlot &slot) +{ + cairo_surface_t *input = slot.getcairo(_input); + cairo_surface_t *out = ink_cairo_surface_create_same_size(input, CAIRO_CONTENT_COLOR_ALPHA); + + NRRectL const &slot_area = slot.get_slot_area(); + Geom::Matrix trans = slot.get_units().get_matrix_primitiveunits2pb(); + double x0 = slot_area.x0, y0 = slot_area.y0; + double scale = surfaceScale * trans[0]; + switch (light_type) { - case DISTANT_LIGHT: - //the light vector is constant - { - DistantLight *dl = new DistantLight(light.distant, lighting_color); - dl->light_vector(L); - dl->light_components(LC); - //finish the work - for (i = 0, j = 0; i < w*h; i++) { - NR::compute_surface_normal(N, ss, in, i / w, i % w, dx, dy); - inter = kd * NR::scalar_product(N, L); - - data_o[j++] = CLAMP_D_TO_U8(inter * LC[LIGHT_RED]); // CLAMP includes rounding! - data_o[j++] = CLAMP_D_TO_U8(inter * LC[LIGHT_GREEN]); - data_o[j++] = CLAMP_D_TO_U8(inter * LC[LIGHT_BLUE]); - data_o[j++] = 255; - } - out->empty = FALSE; - delete dl; - } - break; - case POINT_LIGHT: - { - PointLight *pl = new PointLight(light.point, lighting_color, trans); - pl->light_components(LC); - //TODO we need a reference to the filter to determine primitiveUnits - //if objectBoundingBox is used, use a different matrix for light_vector - // UPDATE: trans is now correct matrix from primitiveUnits to - // pixblock coordinates - //finish the work - for (i = 0, j = 0; i < w*h; i++) { - NR::compute_surface_normal(N, ss, in, i / w, i % w, dx, dy); - pl->light_vector(L, - i % w + x0, - i / w + y0, - ss * (double) data_i[4*i+3]/ 255); - inter = kd * NR::scalar_product(N, L); - - data_o[j++] = CLAMP_D_TO_U8(inter * LC[LIGHT_RED]); - data_o[j++] = CLAMP_D_TO_U8(inter * LC[LIGHT_GREEN]); - data_o[j++] = CLAMP_D_TO_U8(inter * LC[LIGHT_BLUE]); - data_o[j++] = 255; - } - out->empty = FALSE; - delete pl; - } - break; - case SPOT_LIGHT: - { - SpotLight *sl = new SpotLight(light.spot, lighting_color, trans); - //TODO we need a reference to the filter to determine primitiveUnits - //if objectBoundingBox is used, use a different matrix for light_vector - // UPDATE: trans is now correct matrix from primitiveUnits to - // pixblock coordinates - //finish the work - for (i = 0, j = 0; i < w*h; i++) { - NR::compute_surface_normal(N, ss, in, i / w, i % w, dx, dy); - sl->light_vector(L, - i % w + x0, - i / w + y0, - ss * (double) data_i[4*i+3]/ 255); - sl->light_components(LC, L); - inter = kd * NR::scalar_product(N, L); - - data_o[j++] = CLAMP_D_TO_U8(inter * LC[LIGHT_RED]); - data_o[j++] = CLAMP_D_TO_U8(inter * LC[LIGHT_GREEN]); - data_o[j++] = CLAMP_D_TO_U8(inter * LC[LIGHT_BLUE]); - data_o[j++] = 255; - } - out->empty = FALSE; - delete sl; - } - break; - //else unknown light source, doing nothing - case NO_LIGHT: - default: - { - if (light_type != NO_LIGHT) - g_warning("unknown light source %d", light_type); - for (i = 0; i < w*h; i++) { - data_o[4*i+3] = 255; - } - out->empty = false; - } + case DISTANT_LIGHT: + ink_cairo_surface_synthesize(out, + DiffuseDistantLight(input, light.distant, lighting_color, scale, diffuseConstant)); + break; + case POINT_LIGHT: + ink_cairo_surface_synthesize(out, + DiffusePointLight(input, light.point, lighting_color, trans, scale, diffuseConstant, x0, y0)); + break; + case SPOT_LIGHT: + ink_cairo_surface_synthesize(out, + DiffuseSpotLight(input, light.spot, lighting_color, trans, scale, diffuseConstant, x0, y0)); + break; + default: { + cairo_t *ct = cairo_create(out); + cairo_set_source_rgba(ct, 0,0,0,1); + cairo_set_operator(ct, CAIRO_OPERATOR_SOURCE); + cairo_paint(ct); + cairo_destroy(ct); + } break; } - - //finishing + slot.set(_output, out); - //nr_pixblock_release(in); - //delete in; - return 0; + cairo_surface_destroy(out); } void FilterDiffuseLighting::area_enlarge(NRRectL &area, Geom::Matrix const &trans) @@ -181,10 +185,6 @@ void FilterDiffuseLighting::area_enlarge(NRRectL &area, Geom::Matrix const &tran area.y1 += (int)(scaley) + 2; } -FilterTraits FilterDiffuseLighting::get_input_traits() { - return TRAIT_PARALLER; -} - } /* namespace Filters */ } /* namespace Inkscape */ diff --git a/src/display/nr-filter-diffuselighting.h b/src/display/nr-filter-diffuselighting.h index 708c7a0a2..6e46bc1e1 100644 --- a/src/display/nr-filter-diffuselighting.h +++ b/src/display/nr-filter-diffuselighting.h @@ -18,16 +18,22 @@ #include "display/nr-filter-primitive.h" #include "display/nr-filter-slot.h" #include "display/nr-filter-units.h" -#include "filters/distantlight.h" -#include "filters/pointlight.h" -#include "filters/spotlight.h" -#include "color.h" + +class SPFeDistantLight; +class SPFePointLight; +class SPFeSpotLight; namespace Inkscape { namespace Filters { class FilterDiffuseLighting : public FilterPrimitive { public: + FilterDiffuseLighting(); + static FilterPrimitive *create(); + virtual ~FilterDiffuseLighting(); + virtual void render_cairo(FilterSlot &slot); + virtual void area_enlarge(NRRectL &area, Geom::Matrix const &trans); + union { SPFeDistantLight *distant; SPFePointLight *point; @@ -37,13 +43,6 @@ public: gdouble diffuseConstant; gdouble surfaceScale; guint32 lighting_color; - - FilterDiffuseLighting(); - static FilterPrimitive *create(); - virtual ~FilterDiffuseLighting(); - virtual int render(FilterSlot &slot, FilterUnits const &units); - virtual void area_enlarge(NRRectL &area, Geom::Matrix const &trans); - virtual FilterTraits get_input_traits(); private: }; diff --git a/src/display/nr-filter-slot.h b/src/display/nr-filter-slot.h index 92f66ddf8..a9fac61d9 100644 --- a/src/display/nr-filter-slot.h +++ b/src/display/nr-filter-slot.h @@ -62,8 +62,6 @@ public: cairo_surface_t *get_result(int slot_nr); - NRRectL const *get_slot_area(); - /** Returns the number of slots in use. */ int get_slot_count(); @@ -80,6 +78,7 @@ public: int get_blurquality(void); FilterUnits const &get_units() const { return _units; } + NRRectL const &get_slot_area() const { return _slot_area; } private: typedef std::map<int, cairo_surface_t *> SlotMap; diff --git a/src/filters/diffuselighting.cpp b/src/filters/diffuselighting.cpp index 117b9d145..59b00d183 100644 --- a/src/filters/diffuselighting.cpp +++ b/src/filters/diffuselighting.cpp @@ -24,6 +24,9 @@ #include "sp-object.h" #include "svg/svg-color.h" #include "filters/diffuselighting.h" +#include "filters/distantlight.h" +#include "filters/pointlight.h" +#include "filters/spotlight.h" #include "display/nr-filter.h" #include "xml/repr.h" #include "display/nr-filter-diffuselighting.h" |
