Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
Browse files

[BitmapData] Implement floodFill

  • Loading branch information...
commit 901cc5b93e3a15c824e71a0f6de51b11c13803b8 1 parent 43b5b4b
@aajanki aajanki authored
View
122 src/scripting/flash/display/BitmapContainer.cpp
@@ -17,6 +17,7 @@
along with this program. If not, see <http://www.gnu.org/licenses/>.
**************************************************************************/
+#include <stack>
#include "scripting/flash/display/BitmapContainer.h"
#include "backends/rendering_context.h"
#include "backends/image.h"
@@ -255,3 +256,124 @@ bool BitmapContainer::scroll(int32_t x, int32_t y)
return true;
}
+
+inline uint32_t *BitmapContainer::getDataNoBoundsChecking(int32_t x, int32_t y)
+{
+ return (uint32_t*)&data[y*stride + 4*x];
+}
+
+/*
+ * Fill a connected area around (startX, startY) with the given color.
+ *
+ * Adapted from "A simple non-recursive scan line method" at
+ * http://www.codeproject.com/Articles/6017/QuickFill-An-efficient-flood-fill-algorithm
+ */
+void BitmapContainer::floodFill(int32_t startX, int32_t startY, uint32_t color)
+{
+ struct LineSegment {
+ LineSegment(int32_t _x1, int32_t _x2, int32_t _y, int32_t _dy)
+ : x1(_x1), x2(_x2), y(_y), dy(_dy) {};
+ int32_t x1; // leftmost filled point on last line
+ int32_t x2; // rightmost filled point on last line
+ int32_t y; // y coordinate (may be invalid!)
+ int32_t dy; // vertical direction (1 or -1)
+ };
+
+ stack<LineSegment> segments;
+
+ if (startX < 0 || startX >= width || startY < 0 || startY >= height)
+ return;
+
+ uint32_t seedColor = getPixel(startX, startY);
+
+ // Comment on the codeproject.com: "needed in some cases" ???
+ segments.push(LineSegment(startX, startX, startY+1, 1));
+ // The starting point
+ segments.push(LineSegment(startX, startX, startY, -1));
+
+ while (!segments.empty())
+ {
+ int32_t left;
+ LineSegment r = segments.top();
+ segments.pop();
+ if (r.y < 0 || r.y >= height)
+ continue;
+
+ assert(r.x1 <= r.x2);
+ assert(r.x1 >= 0);
+ assert(r.x2 < width);
+
+ // current x-coordinate
+ int t = r.x1;
+ // pointer to the current pixel, keep in sync with t
+ uint32_t *p = getDataNoBoundsChecking(r.x1, r.y);
+
+ // extend left
+ while (t >= 0 && *p == seedColor)
+ {
+ *p = color;
+ p--;
+ t--;
+ }
+
+ if (t >= r.x1)
+ {
+ // Did not extend to left. Skip over border if
+ // any.
+ while (t <= r.x2 && *p != seedColor)
+ {
+ p++;
+ t++;
+ }
+ left = t;
+ }
+ else
+ {
+ // Extended past r.x1, push the segment on the
+ // previous line
+ left = t+1;
+ if (left < r.x1)
+ {
+ segments.push(LineSegment(left, r.x1-1, r.y-r.dy, -r.dy));
+ }
+
+ t = r.x1 + 1;
+ }
+
+ // fill rightwards starting from r.x1 or the leftmost
+ // filled point
+ do
+ {
+ p = getDataNoBoundsChecking(t, r.y);
+ while (t < width && *p == seedColor)
+ {
+ *p = color;
+ p++;
+ t++;
+ }
+
+ // push the segment on the next line
+ if (t >= left+1)
+ segments.push(LineSegment(left, t-1, r.y+r.dy, r.dy));
+
+ // If extended past r.x2, push the segment on
+ // the previous line
+ if (t > r.x2+1)
+ {
+ segments.push(LineSegment(r.x2, t-1, r.y-r.dy, -r.dy));
+ break; // we are done with this segment
+ }
+
+ // Skip forward
+ p++;
+ t++;
+ while (t <= r.x2 && *p != seedColor)
+ {
+ p++;
+ t++;
+ }
+ left = t;
+ }
+ while (t <= r.x2);
+ }
+}
View
2  src/scripting/flash/display/BitmapContainer.h
@@ -35,6 +35,7 @@ class BitmapContainer : public RefCountable
size_t dataSize;
int32_t width;
int32_t height;
+ uint32_t *getDataNoBoundsChecking(int32_t x, int32_t y);
public:
BitmapContainer(MemoryAccount* m);
std::vector<uint8_t, reporter_allocator<uint8_t>> data;
@@ -54,6 +55,7 @@ class BitmapContainer : public RefCountable
int32_t width, int32_t height, bool mergeAlpha);
void fillRectangle(int32_t x, int32_t y, int32_t width, int32_t height, uint32_t color, bool useAlpha);
bool scroll(int32_t x, int32_t y);
+ void floodFill(int32_t x, int32_t y, uint32_t color);
int getWidth() const { return width; }
int getHeight() const { return height; }
bool isEmpty() const { return data.empty(); }
View
20 src/scripting/flash/display/BitmapData.cpp
@@ -71,6 +71,7 @@ void BitmapData::sinit(Class_base* c)
c->setDeclaredMethodByQName("copyChannel","",Class<IFunction>::getFunction(copyChannel),NORMAL_METHOD,true);
c->setDeclaredMethodByQName("lock","",Class<IFunction>::getFunction(lock),NORMAL_METHOD,true);
c->setDeclaredMethodByQName("unlock","",Class<IFunction>::getFunction(unlock),NORMAL_METHOD,true);
+ c->setDeclaredMethodByQName("floodFill","",Class<IFunction>::getFunction(floodFill),NORMAL_METHOD,true);
// properties
c->setDeclaredMethodByQName("height","",Class<IFunction>::getFunction(_getHeight),GETTER_METHOD,true);
@@ -526,3 +527,22 @@ ASFUNCTIONBODY(BitmapData,unlock)
return NULL;
}
+
+ASFUNCTIONBODY(BitmapData,floodFill)
+{
+ BitmapData* th = obj->as<BitmapData>();
+ if(th->pixels.isNull())
+ throw Class<ArgumentError>::getInstanceS("Disposed BitmapData", 2015);
+
+ int32_t x;
+ int32_t y;
+ uint32_t color;
+ ARG_UNPACK (x) (y) (color);
+
+ if (!th->transparent)
+ color = 0xFF000000 | color;
+
+ th->pixels->floodFill(x, y, color);
+ th->notifyUsers();
+ return NULL;
+}
View
1  src/scripting/flash/display/BitmapData.h
@@ -85,6 +85,7 @@ class BitmapData: public ASObject, public IBitmapDrawable
ASFUNCTION(copyChannel);
ASFUNCTION(lock);
ASFUNCTION(unlock);
+ ASFUNCTION(floodFill);
};
};
Please sign in to comment.
Something went wrong with that request. Please try again.