diff options
| author | Krzysztof Kosi??ski <tweenk.pl@gmail.com> | 2010-07-23 18:12:24 +0000 |
|---|---|---|
| committer | Krzysztof Kosiński <tweenk.pl@gmail.com> | 2010-07-23 18:12:24 +0000 |
| commit | 479779b784d886078444da59ee873a9c1a847a46 (patch) | |
| tree | eb0ba279850e919a66ec5616451282df5423e223 /src | |
| parent | Diffuse lighting filter (diff) | |
| download | inkscape-479779b784d886078444da59ee873a9c1a847a46.tar.gz inkscape-479779b784d886078444da59ee873a9c1a847a46.zip | |
Specular lighting filter
(bzr r9508.1.29)
Diffstat (limited to 'src')
| -rw-r--r-- | src/display/cairo-templates.h | 6 | ||||
| -rw-r--r-- | src/display/nr-filter-diffuselighting.cpp | 102 | ||||
| -rw-r--r-- | src/display/nr-filter-specularlighting.cpp | 155 | ||||
| -rw-r--r-- | src/display/nr-filter-specularlighting.h | 22 | ||||
| -rw-r--r-- | src/filters/specularlighting.cpp | 5 |
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" |
