From ad7e78cb16ace844160e613742645e012fd22cc9 Mon Sep 17 00:00:00 2001 From: kiirala Date: Thu, 26 Jul 2007 11:38:36 +0000 Subject: [PATCH] Added support for feMerge filter priitive --- src/Makefile_insert | 1 + src/display/Makefile_insert | 2 + src/display/nr-filter-merge.cpp | 140 +++++++++++++++++++++++++ src/display/nr-filter-merge.h | 51 +++++++++ src/display/nr-filter.cpp | 3 +- src/sp-femerge.cpp | 42 ++++++-- src/sp-femerge.h | 1 - src/sp-femergenode.cpp | 177 ++++++++++++++++++++++++++++++++ src/sp-femergenode.h | 49 +++++++++ src/sp-object-repr.cpp | 2 + 10 files changed, 459 insertions(+), 9 deletions(-) create mode 100644 src/display/nr-filter-merge.cpp create mode 100644 src/display/nr-filter-merge.h create mode 100644 src/sp-femergenode.cpp create mode 100644 src/sp-femergenode.h diff --git a/src/Makefile_insert b/src/Makefile_insert index 548a49334..d57dd5774 100644 --- a/src/Makefile_insert +++ b/src/Makefile_insert @@ -173,6 +173,7 @@ libinkpre_a_SOURCES = \ sp-feimage-fns.h \ sp-femerge.cpp sp-femerge.h \ sp-femerge-fns.h \ + sp-femergenode.cpp sp-femergenode.h \ sp-femorphology.cpp sp-femorphology.h \ sp-femorphology-fns.h \ sp-feoffset.cpp sp-feoffset.h \ diff --git a/src/display/Makefile_insert b/src/display/Makefile_insert index 624733a42..1713dc751 100644 --- a/src/display/Makefile_insert +++ b/src/display/Makefile_insert @@ -83,6 +83,8 @@ display_libspdisplay_a_SOURCES = \ display/nr-filter-getalpha.h \ display/nr-filter-image.cpp \ display/nr-filter-image.h \ + display/nr-filter-merge.cpp \ + display/nr-filter-merge.h \ display/nr-filter-offset.cpp \ display/nr-filter-offset.h \ display/nr-filter-primitive.cpp \ diff --git a/src/display/nr-filter-merge.cpp b/src/display/nr-filter-merge.cpp new file mode 100644 index 000000000..8650fee8b --- /dev/null +++ b/src/display/nr-filter-merge.cpp @@ -0,0 +1,140 @@ +/* + * feMerge filter effect renderer + * + * Authors: + * Niko Kiirala + * + * Copyright (C) 2007 authors + * + * Released under GNU GPL, read the file 'COPYING' for more information + */ + +#include +#include + +#include "isnan.h" +#include "sp-femerge.h" +#include "display/nr-filter-merge.h" +#include "display/nr-filter-pixops.h" +#include "display/nr-filter-slot.h" +#include "display/nr-filter-utils.h" +#include "libnr/nr-blit.h" +#include "libnr/nr-pixblock.h" +#include "libnr/nr-pixops.h" +#include "libnr/nr-matrix.h" + +inline void +composite_over(unsigned char *r, unsigned char const *a, unsigned char const *b) +{ + r[0] = a[0] + NR_NORMALIZE_21(b[0] * (255 - a[3])); + r[1] = a[1] + NR_NORMALIZE_21(b[1] * (255 - a[3])); + r[2] = a[2] + NR_NORMALIZE_21(b[2] * (255 - a[3])); + r[3] = a[3] + NR_NORMALIZE_21(b[3] * (255 - a[3])); +} + +namespace NR { + +FilterMerge::FilterMerge() : + _input_image(1, NR_FILTER_SLOT_NOT_SET) +{} + +FilterPrimitive * FilterMerge::create() { + return new FilterMerge(); +} + +FilterMerge::~FilterMerge() +{} + +int FilterMerge::render(FilterSlot &slot, Matrix const &trans) { + NRPixBlock *in[_input_image.size()]; + NRPixBlock *original_in[_input_image.size()]; + + for (unsigned int i = 0 ; i < _input_image.size() ; i++) { + in[i] = slot.get(_input_image[i]); + original_in[i] = in[i]; + } + + NRPixBlock *out; + + // Bail out if either one of source images is missing + for (unsigned int i = 0 ; i < _input_image.size() ; i++) { + if (!in[i]) { + g_warning("Missing source image for feMerge (number=%d slot=%d)", i, _input_image[i]); + return 1; + } + } + + out = new NRPixBlock; + NRRectL out_area = in[0]->area; + for (unsigned int i = 1 ; i < _input_image.size() ; i++) { + nr_rect_l_union(&out_area, &out_area, &in[i]->area); + } + nr_pixblock_setup_fast(out, NR_PIXBLOCK_MODE_R8G8B8A8P, + out_area.x0, out_area.y0, out_area.x1, out_area.y1, + true); + + // Merge is defined for premultiplied RGBA values, thus convert them to + // that format before blending + for (unsigned int i = 0 ; i < _input_image.size() ; i++) { + if (in[i]->mode != NR_PIXBLOCK_MODE_R8G8B8A8P) { + in[i] = new NRPixBlock; + nr_pixblock_setup_fast(in[i], NR_PIXBLOCK_MODE_R8G8B8A8P, + original_in[i]->area.x0, + original_in[i]->area.y0, + original_in[i]->area.x1, + original_in[i]->area.y1, + false); + nr_blit_pixblock_pixblock(in[i], original_in[i]); + } + } + + /* pixops_mix is defined in display/nr-filter-pixops.h + * It mixes the two input images with the function given as template + * and places the result in output image. + */ + for (unsigned int i = 0 ; i < _input_image.size() ; i++) { + pixops_mix(*out, *in[i], *out); + } + + for (unsigned int i = 0 ; i < _input_image.size() ; i++) { + if (in[i] != original_in[i]) { + nr_pixblock_release(in[i]); + delete in[i]; + } + } + + out->empty = FALSE; + slot.set(_output, out); + + return 0; +} + +void FilterMerge::set_input(int slot) { + _input_image[0] = slot; +} + +void FilterMerge::set_input(int input, int slot) { + if (input < 0) return; + + if (_input_image.size() > input) { + _input_image[input] = slot; + } else { + for (unsigned int i = _input_image.size() ; i < input ; i++) { + _input_image.push_back(NR_FILTER_SLOT_NOT_SET); + } + _input_image.push_back(slot); + } +} + +} /* 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-merge.h b/src/display/nr-filter-merge.h new file mode 100644 index 000000000..a88819c50 --- /dev/null +++ b/src/display/nr-filter-merge.h @@ -0,0 +1,51 @@ +#ifndef __NR_FILTER_MERGE_H__ +#define __NR_FILTER_MERGE_H__ + +/* + * feMerge filter effect renderer + * + * Authors: + * Niko Kiirala + * + * Copyright (C) 2007 authors + * + * Released under GNU GPL, read the file 'COPYING' for more information + */ + +#include + +#include "sp-femerge.h" +#include "display/nr-filter-primitive.h" +#include "display/nr-filter-slot.h" +#include "libnr/nr-matrix.h" + +namespace NR { + +class FilterMerge : public FilterPrimitive { +public: + FilterMerge(); + static FilterPrimitive *create(); + virtual ~FilterMerge(); + + virtual int render(FilterSlot &slot, Matrix const &trans); + + virtual void set_input(int input); + virtual void set_input(int input, int slot); + +private: + std::vector _input_image; +}; + +} /* namespace NR */ + +#endif /* __NR_FILTER_MERGE_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 f09573eb4..95867363b 100644 --- a/src/display/nr-filter.cpp +++ b/src/display/nr-filter.cpp @@ -28,6 +28,7 @@ #include "display/nr-filter-displacement-map.h" #include "display/nr-filter-gaussian.h" #include "display/nr-filter-image.h" +#include "display/nr-filter-merge.h" #include "display/nr-filter-offset.h" #include "display/nr-filter-specularlighting.h" #include "display/nr-filter-turbulence.h" @@ -326,7 +327,7 @@ void Filter::_create_constructor_table() _constructor[NR_FILTER_FLOOD] = NULL; _constructor[NR_FILTER_GAUSSIANBLUR] = &FilterGaussian::create; _constructor[NR_FILTER_IMAGE] = &FilterImage::create; - _constructor[NR_FILTER_MERGE] = NULL; + _constructor[NR_FILTER_MERGE] = &FilterMerge::create; _constructor[NR_FILTER_MORPHOLOGY] = NULL; _constructor[NR_FILTER_OFFSET] = &FilterOffset::create; _constructor[NR_FILTER_SPECULARLIGHTING] = &FilterSpecularLighting::create; diff --git a/src/sp-femerge.cpp b/src/sp-femerge.cpp index 2b262db0d..dfa664941 100644 --- a/src/sp-femerge.cpp +++ b/src/sp-femerge.cpp @@ -19,9 +19,11 @@ #include "attributes.h" #include "svg/svg.h" -#include "sp-femerge.h" #include "xml/repr.h" +#include "sp-femerge.h" +#include "sp-femergenode.h" +#include "display/nr-filter-merge.h" /* FeMerge base class */ @@ -33,6 +35,7 @@ static void sp_feMerge_release(SPObject *object); static void sp_feMerge_set(SPObject *object, unsigned int key, gchar const *value); static void sp_feMerge_update(SPObject *object, SPCtx *ctx, guint flags); static Inkscape::XML::Node *sp_feMerge_write(SPObject *object, Inkscape::XML::Node *repr, guint flags); +static void sp_feMerge_build_renderer(SPFilterPrimitive *primitive, NR::Filter *filter); static SPFilterPrimitiveClass *feMerge_parent_class; @@ -61,6 +64,7 @@ static void sp_feMerge_class_init(SPFeMergeClass *klass) { SPObjectClass *sp_object_class = (SPObjectClass *)klass; + SPFilterPrimitiveClass *sp_primitive_class = (SPFilterPrimitiveClass *)klass; feMerge_parent_class = (SPFilterPrimitiveClass*)g_type_class_peek_parent(klass); @@ -69,6 +73,8 @@ sp_feMerge_class_init(SPFeMergeClass *klass) sp_object_class->write = sp_feMerge_write; sp_object_class->set = sp_feMerge_set; sp_object_class->update = sp_feMerge_update; + + sp_primitive_class->build_renderer = sp_feMerge_build_renderer; } static void @@ -126,11 +132,8 @@ sp_feMerge_set(SPObject *object, unsigned int key, gchar const *value) static void sp_feMerge_update(SPObject *object, SPCtx *ctx, guint flags) { - if (flags & (SP_OBJECT_MODIFIED_FLAG | SP_OBJECT_STYLE_MODIFIED_FLAG | - SP_OBJECT_VIEWPORT_MODIFIED_FLAG)) { - - /* do something to trigger redisplay, updates? */ - + if (flags & SP_OBJECT_MODIFIED_FLAG) { + object->parent->requestModified(SP_OBJECT_MODIFIED_FLAG); } if (((SPObjectClass *) feMerge_parent_class)->update) { @@ -148,7 +151,7 @@ sp_feMerge_write(SPObject *object, Inkscape::XML::Node *repr, guint flags) if (flags & SP_OBJECT_WRITE_EXT) { if (repr) { // is this sane? - repr->mergeFrom(SP_OBJECT_REPR(object), "id"); + //repr->mergeFrom(SP_OBJECT_REPR(object), "id"); } else { repr = SP_OBJECT_REPR(object)->duplicate(NULL); // FIXME } @@ -161,6 +164,31 @@ sp_feMerge_write(SPObject *object, Inkscape::XML::Node *repr, guint flags) return repr; } +static void sp_feMerge_build_renderer(SPFilterPrimitive *primitive, NR::Filter *filter) { + g_assert(primitive != NULL); + g_assert(filter != NULL); + + SPFeMerge *sp_merge = SP_FEMERGE(primitive); + + int primitive_n = filter->add_primitive(NR::NR_FILTER_MERGE); + NR::FilterPrimitive *nr_primitive = filter->get_primitive(primitive_n); + NR::FilterMerge *nr_merge = dynamic_cast(nr_primitive); + g_assert(nr_merge != NULL); + + sp_filter_primitive_renderer_common(primitive, nr_primitive); + + SPObject *input = primitive->children; + int in_nr = 0; + while (input) { + if (SP_IS_FEMERGENODE(input)) { + SPFeMergeNode *node = SP_FEMERGENODE(input); + nr_merge->set_input(in_nr, node->input); + in_nr++; + } + input = input->next; + } +} + /* Local Variables: diff --git a/src/sp-femerge.h b/src/sp-femerge.h index 015f2e33c..f83697fca 100644 --- a/src/sp-femerge.h +++ b/src/sp-femerge.h @@ -20,7 +20,6 @@ class SPFeMergeClass; struct SPFeMerge : public SPFilterPrimitive { - /** MERGE ATTRIBUTES HERE */ }; diff --git a/src/sp-femergenode.cpp b/src/sp-femergenode.cpp new file mode 100644 index 000000000..09687e54b --- /dev/null +++ b/src/sp-femergenode.cpp @@ -0,0 +1,177 @@ +#define __SP_FEMERGENODE_CPP__ + +/** \file + * feMergeNode implementation. A feMergeNode contains the name of one + * input image for feMerge. + */ +/* + * Authors: + * Kees Cook + * Niko Kiirala + * + * Copyright (C) 2004,2007 authors + * + * Released under GNU GPL, read the file 'COPYING' for more information + */ + +#ifdef HAVE_CONFIG_H +# include "config.h" +#endif + +#include "attributes.h" +#include "xml/repr.h" +#include "sp-femergenode.h" +#include "sp-femerge.h" + +static void sp_feMergeNode_class_init(SPFeMergeNodeClass *klass); +static void sp_feMergeNode_init(SPFeMergeNode *skeleton); + +static void sp_feMergeNode_build(SPObject *object, SPDocument *document, Inkscape::XML::Node *repr); +static void sp_feMergeNode_release(SPObject *object); +static void sp_feMergeNode_set(SPObject *object, unsigned int key, gchar const *value); +static void sp_feMergeNode_update(SPObject *object, SPCtx *ctx, guint flags); +static Inkscape::XML::Node *sp_feMergeNode_write(SPObject *object, Inkscape::XML::Node *repr, guint flags); + +static SPObjectClass *feMergeNode_parent_class; + +GType +sp_feMergeNode_get_type() +{ + static GType feMergeNode_type = 0; + + if (!feMergeNode_type) { + GTypeInfo feMergeNode_info = { + sizeof(SPFeMergeNodeClass), + NULL, NULL, + (GClassInitFunc) sp_feMergeNode_class_init, + NULL, NULL, + sizeof(SPFeMergeNode), + 16, + (GInstanceInitFunc) sp_feMergeNode_init, + NULL, /* value_table */ + }; + feMergeNode_type = g_type_register_static(SP_TYPE_OBJECT, "SPFeMergeNode", &feMergeNode_info, (GTypeFlags)0); + } + return feMergeNode_type; +} + +static void +sp_feMergeNode_class_init(SPFeMergeNodeClass *klass) +{ + //GObjectClass *gobject_class = (GObjectClass *)klass; + SPObjectClass *sp_object_class = (SPObjectClass *)klass; + + feMergeNode_parent_class = (SPObjectClass*)g_type_class_peek_parent(klass); + + sp_object_class->build = sp_feMergeNode_build; + sp_object_class->release = sp_feMergeNode_release; + sp_object_class->write = sp_feMergeNode_write; + sp_object_class->set = sp_feMergeNode_set; + sp_object_class->update = sp_feMergeNode_update; +} + +static void +sp_feMergeNode_init(SPFeMergeNode *feMergeNode) +{ + feMergeNode->input = NR::NR_FILTER_SLOT_NOT_SET; +} + +/** + * Reads the Inkscape::XML::Node, and initializes SPFeMergeNode variables. For this to get called, + * our name must be associated with a repr via "sp_object_type_register". Best done through + * sp-object-repr.cpp's repr_name_entries array. + */ +static void +sp_feMergeNode_build(SPObject *object, SPDocument *document, Inkscape::XML::Node *repr) +{ + sp_object_read_attr(object, "in"); +} + +/** + * Drops any allocated memory. + */ +static void +sp_feMergeNode_release(SPObject *object) +{ + /* deal with our children and our selves here */ + + if (((SPObjectClass *) feMergeNode_parent_class)->release) + ((SPObjectClass *) feMergeNode_parent_class)->release(object); +} + +/** + * Sets a specific value in the SPFeMergeNode. + */ +static void +sp_feMergeNode_set(SPObject *object, unsigned int key, gchar const *value) +{ + SPFeMergeNode *feMergeNode = SP_FEMERGENODE(object); + SPFeMerge *parent = SP_FEMERGE(object->parent); + + if (key == SP_ATTR_IN) { + int input = sp_filter_primitive_read_in(parent, value); + if (input != feMergeNode->input) { + feMergeNode->input = input; + object->requestModified(SP_OBJECT_MODIFIED_FLAG); + } + } + + /* See if any parents need this value. */ + if (((SPObjectClass *) feMergeNode_parent_class)->set) { + ((SPObjectClass *) feMergeNode_parent_class)->set(object, key, value); + } +} + +/** + * Receives update notifications. + */ +static void +sp_feMergeNode_update(SPObject *object, SPCtx *ctx, guint flags) +{ + //SPFeMergeNode *feMergeNode = SP_FEMERGENODE(object); + + if (flags & SP_OBJECT_MODIFIED_FLAG) { + object->parent->requestModified(SP_OBJECT_MODIFIED_FLAG); + } + + if (((SPObjectClass *) feMergeNode_parent_class)->update) { + ((SPObjectClass *) feMergeNode_parent_class)->update(object, ctx, flags); + } +} + +/** + * Writes its settings to an incoming repr object, if any. + */ +static Inkscape::XML::Node * +sp_feMergeNode_write(SPObject *object, Inkscape::XML::Node *repr, guint flags) +{ + //SPFeMergeNode *feMergeNode = SP_FEMERGENODE(object); + + // Inkscape-only object, not copied during an "plain SVG" dump: + if (flags & SP_OBJECT_WRITE_EXT) { + if (repr) { + // is this sane? + repr->mergeFrom(SP_OBJECT_REPR(object), "id"); + } else { + repr = SP_OBJECT_REPR(object)->duplicate(NULL); // FIXME + } + } + + if (((SPObjectClass *) feMergeNode_parent_class)->write) { + ((SPObjectClass *) feMergeNode_parent_class)->write(object, repr, flags); + } + + return repr; +} + + +/* + 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/sp-femergenode.h b/src/sp-femergenode.h new file mode 100644 index 000000000..8ec00bdcd --- /dev/null +++ b/src/sp-femergenode.h @@ -0,0 +1,49 @@ +#ifndef SP_FEMERGENODE_H_SEEN +#define SP_FEMERGENODE_H_SEEN + +/** \file + * feMergeNode implementation. A feMergeNode stores information about one + * input image for feMerge filter primitive. + */ +/* + * Authors: + * Kees Cook + * Niko Kiirala + * + * Copyright (C) 2004,2007 authors + * + * Released under GNU GPL, read the file 'COPYING' for more information + */ + +#include "sp-object.h" + +#define SP_TYPE_FEMERGENODE (sp_feMergeNode_get_type()) +#define SP_FEMERGENODE(o) (G_TYPE_CHECK_INSTANCE_CAST((o), SP_TYPE_FEMERGENODE, SPFeMergeNode)) +#define SP_IS_FEMERGENODE(o) (G_TYPE_CHECK_INSTANCE_TYPE((o), SP_TYPE_FEMERGENODE)) + +class SPFeMergeNode; +class SPFeMergeNodeClass; + +struct SPFeMergeNode : public SPObject { + int input; +}; + +struct SPFeMergeNodeClass { + SPObjectClass parent_class; +}; + +GType sp_feMergeNode_get_type(); + + +#endif /* !SP_FEMERGENODE_H_SEEN */ + +/* + 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/sp-object-repr.cpp b/src/sp-object-repr.cpp index 4e417e294..f05455e84 100644 --- a/src/sp-object-repr.cpp +++ b/src/sp-object-repr.cpp @@ -65,6 +65,7 @@ #include "sp-fespotlight.h" #include "sp-fetile.h" #include "sp-feturbulence.h" +#include "sp-femergenode.h" enum NameType { REPR_NAME, SODIPODI_TYPE }; static unsigned const N_NAME_TYPES = SODIPODI_TYPE + 1; @@ -153,6 +154,7 @@ populate_dtables() { "svg:feSpotLight", SP_TYPE_FESPOTLIGHT }, { "svg:feTile", SP_TYPE_FETILE }, { "svg:feTurbulence", SP_TYPE_FETURBULENCE }, + { "svg:feMergeNode", SP_TYPE_FEMERGENODE }, { "svg:image", SP_TYPE_IMAGE }, { "svg:line", SP_TYPE_LINE }, { "svg:linearGradient", SP_TYPE_LINEARGRADIENT }, -- 2.30.2