summaryrefslogtreecommitdiffstats
path: root/src/display
diff options
context:
space:
mode:
Diffstat (limited to 'src/display')
-rw-r--r--src/display/Makefile_insert11
-rw-r--r--src/display/nr-3dutils.cpp185
-rw-r--r--src/display/nr-3dutils.h111
-rw-r--r--src/display/nr-filter-diffuselighting.cpp181
-rw-r--r--src/display/nr-filter-diffuselighting.h60
-rw-r--r--src/display/nr-filter-specularlighting.cpp190
-rw-r--r--src/display/nr-filter-specularlighting.h61
-rw-r--r--src/display/nr-filter.cpp6
-rw-r--r--src/display/nr-light-types.h25
-rw-r--r--src/display/nr-light.cpp119
-rw-r--r--src/display/nr-light.h160
11 files changed, 1106 insertions, 3 deletions
diff --git a/src/display/Makefile_insert b/src/display/Makefile_insert
index 1a4c01011..bc6fb3336 100644
--- a/src/display/Makefile_insert
+++ b/src/display/Makefile_insert
@@ -15,6 +15,8 @@ display/canvas-arena.$(OBJEXT): helper/sp-marshal.h
display/sp-canvas.$(OBJEXT): helper/sp-marshal.h
display_libspdisplay_a_SOURCES = \
+ display/nr-3dutils.h \
+ display/nr-3dutils.cpp \
display/nr-arena-forward.h \
display/nr-arena.cpp \
display/nr-arena.h \
@@ -71,8 +73,12 @@ display_libspdisplay_a_SOURCES = \
display/nr-filter-gaussian.h \
display/nr-filter-blend.cpp \
display/nr-filter-blend.h \
+ display/nr-filter-diffuselighting.cpp \
+ display/nr-filter-diffuselighting.h \
display/nr-filter-offset.cpp \
display/nr-filter-offset.h \
+ display/nr-filter-specularlighting.cpp \
+ display/nr-filter-specularlighting.h \
display/nr-filter-composite.h \
display/nr-filter-composite.cpp \
display/nr-filter-slot.cpp \
@@ -86,7 +92,10 @@ display_libspdisplay_a_SOURCES = \
display/pixblock-transform.cpp \
display/pixblock-transform.h \
display/inkscape-cairo.cpp \
- display/inkscape-cairo.h
+ display/inkscape-cairo.h \
+ display/nr-light.h \
+ display/nr-light.cpp \
+ display/nr-light-types.h
display_bezier_utils_test_SOURCES = display/bezier-utils-test.cpp
display_bezier_utils_test_LDADD = libnr/libnr.a -lglib-2.0
diff --git a/src/display/nr-3dutils.cpp b/src/display/nr-3dutils.cpp
new file mode 100644
index 000000000..c8171ccd2
--- /dev/null
+++ b/src/display/nr-3dutils.cpp
@@ -0,0 +1,185 @@
+/*
+ * 3D utils.
+ *
+ * Authors:
+ * Jean-Rene Reinhard <jr@komite.net>
+ *
+ * Copyright (C) 2007 authors
+ *
+ * Released under GNU GPL, read the file 'COPYING' for more information
+ */
+
+#include <glib/gmessages.h>
+
+#include "libnr/nr-pixblock.h"
+#include "libnr/nr-matrix.h"
+#include "display/nr-3dutils.h"
+#include <cmath>
+
+namespace NR {
+
+#define BEGIN 0 // TOP or LEFT
+#define MIDDLE 1
+#define END 2 // BOTTOM or RIGHT
+
+#define START(v) ((v)==BEGIN? 1 : 0)
+#define FINISH(v) ((v)==END? 1 : 2)
+
+signed char K_X[3][3][3][3] = {
+ //K_X[TOP]
+ {
+ //K_X[TOP][LEFT]
+ {
+ { 0, 0, 0},
+ { 0, -2, 2},
+ { 0, -1, 1}
+ },
+ {
+ { 0, 0, 0},
+ {-2, 0, 2},
+ {-1, 0, 1}
+ },
+ {
+ { 0, 0, 0},
+ {-2, 2, 0},
+ {-1, 1, 0}
+ }
+ },
+ //K_X[MIDDLE]
+ {
+ //K_X[MIDDLE][LEFT]
+ {
+ { 0, -1, 1},
+ { 0, -2, 2},
+ { 0, -1, 1}
+ },
+ {
+ {-1, 0, 1},
+ {-2, 0, 2},
+ {-1, 0, 1}
+ },
+ {
+ {-1, 1, 0},
+ {-2, 2, 0},
+ {-1, 1, 0}
+ }
+ },
+ //K_X[BOTTOM]
+ {
+ //K_X[BOTTOM][LEFT]
+ {
+ { 0, -1, 1},
+ { 0, -2, 2},
+ { 0, 0, 0}
+ },
+ {
+ {-1, 0, 1},
+ {-2, 0, 2},
+ { 0, 0, 0}
+ },
+ {
+ {-1, 1, 0},
+ {-2, 2, 0},
+ { 0, 0, 0}
+ }
+ }
+};
+
+//K_Y is obtained by transposing K_X globally and each of its components
+
+gdouble FACTOR_X[3][3] = {
+ {2./3, 1./3, 2./3},
+ {1./2, 1./4, 1./2},
+ {2./3, 1./3, 2./3}
+};
+
+//FACTOR_Y is obtained by transposing FACTOR_X
+
+inline
+int get_carac(int i, int len, int delta) {
+ if (i < delta)
+ return BEGIN;
+ else if (i > len - 1 - delta)
+ return END;
+ else
+ return MIDDLE;
+}
+
+//assumes in is RGBA
+//should be made more resistant
+void compute_surface_normal(Fvector &N, gdouble ss, NRPixBlock *in, int i, int j, int dx, int dy) {
+ int w = in->area.x1 - in->area.x0;
+ int h = in->area.y1 - in->area.y0;
+ int k, l, alpha_idx, alpha_idx_y;
+ int x_carac, y_carac;
+ gdouble alpha;
+ gdouble accu_x;
+ gdouble accu_y;
+ unsigned char *data = NR_PIXBLOCK_PX (in);
+ g_assert(in->mode == NR_PIXBLOCK_MODE_R8G8B8A8P);
+ x_carac = get_carac(j, w, dx); //LEFT, MIDDLE or RIGHT
+ y_carac = get_carac(i, h, dy); //TOP, MIDDLE or BOTTOM
+ alpha_idx = 4*(i*w + j);
+ accu_x = 0;
+ accu_y = 0;
+ for (k = START(y_carac); k <= FINISH(y_carac); k++) {
+ alpha_idx_y = alpha_idx + 4*(k-1)*dy*w;
+ for (l = START(x_carac); l <= FINISH(x_carac); l++) {
+ alpha = (data + alpha_idx_y + 4*dx*(l-1))[3];
+ accu_x += K_X[y_carac][x_carac][k][l] * alpha / 255;
+ accu_y += K_X[x_carac][y_carac][l][k] * alpha / 255;
+ }
+ }
+ N[X_3D] = -1 * ss * FACTOR_X[y_carac][x_carac] * accu_x / dx;
+ N[Y_3D] = -1 * ss * FACTOR_X[x_carac][y_carac] * accu_y / dy;
+ N[Z_3D] = 1;
+ normalize_vector(N);
+ //std::cout << "(" << N[X_3D] << ", " << N[Y_3D] << ", " << N[Z_3D] << ")" << std::endl;
+}
+
+void convert_coord(gdouble &x, gdouble &y, gdouble &z, Matrix const &trans) {
+ Point p = Point(x, y);
+ p *= trans;
+ x = p[X];
+ y = p[Y];
+ z *= trans[0];
+}
+
+gdouble norm(const Fvector &v) {
+ return sqrt(v[X_3D]*v[X_3D] + v[Y_3D]*v[Y_3D] + v[Z_3D]*v[Z_3D]);
+}
+
+void normalize_vector(Fvector &v) {
+ int i, j;
+ gdouble nv = norm(v);
+ //TODO test nv == 0
+ for (j = 0; j < 3; j++) {
+ v[j] /= nv;
+ }
+}
+
+gdouble scalar_product(const Fvector &a, const Fvector &b) {
+ return a[X_3D] * b[X_3D] +
+ a[Y_3D] * b[Y_3D] +
+ a[Z_3D] * b[Z_3D];
+}
+
+void normalized_sum(Fvector &r, const Fvector &a, const Fvector &b) {
+ r[X_3D] = a[X_3D] + b[X_3D];
+ r[Y_3D] = a[Y_3D] + b[Y_3D];
+ r[Z_3D] = a[Z_3D] + b[Z_3D];
+ normalize_vector(r);
+}
+
+}/* namespace NR */
+
+/*
+ Local Variables:
+ mode:c++
+ c-file-style:"stroustrup"
+ c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))
+ indent-tabs-mode:nil
+ fill-column:99
+ End:
+*/
+// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:encoding=utf-8:textwidth=99 :
diff --git a/src/display/nr-3dutils.h b/src/display/nr-3dutils.h
new file mode 100644
index 000000000..4baa9cc86
--- /dev/null
+++ b/src/display/nr-3dutils.h
@@ -0,0 +1,111 @@
+#ifndef __NR_3DUTILS_H__
+#define __NR_3DUTILS_H__
+
+/*
+ * 3D utils. Definition of gdouble vectors of dimension 3 and of some basic
+ * functions.
+ *
+ * Authors:
+ * Jean-Rene Reinhard <jr@komite.net>
+ *
+ * Copyright (C) 2007 authors
+ *
+ * Released under GNU GPL, read the file 'COPYING' for more information
+ */
+
+#include <gdk/gdktypes.h>
+
+struct NRPixBlock;
+
+namespace NR {
+
+struct Matrix;
+
+#define X_3D 0
+#define Y_3D 1
+#define Z_3D 2
+
+/**
+ * a type of 3 gdouble components vectors
+ */
+typedef gdouble Fvector[3];
+
+/**
+ * The eye vector
+ */
+const static Fvector EYE_VECTOR = {0, 0, 1};
+
+/**
+ * returns the euclidian norm of the vector v
+ *
+ * \param v a reference to a vector with double components
+ * \return the euclidian norm of v
+ */
+gdouble norm(const Fvector &v);
+
+/**
+ * Normalizes a vector
+ *
+ * \param v a reference to a vector to normalize
+ */
+void normalize_vector(Fvector &v);
+
+/**
+ * Computes the scalar product between two Fvectors
+ *
+ * \param a a Fvector reference
+ * \param b a Fvector reference
+ * \return the scalar product of a and b
+ */
+gdouble scalar_product(const Fvector &a, const Fvector &b);
+
+/**
+ * Computes the normalized sum of two Fvectors
+ *
+ * \param r a Fvector reference where we store the result
+ * \param a a Fvector reference
+ * \param b a Fvector reference
+ */
+void normalized_sum(Fvector &r, const Fvector &a, const Fvector &b);
+
+/**
+ * Computes the unit suface normal vector of surface given by "in" at (i, j)
+ * and store it into N. "in" is a (NRPixBlock *) in mode RGBA but only the alpha
+ * channel is considered as a bump map. ss is the altitude when for the alpha
+ * value 255. dx and dy are the deltas used to compute in our discrete setting
+ *
+ * \param N a reference to a Fvector in which we store the unit surface normal
+ * \param ss the surface scale
+ * \param in a NRPixBlock * whose alpha channel codes the surface
+ * \param i the x coordinate of the point at which we compute the normal
+ * \param j the y coordinate of the point at which we compute the normal
+ * \param dx the delta used in the x coordinate
+ * \param dy the delta used in the y coordinate
+ */
+void compute_surface_normal(Fvector &N, gdouble ss, NRPixBlock *in, int i, int j, int dx, int dy);
+
+/**
+ * Applies the transformation matrix to (x, y, z). This function assumes that
+ * trans[0] = trans[3]. x and y are transformed according to trans, z is
+ * multiplied by trans[0].
+ *
+ * \param x a reference to a x coordinate
+ * \param y a reference to a y coordinate
+ * \param z a reference to a z coordinate
+ * \param z a reference to a transformation matrix
+ */
+void convert_coord(gdouble &x, gdouble &y, gdouble &z, Matrix const &trans);
+
+} /* namespace NR */
+
+#endif /* __NR_3DUTILS_H__ */
+/*
+ Local Variables:
+ mode:c++
+ c-file-style:"stroustrup"
+ c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))
+ indent-tabs-mode:nil
+ fill-column:99
+ End:
+*/
+// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:encoding=utf-8:textwidth=99 :
diff --git a/src/display/nr-filter-diffuselighting.cpp b/src/display/nr-filter-diffuselighting.cpp
new file mode 100644
index 000000000..736055f32
--- /dev/null
+++ b/src/display/nr-filter-diffuselighting.cpp
@@ -0,0 +1,181 @@
+/*
+ * feDiffuseLighting renderer
+ *
+ * Authors:
+ * Niko Kiirala <niko@kiirala.com>
+ * Jean-Rene Reinhard <jr@komite.net>
+ *
+ * Copyright (C) 2007 authors
+ *
+ * Released under GNU GPL, read the file 'COPYING' for more information
+ */
+
+#include <glib/gmessages.h>
+
+#include "display/nr-3dutils.h"
+#include "display/nr-arena-item.h"
+#include "display/nr-filter-diffuselighting.h"
+#include "display/nr-filter-getalpha.h"
+#include "display/nr-filter-slot.h"
+#include "display/nr-light.h"
+#include "libnr/nr-blit.h"
+#include "libnr/nr-pixblock.h"
+#include "libnr/nr-matrix.h"
+#include "libnr/nr-rect-l.h"
+#include "color.h"
+#include "round.h"
+
+namespace NR {
+
+FilterDiffuseLighting::FilterDiffuseLighting()
+{
+ light_type = NO_LIGHT;
+ diffuseConstant = 1;
+ surfaceScale = 1;
+ lighting_color = 0xffffffff;
+}
+
+FilterPrimitive * FilterDiffuseLighting::create() {
+ return new FilterDiffuseLighting();
+}
+
+FilterDiffuseLighting::~FilterDiffuseLighting()
+{}
+
+#define COMPUTE_INTER(inter, N, L, kd) \
+do {\
+ (inter) = (kd) * scalar_product((N), (L)); \
+ if ((inter) < 0) (inter) = 0; \
+}while(0)
+
+int FilterDiffuseLighting::render(FilterSlot &slot, Matrix const &trans) {
+ NRPixBlock *in = filter_get_alpha(slot.get(_input));
+ 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
+ //TODO for the time being, assumes userSpaceOnUse
+ gdouble ss = surfaceScale * trans[0];
+ gdouble kd = diffuseConstant; //diffuse lighting constant
+
+ 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
+ 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++) {
+ compute_surface_normal(N, ss, in, i / w, i % w, dx, dy);
+ COMPUTE_INTER(inter, N, L, kd);
+
+ data_o[j++] = (unsigned char) round(inter * LC[LIGHT_RED]);
+ data_o[j++] = (unsigned char) round(inter * LC[LIGHT_GREEN]);
+ data_o[j++] = (unsigned char) round(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
+ //slot._arena_item->filter seems to be ok on simple examples
+ //for now assume userSpaceOnUse
+ //if objectBoundingBox is used, use a different matrix for light_vector
+ //finish the work
+ for (i = 0, j = 0; i < w*h; i++) {
+ 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);
+ COMPUTE_INTER(inter, N, L, kd);
+
+ data_o[j++] = (unsigned char) round(inter * LC[LIGHT_RED]);
+ data_o[j++] = (unsigned char) round(inter * LC[LIGHT_GREEN]);
+ data_o[j++] = (unsigned char) round(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
+ //slot._arena_item->filter seems to be ok on simple examples
+ //for now assume userSpaceOnUse
+ //if objectBoundingBox is used, use a different matrix for light_vector
+ //finish the work
+ for (i = 0, j = 0; i < w*h; i++) {
+ 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);
+ COMPUTE_INTER(inter, N, L, kd);
+
+ data_o[j++] = (unsigned char) round(inter * LC[LIGHT_RED]);
+ data_o[j++] = (unsigned char) round(inter * LC[LIGHT_GREEN]);
+ data_o[j++] = (unsigned char) round(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;
+ }
+ }
+
+ //finishing
+ slot.set(_output, out);
+ delete in;
+ return 0;
+}
+
+} /* namespace NR */
+
+/*
+ Local Variables:
+ mode:c++
+ c-file-style:"stroustrup"
+ c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))
+ indent-tabs-mode:nil
+ fill-column:99
+ End:
+*/
+// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:encoding=utf-8:textwidth=99 :
diff --git a/src/display/nr-filter-diffuselighting.h b/src/display/nr-filter-diffuselighting.h
new file mode 100644
index 000000000..486b81aca
--- /dev/null
+++ b/src/display/nr-filter-diffuselighting.h
@@ -0,0 +1,60 @@
+#ifndef __NR_FILTER_DIFFUSELIGHTING_H__
+#define __NR_FILTER_DIFFUSELIGHTING_H__
+
+/*
+ * feDiffuseLighting renderer
+ *
+ * Authors:
+ * Niko Kiirala <niko@kiirala.com>
+ * Jean-Rene Reinhard <jr@komite.net>
+ *
+ * Copyright (C) 2007 authors
+ *
+ * Released under GNU GPL, read the file 'COPYING' for more information
+ */
+
+#include <gdk/gdktypes.h>
+#include "display/nr-light-types.h"
+#include "display/nr-filter-primitive.h"
+#include "display/nr-filter-slot.h"
+#include "libnr/nr-matrix.h"
+#include "sp-fedistantlight.h"
+#include "sp-fepointlight.h"
+#include "sp-fespotlight.h"
+#include "color.h"
+
+namespace NR {
+
+class FilterDiffuseLighting : public FilterPrimitive {
+public:
+ union {
+ SPFeDistantLight *distant;
+ SPFePointLight *point;
+ SPFeSpotLight *spot;
+ } light;
+ LightType light_type;
+ gdouble diffuseConstant;
+ gdouble surfaceScale;
+ guint32 lighting_color;
+
+ FilterDiffuseLighting();
+ static FilterPrimitive *create();
+ virtual ~FilterDiffuseLighting();
+ virtual int render(FilterSlot &slot, Matrix const &trans);
+
+private:
+};
+
+} /* namespace NR */
+
+#endif /* __NR_FILTER_DIFFUSELIGHTING_H__ */
+/*
+ Local Variables:
+ mode:c++
+ c-file-style:"stroustrup"
+ c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))
+ indent-tabs-mode:nil
+ fill-column:99
+ End:
+*/
+// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:encoding=utf-8:textwidth=99 :
diff --git a/src/display/nr-filter-specularlighting.cpp b/src/display/nr-filter-specularlighting.cpp
new file mode 100644
index 000000000..117df28f7
--- /dev/null
+++ b/src/display/nr-filter-specularlighting.cpp
@@ -0,0 +1,190 @@
+/*
+ * feSpecularLighting renderer
+ *
+ * Authors:
+ * Niko Kiirala <niko@kiirala.com>
+ * Jean-Rene Reinhard <jr@komite.net>
+ *
+ * Copyright (C) 2007 authors
+ *
+ * Released under GNU GPL, read the file 'COPYING' for more information
+ */
+
+#include <glib/gmessages.h>
+#include <cmath>
+
+#include "display/nr-3dutils.h"
+#include "display/nr-arena-item.h"
+#include "display/nr-filter-specularlighting.h"
+#include "display/nr-filter-getalpha.h"
+#include "display/nr-filter-slot.h"
+#include "display/nr-light.h"
+#include "libnr/nr-blit.h"
+#include "libnr/nr-pixblock.h"
+#include "libnr/nr-matrix.h"
+#include "libnr/nr-rect-l.h"
+#include "color.h"
+#include "round.h"
+
+namespace NR {
+
+FilterSpecularLighting::FilterSpecularLighting()
+{
+ light_type = NO_LIGHT;
+ specularConstant = 1;
+ specularExponent = 1;
+ surfaceScale = 1;
+ lighting_color = 0xffffffff;
+}
+
+FilterPrimitive * FilterSpecularLighting::create() {
+ return new FilterSpecularLighting();
+}
+
+FilterSpecularLighting::~FilterSpecularLighting()
+{}
+
+//Investigating Phong Lighting model we should not take N.H but
+//R.E which equals to 2*N.H^2 - 1
+#define COMPUTE_INTER(inter, H, N, ks, speculaExponent) \
+do {\
+ gdouble scal = scalar_product((N), (H));\
+ scal = 2 * scal * scal - 1;\
+ if (scal <= 0)\
+ (inter) = 0;\
+ else\
+ (inter) = (ks) * std::pow(scal, (specularExponent));\
+}while(0)
+
+int FilterSpecularLighting::render(FilterSlot &slot, Matrix const &trans) {
+ NRPixBlock *in = filter_get_alpha(slot.get(_input));
+ NRPixBlock *out = new NRPixBlock;
+
+ //Fvector *L = NULL; //vector to the light
+
+ 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
+ //TODO for the time being, assumes userSpaceOnUse
+ gdouble ss = surfaceScale * trans[0];
+ gdouble ks = specularConstant; //diffuse lighting constant
+ Fvector L, N, LC, H;
+ 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
+ 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);
+ normalized_sum(H, L, EYE_VECTOR);
+ //finish the work
+ for (i = 0, j = 0; i < w*h; i++) {
+ compute_surface_normal(N, ss, in, i / w, i % w, dx, dy);
+ COMPUTE_INTER(inter, N, H, ks, specularExponent);
+
+ data_o[j++] = (unsigned char) round(inter * LC[LIGHT_RED]);
+ data_o[j++] = (unsigned char) round(inter * LC[LIGHT_GREEN]);
+ data_o[j++] = (unsigned char) round(inter * LC[LIGHT_BLUE]);
+ data_o[j++] = MAX(MAX(data_o[j-3], data_o[j-2]), data_o[j-1]);
+ }
+ 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
+ //slot._arena_item->filter seems to be ok on simple examples
+ //for now assume userSpaceOnUse
+ //if objectBoundingBox is used, use a different matrix for light_vector
+ //finish the work
+ for (i = 0, j = 0; i < w*h; i++) {
+ 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);
+ normalized_sum(H, L, EYE_VECTOR);
+ COMPUTE_INTER(inter, N, H, ks, specularExponent);
+
+ data_o[j++] = (unsigned char) round(inter * LC[LIGHT_RED]);
+ data_o[j++] = (unsigned char) round(inter * LC[LIGHT_GREEN]);
+ data_o[j++] = (unsigned char) round(inter * LC[LIGHT_BLUE]);
+ data_o[j++] = MAX(MAX(data_o[j-3], data_o[j-2]), data_o[j-1]);
+ }
+ 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
+ //slot._arena_item->filter seems to be ok on simple examples
+ //for now assume userSpaceOnUse
+ //if objectBoundingBox is used, use a different matrix for light_vector
+ //finish the work
+ for (i = 0, j = 0; i < w*h; i++) {
+ 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);
+ normalized_sum(H, L, EYE_VECTOR);
+ COMPUTE_INTER(inter, N, H, ks, specularExponent);
+
+ data_o[j++] = (unsigned char) round(inter * LC[LIGHT_RED]);
+ data_o[j++] = (unsigned char) round(inter * LC[LIGHT_GREEN]);
+ data_o[j++] = (unsigned char) round(inter * LC[LIGHT_BLUE]);
+ data_o[j++] = MAX(MAX(data_o[j-3], data_o[j-2]), data_o[j-1]);
+ }
+ 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);
+ out->empty = false;
+ }
+ }
+
+ //finishing
+ slot.set(_output, out);
+ delete in;
+ return 0;
+}
+
+} /* namespace NR */
+
+/*
+ Local Variables:
+ mode:c++
+ c-file-style:"stroustrup"
+ c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))
+ indent-tabs-mode:nil
+ fill-column:99
+ End:
+*/
+// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:encoding=utf-8:textwidth=99 :
diff --git a/src/display/nr-filter-specularlighting.h b/src/display/nr-filter-specularlighting.h
new file mode 100644
index 000000000..a9b3429f4
--- /dev/null
+++ b/src/display/nr-filter-specularlighting.h
@@ -0,0 +1,61 @@
+#ifndef __NR_FILTER_SPECULARLIGHTING_H__
+#define __NR_FILTER_SPECULARLIGHTING_H__
+
+/*
+ * feSpecularLighting renderer
+ *
+ * Authors:
+ * Niko Kiirala <niko@kiirala.com>
+ * Jean-Rene Reinhard <jr@komite.net>
+ *
+ * Copyright (C) 2007 authors
+ *
+ * Released under GNU GPL, read the file 'COPYING' for more information
+ */
+
+#include <gdk/gdktypes.h>
+#include "display/nr-light-types.h"
+#include "display/nr-filter-primitive.h"
+#include "display/nr-filter-slot.h"
+#include "libnr/nr-matrix.h"
+#include "sp-fedistantlight.h"
+#include "sp-fepointlight.h"
+#include "sp-fespotlight.h"
+#include "color.h"
+
+namespace NR {
+
+class FilterSpecularLighting : public FilterPrimitive {
+public:
+ union {
+ SPFeDistantLight *distant;
+ SPFePointLight *point;
+ SPFeSpotLight *spot;
+ } light;
+ LightType light_type;
+ gdouble surfaceScale;
+ gdouble specularConstant;
+ gdouble specularExponent;
+ guint32 lighting_color;
+
+ FilterSpecularLighting();
+ static FilterPrimitive *create();
+ virtual ~FilterSpecularLighting();
+ virtual int render(FilterSlot &slot, Matrix const &trans);
+
+private:
+};
+
+} /* namespace NR */
+
+#endif /* __NR_FILTER_SPECULARLIGHTING_H__ */
+/*
+ Local Variables:
+ mode:c++
+ c-file-style:"stroustrup"
+ c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))
+ indent-tabs-mode:nil
+ fill-column:99
+ End:
+*/
+// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:encoding=utf-8:textwidth=99 :
diff --git a/src/display/nr-filter.cpp b/src/display/nr-filter.cpp
index 61571f43b..8a22778a1 100644
--- a/src/display/nr-filter.cpp
+++ b/src/display/nr-filter.cpp
@@ -25,6 +25,8 @@
#include "display/nr-filter-blend.h"
#include "display/nr-filter-offset.h"
#include "display/nr-filter-composite.h"
+#include "display/nr-filter-diffuselighting.h"
+#include "display/nr-filter-specularlighting.h"
#include "display/nr-arena-item.h"
#include "libnr/nr-pixblock.h"
@@ -313,7 +315,7 @@ void Filter::_create_constructor_table()
_constructor[NR_FILTER_COMPONENTTRANSFER] = NULL;
_constructor[NR_FILTER_COMPOSITE] = &FilterComposite::create;
_constructor[NR_FILTER_CONVOLVEMATRIX] = NULL;
- _constructor[NR_FILTER_DIFFUSELIGHTING] = NULL;
+ _constructor[NR_FILTER_DIFFUSELIGHTING] = &FilterDiffuseLighting::create;
_constructor[NR_FILTER_DISPLACEMENTMAP] = NULL;
_constructor[NR_FILTER_FLOOD] = NULL;
_constructor[NR_FILTER_GAUSSIANBLUR] = &FilterGaussian::create;
@@ -321,7 +323,7 @@ void Filter::_create_constructor_table()
_constructor[NR_FILTER_MERGE] = NULL;
_constructor[NR_FILTER_MORPHOLOGY] = NULL;
_constructor[NR_FILTER_OFFSET] = &FilterOffset::create;
- _constructor[NR_FILTER_SPECULARLIGHTING] = NULL;
+ _constructor[NR_FILTER_SPECULARLIGHTING] = &FilterSpecularLighting::create;
_constructor[NR_FILTER_TILE] = NULL;
_constructor[NR_FILTER_TURBULENCE] = NULL;
created = true;
diff --git a/src/display/nr-light-types.h b/src/display/nr-light-types.h
new file mode 100644
index 000000000..87865467c
--- /dev/null
+++ b/src/display/nr-light-types.h
@@ -0,0 +1,25 @@
+#ifndef __NR_LIGHT_TYPES_H__
+#define __NR_LIGHT_TYPES_H__
+
+namespace NR {
+
+enum LightType{
+ NO_LIGHT = 0,
+ DISTANT_LIGHT,
+ POINT_LIGHT,
+ SPOT_LIGHT
+};
+
+} /* namespace NR */
+
+#endif // __NR_LIGHT_TYPES_H__
+/*
+ Local Variables:
+ mode:c++
+ c-file-style:"stroustrup"
+ c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))
+ indent-tabs-mode:nil
+ fill-column:99
+ End:
+*/
+// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:encoding=utf-8:textwidth=99 :
diff --git a/src/display/nr-light.cpp b/src/display/nr-light.cpp
new file mode 100644
index 000000000..c2e6f1f83
--- /dev/null
+++ b/src/display/nr-light.cpp
@@ -0,0 +1,119 @@
+#define __NR_LIGHT_CPP__
+
+/*
+ * Light rendering helpers
+ *
+ * Author:
+ * Jean-Rene Reinhard <jr@komite.net>
+ *
+ * Copyright (C) 2006 Jean-Rene Reinhard
+ *
+ * Released under GNU GPL, read the file 'COPYING' for more information
+ */
+
+#include <cmath>
+
+#include "libnr/nr-pixops.h"
+#include "display/nr-light.h"
+#include "display/nr-3dutils.h"
+#include "sp-fedistantlight.h"
+#include "sp-fepointlight.h"
+#include "sp-fespotlight.h"
+
+namespace NR {
+
+DistantLight::DistantLight(SPFeDistantLight *light, guint32 lighting_color) {
+ color = lighting_color;
+ azimuth = M_PI / 180 * light->azimuth;
+ elevation = M_PI / 180 * light->elevation;
+}
+
+DistantLight::~DistantLight() {}
+
+void DistantLight::light_vector(Fvector &v) {
+ v[X_3D] = std::cos(azimuth)*std::cos(elevation);
+ v[Y_3D] = std::sin(azimuth)*std::cos(elevation);
+ v[Z_3D] = std::sin(elevation);
+}
+
+void DistantLight::light_components(Fvector &lc) {
+ lc[LIGHT_RED] = NR_RGBA32_R(color);
+ lc[LIGHT_GREEN] = NR_RGBA32_G(color);
+ lc[LIGHT_BLUE] = NR_RGBA32_B(color);
+}
+
+PointLight::PointLight(SPFePointLight *light, guint32 lighting_color, const Matrix &trans) {
+ color = lighting_color;
+ l_x = light->x;
+ l_y = light->y;
+ l_z = light->z;
+ convert_coord(l_x, l_y, l_z, trans);
+}
+
+PointLight::~PointLight() {}
+
+void PointLight::light_vector(Fvector &v, gdouble x, gdouble y, gdouble z) {
+ v[X_3D] = l_x - x;
+ v[Y_3D] = l_y - y;
+ v[Z_3D] = l_z - z;
+ normalize_vector(v);
+}
+
+void PointLight::light_components(Fvector &lc) {
+ lc[LIGHT_RED] = NR_RGBA32_R(color);
+ lc[LIGHT_GREEN] = NR_RGBA32_G(color);
+ lc[LIGHT_BLUE] = NR_RGBA32_B(color);
+}
+
+SpotLight::SpotLight(SPFeSpotLight *light, guint32 lighting_color, const Matrix &trans) {
+ gdouble p_x, p_y, p_z;
+ color = lighting_color;
+ l_x = light->x;
+ l_y = light->y;
+ l_z = light->z;
+ p_x = light->pointsAtX;
+ p_y = light->pointsAtY;
+ p_z = light->pointsAtZ;
+ cos_lca = std::cos(M_PI / 180 * light->limitingConeAngle);
+ speExp = light->specularExponent;
+ convert_coord(l_x, l_y, l_z, trans);
+ convert_coord(p_x, p_y, p_z, trans);
+ S[X_3D] = p_x - l_x;
+ S[Y_3D] = p_y - l_y;
+ S[Z_3D] = p_z - l_z;
+ normalize_vector(S);
+
+}
+
+SpotLight::~SpotLight() {}
+
+void SpotLight::light_vector(Fvector &v, gdouble x, gdouble y, gdouble z) {
+ v[X_3D] = l_x - x;
+ v[Y_3D] = l_y - y;
+ v[Z_3D] = l_z - z;
+ normalize_vector(v);
+}
+
+void SpotLight::light_components(Fvector &lc, const Fvector &L) {
+ gdouble spmod = (-1) * scalar_product(L, S);
+ if (spmod <= cos_lca)
+ spmod = 0;
+ else
+ spmod = std::pow(spmod, speExp);
+ lc[LIGHT_RED] = spmod * NR_RGBA32_R(color);
+ lc[LIGHT_GREEN] = spmod * NR_RGBA32_G(color);
+ lc[LIGHT_BLUE] = spmod * NR_RGBA32_B(color);
+}
+
+} /* namespace NR */
+
+/*
+ Local Variables:
+ mode:c++
+ c-file-style:"stroustrup"
+ c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))
+ indent-tabs-mode:nil
+ fill-column:99
+ End:
+*/
+// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:encoding=utf-8:textwidth=99 :
diff --git a/src/display/nr-light.h b/src/display/nr-light.h
new file mode 100644
index 000000000..61c3c3909
--- /dev/null
+++ b/src/display/nr-light.h
@@ -0,0 +1,160 @@
+#ifndef __NR_LIGHT_H__
+#define __NR_LIGHT_H__
+/** \file
+ * These classes provide tools to compute interesting objects relative to light
+ * sources. Each class provides a constructor converting information contained
+ * in a sp light object into information useful in the current setting, a
+ * method to get the light vector (at a given point) and a method to get the
+ * light color components (at a given point).
+ */
+
+#include <gdk/gdktypes.h>
+#include "display/nr-3dutils.h"
+#include "display/nr-light-types.h"
+
+struct SPFeDistantLight;
+struct SPFePointLight;
+struct SPFeSpotLight;
+
+namespace NR {
+
+struct Matrix;
+
+enum LightComponent {
+ LIGHT_RED = 0,
+ LIGHT_GREEN,
+ LIGHT_BLUE
+};
+
+class DistantLight {
+ public:
+ /**
+ * Constructor
+ *
+ * \param light the sp light object
+ * \param lighting_color the lighting_color used
+ */
+ DistantLight(SPFeDistantLight *light, guint32 lighting_color);
+ ~DistantLight();
+
+ /**
+ * Computes the light vector of the distant light
+ *
+ * \param v a Fvector referece where we store the result
+ */
+ void light_vector(Fvector &v);
+
+ /**
+ * Computes the light components of the distant light
+ *
+ * \param lc a Fvector referece where we store the result, X=R, Y=G, Z=B
+ */
+ void light_components(Fvector &lc);
+
+ private:
+ guint32 color;
+ gdouble azimuth; //azimuth in rad
+ gdouble elevation; //elevation in rad
+};
+
+class PointLight {
+ public:
+ /**
+ * Constructor
+ *
+ * \param light the sp light object
+ * \param lighting_color the lighting_color used
+ * \param trans the transformation between absolute coordinate (those
+ * employed in the sp light object) and current coordinate (those
+ * employed in the rendering)
+ */
+ PointLight(SPFePointLight *light, guint32 lighting_color, const Matrix &trans);
+ ~PointLight();
+ /**
+ * Computes the light vector of the distant light at point (x,y,z).
+ * x, y and z are given in the arena_item coordinate, they are used as
+ * is
+ *
+ * \param v a Fvector referece where we store the result
+ * \param x x coordinate of the current point
+ * \param y y coordinate of the current point
+ * \param z z coordinate of the current point
+ */
+ void light_vector(Fvector &v, gdouble x, gdouble y, gdouble z);
+
+ /**
+ * Computes the light components of the distant light
+ *
+ * \param lc a Fvector referece where we store the result, X=R, Y=G, Z=B
+ */
+ void light_components(Fvector &lc);
+
+ private:
+ guint32 color;
+ //light position coordinates in render setting
+ gdouble l_x;
+ gdouble l_y;
+ gdouble l_z;
+};
+
+class SpotLight {
+ public:
+ /**
+ * Constructor
+ *
+ * \param light the sp light object
+ * \param lighting_color the lighting_color used
+ * \param trans the transformation between absolute coordinate (those
+ * employed in the sp light object) and current coordinate (those
+ * employed in the rendering)
+ */
+ SpotLight(SPFeSpotLight *light, guint32 lighting_color, const Matrix &trans);
+ ~SpotLight();
+
+ /**
+ * Computes the light vector of the distant light at point (x,y,z).
+ * x, y and z are given in the arena_item coordinate, they are used as
+ * is
+ *
+ * \param v a Fvector referece where we store the result
+ * \param x x coordinate of the current point
+ * \param y y coordinate of the current point
+ * \param z z coordinate of the current point
+ */
+ void light_vector(Fvector &v, gdouble x, gdouble y, gdouble z);
+
+ /**
+ * Computes the light components of the distant light at the current
+ * point. We only need the light vector to compute theses
+ *
+ * \param lc a Fvector referece where we store the result, X=R, Y=G, Z=B
+ * \param L the light vector of the current point
+ */
+ void light_components(Fvector &lc, const Fvector &L);
+
+ private:
+ guint32 color;
+ //light position coordinates in render setting
+ gdouble l_x;
+ gdouble l_y;
+ gdouble l_z;
+ gdouble cos_lca; //cos of the limiting cone angle
+ gdouble speExp; //specular exponent;
+ Fvector S; //unit vector from light position in the direction
+ //the spot point at
+};
+
+
+} /* namespace NR */
+
+#endif // __NR_LIGHT_H__
+/*
+ Local Variables:
+ mode:c++
+ c-file-style:"stroustrup"
+ c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))
+ indent-tabs-mode:nil
+ fill-column:99
+ End:
+*/
+// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:encoding=utf-8:textwidth=99 :