Code

Added support for feMerge filter priitive
authorkiirala <kiirala@users.sourceforge.net>
Thu, 26 Jul 2007 11:38:36 +0000 (11:38 +0000)
committerkiirala <kiirala@users.sourceforge.net>
Thu, 26 Jul 2007 11:38:36 +0000 (11:38 +0000)
src/Makefile_insert
src/display/Makefile_insert
src/display/nr-filter-merge.cpp [new file with mode: 0644]
src/display/nr-filter-merge.h [new file with mode: 0644]
src/display/nr-filter.cpp
src/sp-femerge.cpp
src/sp-femerge.h
src/sp-femergenode.cpp [new file with mode: 0644]
src/sp-femergenode.h [new file with mode: 0644]
src/sp-object-repr.cpp

index 548a4933491ffcfcd19c7eab85e3fbc9e9ddcbe1..d57dd5774c06d2e4547e7fa6c16e311e8e616a2a 100644 (file)
@@ -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   \
index 624733a42f2efbf3b9e7183f3186f541ec33dc82..1713dc75114dcf11071c82fa081a769c156272e7 100644 (file)
@@ -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 (file)
index 0000000..8650fee
--- /dev/null
@@ -0,0 +1,140 @@
+/*
+ * feMerge filter effect renderer
+ *
+ * Authors:
+ *   Niko Kiirala <niko@kiirala.com>
+ *
+ * Copyright (C) 2007 authors
+ *
+ * Released under GNU GPL, read the file 'COPYING' for more information
+ */
+
+#include <cmath>
+#include <vector>
+
+#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<composite_over>(*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 (file)
index 0000000..a88819c
--- /dev/null
@@ -0,0 +1,51 @@
+#ifndef __NR_FILTER_MERGE_H__
+#define __NR_FILTER_MERGE_H__
+
+/*
+ * feMerge filter effect renderer
+ *
+ * Authors:
+ *   Niko Kiirala <niko@kiirala.com>
+ *
+ * Copyright (C) 2007 authors
+ *
+ * Released under GNU GPL, read the file 'COPYING' for more information
+ */
+
+#include <vector>
+
+#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<int> _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 :
index f09573eb4694e5d4eb7c17b365d5596c692ef26e..95867363b8956b90b46e175584e5681205dc1ecb 100644 (file)
@@ -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;
index 2b262db0d2cfadbac7cae03ea6952b889d41735c..dfa664941d27263eb55225ae1ddf3ce5c8abd889 100644 (file)
 
 #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::FilterMerge*>(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:
index 015f2e33c415f435a1fdcba4d8c6159e170f5102..f83697fca9d914dfc1cdf4d6afcafb0327d6180f 100644 (file)
@@ -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 (file)
index 0000000..09687e5
--- /dev/null
@@ -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 <kees@outflux.net>
+ *   Niko Kiirala <niko@kiirala.com>
+ *
+ * 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 (file)
index 0000000..8ec00bd
--- /dev/null
@@ -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 <kees@outflux.net>
+ *   Niko Kiirala <niko@kiirala.com>
+ *
+ * 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 :
index 4e417e29434a6902864276e64584dbe8987df9c0..f05455e84f39fa9b73519ee846f99d4cf9408bd1 100644 (file)
@@ -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 },