summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorNiko Kiirala <niko@kiirala.com>2008-01-09 21:05:06 +0000
committerkiirala <kiirala@users.sourceforge.net>2008-01-09 21:05:06 +0000
commita909994982c3684956b271cdd223ec8b700ff909 (patch)
tree3dadb96d683f26ec5d61f95fc203ce073d237158 /src
parentand in one more place (diff)
downloadinkscape-a909994982c3684956b271cdd223ec8b700ff909.tar.gz
inkscape-a909994982c3684956b271cdd223ec8b700ff909.zip
Made turbulence filter resolution-independent and renderable at any size
(bzr r4444)
Diffstat (limited to 'src')
-rw-r--r--src/display/nr-filter-turbulence.cpp116
-rw-r--r--src/display/nr-filter-turbulence.h3
-rw-r--r--src/display/nr-filter-units.cpp29
-rw-r--r--src/display/nr-filter-units.h11
4 files changed, 105 insertions, 54 deletions
diff --git a/src/display/nr-filter-turbulence.cpp b/src/display/nr-filter-turbulence.cpp
index 74c229109..06f4409a7 100644
--- a/src/display/nr-filter-turbulence.cpp
+++ b/src/display/nr-filter-turbulence.cpp
@@ -15,6 +15,7 @@
#include "display/nr-filter-units.h"
#include "display/nr-filter-utils.h"
#include "libnr/nr-rect-l.h"
+#include "libnr/nr-blit.h"
#include <math.h>
namespace NR {
@@ -71,15 +72,57 @@ void FilterTurbulence::set_updated(bool u){
updated=u;
}
-void FilterTurbulence::update_pixbuffer(FilterSlot &/*slot*/, IRect &area) {
+void FilterTurbulence::render_area(NRPixBlock *pix, IRect &full_area, FilterUnits const &units) {
+ const int bbox_x0 = full_area.min()[X];
+ const int bbox_y0 = full_area.min()[Y];
+ const int bbox_x1 = full_area.max()[X];
+ const int bbox_y1 = full_area.max()[Y];
+
+ Matrix unit_trans = units.get_matrix_primitiveunits2pb().inverse();
+
+ double point[2];
+
+ unsigned char *pb = NR_PIXBLOCK_PX(pix);
+
+ if (type==TURBULENCE_TURBULENCE){
+ for (int y = std::max(bbox_y0, pix->area.y0); y < std::min(bbox_y1, pix->area.y1); y++){
+ int out_line = (y - pix->area.y0) * pix->rs;
+ point[1] = y * unit_trans[3] + unit_trans[5];
+ for (int x = std::max(bbox_x0, pix->area.x0); x < std::min(bbox_x1, pix->area.x1); x++){
+ int out_pos = out_line + 4 * (x - pix->area.x0);
+ point[0] = x * unit_trans[0] + unit_trans[4];
+ pb[out_pos] = CLAMP_D_TO_U8( turbulence(0,point)*255 );
+ pb[out_pos + 1] = CLAMP_D_TO_U8( turbulence(1,point)*255 );
+ pb[out_pos + 2] = CLAMP_D_TO_U8( turbulence(2,point)*255 );
+ pb[out_pos + 3] = CLAMP_D_TO_U8( turbulence(3,point)*255 );
+ }
+ }
+ } else {
+ for (int y = std::max(bbox_y0, pix->area.y0); y < std::min(bbox_y1, pix->area.y1); y++){
+ int out_line = (y - pix->area.y0) * pix->rs;
+ point[1] = y * unit_trans[3] + unit_trans[5];
+ for (int x = std::max(bbox_x0, pix->area.x0); x < std::min(bbox_x1, pix->area.x1); x++){
+ int out_pos = out_line + 4 * (x - pix->area.x0);
+ point[0] = x * unit_trans[0] + unit_trans[4];
+ pb[out_pos] = CLAMP_D_TO_U8( ((turbulence(0,point)*255) +255)/2 );
+ pb[out_pos + 1] = CLAMP_D_TO_U8( ((turbulence(1,point)*255)+255)/2 );
+ pb[out_pos + 2] = CLAMP_D_TO_U8( ((turbulence(2,point)*255) +255)/2 );
+ pb[out_pos + 3] = CLAMP_D_TO_U8( ((turbulence(3,point)*255) +255)/2 );
+ }
+ }
+ }
+
+ pix->empty = FALSE;
+}
+
+void FilterTurbulence::update_pixbuffer(IRect &area, FilterUnits const &units) {
//g_warning("update_pixbuf");
int bbox_x0 = area.min()[X];
int bbox_y0 = area.min()[Y];
int bbox_x1 = area.max()[X];
int bbox_y1 = area.max()[Y];
- int w = bbox_x1 - bbox_x0;
- int h = bbox_y1 - bbox_y0;
+ TurbulenceInit((long)seed);
if (!pix){
pix = new NRPixBlock;
@@ -94,38 +137,19 @@ void FilterTurbulence::update_pixbuffer(FilterSlot &/*slot*/, IRect &area) {
nr_pixblock_setup_fast(pix, NR_PIXBLOCK_MODE_R8G8B8A8N, bbox_x0, bbox_y0, bbox_x1, bbox_y1, true);
}
- if (!pix || (pix->size != NR_PIXBLOCK_SIZE_TINY && pix->data.px == NULL)) {
- /* TODO: Should render the visible area or something instead. */
- g_warning("Unable to reserve image buffer for feTurbulence");
+ /* This limits pre-rendered turbulence to two megapixels. This is
+ * arbitary limit and could be something other, too.
+ * If bigger area is needed, visible area is rendered on demand. */
+ if (!pix || (pix->size != NR_PIXBLOCK_SIZE_TINY && pix->data.px == NULL) ||
+ ((bbox_x1 - bbox_x0) * (bbox_y1 - bbox_y0) > 2*1024*1024)) {
pix_data = NULL;
return;
}
- pix_data = NR_PIXBLOCK_PX(pix);
-
- TurbulenceInit((long)seed);
-
- double point[2];
+ render_area(pix, area, units);
- if (type==TURBULENCE_TURBULENCE){
- for (point[0]=0; point[0] < w; point[0]++){
- for (point[1]=0; point[1] < h; point[1]++){
- pix_data[4*(int(point[0]) + w*int(point[1]))] = CLAMP_D_TO_U8( turbulence(0,point)*255 );
- pix_data[4*(int(point[0]) + w*int(point[1])) + 1] = CLAMP_D_TO_U8( turbulence(1,point)*255 );
- pix_data[4*(int(point[0]) + w*int(point[1])) + 2] = CLAMP_D_TO_U8( turbulence(2,point)*255 );
- pix_data[4*(int(point[0]) + w*int(point[1])) + 3] = CLAMP_D_TO_U8( turbulence(3,point)*255 );
- }
- }
- } else {
- for (point[0]=0; point[0] < w; point[0]++){
- for (point[1]=0; point[1] < h; point[1]++){
- pix_data[4*(int(point[0]) + w*int(point[1]))] = CLAMP_D_TO_U8( ((turbulence(0,point)*255) +255)/2 );
- pix_data[4*(int(point[0]) + w*int(point[1])) + 1] = CLAMP_D_TO_U8( ((turbulence(1,point)*255)+255)/2 );
- pix_data[4*(int(point[0]) + w*int(point[1])) + 2] = CLAMP_D_TO_U8( ((turbulence(2,point)*255) +255)/2 );
- pix_data[4*(int(point[0]) + w*int(point[1])) + 3] = CLAMP_D_TO_U8( ((turbulence(3,point)*255) +255)/2 );
- }
- }
- }
+ pix_data = NR_PIXBLOCK_PX(pix);
+
updated=true;
updated_area = area;
}
@@ -134,39 +158,27 @@ int FilterTurbulence::render(FilterSlot &slot, FilterUnits const &units) {
//g_warning("render");
IRect area = units.get_pixblock_filterarea_paraller();
// TODO: could be faster - updated_area only has to be same size as area
- if (!updated || updated_area != area) update_pixbuffer(slot, area);
- if (!pix_data) {
- /* update_pixbuffer couldn't render the turbulence */
- return 1;
- }
+ if (!updated || updated_area != area) update_pixbuffer(area, units);
+
NRPixBlock *in = slot.get(_input);
if (!in) {
g_warning("Missing source image for feTurbulence (in=%d)", _input);
return 1;
}
- NRPixBlock *out = new NRPixBlock;
- int x,y;
+ NRPixBlock *out = new NRPixBlock;
int x0 = in->area.x0, y0 = in->area.y0;
int x1 = in->area.x1, y1 = in->area.y1;
- int w = x1 - x0;
nr_pixblock_setup_fast(out, NR_PIXBLOCK_MODE_R8G8B8A8N, x0, y0, x1, y1, true);
- int bbox_x0 = area.min()[X];
- int bbox_y0 = area.min()[Y];
- int bbox_x1 = area.max()[X];
- int bbox_y1 = area.max()[Y];
- int bbox_w = bbox_x1 - bbox_x0;
-
- unsigned char *out_data = NR_PIXBLOCK_PX(out);
- for (x = std::max(x0, bbox_x0); x < std::min(x1, bbox_x1); x++){
- for (y = std::max(y0, bbox_y0); y < std::min(y1, bbox_y1); y++){
- out_data[4*((x - x0)+w*(y - y0))] = pix_data[4*(x - bbox_x0 + bbox_w*(y - bbox_y0)) ];
- out_data[4*((x - x0)+w*(y - y0)) + 1] = pix_data[4*(x - bbox_x0 + bbox_w*(y - bbox_y0))+1];
- out_data[4*((x - x0)+w*(y - y0)) + 2] = pix_data[4*(x - bbox_x0 + bbox_w*(y - bbox_y0))+2];
- out_data[4*((x - x0)+w*(y - y0)) + 3] = pix_data[4*(x - bbox_x0 + bbox_w*(y - bbox_y0))+3];
- }
+ if (pix_data) {
+ /* If pre-rendered output of whole filter area exists, just copy it. */
+ nr_blit_pixblock_pixblock(out, pix);
+ } else {
+ /* No pre-rendered output, render the required area here. */
+ render_area(out, area, units);
}
+
out->empty = FALSE;
slot.set(_output, out);
return 0;
diff --git a/src/display/nr-filter-turbulence.h b/src/display/nr-filter-turbulence.h
index 7325543b1..f2bbb9628 100644
--- a/src/display/nr-filter-turbulence.h
+++ b/src/display/nr-filter-turbulence.h
@@ -60,7 +60,8 @@ public:
virtual ~FilterTurbulence();
virtual int render(FilterSlot &slot, FilterUnits const &units);
- void update_pixbuffer(FilterSlot &slot, IRect &area);
+ void update_pixbuffer(IRect &area, FilterUnits const &units);
+ void render_area(NRPixBlock *pix, IRect &full_area, FilterUnits const &units);
void set_baseFrequency(int axis, double freq);
void set_numOctaves(int num);
diff --git a/src/display/nr-filter-units.cpp b/src/display/nr-filter-units.cpp
index 0cad1b4c1..5b7bcdd4e 100644
--- a/src/display/nr-filter-units.cpp
+++ b/src/display/nr-filter-units.cpp
@@ -102,7 +102,7 @@ Matrix FilterUnits::get_matrix_units2pb(SPFilterUnits units) const {
} 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");
+ g_warning("Error in NR::FilterUnits::get_matrix_units2pb: unrecognized unit type (%d)", units);
return Matrix();
}
}
@@ -127,6 +127,33 @@ Matrix FilterUnits::get_matrix_pb2display() const {
return pb2d;
}
+Matrix FilterUnits::get_matrix_user2units(SPFilterUnits units) const {
+ if (units == SP_FILTER_UNITS_OBJECTBOUNDINGBOX) {
+ /* No need to worry about rotations: bounding box coordinates
+ * always have base vectors paraller with userspace coordinates */
+ Point min(item_bbox.min());
+ Point max(item_bbox.max());
+ double scale_x = 1.0 / (max[X] - min[X]);
+ double scale_y = 1.0 / (max[Y] - min[Y]);
+ return Matrix(scale_x, 0,
+ 0, scale_y,
+ min[X] * scale_x, min[Y] * scale_y);
+ } else if (units == SP_FILTER_UNITS_USERSPACEONUSE) {
+ return Matrix(NULL);
+ } else {
+ g_warning("Error in NR::FilterUnits::get_matrix_user2units: unrecognized unit type (%d)", units);
+ return Matrix();
+ }
+}
+
+Matrix FilterUnits::get_matrix_user2filterunits() const {
+ return get_matrix_user2units(filterUnits);
+}
+
+Matrix FilterUnits::get_matrix_user2primitiveunits() const {
+ return get_matrix_user2units(primitiveUnits);
+}
+
IRect FilterUnits::get_pixblock_filterarea_paraller() const {
int min_x = INT_MAX, min_y = INT_MAX, max_x = INT_MIN, max_y = INT_MIN;
Matrix u2pb = get_matrix_user2pb();
diff --git a/src/display/nr-filter-units.h b/src/display/nr-filter-units.h
index 7f90d6d31..49fe30aa9 100644
--- a/src/display/nr-filter-units.h
+++ b/src/display/nr-filter-units.h
@@ -86,6 +86,16 @@ public:
Matrix get_matrix_pb2display() const;
/**
+ * Gets the user coordinates to filterUnits transformation matrix.
+ */
+ Matrix get_matrix_user2filterunits() const;
+
+ /**
+ * Gets the user coordinates to primitiveUnits transformation matrix.
+ */
+ Matrix get_matrix_user2primitiveunits() const;
+
+ /**
* Returns the filter area in pixblock coordinates.
* NOTE: use only in filters, that define TRAIT_PARALLER in
* get_input_traits. The filter effects area may not be representable
@@ -96,6 +106,7 @@ public:
private:
Matrix get_matrix_units2pb(SPFilterUnits units) const;
+ Matrix get_matrix_user2units(SPFilterUnits units) const;
SPFilterUnits filterUnits, primitiveUnits;
double resolution_x, resolution_y;