summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorKrzysztof Kosi??ski <tweenk.pl@gmail.com>2010-07-23 18:12:24 +0000
committerKrzysztof Kosiński <tweenk.pl@gmail.com>2010-07-23 18:12:24 +0000
commit479779b784d886078444da59ee873a9c1a847a46 (patch)
treeeb0ba279850e919a66ec5616451282df5423e223 /src
parentDiffuse lighting filter (diff)
downloadinkscape-479779b784d886078444da59ee873a9c1a847a46.tar.gz
inkscape-479779b784d886078444da59ee873a9c1a847a46.zip
Specular lighting filter
(bzr r9508.1.29)
Diffstat (limited to 'src')
-rw-r--r--src/display/cairo-templates.h6
-rw-r--r--src/display/nr-filter-diffuselighting.cpp102
-rw-r--r--src/display/nr-filter-specularlighting.cpp155
-rw-r--r--src/display/nr-filter-specularlighting.h22
-rw-r--r--src/filters/specularlighting.cpp5
5 files changed, 201 insertions, 89 deletions
diff --git a/src/display/cairo-templates.h b/src/display/cairo-templates.h
index 8041d0229..9c2a8c782 100644
--- a/src/display/cairo-templates.h
+++ b/src/display/cairo-templates.h
@@ -279,7 +279,8 @@ void ink_cairo_surface_filter(cairo_surface_t *in, cairo_surface_t *out, Filter
* 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 */
+ * @param out_area The region of the output surface that should be synthesized
+ * @param synth Synthesis functor */
template <typename Synth>
void ink_cairo_surface_synthesize(cairo_surface_t *out, cairo_rectangle_t const &out_area, Synth synth)
{
@@ -493,10 +494,11 @@ protected:
+1.0 * p01 +2.0 * p11 +1.0 * p21;
} else {
// interior pixels
+ // note: p11 is actually unused, so we don't fetch its value
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 ),
+ p01 = alphaAt(x-1, y ), p11 = 0.0, 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
diff --git a/src/display/nr-filter-diffuselighting.cpp b/src/display/nr-filter-diffuselighting.cpp
index 04de6ebf9..d48b6d690 100644
--- a/src/display/nr-filter-diffuselighting.cpp
+++ b/src/display/nr-filter-diffuselighting.cpp
@@ -4,8 +4,9 @@
* Authors:
* Niko Kiirala <niko@kiirala.com>
* Jean-Rene Reinhard <jr@komite.net>
+ * Krzysztof Kosiński <tweenk.pl@gmail.com>
*
- * Copyright (C) 2007 authors
+ * Copyright (C) 2007-2010 Authors
*
* Released under GNU GPL, read the file 'COPYING' for more information
*/
@@ -17,15 +18,11 @@
#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-filter-units.h"
#include "display/nr-filter-utils.h"
#include "display/nr-light.h"
-#include "libnr/nr-blit.h"
-#include "libnr/nr-pixblock.h"
#include "libnr/nr-rect-l.h"
-#include "color.h"
namespace Inkscape {
namespace Filters {
@@ -45,12 +42,32 @@ FilterPrimitive * FilterDiffuseLighting::create() {
FilterDiffuseLighting::~FilterDiffuseLighting()
{}
-struct DiffuseDistantLight : public SurfaceSynth {
- DiffuseDistantLight(cairo_surface_t *bumpmap, SPFeDistantLight *light, guint32 color,
- double scale, double diffuse_constant)
+struct DiffuseLight : public SurfaceSynth {
+ DiffuseLight(cairo_surface_t *bumpmap, double scale, double kd)
: SurfaceSynth(bumpmap)
, _scale(scale)
- , _kd(diffuse_constant)
+ , _kd(kd)
+ {}
+
+protected:
+ guint32 diffuseLighting(int x, int y, NR::Fvector const &light, NR::Fvector const &light_components) {
+ NR::Fvector normal = surfaceNormalAt(x, y, _scale);
+ 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;
+ }
+ double _scale, _kd;
+};
+
+struct DiffuseDistantLight : public DiffuseLight {
+ DiffuseDistantLight(cairo_surface_t *bumpmap, SPFeDistantLight *light, guint32 color,
+ double scale, double diffuse_constant)
+ : DiffuseLight(bumpmap, scale, diffuse_constant)
{
DistantLight dl(light, color);
dl.light_vector(_lightv);
@@ -58,28 +75,17 @@ struct DiffuseDistantLight : public SurfaceSynth {
}
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;
+ return diffuseLighting(x, y, _lightv, _light_components);
}
private:
NR::Fvector _lightv, _light_components;
- double _scale, _kd;
};
-struct DiffusePointLight : public SurfaceSynth {
+struct DiffusePointLight : public DiffuseLight {
DiffusePointLight(cairo_surface_t *bumpmap, SPFePointLight *light, guint32 color,
Geom::Matrix const &trans, double scale, double diffuse_constant, double x0, double y0)
- : SurfaceSynth(bumpmap)
+ : DiffuseLight(bumpmap, scale, diffuse_constant)
, _light(light, color, trans)
- , _scale(scale)
- , _kd(diffuse_constant)
, _x0(x0)
, _y0(y0)
{
@@ -87,53 +93,34 @@ struct DiffusePointLight : public SurfaceSynth {
}
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;
+ return diffuseLighting(x, y, light, _light_components);
}
private:
PointLight _light;
NR::Fvector _light_components;
- double _scale, _kd, _x0, _y0;
+ double _x0, _y0;
};
-struct DiffuseSpotLight : public SurfaceSynth {
+struct DiffuseSpotLight : public DiffuseLight {
DiffuseSpotLight(cairo_surface_t *bumpmap, SPFeSpotLight *light, guint32 color,
Geom::Matrix const &trans, double scale, double diffuse_constant, double x0, double y0)
- : SurfaceSynth(bumpmap)
+ : DiffuseLight(bumpmap, scale, diffuse_constant)
, _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;
+ NR::Fvector light, 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;
+ return diffuseLighting(x, y, light, light_components);
}
private:
SpotLight _light;
- double _scale, _kd, _x0, _y0;
+ double _x0, _y0;
};
void FilterDiffuseLighting::render_cairo(FilterSlot &slot)
@@ -144,7 +131,7 @@ void FilterDiffuseLighting::render_cairo(FilterSlot &slot)
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];
+ double scale = surfaceScale * trans.descrim();
switch (light_type) {
case DISTANT_LIGHT:
@@ -175,14 +162,13 @@ void FilterDiffuseLighting::render_cairo(FilterSlot &slot)
void FilterDiffuseLighting::area_enlarge(NRRectL &area, Geom::Matrix const &trans)
{
// TODO: support kernelUnitLength
- double scalex = std::fabs(trans[0]) + std::fabs(trans[1]);
- double scaley = std::fabs(trans[2]) + std::fabs(trans[3]);
-
- //FIXME: no +2 should be there!... (noticable only for big scales at big zoom factor)
- area.x0 -= (int)(scalex) + 2;
- area.x1 += (int)(scalex) + 2;
- area.y0 -= (int)(scaley) + 2;
- area.y1 += (int)(scaley) + 2;
+
+ // We expand the area by 1 in every direction to avoid artifacts on tile edges.
+ // However, it means that edge pixels will be incorrect.
+ area.x0 -= 1;
+ area.x1 += 1;
+ area.y0 -= 1;
+ area.y1 += 1;
}
} /* namespace Filters */
diff --git a/src/display/nr-filter-specularlighting.cpp b/src/display/nr-filter-specularlighting.cpp
index 6a6ce38a8..23b9b20ac 100644
--- a/src/display/nr-filter-specularlighting.cpp
+++ b/src/display/nr-filter-specularlighting.cpp
@@ -13,18 +13,16 @@
#include <glib/gmessages.h>
#include <cmath>
+#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-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"
#include "display/nr-light.h"
-#include "libnr/nr-blit.h"
-#include "libnr/nr-pixblock.h"
#include "libnr/nr-rect-l.h"
-#include "color.h"
namespace Inkscape {
namespace Filters {
@@ -59,6 +57,138 @@ do {\
(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)
+ : SurfaceSynth(bumpmap)
+ , _scale(scale)
+ , _ks(specular_constant)
+ , _exp(specular_exponent)
+ {}
+protected:
+ guint32 specularLighting(int x, int y, NR::Fvector const &halfway, NR::Fvector const &light_components) {
+ NR::Fvector normal = surfaceNormalAt(x, y, _scale);
+ double sp = NR::scalar_product(normal, halfway);
+ double k = sp <= 0.0 ? 0.0 : _ks * pow(sp, _exp);
+
+ 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]);
+ guint32 a = std::max(std::max(r, g), b);
+
+ r = premul_alpha(r, a);
+ g = premul_alpha(g, a);
+ b = premul_alpha(b, a);
+
+ ASSEMBLE_ARGB32(pxout, a,r,g,b)
+ return pxout;
+ }
+ double _scale, _ks, _exp;
+};
+
+struct SpecularDistantLight : public SpecularLight {
+ SpecularDistantLight(cairo_surface_t *bumpmap, SPFeDistantLight *light, guint32 color,
+ double scale, double specular_constant, double specular_exponent)
+ : SpecularLight(bumpmap, scale, specular_constant, specular_exponent)
+ {
+ DistantLight dl(light, color);
+ NR::Fvector lv;
+ dl.light_vector(lv);
+ dl.light_components(_light_components);
+ NR::normalized_sum(_halfway, lv, NR::EYE_VECTOR);
+ }
+ guint32 operator()(int x, int y) {
+ return specularLighting(x, y, _halfway, _light_components);
+ }
+private:
+ NR::Fvector _halfway, _light_components;
+};
+
+struct SpecularPointLight : public SpecularLight {
+ SpecularPointLight(cairo_surface_t *bumpmap, SPFePointLight *light, guint32 color,
+ Geom::Matrix const &trans, double scale, double specular_constant,
+ double specular_exponent, double x0, double y0)
+ : SpecularLight(bumpmap, scale, specular_constant, specular_exponent)
+ , _light(light, color, trans)
+ , _x0(x0)
+ , _y0(y0)
+ {
+ _light.light_components(_light_components);
+ }
+
+ guint32 operator()(int x, int y) {
+ NR::Fvector light, halfway;
+ _light.light_vector(light, _x0 + x, _y0 + y, alphaAt(x, y)/255.0);
+ NR::normalized_sum(halfway, light, NR::EYE_VECTOR);
+ return specularLighting(x, y, halfway, _light_components);
+ }
+private:
+ PointLight _light;
+ NR::Fvector _light_components;
+ double _x0, _y0;
+};
+
+struct SpecularSpotLight : public SpecularLight {
+ SpecularSpotLight(cairo_surface_t *bumpmap, SPFeSpotLight *light, guint32 color,
+ Geom::Matrix const &trans, double scale, double specular_constant,
+ double specular_exponent, double x0, double y0)
+ : SpecularLight(bumpmap, scale, specular_constant, specular_exponent)
+ , _light(light, color, trans)
+ , _x0(x0)
+ , _y0(y0)
+ {}
+
+ guint32 operator()(int x, int y) {
+ NR::Fvector light, halfway, light_components;
+ _light.light_vector(light, _x0 + x, _y0 + y, alphaAt(x, y)/255.0);
+ _light.light_components(light_components, light);
+ NR::normalized_sum(halfway, light, NR::EYE_VECTOR);
+ return specularLighting(x, y, halfway, light_components);
+ }
+private:
+ SpotLight _light;
+ double _x0, _y0;
+};
+
+void FilterSpecularLighting::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.descrim();
+ double ks = specularConstant;
+ double se = specularExponent;
+
+ switch (light_type) {
+ case DISTANT_LIGHT:
+ ink_cairo_surface_synthesize(out,
+ SpecularDistantLight(input, light.distant, lighting_color, scale, ks, se));
+ break;
+ case POINT_LIGHT:
+ ink_cairo_surface_synthesize(out,
+ SpecularPointLight(input, light.point, lighting_color, trans, scale, ks, se, x0, y0));
+ break;
+ case SPOT_LIGHT:
+ ink_cairo_surface_synthesize(out,
+ SpecularSpotLight(input, light.spot, lighting_color, trans, scale, ks, se, 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;
+ }
+
+ slot.set(_output, out);
+ cairo_surface_destroy(out);
+}
+
+/*
int FilterSpecularLighting::render(FilterSlot &slot, FilterUnits const &units) {
NRPixBlock *in = slot.get(_input);
if (!in) {
@@ -186,23 +316,16 @@ int FilterSpecularLighting::render(FilterSlot &slot, FilterUnits const &units) {
//nr_pixblock_release(in);
//delete in;
return 0;
-}
+}*/
void FilterSpecularLighting::area_enlarge(NRRectL &area, Geom::Matrix const &trans)
{
// TODO: support kernelUnitLength
- double scalex = std::fabs(trans[0]) + std::fabs(trans[1]);
- double scaley = std::fabs(trans[2]) + std::fabs(trans[3]);
-
- //FIXME: no +2 should be there!... (noticable only for big scales at big zoom factor)
- area.x0 -= (int)(scalex) + 2;
- area.x1 += (int)(scalex) + 2;
- area.y0 -= (int)(scaley) + 2;
- area.y1 += (int)(scaley) + 2;
-}
-FilterTraits FilterSpecularLighting::get_input_traits() {
- return TRAIT_PARALLER;
+ area.x0 -= 1;
+ area.x1 += 1;
+ area.y0 -= 1;
+ area.y1 += 1;
}
} /* namespace Filters */
diff --git a/src/display/nr-filter-specularlighting.h b/src/display/nr-filter-specularlighting.h
index 0f9e6dfe9..a350c4b29 100644
--- a/src/display/nr-filter-specularlighting.h
+++ b/src/display/nr-filter-specularlighting.h
@@ -17,17 +17,22 @@
#include "display/nr-light-types.h"
#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 FilterSpecularLighting : public FilterPrimitive {
public:
+ FilterSpecularLighting();
+ static FilterPrimitive *create();
+ virtual ~FilterSpecularLighting();
+ virtual void render_cairo(FilterSlot &slot);
+ virtual void area_enlarge(NRRectL &area, Geom::Matrix const &trans);
+
union {
SPFeDistantLight *distant;
SPFePointLight *point;
@@ -38,13 +43,6 @@ public:
gdouble specularConstant;
gdouble specularExponent;
guint32 lighting_color;
-
- FilterSpecularLighting();
- static FilterPrimitive *create();
- virtual ~FilterSpecularLighting();
- 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/filters/specularlighting.cpp b/src/filters/specularlighting.cpp
index 1b6000522..2c38d6bda 100644
--- a/src/filters/specularlighting.cpp
+++ b/src/filters/specularlighting.cpp
@@ -23,7 +23,10 @@
#include "svg/svg.h"
#include "sp-object.h"
#include "svg/svg-color.h"
-#include "specularlighting.h"
+#include "filters/specularlighting.h"
+#include "filters/distantlight.h"
+#include "filters/pointlight.h"
+#include "filters/spotlight.h"
#include "xml/repr.h"
#include "display/nr-filter.h"
#include "display/nr-filter-specularlighting.h"