summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorKrzysztof Kosi??ski <tweenk.pl@gmail.com>2010-07-23 14:44:54 +0000
committerKrzysztof KosiƄski <tweenk.pl@gmail.com>2010-07-23 14:44:54 +0000
commit8446900929f553aa8956e2c1b85fdd3d05cd213f (patch)
treef2eb2a756656f9af66ba32c73af687ed3a46abad /src
parentMatrix convolution filter (lazy version) (diff)
downloadinkscape-8446900929f553aa8956e2c1b85fdd3d05cd213f.tar.gz
inkscape-8446900929f553aa8956e2c1b85fdd3d05cd213f.zip
Diffuse lighting filter
(bzr r9508.1.28)
Diffstat (limited to 'src')
-rw-r--r--src/display/cairo-templates.h223
-rw-r--r--src/display/nr-3dutils.h16
-rw-r--r--src/display/nr-filter-convolve-matrix.cpp5
-rw-r--r--src/display/nr-filter-convolve-matrix.h1
-rw-r--r--src/display/nr-filter-diffuselighting.cpp244
-rw-r--r--src/display/nr-filter-diffuselighting.h21
-rw-r--r--src/display/nr-filter-slot.h3
-rw-r--r--src/filters/diffuselighting.cpp3
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"