From cca66b9ec4e494c1d919bff0f71a820d8afab1fa Mon Sep 17 00:00:00 2001 From: Daniel Baumann Date: Sun, 7 Apr 2024 20:24:48 +0200 Subject: Adding upstream version 1.2.2. Signed-off-by: Daniel Baumann --- src/display/nr-filter-displacement-map.cpp | 172 +++++++++++++++++++++++++++++ 1 file changed, 172 insertions(+) create mode 100644 src/display/nr-filter-displacement-map.cpp (limited to 'src/display/nr-filter-displacement-map.cpp') diff --git a/src/display/nr-filter-displacement-map.cpp b/src/display/nr-filter-displacement-map.cpp new file mode 100644 index 0000000..9d83e54 --- /dev/null +++ b/src/display/nr-filter-displacement-map.cpp @@ -0,0 +1,172 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * feDisplacementMap filter primitive renderer + * + * Authors: + * Felipe CorrĂȘa da Silva Sanches + * + * Copyright (C) 2007 authors + * + * Released under GNU GPL v2+, read the file 'COPYING' for more information. + */ + +#include "display/cairo-templates.h" +#include "display/cairo-utils.h" +#include "display/nr-filter-displacement-map.h" +#include "display/nr-filter-types.h" +#include "display/nr-filter-units.h" + +namespace Inkscape { +namespace Filters { + +FilterDisplacementMap::FilterDisplacementMap() += default; + +FilterPrimitive * FilterDisplacementMap::create() { + return new FilterDisplacementMap(); +} + +FilterDisplacementMap::~FilterDisplacementMap() += default; + +struct Displace { + Displace(cairo_surface_t *texture, cairo_surface_t *map, + unsigned xch, unsigned ych, double scalex, double scaley) + : _texture(texture) + , _map(map) + , _xch(xch) + , _ych(ych) + , _scalex(scalex/255.0) + , _scaley(scaley/255.0) + {} + guint32 operator()(int x, int y) { + guint32 mappx = _map.pixelAt(x, y); + guint32 a = (mappx & 0xff000000) >> 24; + guint32 xpx = 0, ypx = 0; + double xtex = x, ytex = y; + + guint32 xshift = _xch * 8, yshift = _ych * 8; + xpx = (mappx & (0xff << xshift)) >> xshift; + ypx = (mappx & (0xff << yshift)) >> yshift; + if (a) { + if (_xch != 3) xpx = unpremul_alpha(xpx, a); + if (_ych != 3) ypx = unpremul_alpha(ypx, a); + } + xtex += _scalex * (xpx - 127.5); + ytex += _scaley * (ypx - 127.5); + + if (xtex >= 0 && xtex < (_texture._w - 1) && + ytex >= 0 && ytex < (_texture._h - 1)) + { + return _texture.pixelAt(xtex, ytex); + } else { + return 0; + } + } +private: + SurfaceSynth _texture; + SurfaceSynth _map; + unsigned _xch, _ych; + double _scalex, _scaley; +}; + +void FilterDisplacementMap::render_cairo(FilterSlot &slot) +{ + cairo_surface_t *texture = slot.getcairo(_input); + cairo_surface_t *map = slot.getcairo(_input2); + cairo_surface_t *out = ink_cairo_surface_create_identical(texture); + // color_interpolation_filters for out same as texture. See spec. + copy_cairo_surface_ci( texture, out ); + + // We may need to transform map surface to correct color interpolation space. The map surface + // might be used as input to another primitive but it is likely that all the primitives in a given + // filter use the same color interpolation space so we don't copy the map before converting. + SPColorInterpolation ci_fp = SP_CSS_COLOR_INTERPOLATION_AUTO; + if( _style ) { + ci_fp = (SPColorInterpolation)_style->color_interpolation_filters.computed; + } + set_cairo_surface_ci( map, ci_fp ); + + Geom::Affine trans = slot.get_units().get_matrix_primitiveunits2pb(); + + int device_scale = slot.get_device_scale(); + double scalex = scale * trans.expansionX() * device_scale; + double scaley = scale * trans.expansionY() * device_scale; + + ink_cairo_surface_synthesize(out, Displace(texture, map, Xchannel, Ychannel, scalex, scaley)); + + slot.set(_output, out); + cairo_surface_destroy(out); +} + +void FilterDisplacementMap::set_input(int slot) { + _input = slot; +} + +void FilterDisplacementMap::set_scale(double s) { + scale = s; +} + +void FilterDisplacementMap::set_input(int input, int slot) { + if (input == 0) _input = slot; + if (input == 1) _input2 = slot; +} + +void FilterDisplacementMap::set_channel_selector(int s, FilterDisplacementMapChannelSelector channel) { + if (channel > DISPLACEMENTMAP_CHANNEL_ALPHA || channel < DISPLACEMENTMAP_CHANNEL_RED) { + g_warning("Selected an invalid channel value. (%d)", channel); + return; + } + + // channel numbering: + // a = 3, r = 2, g = 1, b = 0 + // this way we can get the component value using: + // component = (color & (ch*8)) >> (ch*8) + unsigned ch = 4; + switch (channel) { + case DISPLACEMENTMAP_CHANNEL_ALPHA: + ch = 3; break; + case DISPLACEMENTMAP_CHANNEL_RED: + ch = 2; break; + case DISPLACEMENTMAP_CHANNEL_GREEN: + ch = 1; break; + case DISPLACEMENTMAP_CHANNEL_BLUE: + ch = 0; break; + default: break; + } + if (ch == 4) return; + + if (s == 0) Xchannel = ch; + if (s == 1) Ychannel = ch; +} + +void FilterDisplacementMap::area_enlarge(Geom::IntRect &area, Geom::Affine const &trans) +{ + //I assume scale is in user coordinates (?!?) + //FIXME: trans should be multiplied by some primitiveunits2user, shouldn't it? + + double scalex = scale/2.*(std::fabs(trans[0])+std::fabs(trans[1])); + double scaley = scale/2.*(std::fabs(trans[2])+std::fabs(trans[3])); + + //FIXME: no +2 should be there!... (noticeable only for big scales at big zoom factor) + area.expandBy(scalex+2, scaley+2); +} + +double FilterDisplacementMap::complexity(Geom::Affine const &) +{ + return 3.0; +} + +} /* namespace Filters */ +} /* namespace Inkscape */ + +/* + 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:fileencoding=utf-8:textwidth=99 : -- cgit v1.2.3