Code

Fized crashes & odd behaviour when resizing, zooming and rotating feTurbulence
authorkiirala <kiirala@users.sourceforge.net>
Thu, 6 Dec 2007 23:31:29 +0000 (23:31 +0000)
committerkiirala <kiirala@users.sourceforge.net>
Thu, 6 Dec 2007 23:31:29 +0000 (23:31 +0000)
src/display/nr-filter-turbulence.cpp
src/display/nr-filter-turbulence.h
src/display/nr-filter-units.cpp
src/display/nr-filter-units.h
src/libnr/nr-point-l.h
src/libnr/nr-rect-l.h

index 2c5d0ee64ecbf1aa626fa2a2fffbfa3861d3b234..869c66fcfb2f029e587ea62bba928f1fb0c3277b 100644 (file)
@@ -14,6 +14,7 @@
 #include "display/nr-filter-turbulence.h"
 #include "display/nr-filter-units.h"
 #include "display/nr-filter-utils.h"
+#include "libnr/nr-rect-l.h"
 #include <math.h>
 
 namespace NR {
@@ -24,6 +25,7 @@ FilterTurbulence::FilterTurbulence()
   numOctaves(1),
   seed(0),
   updated(false),
+  updated_area(IPoint(), IPoint()),
   pix(NULL),
   fTileWidth(10), //guessed
   fTileHeight(10), //guessed
@@ -37,7 +39,12 @@ FilterPrimitive * FilterTurbulence::create() {
 }
 
 FilterTurbulence::~FilterTurbulence()
-{}
+{
+    if (pix) {
+        nr_pixblock_release(pix);
+        delete pix;
+    }
+}
 
 void FilterTurbulence::set_baseFrequency(int axis, double freq){
     if (axis==0) XbaseFrequency=freq;
@@ -64,19 +71,28 @@ void FilterTurbulence::set_updated(bool u){
     updated=u;
 }
 
-void FilterTurbulence::update_pixbuffer(FilterSlot &slot) {
+void FilterTurbulence::update_pixbuffer(FilterSlot &slot, IRect &area) {
 //g_warning("update_pixbuf");
-    int bbox_x0 = (int) slot.get_arenaitem()->bbox.x0;
-    int bbox_y0 = (int) slot.get_arenaitem()->bbox.y0;
-    int bbox_x1 = (int) slot.get_arenaitem()->bbox.x1;
-    int bbox_y1 = (int) slot.get_arenaitem()->bbox.y1;
+    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;
 
     if (!pix){
         pix = new NRPixBlock;
-        nr_pixblock_setup_fast(pix, NR_PIXBLOCK_MODE_R8G8B8A8P, bbox_x0, bbox_y0, bbox_x1, bbox_y1, true);
+        nr_pixblock_setup_fast(pix, NR_PIXBLOCK_MODE_R8G8B8A8N, bbox_x0, bbox_y0, bbox_x1, bbox_y1, true);
+        pix_data = NR_PIXBLOCK_PX(pix);
+    }
+    else if (bbox_x0 != pix->area.x0 || bbox_y0 != pix->area.y0 ||
+        bbox_x1 != pix->area.x1 || bbox_y1 != pix->area.y1)
+    {
+        /* TODO: release-setup cycle not actually needed, if pixblock
+         * width and height don't change */
+        nr_pixblock_release(pix);
+        nr_pixblock_setup_fast(pix, NR_PIXBLOCK_MODE_R8G8B8A8N, bbox_x0, bbox_y0, bbox_x1, bbox_y1, true);
         pix_data = NR_PIXBLOCK_PX(pix);
     }
 
@@ -104,11 +120,14 @@ void FilterTurbulence::update_pixbuffer(FilterSlot &slot) {
         }
     }
     updated=true;
+    updated_area = area;
 }
 
-int FilterTurbulence::render(FilterSlot &slot, FilterUnits const &/*units*/) {
+int FilterTurbulence::render(FilterSlot &slot, FilterUnits const &units) {
 //g_warning("render");
-    if (!updated) update_pixbuffer(slot);
+    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);
 
     NRPixBlock *in = slot.get(_input);
     NRPixBlock *out = new NRPixBlock;
@@ -116,16 +135,17 @@ int FilterTurbulence::render(FilterSlot &slot, FilterUnits const &/*units*/) {
     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, in->mode, x0, y0, x1, y1, true);
+    nr_pixblock_setup_fast(out, NR_PIXBLOCK_MODE_R8G8B8A8N, x0, y0, x1, y1, true);
 
-    int bbox_x0 = (int) slot.get_arenaitem()->bbox.x0;
-    int bbox_y0 = (int) slot.get_arenaitem()->bbox.y0;
-    int bbox_x1 = (int) slot.get_arenaitem()->bbox.x1;
+    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=x0; x < x1; x++){
-        for (y=y0; y < y1; y++){
+    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];
@@ -154,7 +174,7 @@ long FilterTurbulence::TurbulenceRandom(long lSeed)
 
 void FilterTurbulence::TurbulenceInit(long lSeed)
 {
-g_warning("init");
+//g_warning("init");
   double s;
   int i, j, k;
   lSeed = Turbulence_setup_seed(lSeed);
index 144e3ec4cda5a5f3aafb5fac76c5b2b3dd0caacb..bfbacc9f36c111b968453ed0d2e4746a5f007d14 100644 (file)
@@ -16,6 +16,7 @@
 #include "display/nr-filter-primitive.h"
 #include "display/nr-filter-slot.h"
 #include "display/nr-filter-units.h"
+#include "libnr/nr-rect-l.h"
 
 namespace NR {
 
@@ -59,14 +60,14 @@ public:
     virtual ~FilterTurbulence();
 
     virtual int render(FilterSlot &slot, FilterUnits const &units);
-    virtual void update_pixbuffer(FilterSlot &slot);
+    void update_pixbuffer(FilterSlot &slot, IRect &area);
     
-    virtual void set_baseFrequency(int axis, double freq);
-    virtual void set_numOctaves(int num);
-    virtual void set_seed(double s);
-    virtual void set_stitchTiles(bool st);
-    virtual void set_type(FilterTurbulenceType t);
-    virtual void set_updated(bool u);
+    void set_baseFrequency(int axis, double freq);
+    void set_numOctaves(int num);
+    void set_seed(double s);
+    void set_stitchTiles(bool st);
+    void set_type(FilterTurbulenceType t);
+    void set_updated(bool u);
     virtual FilterTraits get_input_traits();
 private:
 
@@ -82,6 +83,7 @@ private:
     bool stitchTiles;
     FilterTurbulenceType type;
     bool updated;
+    IRect updated_area;
     NRPixBlock *pix;
     unsigned char *pix_data;
 
index 2c84800d69c20ab57bb9b9e37aa5ab6a28375924..0cad1b4c1b0fa7c856395f0b3761d34c2a76e007 100644 (file)
@@ -14,6 +14,7 @@
 #include "display/nr-filter-units.h"
 #include "libnr/nr-matrix.h"
 #include "libnr/nr-rect.h"
+#include "libnr/nr-rect-l.h"
 #include "libnr/nr-scale.h"
 #include "sp-filter-units.h"
 
@@ -71,8 +72,8 @@ Matrix FilterUnits::get_matrix_user2pb() const {
         u2pb[1] = 0;
         u2pb[2] = 0;
         u2pb[3] = resolution_y / (filter_area.max()[Y] - filter_area.min()[Y]);
-        u2pb[4] = 0;
-        u2pb[5] = 0;
+        u2pb[4] = ctm[4];
+        u2pb[5] = ctm[5];
     }
 
     return u2pb;
@@ -126,6 +127,22 @@ Matrix FilterUnits::get_matrix_pb2display() const {
     return pb2d;
 }
 
+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();
+
+    for (int i = 0 ; i < 4 ; i++) {
+        Point p = filter_area.corner(i);
+        p *= u2pb;
+        if (p[X] < min_x) min_x = (int)std::floor(p[X]);
+        if (p[X] > max_x) max_x = (int)std::ceil(p[X]);
+        if (p[Y] < min_y) min_y = (int)std::floor(p[Y]);
+        if (p[Y] > max_y) max_y = (int)std::ceil(p[Y]);
+    }
+    IRect ret(IPoint(min_x, min_y), IPoint(max_x, max_y));
+    return ret;
+}
+
 FilterUnits& FilterUnits::operator=(FilterUnits const &other) {
     filterUnits = other.filterUnits;
     primitiveUnits = other.primitiveUnits;
index 8ebb5032791a0133cb92932ecd7cf995b40ff079..7f90d6d3107fea65c5f7a7bf26be61b29c1a61ca 100644 (file)
@@ -15,6 +15,7 @@
 #include "sp-filter-units.h"
 #include "libnr/nr-matrix.h"
 #include "libnr/nr-rect.h"
+#include "libnr/nr-rect-l.h"
 
 namespace NR {
 
@@ -84,6 +85,13 @@ public:
      */
     Matrix get_matrix_pb2display() 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
+     * by simple rectangle otherwise. */
+    IRect get_pixblock_filterarea_paraller() const;
+
     FilterUnits& operator=(FilterUnits const &other);
 
 private:
index 8ddfd5e6f638d02f61c741e52c392d1c196ad359..4ae1a8b82bbbaffe8ebe9f52aa0dc952641ea15e 100644 (file)
@@ -73,7 +73,15 @@ public:
         }
         return *this;
     }
-  
+
+    bool operator==(IPoint const &other) const {
+        return _pt[X] == other[X] && _pt[Y] == other[Y];
+    }
+
+    bool operator!=(IPoint const &other) const {
+        return _pt[X] != other[X] || _pt[Y] != other[Y];
+    }
+
 private:
     ICoord _pt[2];
 };
index b84a8f0cbb9c41dfbab080aa2f2694cb8cf6cde6..18065d1d7aa627ac2ebb395f604ce2c80d49e17d 100644 (file)
@@ -19,7 +19,7 @@ class IRect {
 public:
     IRect(const NRRectL& r) : _min(r.x0, r.y0), _max(r.x1, r.y1) {}
     IRect(const IRect& r) : _min(r._min), _max(r._max) {}
-    IRect(const IPoint &p0, const IPoint &p1);
+    IRect(const IPoint &p0, const IPoint &p1) : _min(p0), _max(p1) {}
     
     /** as not all Rects are representable by IRects this gives the smallest IRect that contains
      * r. */
@@ -84,6 +84,14 @@ public:
     /** Returns the smallest rectangle that encloses both rectangles. */
     static IRect union_bounds(const IRect &a, const IRect &b);
 
+    bool operator==(const IRect &other) const {
+        return (min() == other.min()) && (max() == other.max());
+    }
+
+    bool operator!=(const IRect &other) const {
+        return (min() != other.min()) || (max() != other.max());
+    }
+
 private:
     IRect() {}