summary | shortlog | log | commit | commitdiff | tree
raw | patch | inline | side by side (parent: 0eeda2c)
raw | patch | inline | side by side (parent: 0eeda2c)
author | kiirala <kiirala@users.sourceforge.net> | |
Mon, 9 Jul 2007 12:04:51 +0000 (12:04 +0000) | ||
committer | kiirala <kiirala@users.sourceforge.net> | |
Mon, 9 Jul 2007 12:04:51 +0000 (12:04 +0000) |
src/display/Makefile_insert | patch | blob | history | |
src/display/nr-filter-blend.cpp | patch | blob | history | |
src/display/nr-filter-composite.cpp | [new file with mode: 0644] | patch | blob |
src/display/nr-filter-composite.h | [new file with mode: 0644] | patch | blob |
src/display/nr-filter-pixops.h | [new file with mode: 0644] | patch | blob |
src/display/nr-filter-skeleton.cpp | patch | blob | history | |
src/display/nr-filter-skeleton.h | patch | blob | history | |
src/display/nr-filter.cpp | patch | blob | history | |
src/sp-fecomposite.cpp | patch | blob | history | |
src/sp-fecomposite.h | patch | blob | history | |
src/sp-feoffset.cpp | patch | blob | history |
index 462da04c58f05d31a05fc7960a373e6fbbd1a697..1a4c01011af4648086e5c68d2363f8d87baa42e4 100644 (file)
display/nr-filter-blend.h \
display/nr-filter-offset.cpp \
display/nr-filter-offset.h \
+ display/nr-filter-composite.h \
+ display/nr-filter-composite.cpp \
display/nr-filter-slot.cpp \
display/nr-filter-slot.h \
display/nr-filter-getalpha.cpp \
display/nr-filter-getalpha.h \
+ display/nr-filter-pixops.h \
display/nr-filter-types.h \
display/pixblock-scaler.cpp \
display/pixblock-scaler.h \
index 0e2f965b7256cbe4ac0f0444cb929e4d184a1ac5..b02b20cbf6d8eddcfbaa2e97bf400d40d1865128 100644 (file)
*/
#include "display/nr-filter-blend.h"
+#include "display/nr-filter-pixops.h"
#include "display/nr-filter-primitive.h"
#include "display/nr-filter-slot.h"
#include "display/nr-filter-types.h"
#include "libnr/nr-blit.h"
#include "libnr/nr-pixops.h"
-template <void(*blend)(unsigned char *cr, unsigned char const *ca, unsigned char const *cb)>
-static void _render(NRPixBlock &out, NRPixBlock &in1, NRPixBlock &in2) {
- unsigned char *in1_data = NR_PIXBLOCK_PX(&in1);
- unsigned char *in2_data = NR_PIXBLOCK_PX(&in2);
- unsigned char *out_data = NR_PIXBLOCK_PX(&out);
- unsigned char zero_rgba[4] = {0, 0, 0, 0};
-
- if (in1.area.y0 < in2.area.y0) {
- // in1 begins before in2 on y-axis
- for (int y = in1.area.y0 ; y < in2.area.y0 ; y++) {
- int out_line = (y - out.area.y0) * out.rs;
- int in_line = (y - in1.area.y0) * in1.rs;
- for (int x = in1.area.x0 ; x < in1.area.x1 ; x++) {
- blend(out_data + out_line + 4 * (x - out.area.x0),
- in1_data + in_line + 4 * (x - in1.area.x0),
- zero_rgba);
- }
- }
- } else if (in1.area.y0 > in2.area.y0) {
- // in2 begins before in1 on y-axis
- for (int y = in2.area.y0 ; y < in1.area.y0 ; y++) {
- int out_line = (y - out.area.y0) * out.rs;
- int in_line = (y - in2.area.y0) * in2.rs;
- for (int x = in2.area.x0 ; x < in2.area.x1 ; x++) {
- blend(out_data + out_line + 4 * (x - out.area.x0),
- zero_rgba,
- in2_data + in_line + 4 * (x - in2.area.x0));
- }
- }
- }
-
- for (int y = std::max(in1.area.y0, in2.area.y0) ;
- y < std::min(in1.area.y1, in2.area.y1) ; ++y) {
- int out_line = (y - out.area.y0) * out.rs;
- int in1_line = (y - in1.area.y0) * in1.rs;
- int in2_line = (y - in2.area.y0) * in2.rs;
-
- if (in1.area.x0 < in2.area.x0) {
- // in1 begins before in2 on x-axis
- for (int x = in1.area.x0 ; x < in2.area.x0 ; ++x) {
- blend(out_data + out_line + 4 * (x - out.area.x0),
- in1_data + in1_line + 4 * (x - in1.area.x0),
- zero_rgba);
- }
- } else if (in1.area.x0 > in2.area.x0) {
- // in2 begins before in1 on x-axis
- for (int x = in2.area.x0 ; x < in1.area.x0 ; ++x) {
- blend(out_data + out_line + 4 * (x - out.area.x0),
- zero_rgba,
- in2_data + in2_line + 4 * (x - in2.area.x0));
- }
- }
-
- for (int x = std::max(in1.area.x0, in2.area.x0) ;
- x < std::min(in1.area.x1, in2.area.x1) ; ++x) {
- blend(out_data + out_line + 4 * (x - out.area.x0),
- in1_data + in1_line + 4 * (x - in1.area.x0),
- in2_data + in2_line + 4 * (x - in2.area.x0));
- }
-
- if (in1.area.x1 > in2.area.x1) {
- // in1 ends after in2 on x-axis
- for (int x = in2.area.x1 ; x < in1.area.x1 ; ++x) {
- blend(out_data + out_line + 4 * (x - out.area.x0),
- in1_data + in1_line + 4 * (x - in1.area.x0),
- zero_rgba);
- }
- } else if (in1.area.x1 < in2.area.x1) {
- // in2 ends after in1 on x-axis
- for (int x = in1.area.x1 ; x < in2.area.x1 ; ++x) {
- blend(out_data + out_line + 4 * (x - out.area.x0),
- zero_rgba,
- in2_data + in2_line + 4 * (x - in2.area.x0));
- }
- }
- }
-
- if (in1.area.y1 > in2.area.y1) {
- // in1 ends after in2 on y-axis
- for (int y = in2.area.y1 ; y < in1.area.y1 ; y++) {
- int out_line = (y - out.area.y0) * out.rs;
- int in_line = (y - in1.area.y0) * in1.rs;
- for (int x = in1.area.x0 ; x < in1.area.x1 ; x++) {
- blend(out_data + out_line + 4 * (x - out.area.x0),
- in1_data + in_line + 4 * (x - in1.area.x0),
- zero_rgba);
- }
- }
- } else if (in1.area.y1 < in2.area.y1) {
- // in2 ends after in1 on y-axis
- for (int y = in1.area.y1 ; y < in2.area.y1 ; y++) {
- int out_line = (y - out.area.y0) * out.rs;
- int in_line = (y - in2.area.y0) * in2.rs;
- for (int x = in2.area.x0 ; x < in2.area.x1 ; x++) {
- blend(out_data + out_line + 4 * (x - out.area.x0),
- zero_rgba,
- in2_data + in_line + 4 * (x - in2.area.x0));
- }
- }
- }
-}
+namespace NR {
/*
* From http://www.w3.org/TR/SVG11/filters.html#feBlend
#define SET_ALPHA r[3] = NR_NORMALIZE_21((255 * 255) - (255 - a[3]) * (255 - b[3]))
// cr = (1 - qa) * cb + ca
-inline void blend_normal(unsigned char *r, unsigned char const *a, unsigned char const *b) {
+inline void
+blend_normal(unsigned char *r, unsigned char const *a, unsigned char const *b)
+{
r[0] = NR_NORMALIZE_21((255 - a[3]) * b[0]) + a[0];
r[1] = NR_NORMALIZE_21((255 - a[3]) * b[1]) + a[1];
r[2] = NR_NORMALIZE_21((255 - a[3]) * b[2]) + a[2];
}
// cr = (1-qa)*cb + (1-qb)*ca + ca*cb
-inline void blend_multiply(unsigned char *r, unsigned char const *a, unsigned char const *b) {
+inline void
+blend_multiply(unsigned char *r, unsigned char const *a, unsigned char const *b)
+{
r[0] = NR_NORMALIZE_21((255 - a[3]) * b[0] + (255 - b[3]) * a[0]
+ a[0] * b[0]);
r[1] = NR_NORMALIZE_21((255 - a[3]) * b[1] + (255 - b[3]) * a[1]
}
// cr = cb + ca - ca * cb
-inline void blend_screen(unsigned char *r, unsigned char const *a, unsigned char const *b) {
+inline void
+blend_screen(unsigned char *r, unsigned char const *a, unsigned char const *b)
+{
r[0] = NR_NORMALIZE_21(b[0] * 255 + a[0] * 255 - a[0] * b[0]);
r[1] = NR_NORMALIZE_21(b[1] * 255 + a[1] * 255 - a[1] * b[1]);
r[2] = NR_NORMALIZE_21(b[2] * 255 + a[2] * 255 - a[2] * b[2]);
}
// cr = Min ((1 - qa) * cb + ca, (1 - qb) * ca + cb)
-inline void blend_darken(unsigned char *r, unsigned char const *a, unsigned char const *b) {
+inline void
+blend_darken(unsigned char *r, unsigned char const *a, unsigned char const *b)
+{
r[0] = std::min(NR_NORMALIZE_21((255 - a[3]) * b[0]) + a[0],
NR_NORMALIZE_21((255 - b[3]) * a[0]) + b[0]);
r[1] = std::min(NR_NORMALIZE_21((255 - a[3]) * b[1]) + a[1],
}
// cr = Max ((1 - qa) * cb + ca, (1 - qb) * ca + cb)
-inline void blend_lighten(unsigned char *r, unsigned char const *a, unsigned char const *b) {
+inline void
+blend_lighten(unsigned char *r, unsigned char const *a, unsigned char const *b)
+{
r[0] = std::max(NR_NORMALIZE_21((255 - a[3]) * b[0]) + a[0],
NR_NORMALIZE_21((255 - b[3]) * a[0]) + b[0]);
r[1] = std::max(NR_NORMALIZE_21((255 - a[3]) * b[1]) + a[1],
@@ -200,8 +111,6 @@ inline void blend_lighten(unsigned char *r, unsigned char const *a, unsigned cha
SET_ALPHA;
}
-namespace NR {
-
FilterBlend::FilterBlend()
: _blend_mode(BLEND_NORMAL),
_input2(NR_FILTER_SLOT_NOT_SET)
nr_blit_pixblock_pixblock(in2, original_in2);
}
+ /* 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.
+ */
switch (_blend_mode) {
case BLEND_MULTIPLY:
- _render<blend_multiply>(*out, *in1, *in2);
+ pixops_mix<blend_multiply>(*out, *in1, *in2);
break;
case BLEND_SCREEN:
- _render<blend_screen>(*out, *in1, *in2);
+ pixops_mix<blend_screen>(*out, *in1, *in2);
break;
case BLEND_DARKEN:
- _render<blend_darken>(*out, *in1, *in2);
+ pixops_mix<blend_darken>(*out, *in1, *in2);
break;
case BLEND_LIGHTEN:
- _render<blend_lighten>(*out, *in1, *in2);
+ pixops_mix<blend_lighten>(*out, *in1, *in2);
break;
case BLEND_NORMAL:
default:
- _render<blend_normal>(*out, *in1, *in2);
+ pixops_mix<blend_normal>(*out, *in1, *in2);
break;
}
diff --git a/src/display/nr-filter-composite.cpp b/src/display/nr-filter-composite.cpp
--- /dev/null
@@ -0,0 +1,235 @@
+/*
+ * feComposite 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 "isnan.h"
+#include "sp-fecomposite.h"
+#include "display/nr-filter-composite.h"
+#include "display/nr-filter-pixops.h"
+#include "display/nr-filter-slot.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]));
+}
+
+inline void
+composite_in(unsigned char *r, unsigned char const *a, unsigned char const *b)
+{
+ r[0] = NR_NORMALIZE_21(a[0] * b[3]);
+ r[1] = NR_NORMALIZE_21(a[1] * b[3]);
+ r[2] = NR_NORMALIZE_21(a[2] * b[3]);
+ r[3] = NR_NORMALIZE_21(a[3] * b[3]);
+}
+
+inline void
+composite_out(unsigned char *r, unsigned char const *a, unsigned char const *b)
+{
+ r[0] = NR_NORMALIZE_21(a[0] * (255 - b[3]));
+ r[1] = NR_NORMALIZE_21(a[1] * (255 - b[3]));
+ r[2] = NR_NORMALIZE_21(a[2] * (255 - b[3]));
+ r[3] = NR_NORMALIZE_21(a[3] * (255 - b[3]));
+}
+
+inline void
+composite_atop(unsigned char *r, unsigned char const *a, unsigned char const *b)
+{
+ r[0] = NR_NORMALIZE_21(a[0] * b[3] + b[0] * (255 - a[3]));
+ r[1] = NR_NORMALIZE_21(a[1] * b[3] + b[1] * (255 - a[3]));
+ r[2] = NR_NORMALIZE_21(a[2] * b[3] + b[2] * (255 - a[3]));
+ r[3] = b[3];
+}
+
+inline void
+composite_xor(unsigned char *r, unsigned char const *a, unsigned char const *b)
+{
+ r[0] = NR_NORMALIZE_21(a[0] * (255 - b[3]) + b[0] * (255 - a[3]));
+ r[1] = NR_NORMALIZE_21(a[1] * (255 - b[3]) + b[1] * (255 - a[3]));
+ r[2] = NR_NORMALIZE_21(a[2] * (255 - b[3]) + b[2] * (255 - a[3]));
+ r[3] = NR_NORMALIZE_21(a[3] * (255 - b[3]) + b[3] * (255 - a[3]));
+}
+
+static int clamp(int val) {
+ if (val < 0) return 0;
+ if (val > 255) return 255;
+ return val;
+}
+
+// BUGBUG / TODO
+// This makes arithmetic compositing non re-entrant and non thread safe.
+static int arith_k1, arith_k2, arith_k3, arith_k4;
+inline void
+composite_arithmetic(unsigned char *r, unsigned char const *a, unsigned char const *b)
+{
+ r[0] = clamp(NR_NORMALIZE_31(arith_k1 * a[0] * b[0]
+ + arith_k2 * a[0] + arith_k3 * b[0] + arith_k4));
+ r[1] = clamp(NR_NORMALIZE_31(arith_k1 * a[1] * b[1]
+ + arith_k2 * a[1] + arith_k3 * b[1] + arith_k4));
+ r[2] = clamp(NR_NORMALIZE_31(arith_k1 * a[2] * b[2]
+ + arith_k2 * a[2] + arith_k3 * b[2] + arith_k4));
+ r[3] = clamp(NR_NORMALIZE_31(arith_k1 * a[3] * b[3]
+ + arith_k2 * a[3] + arith_k3 * b[3] + arith_k4));
+}
+
+namespace NR {
+
+FilterComposite::FilterComposite() :
+ op(COMPOSITE_DEFAULT), k1(0), k2(0), k3(0), k4(0),
+ _input2(NR::NR_FILTER_SLOT_NOT_SET)
+{}
+
+FilterPrimitive * FilterComposite::create() {
+ return new FilterComposite();
+}
+
+FilterComposite::~FilterComposite()
+{}
+
+int FilterComposite::render(FilterSlot &slot, Matrix const &trans) {
+ NRPixBlock *in1 = slot.get(_input);
+ NRPixBlock *in2 = slot.get(_input2);
+ NRPixBlock *original_in1 = in1;
+ NRPixBlock *original_in2 = in2;
+ NRPixBlock *out;
+
+ // Bail out if either one of source images is missing
+ if (!in1 || !in2) {
+ g_warning("Missing source image for feComposite (in=%d in2=%d)", _input, _input2);
+ return 1;
+ }
+
+ out = new NRPixBlock;
+ NRRectL out_area;
+ nr_rect_l_union(&out_area, &in1->area, &in2->area);
+ nr_pixblock_setup_fast(out, NR_PIXBLOCK_MODE_R8G8B8A8P,
+ out_area.x0, out_area.y0, out_area.x1, out_area.y1,
+ true);
+
+ // Blending modes are defined for premultiplied RGBA values,
+ // thus convert them to that format before blending
+ if (in1->mode != NR_PIXBLOCK_MODE_R8G8B8A8P) {
+ in1 = new NRPixBlock;
+ nr_pixblock_setup_fast(in1, NR_PIXBLOCK_MODE_R8G8B8A8P,
+ original_in1->area.x0, original_in1->area.y0,
+ original_in1->area.x1, original_in1->area.y1,
+ false);
+ nr_blit_pixblock_pixblock(in1, original_in1);
+ }
+ if (in2->mode != NR_PIXBLOCK_MODE_R8G8B8A8P) {
+ in2 = new NRPixBlock;
+ nr_pixblock_setup_fast(in2, NR_PIXBLOCK_MODE_R8G8B8A8P,
+ original_in2->area.x0, original_in2->area.y0,
+ original_in2->area.x1, original_in2->area.y1,
+ false);
+ nr_blit_pixblock_pixblock(in2, original_in2);
+ }
+
+ /* 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.
+ */
+ switch (op) {
+ case COMPOSITE_IN:
+ pixops_mix<composite_in>(*out, *in1, *in2);
+ break;
+ case COMPOSITE_OUT:
+ pixops_mix<composite_out>(*out, *in1, *in2);
+ break;
+ case COMPOSITE_ATOP:
+ pixops_mix<composite_atop>(*out, *in1, *in2);
+ break;
+ case COMPOSITE_XOR:
+ pixops_mix<composite_xor>(*out, *in1, *in2);
+ break;
+ case COMPOSITE_ARITHMETIC:
+ arith_k1 = (int)(k1 * 255);
+ arith_k2 = (int)(k2 * 255 * 255);
+ arith_k3 = (int)(k3 * 255 * 255);
+ arith_k4 = (int)(k4 * 255 * 255 * 255);
+ pixops_mix<composite_arithmetic>(*out, *in1, *in2);
+ break;
+ case COMPOSITE_DEFAULT:
+ case COMPOSITE_OVER:
+ default:
+ pixops_mix<composite_over>(*out, *in1, *in2);
+ break;
+ }
+
+ if (in1 != original_in1) {
+ nr_pixblock_release(in1);
+ delete in1;
+ }
+ if (in2 != original_in2) {
+ nr_pixblock_release(in2);
+ delete in2;
+ }
+
+ out->empty = FALSE;
+ slot.set(_output, out);
+
+ return 0;
+}
+
+void FilterComposite::set_input(int input) {
+ _input = input;
+}
+
+void FilterComposite::set_input(int input, int slot) {
+ if (input == 0) _input = slot;
+ if (input == 1) _input2 = slot;
+}
+
+void FilterComposite::set_operator(FeCompositeOperator op) {
+ if (op == COMPOSITE_DEFAULT) {
+ this->op = COMPOSITE_OVER;
+ } else if (op == COMPOSITE_OVER ||
+ op == COMPOSITE_IN ||
+ op == COMPOSITE_OUT ||
+ op == COMPOSITE_ATOP ||
+ op == COMPOSITE_XOR ||
+ op == COMPOSITE_ARITHMETIC)
+ {
+ this->op = op;
+ }
+}
+
+void FilterComposite::set_arithmetic(double k1, double k2, double k3, double k4) {
+ if (!isFinite(k1) || !isFinite(k2) || !isFinite(k3) || !isFinite(k4)) {
+ g_warning("Non-finite parameter for feComposite arithmetic operator");
+ return;
+ }
+ this->k1 = k1;
+ this->k2 = k2;
+ this->k3 = k3;
+ this->k4 = k4;
+}
+
+} /* 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-composite.h b/src/display/nr-filter-composite.h
--- /dev/null
@@ -0,0 +1,54 @@
+#ifndef __NR_FILTER_COMPOSITE_H__
+#define __NR_FILTER_COMPOSITE_H__
+
+/*
+ * feComposite 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 "sp-fecomposite.h"
+#include "display/nr-filter-primitive.h"
+#include "display/nr-filter-slot.h"
+#include "libnr/nr-matrix.h"
+
+namespace NR {
+
+class FilterComposite : public FilterPrimitive {
+public:
+ FilterComposite();
+ static FilterPrimitive *create();
+ virtual ~FilterComposite();
+
+ virtual int render(FilterSlot &slot, Matrix const &trans);
+
+ virtual void set_input(int input);
+ virtual void set_input(int input, int slot);
+
+ void set_operator(FeCompositeOperator op);
+ void set_arithmetic(double k1, double k2, double k3, double k4);
+
+private:
+ FeCompositeOperator op;
+ double k1, k2, k3, k4;
+ int _input2;
+};
+
+} /* namespace NR */
+
+#endif /* __NR_FILTER_COMPOSITE_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-pixops.h b/src/display/nr-filter-pixops.h
--- /dev/null
@@ -0,0 +1,148 @@
+#ifndef __NR_FILTER_PIXOPS_H__
+#define __NR_FILTER_PIXOPS_H__
+
+/*
+ * Per-pixel image manipulation functions.
+ * These can be used by all filter primitives, which combine two images on
+ * per-pixel basis. These are at least feBlend, feComposite and feMerge.
+ *
+ * Authors:
+ * Niko Kiirala <niko@kiirala.com>
+ *
+ * Copyright (C) 2007 authors
+ *
+ * Released under GNU GPL, read the file 'COPYING' for more information
+ */
+
+namespace NR {
+
+/**
+ * Mixes the two input images using the function given as template.
+ * The result is placed in out.
+ * The mixing function should have the following type:
+ * void mix(unsigned char *result, unsigned char const *in1,
+ * unsigned char const *in2);
+ * Each of the parameters for mix-function is a pointer to four bytes of data,
+ * giving the RGBA values for that pixel. The mix function must only access
+ * the four bytes beginning at a pointer given as parameter.
+ */
+/*
+ * The implementation is in a header file because of the template. It has to
+ * be in the same compilation unit as the code using it. Otherwise, linking
+ * the program will not succeed.
+ */
+template <void(*blend)(unsigned char *cr, unsigned char const *ca, unsigned char const *cb)>
+void pixops_mix(NRPixBlock &out, NRPixBlock &in1, NRPixBlock &in2) {
+ unsigned char *in1_data = NR_PIXBLOCK_PX(&in1);
+ unsigned char *in2_data = NR_PIXBLOCK_PX(&in2);
+ unsigned char *out_data = NR_PIXBLOCK_PX(&out);
+ unsigned char zero_rgba[4] = {0, 0, 0, 0};
+
+ if (in1.area.y0 < in2.area.y0) {
+ // in1 begins before in2 on y-axis
+ for (int y = in1.area.y0 ; y < in2.area.y0 ; y++) {
+ int out_line = (y - out.area.y0) * out.rs;
+ int in_line = (y - in1.area.y0) * in1.rs;
+ for (int x = in1.area.x0 ; x < in1.area.x1 ; x++) {
+ blend(out_data + out_line + 4 * (x - out.area.x0),
+ in1_data + in_line + 4 * (x - in1.area.x0),
+ zero_rgba);
+ }
+ }
+ } else if (in1.area.y0 > in2.area.y0) {
+ // in2 begins before in1 on y-axis
+ for (int y = in2.area.y0 ; y < in1.area.y0 ; y++) {
+ int out_line = (y - out.area.y0) * out.rs;
+ int in_line = (y - in2.area.y0) * in2.rs;
+ for (int x = in2.area.x0 ; x < in2.area.x1 ; x++) {
+ blend(out_data + out_line + 4 * (x - out.area.x0),
+ zero_rgba,
+ in2_data + in_line + 4 * (x - in2.area.x0));
+ }
+ }
+ }
+
+ for (int y = std::max(in1.area.y0, in2.area.y0) ;
+ y < std::min(in1.area.y1, in2.area.y1) ; ++y) {
+ int out_line = (y - out.area.y0) * out.rs;
+ int in1_line = (y - in1.area.y0) * in1.rs;
+ int in2_line = (y - in2.area.y0) * in2.rs;
+
+ if (in1.area.x0 < in2.area.x0) {
+ // in1 begins before in2 on x-axis
+ for (int x = in1.area.x0 ; x < in2.area.x0 ; ++x) {
+ blend(out_data + out_line + 4 * (x - out.area.x0),
+ in1_data + in1_line + 4 * (x - in1.area.x0),
+ zero_rgba);
+ }
+ } else if (in1.area.x0 > in2.area.x0) {
+ // in2 begins before in1 on x-axis
+ for (int x = in2.area.x0 ; x < in1.area.x0 ; ++x) {
+ blend(out_data + out_line + 4 * (x - out.area.x0),
+ zero_rgba,
+ in2_data + in2_line + 4 * (x - in2.area.x0));
+ }
+ }
+
+ for (int x = std::max(in1.area.x0, in2.area.x0) ;
+ x < std::min(in1.area.x1, in2.area.x1) ; ++x) {
+ blend(out_data + out_line + 4 * (x - out.area.x0),
+ in1_data + in1_line + 4 * (x - in1.area.x0),
+ in2_data + in2_line + 4 * (x - in2.area.x0));
+ }
+
+ if (in1.area.x1 > in2.area.x1) {
+ // in1 ends after in2 on x-axis
+ for (int x = in2.area.x1 ; x < in1.area.x1 ; ++x) {
+ blend(out_data + out_line + 4 * (x - out.area.x0),
+ in1_data + in1_line + 4 * (x - in1.area.x0),
+ zero_rgba);
+ }
+ } else if (in1.area.x1 < in2.area.x1) {
+ // in2 ends after in1 on x-axis
+ for (int x = in1.area.x1 ; x < in2.area.x1 ; ++x) {
+ blend(out_data + out_line + 4 * (x - out.area.x0),
+ zero_rgba,
+ in2_data + in2_line + 4 * (x - in2.area.x0));
+ }
+ }
+ }
+
+ if (in1.area.y1 > in2.area.y1) {
+ // in1 ends after in2 on y-axis
+ for (int y = in2.area.y1 ; y < in1.area.y1 ; y++) {
+ int out_line = (y - out.area.y0) * out.rs;
+ int in_line = (y - in1.area.y0) * in1.rs;
+ for (int x = in1.area.x0 ; x < in1.area.x1 ; x++) {
+ blend(out_data + out_line + 4 * (x - out.area.x0),
+ in1_data + in_line + 4 * (x - in1.area.x0),
+ zero_rgba);
+ }
+ }
+ } else if (in1.area.y1 < in2.area.y1) {
+ // in2 ends after in1 on y-axis
+ for (int y = in1.area.y1 ; y < in2.area.y1 ; y++) {
+ int out_line = (y - out.area.y0) * out.rs;
+ int in_line = (y - in2.area.y0) * in2.rs;
+ for (int x = in2.area.x0 ; x < in2.area.x1 ; x++) {
+ blend(out_data + out_line + 4 * (x - out.area.x0),
+ zero_rgba,
+ in2_data + in_line + 4 * (x - in2.area.x0));
+ }
+ }
+ }
+}
+
+} // namespace NR
+
+#endif // __NR_FILTER_PIXOPS_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 f595f13f16945fec949a1e9b35cb62911de419d8..68c38c4b22b5a0daac9c17fbf484ef71637129f3 100644 (file)
* type, like gaussian or blend in respective case.
*
* This can be accomplished with the following sed command:
- * sed -e "s/Skeleton/Name/g" -e "s/skeleton/name" -e "s/SKELETON/NAME"
+ * sed -e "s/Skeleton/Name/g" -e "s/skeleton/name/" -e "s/SKELETON/NAME/"
* nr-filter-skeleton.cpp >nr-filter-name.cpp
*
* (on one line, replace occurences of 'name' with your filter name)
index ae3a080468cb861ebd59d063ac4b78d937d2e88d..edba5c2f16834240590b3c6c6abdc8fb1a3912c6 100644 (file)
* type, like gaussian or blend in respective case.
*
* This can be accomplished with the following sed command:
- * sed -e "s/Skeleton/Name/g" -e "s/skeleton/name" -e "s/SKELETON/NAME"
+ * sed -e "s/Skeleton/Name/g" -e "s/skeleton/name/" -e "s/SKELETON/NAME/"
* nr-filter-skeleton.h >nr-filter-name.h
*
* (on one line, replace occurences of 'name' with your filter name)
index 33e89ac3eb3bede580cf4aa2cfc76f4ec2733dc9..61571f43bde80a5321bc764be81c6f532b253b45 100644 (file)
#include "display/nr-filter-types.h"
#include "display/pixblock-scaler.h"
#include "display/pixblock-transform.h"
+
#include "display/nr-filter-gaussian.h"
#include "display/nr-filter-blend.h"
#include "display/nr-filter-offset.h"
+#include "display/nr-filter-composite.h"
#include "display/nr-arena-item.h"
#include "libnr/nr-pixblock.h"
_constructor[NR_FILTER_BLEND] = &FilterBlend::create;
_constructor[NR_FILTER_COLORMATRIX] = NULL;
_constructor[NR_FILTER_COMPONENTTRANSFER] = NULL;
- _constructor[NR_FILTER_COMPOSITE] = NULL;
+ _constructor[NR_FILTER_COMPOSITE] = &FilterComposite::create;
_constructor[NR_FILTER_CONVOLVEMATRIX] = NULL;
_constructor[NR_FILTER_DIFFUSELIGHTING] = NULL;
_constructor[NR_FILTER_DISPLACEMENTMAP] = NULL;
diff --git a/src/sp-fecomposite.cpp b/src/sp-fecomposite.cpp
index 86839aab5bfffea83a9329e3d0c941a3c253c757..68312aa1b9ffd95a046ad120d1e34683f23a263e 100644 (file)
--- a/src/sp-fecomposite.cpp
+++ b/src/sp-fecomposite.cpp
#include "svg/svg.h"
#include "sp-fecomposite.h"
#include "xml/repr.h"
-
+#include "display/nr-filter-composite.h"
/* FeComposite base class */
static void sp_feComposite_set(SPObject *object, unsigned int key, gchar const *value);
static void sp_feComposite_update(SPObject *object, SPCtx *ctx, guint flags);
static Inkscape::XML::Node *sp_feComposite_write(SPObject *object, Inkscape::XML::Node *repr, guint flags);
+static void sp_feComposite_build_renderer(SPFilterPrimitive *primitive, NR::Filter *filter);
static SPFilterPrimitiveClass *feComposite_parent_class;
sp_feComposite_class_init(SPFeCompositeClass *klass)
{
SPObjectClass *sp_object_class = (SPObjectClass *)klass;
+ SPFilterPrimitiveClass *sp_primitive_class = (SPFilterPrimitiveClass *)klass;
feComposite_parent_class = (SPFilterPrimitiveClass*)g_type_class_peek_parent(klass);
sp_object_class->write = sp_feComposite_write;
sp_object_class->set = sp_feComposite_set;
sp_object_class->update = sp_feComposite_update;
+
+ sp_primitive_class->build_renderer = sp_feComposite_build_renderer;
}
static void
sp_feComposite_init(SPFeComposite *feComposite)
{
+ feComposite->composite_operator = COMPOSITE_DEFAULT;
+ feComposite->k1 = 0;
+ feComposite->k2 = 0;
+ feComposite->k3 = 0;
+ feComposite->k4 = 0;
+ feComposite->in2 = NR::NR_FILTER_SLOT_NOT_SET;
}
/**
((SPObjectClass *) feComposite_parent_class)->build(object, document, repr);
}
- /*LOAD ATTRIBUTES FROM REPR HERE*/
+ SPFeComposite *composite = SP_FECOMPOSITE(object);
+
+ sp_object_read_attr(object, "operator");
+ if (composite->composite_operator == COMPOSITE_ARITHMETIC) {
+ sp_object_read_attr(object, "k1");
+ sp_object_read_attr(object, "k2");
+ sp_object_read_attr(object, "k3");
+ sp_object_read_attr(object, "k4");
+ }
+ sp_object_read_attr(object, "in2");
}
/**
((SPObjectClass *) feComposite_parent_class)->release(object);
}
+static double
+sp_feComposite_read_number(gchar const *value) {
+ char *end;
+ double ret = g_ascii_strtod(value, &end);
+ if (*end) {
+ g_warning("Unable to convert \"%s\" to number", value);
+ // We could leave this out, too. If strtod can't convert
+ // anything, it will return zero.
+ ret = 0;
+ }
+ return ret;
+}
+
+static FeCompositeOperator
+sp_feComposite_read_operator(gchar const *value) {
+ if (!value) return COMPOSITE_DEFAULT;
+
+ if (strcmp(value, "over") == 0) return COMPOSITE_OVER;
+ else if (strcmp(value, "in") == 0) return COMPOSITE_IN;
+ else if (strcmp(value, "out") == 0) return COMPOSITE_OUT;
+ else if (strcmp(value, "atop") == 0) return COMPOSITE_ATOP;
+ else if (strcmp(value, "xor") == 0) return COMPOSITE_XOR;
+ else if (strcmp(value, "arithmetic") == 0) return COMPOSITE_ARITHMETIC;
+ return COMPOSITE_DEFAULT;
+}
+
/**
* Sets a specific value in the SPFeComposite.
*/
SPFeComposite *feComposite = SP_FECOMPOSITE(object);
(void)feComposite;
+ int input;
+ FeCompositeOperator op;
+ double k_n;
switch(key) {
/*DEAL WITH SETTING ATTRIBUTES HERE*/
+ case SP_ATTR_OPERATOR:
+ op = sp_feComposite_read_operator(value);
+ if (op != feComposite->composite_operator) {
+ feComposite->composite_operator = op;
+ object->parent->requestModified(SP_OBJECT_MODIFIED_FLAG);
+ }
+ break;
+
+ case SP_ATTR_K1:
+ k_n = sp_feComposite_read_number(value);
+ if (k_n != feComposite->k1) {
+ feComposite->k1 = k_n;
+ if (feComposite->composite_operator == COMPOSITE_ARITHMETIC)
+ object->parent->requestModified(SP_OBJECT_MODIFIED_FLAG);
+ }
+ break;
+
+ case SP_ATTR_K2:
+ k_n = sp_feComposite_read_number(value);
+ if (k_n != feComposite->k2) {
+ feComposite->k2 = k_n;
+ if (feComposite->composite_operator == COMPOSITE_ARITHMETIC)
+ object->parent->requestModified(SP_OBJECT_MODIFIED_FLAG);
+ }
+ break;
+
+ case SP_ATTR_K3:
+ k_n = sp_feComposite_read_number(value);
+ if (k_n != feComposite->k3) {
+ feComposite->k3 = k_n;
+ if (feComposite->composite_operator == COMPOSITE_ARITHMETIC)
+ object->parent->requestModified(SP_OBJECT_MODIFIED_FLAG);
+ }
+ break;
+
+ case SP_ATTR_K4:
+ k_n = sp_feComposite_read_number(value);
+ if (k_n != feComposite->k4) {
+ feComposite->k4 = k_n;
+ if (feComposite->composite_operator == COMPOSITE_ARITHMETIC)
+ object->parent->requestModified(SP_OBJECT_MODIFIED_FLAG);
+ }
+ break;
+
+ case SP_ATTR_IN2:
+ input = sp_filter_primitive_read_in(feComposite, value);
+ if (input != feComposite->in2) {
+ feComposite->in2 = input;
+ object->parent->requestModified(SP_OBJECT_MODIFIED_FLAG);
+ }
+ break;
+
default:
if (((SPObjectClass *) feComposite_parent_class)->set)
((SPObjectClass *) feComposite_parent_class)->set(object, key, value);
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
}
return repr;
}
+static void sp_feComposite_build_renderer(SPFilterPrimitive *primitive, NR::Filter *filter) {
+ g_assert(primitive != NULL);
+ g_assert(filter != NULL);
+
+ SPFeComposite *sp_composite = SP_FECOMPOSITE(primitive);
+
+ int primitive_n = filter->add_primitive(NR::NR_FILTER_COMPOSITE);
+ NR::FilterPrimitive *nr_primitive = filter->get_primitive(primitive_n);
+ NR::FilterComposite *nr_composite = dynamic_cast<NR::FilterComposite*>(nr_primitive);
+ g_assert(nr_composite != NULL);
+
+ sp_filter_primitive_renderer_common(primitive, nr_primitive);
+
+ nr_composite->set_operator(sp_composite->composite_operator);
+ nr_composite->set_input(1, sp_composite->in2);
+ if (sp_composite->composite_operator == COMPOSITE_ARITHMETIC) {
+ nr_composite->set_arithmetic(sp_composite->k1, sp_composite->k2,
+ sp_composite->k3, sp_composite->k4);
+ }
+}
+
/*
Local Variables:
diff --git a/src/sp-fecomposite.h b/src/sp-fecomposite.h
index 4421ebbf254e59ca1c19d952d4c8530fb9777da1..842495644ecd2426136c95348ffc471c9e637eb9 100644 (file)
--- a/src/sp-fecomposite.h
+++ b/src/sp-fecomposite.h
#include "sp-filter.h"
#include "sp-fecomposite-fns.h"
+enum FeCompositeOperator {
+ // Default value is 'over', but let's distinquish specifying the
+ // default and implicitely using the default
+ COMPOSITE_DEFAULT,
+ COMPOSITE_OVER,
+ COMPOSITE_IN,
+ COMPOSITE_OUT,
+ COMPOSITE_ATOP,
+ COMPOSITE_XOR,
+ COMPOSITE_ARITHMETIC
+};
+
/* FeComposite base class */
class SPFeCompositeClass;
struct SPFeComposite : public SPFilterPrimitive {
- /** COMPOSITE ATTRIBUTES HERE */
-
+ FeCompositeOperator composite_operator;
+ double k1, k2, k3, k4;
+ int in2;
};
struct SPFeCompositeClass {
diff --git a/src/sp-feoffset.cpp b/src/sp-feoffset.cpp
index b4a50679ed18fcec7280c5df422c4ce3b35caca2..284846855e2c64277b0aeddeeb328b0380b3634b 100644 (file)
--- a/src/sp-feoffset.cpp
+++ b/src/sp-feoffset.cpp
((SPObjectClass *) feOffset_parent_class)->release(object);
}
-double sp_feOffset_read_number(gchar const *value) {
+static double
+sp_feOffset_read_number(gchar const *value) {
char *end;
double ret = g_ascii_strtod(value, &end);
if (*end) {