summary | shortlog | log | commit | commitdiff | tree
raw | patch | inline | side by side (parent: 818ee43)
raw | patch | inline | side by side (parent: 818ee43)
author | kiirala <kiirala@users.sourceforge.net> | |
Sat, 18 Aug 2007 11:00:22 +0000 (11:00 +0000) | ||
committer | kiirala <kiirala@users.sourceforge.net> | |
Sat, 18 Aug 2007 11:00:22 +0000 (11:00 +0000) |
15 files changed:
src/display/Makefile_insert | patch | blob | history | |
src/display/nr-arena-item.cpp | patch | blob | history | |
src/display/nr-arena-item.h | patch | blob | history | |
src/display/nr-filter-gaussian.cpp | patch | blob | history | |
src/display/nr-filter-gaussian.h | patch | blob | history | |
src/display/nr-filter-primitive.cpp | patch | blob | history | |
src/display/nr-filter-primitive.h | patch | blob | history | |
src/display/nr-filter-slot.cpp | patch | blob | history | |
src/display/nr-filter-slot.h | patch | blob | history | |
src/display/nr-filter-units.cpp | [new file with mode: 0644] | patch | blob |
src/display/nr-filter-units.h | [new file with mode: 0644] | patch | blob |
src/display/nr-filter.cpp | patch | blob | history | |
src/display/nr-filter.h | patch | blob | history | |
src/display/pixblock-scaler.cpp | patch | blob | history | |
src/sp-item.cpp | patch | blob | history |
index de6e64c4a124b261299592deb346325e85692c1d..b43fcb82604b0fe2ab0f9aa9e7e0012dcf3627d4 100644 (file)
display/nr-filter-turbulence.h \
display/nr-filter-pixops.h \
display/nr-filter-types.h \
+ display/nr-filter-units.h \
+ display/nr-filter-units.cpp \
display/nr-filter-utils.h \
display/nr-filter-utils.cpp \
display/pixblock-scaler.cpp \
index 5ebd94a9b62ae15cd0beb2d1e035a373c12695aa..ddde4102e60eea8f309dae65048e6d69c6127ed4 100644 (file)
nr_arena_item_set_child_position (item->parent, item, ref);
}
+void
+nr_arena_item_set_item_bbox (NRArenaItem *item, NR::Maybe<NR::Rect> &bbox)
+{
+ nr_return_if_fail(item != NULL);
+ nr_return_if_fail(NR_IS_ARENA_ITEM(item));
+
+ item->item_bbox = bbox;
+}
+
/** Returns a background image for use with filter effects. */
NRPixBlock *
nr_arena_item_get_background (NRArenaItem const *item, int depth)
index 103315c5eadd2ca4f316cc6c1e53b4938259dfa2..801657cf3403e946a41441ea2d1d07f891cf5b07 100644 (file)
/* BBox in grid coordinates */
NRRectL bbox;
+ /* BBox in item coordinates - this should be a bounding box as
+ * specified in SVG standard. Required by filters. */
+ NR::Maybe<NR::Rect> item_bbox;
/* Our affine */
NRMatrix *transform;
/* Clip item */
void nr_arena_item_set_clip (NRArenaItem *item, NRArenaItem *clip);
void nr_arena_item_set_mask (NRArenaItem *item, NRArenaItem *mask);
void nr_arena_item_set_order (NRArenaItem *item, int order);
+void nr_arena_item_set_item_bbox (NRArenaItem *item, NR::Maybe<NR::Rect> &bbox);
NRPixBlock *nr_arena_item_get_background (NRArenaItem const *item, int depth = 0);
index da8d9f71c791f55197c581ea37cd79c05fb4b5e6..5d79b1c3eba120ad608a851098776d20a7bd953e 100644 (file)
area.y1 += area_max;
}
+FilterTraits FilterGaussian::get_input_traits() {
+ return TRAIT_PARALLER;
+}
+
void FilterGaussian::set_deviation(double deviation)
{
if(isFinite(deviation) && deviation >= 0) {
index d4f6c942c373b1e88f132645470b5c42e25ca285..7b2a96ca583711cf5d77240585a3bcb03ba2c9f6 100644 (file)
virtual int render(FilterSlot &slot, Matrix const &trans);
virtual void area_enlarge(NRRectL &area, Matrix const &m);
+ virtual FilterTraits get_input_traits();
/**
* Set the standard deviation value for gaussian blur. Deviation along
index ec83645422b4d29a021b3055180e28d96a6c9e0c..14f5c00788503acb941b2f7b4123c44f46d7a03a 100644 (file)
if (slot >= 0) _output = slot;
}
+FilterTraits FilterPrimitive::get_input_traits() {
+ return TRAIT_ANYTHING;
+}
+
} /* namespace NR */
/*
index ac747cb551d8b3c8e916548cbefd29357fb46b9b..e1e5984e671de53c9a1417065162cfe76ec1f01f 100644 (file)
namespace NR {
+/*
+ * Different filter effects need different types of inputs. This is what
+ * traits are used for: one can specify, what special restrictions
+ * there are for inputs.
+ *
+ * Example: gaussian blur requires that x- and y-axis of input image
+ * are paraller to blurred object's x- and y-axis, respectively.
+ * Otherwise blur wouldn't rotate with the object.
+ *
+ * Values here should be powers of two, so these can be used as bitfield.
+ * That is: any combination ef existing traits can be specified. (excluding
+ * TRAIT_ANYTHING, which is alias for no traits defined)
+ */
+enum FilterTraits {
+ TRAIT_ANYTHING = 0,
+ TRAIT_PARALLER = 1
+};
+
class FilterPrimitive {
public:
FilterPrimitive();
*/
void reset_region();
+ /**
+ * Queries the filter, which traits it needs from its input buffers.
+ * At the time of writing this, only one trait was needed, having
+ * user coordinate system and input pixelblock coordinates paraller to
+ * each other.
+ */
+ virtual FilterTraits get_input_traits();
+
protected:
int _input;
int _output;
index 9775a99a7e5f913d173ec7d03dcf9c535d6fbf3c..17ea373ae08ba35dc6486247c62ea15b4fb23dbf 100644 (file)
* Author:
* Niko Kiirala <niko@kiirala.com>
*
- * Copyright (C) 2006 Niko Kiirala
+ * Copyright (C) 2006,2007 Niko Kiirala
*
* Released under GNU GPL, read the file 'COPYING' for more information
*/
#include "display/nr-filter-types.h"
#include "display/nr-filter-slot.h"
#include "display/nr-filter-getalpha.h"
+#include "display/nr-filter-units.h"
+#include "display/pixblock-scaler.h"
+#include "display/pixblock-transform.h"
#include "libnr/nr-pixblock.h"
#include "libnr/nr-blit.h"
+__attribute__ ((const))
+inline static int _max4(const double a, const double b,
+ const double c, const double d) {
+ double ret = a;
+ if (b > ret) ret = b;
+ if (c > ret) ret = c;
+ if (d > ret) ret = d;
+ return (int)round(ret);
+}
+
+__attribute__ ((const))
+inline static int _min4(const double a, const double b,
+ const double c, const double d) {
+ double ret = a;
+ if (b < ret) ret = b;
+ if (c < ret) ret = c;
+ if (d < ret) ret = d;
+ return (int)round(ret);
+}
+
+__attribute__ ((const))
+inline static int _max2(const double a, const double b) {
+ if (a > b)
+ return (int)round(a);
+ else
+ return (int)round(b);
+}
+
+__attribute__ ((const))
+inline static int _min2(const double a, const double b) {
+ if (a > b)
+ return (int)round(b);
+ else
+ return (int)round(a);
+}
+
namespace NR {
FilterSlot::FilterSlot(int slots, NRArenaItem const *item)
}
}
+ _slot[index]->empty = false;
assert(slot_nr == NR_FILTER_SLOT_NOT_SET ||_slot_number[index] == slot_nr);
return _slot[index];
}
+void FilterSlot::get_final(int slot_nr, NRPixBlock *result) {
+ NRPixBlock *final_usr = get(slot_nr);
+ Matrix trans = units.get_matrix_pb2display();
+
+ int size = (result->area.x1 - result->area.x0)
+ * (result->area.y1 - result->area.y0)
+ * NR_PIXBLOCK_BPP(result);
+ memset(NR_PIXBLOCK_PX(result), 0, size);
+
+ if (fabs(trans[1]) > 1e-6 || fabs(trans[2]) > 1e-6) {
+ transform_nearest(result, final_usr, trans);
+ } else if (fabs(trans[0] - 1) > 1e-6 || fabs(trans[3] - 1) > 1e-6) {
+ scale_bicubic(result, final_usr);
+ } else {
+ nr_blit_pixblock_pixblock(result, final_usr);
+ }
+}
+
void FilterSlot::set(int slot_nr, NRPixBlock *pb)
{
int index = _get_index(slot_nr);
assert(index >= 0);
assert(slot_nr == NR_FILTER_SLOT_NOT_SET ||_slot_number[index] == slot_nr);
+ if (slot_nr == NR_FILTER_SOURCEGRAPHIC || slot_nr == NR_FILTER_BACKGROUNDIMAGE) {
+ Matrix trans = units.get_matrix_display2pb();
+ if (fabs(trans[1]) > 1e-6 || fabs(trans[2]) > 1e-6) {
+ NRPixBlock *trans_pb = new NRPixBlock;
+ int x0 = pb->area.x0;
+ int y0 = pb->area.y0;
+ int x1 = pb->area.x1;
+ int y1 = pb->area.y1;
+ int min_x = _min4(trans[0] * x0 + trans[2] * y0 + trans[4],
+ trans[0] * x0 + trans[2] * y1 + trans[4],
+ trans[0] * x1 + trans[2] * y0 + trans[4],
+ trans[0] * x1 + trans[2] * y1 + trans[4]);
+ int max_x = _max4(trans[0] * x0 + trans[2] * y0 + trans[4],
+ trans[0] * x0 + trans[2] * y1 + trans[4],
+ trans[0] * x1 + trans[2] * y0 + trans[4],
+ trans[0] * x1 + trans[2] * y1 + trans[4]);
+ int min_y = _min4(trans[1] * x0 + trans[3] * y0 + trans[5],
+ trans[1] * x0 + trans[3] * y1 + trans[5],
+ trans[1] * x1 + trans[3] * y0 + trans[5],
+ trans[1] * x1 + trans[3] * y1 + trans[5]);
+ int max_y = _max4(trans[1] * x0 + trans[3] * y0 + trans[5],
+ trans[1] * x0 + trans[3] * y1 + trans[5],
+ trans[1] * x1 + trans[3] * y0 + trans[5],
+ trans[1] * x1 + trans[3] * y1 + trans[5]);
+
+ nr_pixblock_setup_fast(trans_pb, pb->mode,
+ min_x, min_y,
+ max_x, max_y, true);
+ if (trans_pb->size != NR_PIXBLOCK_SIZE_TINY && trans_pb->data.px == NULL) {
+ // memory allocation failed
+ return;
+ }
+ transform_nearest(trans_pb, pb, trans);
+ nr_pixblock_release(pb);
+ delete pb;
+ pb = trans_pb;
+ } else if (fabs(trans[0] - 1) > 1e-6 || fabs(trans[3] - 1) > 1e-6) {
+ NRPixBlock *trans_pb = new NRPixBlock;
+
+ int x0 = pb->area.x0;
+ int y0 = pb->area.y0;
+ int x1 = pb->area.x1;
+ int y1 = pb->area.y1;
+ int min_x = _min2(trans[0] * x0 + trans[4],
+ trans[0] * x1 + trans[4]);
+ int max_x = _max2(trans[0] * x0 + trans[4],
+ trans[0] * x1 + trans[4]);
+ int min_y = _min2(trans[3] * y0 + trans[5],
+ trans[3] * y1 + trans[5]);
+ int max_y = _max2(trans[3] * y0 + trans[5],
+ trans[3] * y1 + trans[5]);
+
+ nr_pixblock_setup_fast(trans_pb, pb->mode,
+ min_x, min_y, max_x, max_y, true);
+ if (trans_pb->size != NR_PIXBLOCK_SIZE_TINY && trans_pb->data.px == NULL) {
+ //memory allocation failed
+ return;
+ }
+ scale_bicubic(trans_pb, pb);
+ nr_pixblock_release(pb);
+ delete pb;
+ pb = trans_pb;
+ }
+ }
+
if(_slot[index]) {
nr_pixblock_release(_slot[index]);
delete _slot[index];
return index;
}
+void FilterSlot::set_units(FilterUnits const &units) {
+ this->units = units;
+}
+
}
/*
index 8c24a36416014382a379548b2081618c218f8f15..2272c3ae78dbd80b3aaffddf703eff7adf6f4997 100644 (file)
* Author:
* Niko Kiirala <niko@kiirala.com>
*
- * Copyright (C) 2006 Niko Kiirala
+ * Copyright (C) 2006,2007 Niko Kiirala
*
* Released under GNU GPL, read the file 'COPYING' for more information
*/
#include "libnr/nr-pixblock.h"
+#include "display/nr-filter-units.h"
struct NRArenaItem;
*/
NRPixBlock *get(int slot);
+ /** Gets the final result from this filter.
+ * The result is fetched from the specified slot, see description of
+ * method get for valid values. The pixblock 'result' will be modified
+ * to contain the result image, ready to be used in the rest of rendering
+ * pipeline
+ */
+ void get_final(int slot, NRPixBlock *result);
+
/** Sets or re-sets the pixblock associated with given slot.
* If there was a pixblock already assigned with this slot,
* that pixblock is destroyed.
/** arenaitem getter method*/
NRArenaItem const* get_arenaitem();
+ /** Sets the unit system to be used for the internal images. */
+ void set_units(FilterUnits const &units);
+
private:
NRPixBlock **_slot;
int *_slot_number;
NRArenaItem const *_arena_item;
+ FilterUnits units;
+
/** Returns the table index of given slot. If that slot does not exist,
* it is created. Table index can be used to read the correct
* pixblock from _slot */
diff --git a/src/display/nr-filter-units.cpp b/src/display/nr-filter-units.cpp
--- /dev/null
@@ -0,0 +1,154 @@
+/*
+ * Utilities for handling coordinate system transformations in filters
+ *
+ * Author:
+ * Niko Kiirala <niko@kiirala.com>
+ *
+ * Copyright (C) 2007 Niko Kiirala
+ *
+ * Released under GNU GPL, read the file 'COPYING' for more information
+ */
+
+#include <glib.h>
+
+#include "display/nr-filter-units.h"
+#include "libnr/nr-matrix.h"
+#include "libnr/nr-rect.h"
+#include "libnr/nr-scale.h"
+#include "sp-filter-units.h"
+
+namespace NR {
+
+FilterUnits::FilterUnits() :
+ filterUnits(SP_FILTER_UNITS_OBJECTBOUNDINGBOX),
+ primitiveUnits(SP_FILTER_UNITS_USERSPACEONUSE),
+ resolution_x(-1), resolution_y(-1),
+ paraller_axis(false), automatic_resolution(true)
+{}
+
+FilterUnits::FilterUnits(SPFilterUnits const filterUnits, SPFilterUnits const primitiveUnits) :
+ filterUnits(filterUnits), primitiveUnits(primitiveUnits),
+ resolution_x(-1), resolution_y(-1),
+ paraller_axis(false), automatic_resolution(true)
+{}
+
+void FilterUnits::set_ctm(Matrix const &ctm) {
+ this->ctm = ctm;
+}
+
+void FilterUnits::set_resolution(double const x_res, double const y_res) {
+ g_assert(x_res > 0);
+ g_assert(y_res > 0);
+
+ resolution_x = x_res;
+ resolution_y = y_res;
+}
+
+void FilterUnits::set_item_bbox(Rect const &bbox) {
+ item_bbox = bbox;
+}
+
+void FilterUnits::set_filter_area(Rect const &area) {
+ filter_area = area;
+}
+
+void FilterUnits::set_paraller(bool const paraller) {
+ paraller_axis = paraller;
+}
+
+void FilterUnits::set_automatic_resolution(bool const automatic) {
+ automatic_resolution = automatic;
+}
+
+Matrix FilterUnits::get_matrix_user2pb() const {
+ g_assert(resolution_x > 0);
+ g_assert(resolution_y > 0);
+
+ Matrix u2pb = ctm;
+
+ if (paraller_axis || !automatic_resolution) {
+ u2pb[0] = resolution_x / (filter_area.max()[X] - filter_area.min()[X]);
+ u2pb[1] = 0;
+ u2pb[2] = 0;
+ u2pb[3] = resolution_y / (filter_area.max()[Y] - filter_area.min()[Y]);
+ u2pb[4] = 0;
+ u2pb[5] = 0;
+ }
+
+ return u2pb;
+}
+
+Matrix FilterUnits::get_matrix_units2pb(SPFilterUnits units) const {
+ if (units == SP_FILTER_UNITS_OBJECTBOUNDINGBOX) {
+ Matrix u2pb = get_matrix_user2pb();
+ Point origo(item_bbox.min());
+ origo *= u2pb;
+ Point i_end(item_bbox.max()[X], item_bbox.min()[Y]);
+ i_end *= u2pb;
+ Point j_end(item_bbox.min()[X], item_bbox.max()[Y]);
+ j_end *= u2pb;
+
+ double len_i = sqrt((origo[X] - i_end[X]) * (origo[X] - i_end[X])
+ + (origo[Y] - i_end[Y]) * (origo[Y] - i_end[Y]));
+ double len_j = sqrt((origo[X] - j_end[X]) * (origo[X] - j_end[X])
+ + (origo[Y] - j_end[Y]) * (origo[Y] - j_end[Y]));
+
+ /* TODO: make sure that user coordinate system (0,0) is in correct
+ * place in pixblock coordinates */
+ scale scaling(1.0 / len_i, 1.0 / len_j);
+ u2pb *= scaling;
+ return u2pb;
+ } else if (units == SP_FILTER_UNITS_USERSPACEONUSE) {
+ return get_matrix_user2pb();
+ } else {
+ g_warning("Error in NR::FilterUnits::get_matrix_units2pb: unrecognized value of filterUnits");
+ return Matrix();
+ }
+}
+
+Matrix FilterUnits::get_matrix_filterunits2pb() const {
+ return get_matrix_units2pb(filterUnits);
+}
+
+Matrix FilterUnits::get_matrix_primitiveunits2pb() const {
+ return get_matrix_units2pb(primitiveUnits);
+}
+
+Matrix FilterUnits::get_matrix_display2pb() const {
+ Matrix d2pb = ctm.inverse();
+ d2pb *= get_matrix_user2pb();
+ return d2pb;
+}
+
+Matrix FilterUnits::get_matrix_pb2display() const {
+ Matrix pb2d = get_matrix_user2pb().inverse();
+ pb2d *= ctm;
+ return pb2d;
+}
+
+FilterUnits& FilterUnits::operator=(FilterUnits const &other) {
+ filterUnits = other.filterUnits;
+ primitiveUnits = other.primitiveUnits;
+ resolution_x = other.resolution_x;
+ resolution_y = other.resolution_y;
+ paraller_axis = other.paraller_axis;
+ automatic_resolution = other.automatic_resolution;
+ ctm = other.ctm;
+ item_bbox = other.item_bbox;
+ filter_area = other.filter_area;
+ return *this;
+}
+
+} // 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-units.h b/src/display/nr-filter-units.h
--- /dev/null
@@ -0,0 +1,116 @@
+#ifndef __NR_FILTER_UNITS_H__
+#define __NR_FILTER_UNITS_H__
+
+/*
+ * Utilities for handling coordinate system transformations in filters
+ *
+ * Author:
+ * Niko Kiirala <niko@kiirala.com>
+ *
+ * Copyright (C) 2007 Niko Kiirala
+ *
+ * Released under GNU GPL, read the file 'COPYING' for more information
+ */
+
+#include "sp-filter-units.h"
+#include "libnr/nr-matrix.h"
+#include "libnr/nr-rect.h"
+
+namespace NR {
+
+class FilterUnits {
+public:
+ FilterUnits();
+ FilterUnits(SPFilterUnits const filterUnits, SPFilterUnits const primitiveUnits);
+
+ /**
+ * Sets the current transformation matrix, i.e. transformation matrix
+ * from object's user coordinates to screen coordinates
+ */
+ void set_ctm(Matrix const &ctm);
+
+ /**
+ * Sets the resolution, the filter should be rendered with.
+ */
+ void set_resolution(double const x_res, double const y_res);
+
+ /**
+ * Sets the item bounding box in user coordinates
+ */
+ void set_item_bbox(Rect const &bbox);
+
+ /**
+ * Sets the filter effects area in user coordinates
+ */
+ void set_filter_area(Rect const &area);
+
+ /**
+ * Sets, if x and y axis in pixblock coordinates should be paraller
+ * to x and y of user coordinates.
+ */
+ void set_paraller(bool const paraller);
+
+ /**
+ * Sets, if filter resolution is automatic.
+ * NOTE: even if resolution is automatic, it must be set with
+ * set_resolution. This only tells, if the set value is automatic.
+ */
+ void set_automatic_resolution(bool const automatic);
+
+ /**
+ * Gets the user coordinates to pixblock coordinates transformation matrix.
+ */
+ Matrix get_matrix_user2pb() const;
+
+ /**
+ * Gets the filterUnits to pixblock coordinates transformation matrix.
+ */
+ Matrix get_matrix_filterunits2pb() const;
+
+ /**
+ * Gets the primitiveUnits to pixblock coordinates transformation matrix.
+ */
+ Matrix get_matrix_primitiveunits2pb() const;
+
+ /**
+ * Gets the display coordinates to pixblock coordinates transformation
+ * matrix.
+ */
+ Matrix get_matrix_display2pb() const;
+
+ /**
+ * Gets the pixblock coordinates to display coordinates transformation
+ * matrix
+ */
+ Matrix get_matrix_pb2display() const;
+
+ FilterUnits& operator=(FilterUnits const &other);
+
+private:
+ Matrix get_matrix_units2pb(SPFilterUnits units) const;
+
+ SPFilterUnits filterUnits, primitiveUnits;
+ double resolution_x, resolution_y;
+ bool paraller_axis;
+ bool automatic_resolution;
+ Matrix ctm;
+ Rect item_bbox;
+ Rect filter_area;
+
+};
+
+
+} // namespace NR
+
+
+#endif /* __NR_FILTER_UNITS_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 b97784ec406ebf3135a585d7e92534227ba498c3..2e973b4ec9d258b0f928ed912c6fb0d7c4ab77ba 100644 (file)
* Author:
* Niko Kiirala <niko@kiirala.com>
*
- * Copyright (C) 2006 Niko Kiirala
+ * Copyright (C) 2006,2007 Niko Kiirala
*
* Released under GNU GPL, read the file 'COPYING' for more information
*/
#include "display/nr-filter-primitive.h"
#include "display/nr-filter-slot.h"
#include "display/nr-filter-types.h"
-#include "display/pixblock-scaler.h"
-#include "display/pixblock-transform.h"
+#include "display/nr-filter-units.h"
#include "display/nr-filter-blend.h"
#include "display/nr-filter-composite.h"
using Inkscape::round;
#endif
-__attribute__ ((const))
-inline static int _max4(const double a, const double b,
- const double c, const double d) {
- double ret = a;
- if (b > ret) ret = b;
- if (c > ret) ret = c;
- if (d > ret) ret = d;
- return (int)round(ret);
-}
-
-__attribute__ ((const))
-inline static int _min4(const double a, const double b,
- const double c, const double d) {
- double ret = a;
- if (b < ret) ret = b;
- if (c < ret) ret = c;
- if (d < ret) ret = d;
- return (int)round(ret);
-}
-
namespace NR {
Filter::Filter()
int Filter::render(NRArenaItem const *item, NRPixBlock *pb)
{
- if(!_primitive[0]) { // if there are no primitives, do nothing
+ if(!_primitive[0]) {
+ // TODO: Should clear the input buffer instead of just returning
return 0;
}
Matrix trans = *item->ctm;
- Matrix paraller_trans = trans;
- bool notparaller = false;
FilterSlot slot(_slot_count, item);
- NRPixBlock *in = new NRPixBlock;
- // If filter effects region is not paraller to viewport,
- // we must first undo the rotation / shear.
- // It will be redone after filtering.
- // If there is only scaling, let's skip this, as it will not make
- // a difference with gaussian blur.
- // TODO: This should be done in FilterSlot and for all input images
- if (fabs(trans[1]) > 1e-6 || fabs(trans[2]) > 1e-6) {
- notparaller = true;
-
- // TODO: if filter resolution is specified, scaling should be set
- // according to that
- double scaling_factor = sqrt(trans.expansionX() * trans.expansionX() +
- trans.expansionY() * trans.expansionY());
- scale scaling(scaling_factor, scaling_factor);
- scale scaling_inv(1.0 / scaling_factor, 1.0 / scaling_factor);
- trans *= scaling_inv;
- paraller_trans.set_identity();
- paraller_trans *= scaling;
-
- Matrix itrans = trans.inverse();
- int x0 = pb->area.x0;
- int y0 = pb->area.y0;
- int x1 = pb->area.x1;
- int y1 = pb->area.y1;
- int min_x = _min4(itrans[0] * x0 + itrans[2] * y0 + itrans[4],
- itrans[0] * x0 + itrans[2] * y1 + itrans[4],
- itrans[0] * x1 + itrans[2] * y0 + itrans[4],
- itrans[0] * x1 + itrans[2] * y1 + itrans[4]);
- int max_x = _max4(itrans[0] * x0 + itrans[2] * y0 + itrans[4],
- itrans[0] * x0 + itrans[2] * y1 + itrans[4],
- itrans[0] * x1 + itrans[2] * y0 + itrans[4],
- itrans[0] * x1 + itrans[2] * y1 + itrans[4]);
- int min_y = _min4(itrans[1] * x0 + itrans[3] * y0 + itrans[5],
- itrans[1] * x0 + itrans[3] * y1 + itrans[5],
- itrans[1] * x1 + itrans[3] * y0 + itrans[5],
- itrans[1] * x1 + itrans[3] * y1 + itrans[5]);
- int max_y = _max4(itrans[1] * x0 + itrans[3] * y0 + itrans[5],
- itrans[1] * x0 + itrans[3] * y1 + itrans[5],
- itrans[1] * x1 + itrans[3] * y0 + itrans[5],
- itrans[1] * x1 + itrans[3] * y1 + itrans[5]);
-
- nr_pixblock_setup_fast(in, pb->mode,
- min_x, min_y,
- max_x, max_y, true);
- if (in->size != NR_PIXBLOCK_SIZE_TINY && in->data.px == NULL) // memory allocation failed
- return 0;
- transform_nearest(in, pb, itrans);
- } else if (_x_pixels >= 0) {
- // If filter resolution is not set to automatic, we should
- // scale the input image to correct resolution
- /* If filter resolution is zero, the object should not be rendered */
- if (_x_pixels == 0 || _y_pixels == 0) {
- int size = (pb->area.x1 - pb->area.x0)
- * (pb->area.y1 - pb->area.y0)
- * NR_PIXBLOCK_BPP(pb);
- memset(NR_PIXBLOCK_PX(pb), 0, size);
- return 0;
- }
- // Resolution is specified as pixel length of our internal buffer.
- // Though, we might not be rendering the whole object at time,
- // so we need to calculate the correct pixel size
- int x_len = (int)round(((pb->area.x1 - pb->area.x0) * _x_pixels) / (item->bbox.x1 - item->bbox.x0));
- if (x_len < 1) x_len = 1;
- // If y-resolution is also set, count y-area in the same way as x-area
- // Otherwise, make y-area so, that aspect ratio of input pixblock and
- // internal pixblock are the same.
- int y_len;
+ Rect item_bbox = *item->item_bbox;
+ Rect filter_area = filter_effect_area(item_bbox);
+ FilterUnits units(_filter_units, _primitive_units);
+ units.set_ctm(trans);
+ units.set_item_bbox(item_bbox);
+ units.set_filter_area(filter_area);
+
+ // TODO: with filterRes of 0x0 should return an empty image
+ if (_x_pixels > 0) {
+ double y_len;
if (_y_pixels > 0) {
- y_len = (int)round(((pb->area.y1 - pb->area.y0) * _y_pixels) / (item->bbox.y1 - item->bbox.y0));
+ y_len = _y_pixels;
} else {
- y_len = (int)round((x_len * (pb->area.y1 - pb->area.y0)) / (double)(pb->area.x1 - pb->area.x0));
+ y_len = (_x_pixels * (filter_area.max()[Y] - filter_area.min()[Y]))
+ / (filter_area.max()[X] - filter_area.min()[X]);
}
- if (y_len < 1) y_len = 1;
- nr_pixblock_setup_fast(in, pb->mode, 0, 0, x_len, y_len, true);
- if (in->size != NR_PIXBLOCK_SIZE_TINY && in->data.px == NULL) // memory allocation failed
- return 0;
- scale_bicubic(in, pb);
- scale res_scaling(x_len / (double)(pb->area.x1 - pb->area.x0),
- y_len / (double)(pb->area.y1 - pb->area.y0));
- paraller_trans *= res_scaling;
+ units.set_automatic_resolution(false);
+ units.set_resolution(_x_pixels, y_len);
} else {
- // If filter resolution is automatic, just make copy of input image
- nr_pixblock_setup_fast(in, pb->mode,
- pb->area.x0, pb->area.y0,
- pb->area.x1, pb->area.y1, true);
- if (in->size != NR_PIXBLOCK_SIZE_TINY && in->data.px == NULL) // memory allocation failed
- return 0;
- nr_blit_pixblock_pixblock(in, pb);
+ Point origo = filter_area.min();
+ origo *= trans;
+ Point max_i(filter_area.max()[X], filter_area.min()[Y]);
+ max_i *= trans;
+ Point max_j(filter_area.min()[X], filter_area.max()[Y]);
+ max_j *= trans;
+ double i_len = sqrt((origo[X] - max_i[X]) * (origo[X] - max_i[X])
+ + (origo[Y] - max_i[Y]) * (origo[Y] - max_i[Y]));
+ double j_len = sqrt((origo[X] - max_j[X]) * (origo[X] - max_j[X])
+ + (origo[Y] - max_j[Y]) * (origo[Y] - max_j[Y]));
+ units.set_automatic_resolution(true);
+ units.set_resolution(i_len, j_len);
}
+
+ units.set_paraller(false);
+ for (int i = 0 ; i < _primitive_count ; i++) {
+ if (_primitive[i]->get_input_traits() & TRAIT_PARALLER) {
+ units.set_paraller(true);
+ break;
+ }
+ }
+
+ slot.set_units(units);
+
+ NRPixBlock *in = new NRPixBlock;
+ nr_pixblock_setup_fast(in, pb->mode, pb->area.x0, pb->area.y0,
+ pb->area.x1, pb->area.y1, false);
+ if (in->size != NR_PIXBLOCK_SIZE_TINY && in->data.px == NULL) {
+ g_warning("NR::Filter::render: failed to reserve temporary buffer");
+ return 0;
+ }
+ nr_blit_pixblock_pixblock(in, pb);
in->empty = FALSE;
slot.set(NR_FILTER_SOURCEGRAPHIC, in);
+
+ // Check that we are rendering a non-empty area
+ in = slot.get(NR_FILTER_SOURCEGRAPHIC);
+ if (in->area.x1 - in->area.x0 <= 0 || in->area.y1 - in->area.y0 <= 0) {
+ if (in->area.x1 - in->area.x0 < 0 || in->area.y1 - in->area.y0 < 0) {
+ g_warning("NR::Filter::render: negative area! (%d, %d) (%d, %d)",
+ in->area.x0, in->area.y0, in->area.x1, in->area.y1);
+ }
+ return 0;
+ }
in = NULL; // in is now handled by FilterSlot, we should not touch it
+ // TODO: filters may need both filterUnits and primitiveUnits,
+ // so we should pass FilterUnits to render method, not just one Matrix
+ Matrix primitiveunits2pixblock = units.get_matrix_primitiveunits2pb();
for (int i = 0 ; i < _primitive_count ; i++) {
- _primitive[i]->render(slot, paraller_trans);
- }
- NRPixBlock *out = slot.get(_output_slot);
-
- // Clear the pixblock, where the output will be put
- // -> the original image does not show through
- int size = (pb->area.x1 - pb->area.x0)
- * (pb->area.y1 - pb->area.y0)
- * NR_PIXBLOCK_BPP(pb);
- memset(NR_PIXBLOCK_PX(pb), 0, size);
-
- if (notparaller) {
- transform_nearest(pb, out, trans);
- } else if (_x_pixels < 0) {
- // If the filter resolution is automatic, just copy our final image
- // to output pixblock, otherwise use bicubic scaling
- nr_blit_pixblock_pixblock(pb, out);
- } else {
- scale_bicubic(pb, out);
+ _primitive[i]->render(slot, primitiveunits2pixblock);
}
+ slot.get_final(_output_slot, pb);
+
// Take note of the amount of used image slots
// -> next time this filter is rendered, we can reserve enough slots
// immediately
}
}
-void Filter::bbox_enlarge(NRRectL &bbox)
+void Filter::bbox_enlarge(NRRectL &bbox) {
+ /* TODO: this is wrong. Should use bounding box in user coordinates
+ * and find its extents in display coordinates. */
+ Point min(bbox.x0, bbox.y0);
+ Point max(bbox.x1, bbox.y1);
+ Rect tmp_bbox(min, max);
+
+ Rect enlarged = filter_effect_area(tmp_bbox);
+
+ bbox.x0 = (ICoord)enlarged.min()[X];
+ bbox.y0 = (ICoord)enlarged.min()[Y];
+ bbox.x1 = (ICoord)enlarged.max()[X];
+ bbox.y1 = (ICoord)enlarged.max()[Y];
+}
+
+Rect Filter::filter_effect_area(Rect const &bbox)
{
- int len_x = bbox.x1 - bbox.x0;
- int len_y = bbox.y1 - bbox.y0;
+ Point minp, maxp;
+ double len_x = bbox.max()[X] - bbox.min()[X];
+ double len_y = bbox.max()[Y] - bbox.min()[Y];
/* TODO: fetch somehow the object ex and em lengths */
_region_x.update(12, 6, len_x);
_region_y.update(12, 6, len_y);
_region_height.update(12, 6, len_y);
if (_filter_units == SP_FILTER_UNITS_OBJECTBOUNDINGBOX) {
if (_region_x.unit == SVGLength::PERCENT) {
- bbox.x0 += (ICoord)_region_x.computed;
+ minp[X] = bbox.min()[X] + _region_x.computed;
} else {
- bbox.x0 += (ICoord)(_region_x.computed * len_x);
+ minp[X] = bbox.min()[X] + _region_x.computed * len_x;
}
if (_region_width.unit == SVGLength::PERCENT) {
- bbox.x1 = bbox.x0 + (ICoord)_region_width.computed;
+ maxp[X] = minp[X] + _region_width.computed;
} else {
- bbox.x1 = bbox.x0 + (ICoord)(_region_width.computed * len_x);
+ maxp[X] = minp[X] + _region_width.computed * len_x;
}
if (_region_y.unit == SVGLength::PERCENT) {
- bbox.y0 += (ICoord)_region_y.computed;
+ minp[Y] = bbox.min()[Y] + _region_y.computed;
} else {
- bbox.y0 += (ICoord)(_region_y.computed * len_y);
+ minp[Y] = bbox.min()[Y] + _region_y.computed * len_y;
}
if (_region_height.unit == SVGLength::PERCENT) {
- bbox.y1 = bbox.y0 + (ICoord)_region_height.computed;
+ maxp[Y] = minp[Y] + _region_height.computed;
} else {
- bbox.y1 = bbox.y0 + (ICoord)(_region_height.computed * len_y);
+ maxp[Y] = minp[Y] + _region_height.computed * len_y;
}
} else if (_filter_units == SP_FILTER_UNITS_USERSPACEONUSE) {
/* TODO: make sure bbox and fe region are in same coordinate system */
- bbox.x0 = (ICoord) _region_x.computed;
- bbox.x1 = bbox.x0 + (ICoord) _region_width.computed;
- bbox.y0 = (ICoord) _region_y.computed;
- bbox.y1 = bbox.y0 + (ICoord) _region_height.computed;
+ minp[X] = _region_x.computed;
+ maxp[X] = minp[X] + _region_width.computed;
+ minp[Y] = _region_y.computed;
+ maxp[Y] = minp[Y] + _region_height.computed;
} else {
g_warning("Error in NR::Filter::bbox_enlarge: unrecognized value of _filter_units");
}
+ Rect area(minp, maxp);
+ return area;
}
/* Constructor table holds pointers to static methods returning filter
index 9f26a1f3b95fa9c3b4933d1701e288d77cac2892..4d33c3d70e95486be6ce8f1e884785ee06f8dc74 100644 (file)
--- a/src/display/nr-filter.h
+++ b/src/display/nr-filter.h
/**
* Set the primitiveUnits-properterty. If not set, the default value of
- * userSpaceOnUseis used. If the parameter value is not a valid
+ * userSpaceOnUse is used. If the parameter value is not a valid
* enumeration value from SPFilterUnits, no changes to filter state
* are made.
*/
* it contains the filter effect area.
*/
void bbox_enlarge(NRRectL &bbox);
+ /**
+ * Returns the filter effects area in user coordinate system.
+ * The given bounding box should be a bounding box as specified in
+ * SVG standard and in user coordinate system.
+ */
+ Rect filter_effect_area(Rect const &bbox);
/** Creates a new filter with space for one filter element */
Filter();
index d65cfd4e0d78178a49c92289ac5f231df38635ad..ddb4c4ee2652a5a53f4cb374a9be910f510167cf 100644 (file)
* decimal part. (24.8 assuming 32-bit int)
*/
__attribute__ ((const))
-inline int sampley(unsigned const char a, unsigned const char b,
+inline static int sampley(unsigned const char a, unsigned const char b,
unsigned const char c, unsigned const char d,
const double len)
{
* Returns the interpolated value in 8-bit format, ready to be written
* to output buffer.
*/
-inline int samplex(const int a, const int b, const int c, const int d, const double len) {
+inline static int samplex(const int a, const int b, const int c, const int d, const double len) {
double lenf = len - floor(len);
int sum = 0;
sum += (int)(a * (((-1.0 / 3.0) * lenf + 4.0 / 5.0) * lenf - 7.0 / 15.0) * lenf);
* Catches reading and writing outside the pixblock area.
* When enabled, decreases filter rendering speed massively.
*/
-inline void _check_index(NRPixBlock const * const pb, int const location, int const line)
+inline static void _check_index(NRPixBlock const * const pb, int const location, int const line)
{
if(false) {
int max_loc = pb->rs * (pb->area.y1 - pb->area.y0);
@@ -88,10 +88,10 @@ inline void _check_index(NRPixBlock const * const pb, int const location, int co
}
}
-void scale_bicubic(NRPixBlock *to, NRPixBlock *from)
+static void scale_bicubic_rgba(NRPixBlock *to, NRPixBlock *from)
{
if (NR_PIXBLOCK_BPP(from) != 4 || NR_PIXBLOCK_BPP(to) != 4) {
- g_warning("A non-32-bpp image passed to scale_bicubic: scaling aborted.");
+ g_warning("A non-32-bpp image passed to scale_bicubic_rgba: scaling aborted.");
return;
}
}
}
+void scale_bicubic_alpha(NRPixBlock *to, NRPixBlock *from)
+{
+ if (NR_PIXBLOCK_BPP(from) != 1 || NR_PIXBLOCK_BPP(to) != 1) {
+ g_warning("A non-8-bpp image passed to scale_bicubic_alpha: scaling aborted.");
+ return;
+ }
+
+ // Precalculate sizes of source and destination pixblocks
+ int from_width = from->area.x1 - from->area.x0;
+ int from_height = from->area.y1 - from->area.y0;
+ int to_width = to->area.x1 - to->area.x0;
+ int to_height = to->area.y1 - to->area.y0;
+
+ // from_step: when advancing one pixel in destination image,
+ // how much we should advance in source image
+ double from_stepx = (double)from_width / (double)to_width;
+ double from_stepy = (double)from_height / (double)to_height;
+
+ // Loop through every pixel of destination image, a line at a time
+ for (int to_y = 0 ; to_y < to_height ; to_y++) {
+ double from_y = to_y * from_stepy + from_stepy / 2;
+ // Pre-calculate beginning of the four horizontal lines, from
+ // which we should read
+ int from_line[4];
+ for (int i = 0 ; i < 4 ; i++) {
+ if ((int)floor(from_y) + i - 1 >= 0) {
+ if ((int)floor(from_y) + i - 1 < from_height) {
+ from_line[i] = ((int)floor(from_y) + i - 1) * from->rs;
+ } else {
+ from_line[i] = (from_height - 1) * from->rs;
+ }
+ } else {
+ from_line[i] = 0;
+ }
+ }
+ // Loop through this horizontal line in destination image
+ // For every pixel, calculate the color of pixel with
+ // bicubic interpolation and set the pixel value in destination image
+ for (int to_x = 0 ; to_x < to_width ; to_x++) {
+ double from_x = to_x * from_stepx + from_stepx / 2;
+ int line[4];
+ for (int i = 0 ; i < 4 ; i++) {
+ int k = (int)floor(from_x) + i - 1;
+ if (k < 0) k = 0;
+ if (k >= from_width) k = from_width - 1;
+ _check_index(from, from_line[0] + k, __LINE__);
+ _check_index(from, from_line[1] + k, __LINE__);
+ _check_index(from, from_line[2] + k, __LINE__);
+ _check_index(from, from_line[3] + k, __LINE__);
+ line[i] = sampley(NR_PIXBLOCK_PX(from)[from_line[0] + k],
+ NR_PIXBLOCK_PX(from)[from_line[1] + k],
+ NR_PIXBLOCK_PX(from)[from_line[2] + k],
+ NR_PIXBLOCK_PX(from)[from_line[3] + k],
+ from_y);
+ }
+ int result;
+ result = samplex(line[0], line[1], line[2], line[3],
+ from_x);
+
+ _check_index(to, to_y * to->rs + to_x, __LINE__);
+
+ NR_PIXBLOCK_PX(to)[to_y * to->rs + to_x] = clamp(result);
+ }
+ }
+}
+
+void scale_bicubic(NRPixBlock *to, NRPixBlock *from)
+{
+ if (NR_PIXBLOCK_BPP(to) == 4 && NR_PIXBLOCK_BPP(from) == 4) {
+ scale_bicubic_rgba(to, from);
+ } else if (NR_PIXBLOCK_BPP(to) == 1 && NR_PIXBLOCK_BPP(from) == 1) {
+ scale_bicubic_alpha(to, from);
+ } else {
+ g_warning("NR::scale_bicubic: unsupported bitdepths for scaling: to %d, from %d", NR_PIXBLOCK_BPP(to), NR_PIXBLOCK_BPP(from));
+ }
+}
+
} /* namespace NR */
/*
Local Variables:
diff --git a/src/sp-item.cpp b/src/sp-item.cpp
index 309c42c906c5d9b5dbf8c8a9e91bc5062b7ec4e5..338a70c4ed4b838866151848821a4ce8b81ced9e 100644 (file)
--- a/src/sp-item.cpp
+++ b/src/sp-item.cpp
}
}
+ if (item->display && item->display->arenaitem) {
+ NRRect item_bbox;
+ sp_item_invoke_bbox(item, &item_bbox, NR::identity(), TRUE, SPItem::GEOMETRIC_BBOX);
+ NR::Maybe<NR::Rect> i_bbox = item_bbox;
+ nr_arena_item_set_item_bbox(item->display->arenaitem, i_bbox);
+ }
+
// Update libavoid with item geometry (for connector routing).
item->avoidRef->handleSettingChange();
}
@@ -917,6 +924,10 @@ sp_item_invoke_show(SPItem *item, NRArena *arena, unsigned key, unsigned flags)
SP_OBJECT(mask)->requestDisplayUpdate(SP_OBJECT_MODIFIED_FLAG);
}
NR_ARENA_ITEM_SET_DATA(ai, item);
+ NRRect item_bbox;
+ sp_item_invoke_bbox(item, &item_bbox, NR::identity(), TRUE, SPItem::GEOMETRIC_BBOX);
+ NR::Maybe<NR::Rect> i_bbox = item_bbox;
+ nr_arena_item_set_item_bbox(ai, i_bbox);
}
return ai;