A Song of Floodfills and Segfaults
authorSam Moore <matches@ucc.asn.au>
Tue, 26 Aug 2014 10:42:33 +0000 (18:42 +0800)
committerSam Moore <matches@ucc.asn.au>
Tue, 26 Aug 2014 10:42:33 +0000 (18:42 +0800)
Ok, just need to make the FloodFillOnCPU not stack overflow...

14 files changed:
.gitignore
src/Makefile
src/bezier.cpp
src/bezier.h
src/document.cpp
src/document.h
src/group.cpp [deleted file]
src/group.h [deleted file]
src/ipdf.h
src/objectrenderer.cpp
src/objectrenderer.h
src/path.cpp [new file with mode: 0644]
src/path.h [new file with mode: 0644]
src/view.cpp

index 28b8762..7973e79 100644 (file)
@@ -12,3 +12,4 @@
 *.dat
 bin/ipdf
 data/*
+src/moc_controlpanel.cpp
index af72dfa..cec94f2 100644 (file)
@@ -3,7 +3,7 @@ ARCH := $(shell uname -m)
 # TODO: stb_truetype doesn't compile with some of these warnings.
 CXX = g++ -std=gnu++0x -g -Wall -Werror -Wshadow -pedantic -rdynamic
 MAIN = main.o
-OBJ = log.o real.o bezier.o document.o objectrenderer.o view.o screen.o vfpu.o quadtree.o graphicsbuffer.o framebuffer.o shaderprogram.o stb_truetype.o gl_core44.o add_digits_asm.o sub_digits_asm.o mul_digits_asm.o div_digits_asm.o arbint.o moc_controlpanel.o controlpanel.o group.o
+OBJ = log.o real.o bezier.o document.o objectrenderer.o view.o screen.o vfpu.o quadtree.o graphicsbuffer.o framebuffer.o shaderprogram.o stb_truetype.o gl_core44.o add_digits_asm.o sub_digits_asm.o mul_digits_asm.o div_digits_asm.o arbint.o moc_controlpanel.o controlpanel.o path.o
 
 QT_INCLUDE := -I/usr/share/qt4/mkspecs/linux-g++-64 -I. -I/usr/include/qt4/QtCore -I/usr/include/qt4/QtGui -I/usr/include/qt4 -I. -Itests -I.
 QT_DEF := -DQT_NO_DEBUG -DQT_GUI_LIB -DQT_CORE_LIB
index b3129e4..1c83660 100644 (file)
@@ -52,7 +52,7 @@ Real Bernstein(int k, int n, const Real & u)
  * In one coordinate direction
  */
 
-static pair<Real, Real> BezierTurningPoints(const Real & p0, const Real & p1, const Real & p2, const Real & p3)
+pair<Real, Real> BezierTurningPoints(const Real & p0, const Real & p1, const Real & p2, const Real & p3)
 {
        // straight line
        if (p1 == p2 && p2 == p3)
@@ -90,6 +90,155 @@ inline bool CompRealByPtr(const Real * a, const Real * b)
        return (*a) < (*b);
 }
 
+/**
+ * Get top most *point* on Bezier curve
+ */
+pair<Real,Real> Bezier::GetTop() const
+{
+       pair<Real, Real> tsols = BezierTurningPoints(y0,y1,y2,y3);
+       Real tx0; Real ty0;
+       Real tx1; Real ty1;
+       Evaluate(tx0, ty0, tsols.first);
+       Evaluate(tx1, ty1, tsols.second);
+       vector<const Real*> v(4);
+       v[0] = &y0;
+       v[1] = &y3;
+       v[2] = &ty0;
+       v[3] = &ty1;
+       sort(v.begin(), v.end(), CompRealByPtr);
+       pair<Real,Real> result;
+       result.second = *v[0];
+       if (v[0] == &y0)
+       {
+               result.first = x0;
+       }
+       else if (v[0] == &y3)
+       {
+               result.first = x3;
+       }
+       else if (v[0] == &ty0)
+       {
+               result.first = tx0;
+       }
+       else if (v[0] == &ty1)
+       {
+               result.first = tx1;
+       }
+       return result;
+}
+
+/**
+ * Get bottom most *point* on Bezier curve
+ */
+pair<Real,Real> Bezier::GetBottom() const
+{
+       pair<Real, Real> tsols = BezierTurningPoints(y0,y1,y2,y3);
+       Real tx0; Real ty0;
+       Real tx1; Real ty1;
+       Evaluate(tx0, ty0, tsols.first);
+       Evaluate(tx1, ty1, tsols.second);
+       vector<const Real*> v(4);
+       v[0] = &y0;
+       v[1] = &y3;
+       v[2] = &ty0;
+       v[3] = &ty1;
+       sort(v.begin(), v.end(), CompRealByPtr);
+       pair<Real,Real> result;
+       result.second = *v[3];
+       if (v[3] == &y0)
+       {
+               result.first = x0;
+       }
+       else if (v[3] == &y3)
+       {
+               result.first = x3;
+       }
+       else if (v[3] == &ty0)
+       {
+               result.first = tx0;
+       }
+       else if (v[3] == &ty1)
+       {
+               result.first = tx1;
+       }
+       return result;
+}
+
+/**
+ * Get left most *point* on Bezier curve
+ */
+pair<Real,Real> Bezier::GetLeft() const
+{
+       pair<Real, Real> tsols = BezierTurningPoints(x0,x1,x2,x3);
+       Real tx0; Real ty0;
+       Real tx1; Real ty1;
+       Evaluate(tx0, ty0, tsols.first);
+       Evaluate(tx1, ty1, tsols.second);
+       vector<const Real*> v(4);
+       v[0] = &x0;
+       v[1] = &x3;
+       v[2] = &tx0;
+       v[3] = &tx1;
+       sort(v.begin(), v.end(), CompRealByPtr);
+       pair<Real,Real> result;
+       result.first = *v[0];
+       if (v[0] == &x0)
+       {
+               result.second = y0;
+       }
+       else if (v[0] == &x3)
+       {
+               result.second = y3;
+       }
+       else if (v[0] == &tx0)
+       {
+               result.second = ty0;
+       }
+       else if (v[0] == &tx1)
+       {
+               result.second = ty1;
+       }
+       return result;
+}
+
+
+/**
+ * Get left most *point* on Bezier curve
+ */
+pair<Real,Real> Bezier::GetRight() const
+{
+       pair<Real, Real> tsols = BezierTurningPoints(x0,x1,x2,x3);
+       Real tx0; Real ty0;
+       Real tx1; Real ty1;
+       Evaluate(tx0, ty0, tsols.first);
+       Evaluate(tx1, ty1, tsols.second);
+       vector<const Real*> v(4);
+       v[0] = &x0;
+       v[1] = &x3;
+       v[2] = &tx0;
+       v[3] = &tx1;
+       sort(v.begin(), v.end(), CompRealByPtr);
+       pair<Real,Real> result;
+       result.first = *v[3];
+       if (v[3] == &x0)
+       {
+               result.second = y0;
+       }
+       else if (v[3] == &x3)
+       {
+               result.second = y3;
+       }
+       else if (v[3] == &tx0)
+       {
+               result.second = ty0;
+       }
+       else if (v[3] == &tx1)
+       {
+               result.second = ty1;
+       }
+       return result;
+}
+
 /**
  * Get Bounds Rectangle of Bezier
  */
index 17bc5b6..99530b3 100644 (file)
@@ -11,6 +11,7 @@ namespace IPDF
        extern int Factorial(int n);
        extern int BinomialCoeff(int n, int k);
        extern Real Bernstein(int k, int n, const Real & u);
+       extern std::pair<Real,Real> BezierTurningPoints(const Real & p0, const Real & p1, const Real & p2, const Real & p3);
        
        inline std::pair<Real,Real> SolveQuadratic(const Real & a, const Real & b, const Real & c)
        {
@@ -122,6 +123,11 @@ namespace IPDF
 
                Rect SolveBounds() const;
                
+               std::pair<Real,Real> GetTop() const;
+               std::pair<Real,Real> GetBottom() const;
+               std::pair<Real,Real> GetLeft() const;
+               std::pair<Real,Real> GetRight() const;
+               
                Bezier ToAbsolute(const Rect & bounds) const
                {
                        return Bezier(*this, bounds);
@@ -320,6 +326,15 @@ namespace IPDF
                        x = x0*coeff[0] + x1*coeff[1] + x2*coeff[2] + x3*coeff[3];
                        y = y0*coeff[0] + y1*coeff[1] + y2*coeff[2] + y3*coeff[3];
                }
+               
+               bool operator==(const Bezier & equ) const
+               {
+                       return (x0 == equ.x0 && y0 == equ.y0
+                               &&  x1 == equ.x1 && y1 == equ.y1
+                               &&      x2 == equ.x2 && y2 == equ.y2
+                               &&      x3 == equ.x3 && y3 == equ.y3);
+               }
+               bool operator!=(const Bezier & equ) const {return !this->operator==(equ);}
 
        };
 
index 0b72a3e..6c39079 100644 (file)
@@ -295,8 +295,8 @@ void Document::Load(const string & filename)
                        LoadStructVector<Bezier>(file, chunk_size/sizeof(Bezier), m_objects.beziers);
                        break;
                        
-               case CT_OBJGROUPS:
-                       Debug("Group data...");
+               case CT_OBJPATHS:
+                       Debug("Path data...");
                        Warn("Not handled because lazy");
                        break;
                }
@@ -310,32 +310,12 @@ void Document::Load(const string & filename)
 #endif
 }
 
-unsigned Document::AddGroup(unsigned start_index, unsigned end_index, const Colour & fill)
+unsigned Document::AddPath(unsigned start_index, unsigned end_index, const Colour & fill)
 {
-       Real xmin = 0; Real ymin = 0; 
-       Real xmax = 0; Real ymax = 0;
-       
-       for (unsigned i = start_index; i <= end_index; ++i)
-       {
-               Rect & objb = m_objects.bounds[i];
-               
-               if (i == start_index || objb.x < xmin)
-                       xmin = objb.x;
-               if (i == start_index || (objb.x+objb.w) > xmax)
-                       xmax = (objb.x+objb.w);
-                       
-               if (i == start_index || objb.y < ymin)
-                       ymin = objb.y;
-               if (i == start_index || (objb.y+objb.h) > ymax)
-                       ymax = (objb.y+objb.h);
-       }
-       
-       Rect bounds(xmin,ymin, xmax-xmin, ymax-ymin);
-       
-       Group group(start_index, end_index, 0U, fill);
-       
-       unsigned data_index = AddGroupData(group);
-       unsigned result = Add(GROUP, bounds,data_index);
+       Path path(m_objects, start_index, end_index, fill);
+       unsigned data_index = AddPathData(path);
+       Rect bounds = path.SolveBounds(m_objects);
+       unsigned result = Add(PATH, bounds,data_index);
        return result;
 }
 
@@ -346,6 +326,12 @@ unsigned Document::AddBezier(const Bezier & bezier)
 {
        Rect bounds = bezier.SolveBounds();
        Bezier data = bezier.ToRelative(bounds); // Relative
+       if (data.ToAbsolute(bounds) != bezier)
+       {
+               Error("%s != %s", data.ToAbsolute(Rect(0,0,1,1)).Str().c_str(),
+                       bezier.Str().c_str());
+               Fatal("ToAbsolute on ToRelative does not give original Bezier");
+       }
        unsigned index = AddBezierData(data);
        return Add(BEZIER, bounds, index);
 }
@@ -364,10 +350,10 @@ unsigned Document::AddBezierData(const Bezier & bezier)
        return m_objects.beziers.size()-1;
 }
 
-unsigned Document::AddGroupData(const Group & group)
+unsigned Document::AddPathData(const Path & path)
 {
-       m_objects.groups.push_back(group);
-       return m_objects.groups.size()-1;
+       m_objects.paths.push_back(path);
+       return m_objects.paths.size()-1;
 }
 
 void Document::DebugDumpObjects()
@@ -603,7 +589,7 @@ void Document::ParseSVGNode(pugi::xml_node & root, SVGMatrix & parent_transform)
                                }
                                
                                        Debug("fill-opacity is %f", Float(c.a));
-                               AddGroup(range.first, range.second, c);
+                               AddPath(range.first, range.second, c);
                        }
                        
                }
@@ -1008,7 +994,7 @@ void Document::AddFontGlyphAtPoint(stbtt_fontinfo *font, int character, Real sca
        
        if (start_index < m_count && end_index < m_count)
        {
-               AddGroup(start_index, end_index);
+               AddPath(start_index, end_index);
        }
        Debug("Added Glyph \"%c\" at %f %f, scale %f", (char)character, Float(x), Float(y), Float(scale));
 
index cab7684..9169d8a 100644 (file)
@@ -52,11 +52,11 @@ namespace IPDF
                        bool operator==(const Document & equ) const;
                        bool operator!=(const Document & equ) const {return !(this->operator==(equ));}
 
-                       unsigned AddGroup(unsigned start_index, unsigned end_index, const Colour & shading=Colour(0.6,0.6,0.6,1));
+                       unsigned AddPath(unsigned start_index, unsigned end_index, const Colour & shading=Colour(0.6,0.6,0.6,1));
                        unsigned AddBezier(const Bezier & bezier);
                        unsigned Add(ObjectType type, const Rect & bounds, unsigned data_index = 0);
                        unsigned AddBezierData(const Bezier & bezier);
-                       unsigned AddGroupData(const Group & group);
+                       unsigned AddPathData(const Path & path);
 
 
                        /** SVG Related functions **/
diff --git a/src/group.cpp b/src/group.cpp
deleted file mode 100644 (file)
index 8407a4b..0000000
+++ /dev/null
@@ -1,8 +0,0 @@
-#include "group.h"
-using namespace std;
-
-namespace IPDF
-{
-       
-               
-}
diff --git a/src/group.h b/src/group.h
deleted file mode 100644 (file)
index f72369b..0000000
+++ /dev/null
@@ -1,33 +0,0 @@
-#ifndef _GROUP_H
-#define _GROUP_H
-
-#include <vector>
-#include <algorithm>
-
-namespace IPDF
-{
-       
-       struct Colour
-       {
-               float r; float g; float b; float a;
-               Colour() = default;
-               Colour(float _r, float _g, float _b, float _a) : r(_r), g(_g), b(_b), a(_a) {}
-       };
-       
-       class Objects;
-       
-       struct Group
-       {
-               Group(unsigned _start, unsigned _end, unsigned _index, const Colour & _fill = Colour(0.8,0.8,0.8,1))
-                       : m_start(_start), m_end(_end), m_index(_index), m_fill(_fill)
-               {
-                       
-               }
-               unsigned m_start;
-               unsigned m_end;
-               unsigned m_index;
-               Colour m_fill;          
-       };
-
-}
-#endif //_GROUP_H
index f9d3a96..633c8ef 100644 (file)
@@ -6,7 +6,7 @@
 #include "bezier.h"
 #include "rect.h"
 
-#include "group.h"
+#include "path.h"
 
 namespace IPDF
 {
@@ -26,7 +26,7 @@ namespace IPDF
                RECT_FILLED,
                RECT_OUTLINE,
                BEZIER,
-               GROUP,
+               PATH,
                NUMBER_OF_OBJECT_TYPES
        } ObjectType;
 
@@ -37,7 +37,7 @@ namespace IPDF
                CT_OBJBOUNDS,
                CT_OBJINDICES,
                CT_OBJBEZIERS,
-               CT_OBJGROUPS
+               CT_OBJPATHS
        };
 
        struct Objects
@@ -49,8 +49,8 @@ namespace IPDF
                std::vector<unsigned> data_indices;
                /** Used by BEZIER only **/
                std::vector<Bezier> beziers; // bezier curves - look up by data_indices
-               /** Used by GROUP only **/
-               std::vector<Group> groups;
+               /** Used by PATH only **/
+               std::vector<Path> paths;
        };
 
        class View;
index 6108f4f..8234547 100644 (file)
@@ -5,7 +5,7 @@
 
 #include "objectrenderer.h"
 #include "view.h"
-#include <list>
+#include <vector>
 
 using namespace std;
 
@@ -122,6 +122,8 @@ void RectFilledRenderer::RenderUsingCPU(const Objects & objects, const View & vi
                if (m_indexes[i] < first_obj_id) continue;
                if (m_indexes[i] >= last_obj_id) continue;
                PixelBounds bounds(CPURenderBounds(objects.bounds[m_indexes[i]], view, target));
+               FloodFillOnCPU(bounds.x+1, bounds.y+1, bounds, target, Colour(0,0,0,1));
+               /*
                for (int64_t x = max((int64_t)0, bounds.x); x <= min(bounds.x+bounds.w, target.w-1); ++x)
                {
                        for (int64_t y = max((int64_t)0, bounds.y); y <= min(bounds.y+bounds.h, target.h-1); ++y)
@@ -133,6 +135,7 @@ void RectFilledRenderer::RenderUsingCPU(const Objects & objects, const View & vi
                                target.pixels[index+3] = 255;
                        }
                }
+               */
        }
 }
 
@@ -209,6 +212,15 @@ Rect ObjectRenderer::CPURenderBounds(const Rect & bounds, const View & view, con
        result.h *= Real(target.h);
        return result;
 }
+
+pair<int64_t, int64_t> ObjectRenderer::CPUPointLocation(const pair<Real, Real> & point, const View & view, const CPURenderTarget & target)
+{
+       // hack...
+       Rect result = view.TransformToViewCoords(Rect(point.first, point.second,1,1));
+       int64_t x = result.x*target.w;
+       int64_t y = result.y*target.h;
+       return pair<int64_t, int64_t>(x,y);
+}
        
 
 /**
@@ -332,17 +344,12 @@ void BezierRenderer::RenderUsingGPU(unsigned first_obj_id, unsigned last_obj_id)
        glDrawElements(GL_LINES, (last_index-first_index)*2, GL_UNSIGNED_INT, (GLvoid*)(2*first_index*sizeof(uint32_t)));
 }
 
-inline bool IsBlack(uint8_t * pixels, int64_t index)
-{
-       bool result = (pixels[index+0] == 0 && pixels[index+1] == 0 && pixels[index+2] == 0 && pixels[index+3] == 255);
-       //pixels[index+3] = 254; // hax
-       return result;
-}
+
 
 /**
- * Render Group (shading)
+ * Render Path (shading)
  */
-void GroupRenderer::RenderUsingCPU(const Objects & objects, const View & view, const CPURenderTarget & target, unsigned first_obj_id, unsigned last_obj_id)
+void PathRenderer::RenderUsingCPU(const Objects & objects, const View & view, const CPURenderTarget & target, unsigned first_obj_id, unsigned last_obj_id)
 {
        if (!view.ShowingObjectBounds() && !view.PerformingShading())
                return;
@@ -355,75 +362,29 @@ void GroupRenderer::RenderUsingCPU(const Objects & objects, const View & view, c
                
                Rect bounds(CPURenderBounds(objects.bounds[m_indexes[i]], view, target));
                PixelBounds pix_bounds(bounds);
-               
-               const Group & group = objects.groups[objects.data_indices[m_indexes[i]]];
-               if (group.m_fill.a == 0 || !view.PerformingShading())
-                       continue;
-
-               // make the bounds just a little bit bigger
                pix_bounds.x-=1;
                pix_bounds.w+=2;
                pix_bounds.y-=1;
                pix_bounds.h+=2;
-               
-               // Attempt to shade the region
-               // Assumes the outline has been drawn first...
-               //#ifdef SHADING_DUMB
-               for (int64_t y = max((int64_t)0, pix_bounds.y); y <= min(pix_bounds.y+pix_bounds.h, target.h-1); ++y)
-               {
-                       struct Segment
-                       {
-                               int64_t first;
-                               int64_t second;
-                               bool all_black;
-                       };
-                       list<Segment> segments;
-                       int64_t min_x = max((int64_t)0, pix_bounds.x);
-                       int64_t max_x = min(pix_bounds.x+pix_bounds.w, target.w-1);
-                       int64_t yy = y*target.w;
+               const Path & path = objects.paths[objects.data_indices[m_indexes[i]]];
+               if (path.m_fill.a == 0 || !view.PerformingShading())
+                       continue;
 
-                       int64_t x = min_x;
-                       while (x <= max_x)
-                       {
-                               bool start_black = IsBlack(target.pixels, 4*(x+yy));
-                               bool black = start_black;
-                               segments.push_back({x,x,start_black});
-                               while (black == start_black && ++x <= max_x)
-                               {
-                                       black = IsBlack(target.pixels, 4*(x+yy));
-                               }
-                               segments.back().second = x-1;
-                       }
-                       
-                       // Keep only the interior segments
-                       list<Segment>::iterator j = segments.begin();
-                       //TODO: Magically delete unneeded segments here...
-                       
-                       // Fill in remaining segments
-                       for (j=segments.begin(); j != segments.end(); ++j)
-                       {
-                               Colour c(group.m_fill);
-                               if (j->all_black)
-                               {
-                                       c.r = 1;//1; // Change to debug the outline scanning
-                                       c.g = 0;
-                                       c.b = 0;
-                                       c.a = 1;
-                               }
-                               for (x = max(min_x, j->first); x <= min(max_x, j->second); ++x)
-                               {
-                                       int64_t index = 4*(x+yy);
-                                       target.pixels[index+0] = 255*c.r;
-                                       target.pixels[index+1] = 255*c.g;
-                                       target.pixels[index+2] = 255*c.b;
-                                       target.pixels[index+3] = 255*c.a;
-                               }
-                       }
-               }
-               //#endif //SHADING_DUMB
+
+               pair<int64_t,int64_t> top(CPUPointLocation(path.m_top, view, target));
+               pair<int64_t,int64_t> bottom(CPUPointLocation(path.m_bottom, view, target));
+               pair<int64_t,int64_t> left(CPUPointLocation(path.m_left, view, target));
+               pair<int64_t,int64_t> right(CPUPointLocation(path.m_right, view, target));
+               FloodFillOnCPU(top.first, top.second+1, pix_bounds, target, path.m_fill);
+               FloodFillOnCPU(bottom.first, bottom.second-1, pix_bounds, target, path.m_fill);
+               FloodFillOnCPU(left.first+1, left.second, pix_bounds, target, path.m_fill);
+               FloodFillOnCPU(right.first-1, right.second, pix_bounds, target, path.m_fill);
+               
                if (view.ShowingObjectBounds())
                {
-                       const Colour & c = group.m_fill;
+                       Colour c(0,0,1,1);
+                       RenderLineOnCPU(top.first, top.second, bottom.first, bottom.second, target, c);
+                       RenderLineOnCPU(left.first, left.second, right.first, right.second, target, c);
                        ObjectRenderer::RenderLineOnCPU(pix_bounds.x, pix_bounds.y, pix_bounds.x+pix_bounds.w, pix_bounds.y, target, c);
                        ObjectRenderer::RenderLineOnCPU(pix_bounds.x, pix_bounds.y+pix_bounds.h, pix_bounds.x+pix_bounds.w, pix_bounds.y+pix_bounds.h, target, c);
                        ObjectRenderer::RenderLineOnCPU(pix_bounds.x, pix_bounds.y, pix_bounds.x, pix_bounds.y+pix_bounds.h, target, c);
@@ -531,4 +492,22 @@ void ObjectRenderer::RenderLineOnCPU(int64_t x0, int64_t y0, int64_t x1, int64_t
        } while (++x <= x_end);
 }
 
+void ObjectRenderer::FloodFillOnCPU(int64_t x, int64_t y, const PixelBounds & bounds, const CPURenderTarget & target, const Colour & fill)
+{
+       if (x < 0 || x < bounds.x || x > bounds.x+bounds.w || x >= target.w)
+               return;
+       if (y < 0 || y < bounds.y || y > bounds.y+bounds.h || y >= target.h)
+               return;
+               
+       if (GetColour(target, x, y) != Colour(1,1,1,1))
+               return;
+               
+       SetColour(target, x, y, fill);
+       FloodFillOnCPU(x-1, y, bounds, target, fill);
+       FloodFillOnCPU(x+1, y, bounds, target, fill);
+       FloodFillOnCPU(x,y-1,bounds,target,fill);
+       FloodFillOnCPU(x,y+1,bounds,target,fill);
+       
+}
+
 }
index 8f52aa0..66daafb 100644 (file)
@@ -47,7 +47,29 @@ namespace IPDF
                                uint8_t * pixels;
                                int64_t w;
                                int64_t h;
+                               
+                               
+                               
                        };
+                       
+                       static Colour GetColour(const CPURenderTarget & target, int64_t x, int64_t y)
+                       {
+                               int64_t index = 4*(x+y*target.w);
+                               return Colour(Real(target.pixels[index+0])/Real(255),
+                                       Real(target.pixels[index+1])/Real(255),
+                                       Real(target.pixels[index+2])/Real(255),
+                                       Real(target.pixels[index+3])/Real(255));
+                       }
+                       
+                       static void SetColour(const CPURenderTarget & target, int64_t x, int64_t y, const Colour & c)
+                       {
+                               int64_t index = 4*(x+y*target.w);
+                               target.pixels[index+0] = c.r*255;
+                               target.pixels[index+1] = c.g*255;
+                               target.pixels[index+2] = c.b*255;
+                               target.pixels[index+3] = c.a*255;
+                       }
+                       
                        struct PixelBounds
                        {
                                int64_t x; int64_t y; int64_t w; int64_t h;
@@ -55,7 +77,7 @@ namespace IPDF
                        };
 
                        static Rect CPURenderBounds(const Rect & bounds, const View & view, const CPURenderTarget & target);
-
+                       static std::pair<int64_t, int64_t> CPUPointLocation(const std::pair<Real, Real> & point, const View & view, const CPURenderTarget & target);
 
                        static void SaveBMP(const CPURenderTarget & target, const char * filename);
 
@@ -73,6 +95,8 @@ namespace IPDF
                
                        /** Helper for CPU rendering that will render a line using Bresenham's algorithm. Do not use the transpose argument. **/
                        static void RenderLineOnCPU(int64_t x0, int64_t y0, int64_t x1, int64_t y1, const CPURenderTarget & target, const Colour & colour = Colour(0,0,0,1), bool transpose = false);
+                       
+                       static void FloodFillOnCPU(int64_t x0, int64_t y0, const PixelBounds & bounds, const CPURenderTarget & target, const Colour & fill);
 
                        ShaderProgram m_shader_program; /** GLSL shaders for GPU **/
                        GraphicsBuffer m_ibo; /** Index Buffer Object for GPU rendering **/
@@ -130,12 +154,12 @@ namespace IPDF
 
        };
        
-               /** Renderer for filled circles **/
-       class GroupRenderer : public ObjectRenderer
+       /** Renderer for filled paths **/
+       class PathRenderer : public ObjectRenderer
        {
                public:
-                       GroupRenderer() : ObjectRenderer(GROUP, "shaders/rect_vert.glsl", "shaders/rect_frag.glsl", "shaders/rect_outline_geom.glsl") {}
-                       virtual ~GroupRenderer() {}
+                       PathRenderer() : ObjectRenderer(PATH, "shaders/rect_vert.glsl", "shaders/rect_frag.glsl", "shaders/rect_outline_geom.glsl") {}
+                       virtual ~PathRenderer() {}
                        virtual void RenderUsingCPU(const Objects & objects, const View & view, const CPURenderTarget & target, unsigned first_obj_id, unsigned last_obj_id);
                        // do nothing on GPU
                        virtual void RenderUsingGPU(unsigned first_obj_id, unsigned last_obj_id) {}
diff --git a/src/path.cpp b/src/path.cpp
new file mode 100644 (file)
index 0000000..050453b
--- /dev/null
@@ -0,0 +1,68 @@
+#include "ipdf.h"
+#include "path.h"
+using namespace std;
+
+namespace IPDF
+{
+
+Path::Path(const Objects & objects, unsigned start, unsigned end, const Colour & fill)
+       : m_start(start), m_end(end), m_fill(fill)
+{
+       Real xmin = 0; Real ymin = 0; 
+       Real xmax = 0; Real ymax = 0;
+       
+       // Find the bounds coordinates
+       //  and identify the top left and bottom right objects
+       
+       unsigned left;
+       unsigned right;
+       unsigned top;
+       unsigned bottom;
+       
+       for (unsigned i = m_start; i <= m_end; ++i)
+       {
+               const Rect & objb = objects.bounds[i];
+               
+               if (i == m_start || objb.x < xmin)
+               {
+                       xmin = objb.x;
+                       left = i;
+               }
+               if (i == m_start || (objb.x+objb.w) > xmax)
+               {
+                       xmax = (objb.x+objb.w);
+                       right = i;
+               }
+                       
+               if (i == m_start || objb.y < ymin)
+               {
+                       ymin = objb.y;
+                       top = i;
+               }
+               if (i == m_start || (objb.y+objb.h) > ymax)
+               {
+                       ymax = (objb.y+objb.h);
+                       bottom = i;
+               }
+       }
+       
+       // Get actual turning point coords of the 4 edge case beziers
+       m_top = objects.beziers[objects.data_indices[top]].ToAbsolute(objects.bounds[top]).GetTop();
+       m_bottom = objects.beziers[objects.data_indices[bottom]].ToAbsolute(objects.bounds[bottom]).GetBottom();
+       m_left = objects.beziers[objects.data_indices[left]].ToAbsolute(objects.bounds[left]).GetLeft();
+       m_right = objects.beziers[objects.data_indices[right]].ToAbsolute(objects.bounds[right]).GetRight();
+       /*Debug("Top: %f, %f", m_top.first, m_top.second);
+       Debug("Bottom: %f, %f", m_bottom.first, m_bottom.second);
+       Debug("Left: %f, %f", m_left.first, m_left.second);
+       Debug("Right: %f, %f", m_right.first, m_right.second);
+       Debug("Left - Right: %f, %f", m_right.first - m_left.first, m_right.second - m_left.second);
+       Debug("Top - Bottom: %f, %f", m_top.first - m_bottom.first, m_top.second - m_bottom.second);
+       */
+}
+
+Rect Path::SolveBounds(const Objects & objects) const
+{
+               return Rect(m_left.first, m_top.second, m_right.first-m_left.first, m_bottom.second-m_top.second);
+}
+
+}
diff --git a/src/path.h b/src/path.h
new file mode 100644 (file)
index 0000000..ac6956c
--- /dev/null
@@ -0,0 +1,47 @@
+#ifndef _PATH_H
+#define _PATH_H
+
+#include <vector>
+#include <algorithm>
+#include "rect.h"
+#include "real.h"
+
+namespace IPDF
+{
+       
+       struct Colour
+       {
+               float r; float g; float b; float a;
+               Colour() = default;
+               Colour(float _r, float _g, float _b, float _a) : r(_r), g(_g), b(_b), a(_a) {}
+               bool operator==(const Colour & c) const
+               {
+                       return (r == c.r && g == c.g && b == c.b && a == c.a);
+               }
+               bool operator!=(const Colour & c) const {return !this->operator==(c);}
+       };
+       
+       class Objects;
+       
+       struct Path
+       {
+               Path(const Objects & objects, unsigned _start, unsigned _end, const Colour & _fill = Colour(0.8,0.8,0.8,1));
+               
+               Rect SolveBounds(const Objects & objects) const;
+               
+               
+               
+               unsigned m_start; // First bounding Bezier index
+               unsigned m_end; // Last (inclusive) '' ''
+               unsigned m_index; // index into Objects array
+               
+               std::pair<Real,Real> m_top;
+               std::pair<Real,Real> m_bottom;
+               std::pair<Real,Real> m_left;
+               std::pair<Real,Real> m_right;
+               
+               Colour m_fill;  // colour to fill with  
+       };
+
+}
+#endif //_PATH_H
index 48e0a5a..8f4a8a4 100644 (file)
@@ -33,7 +33,7 @@ View::View(Document & document, Screen & screen, const Rect & bounds, const Colo
        m_object_renderers[RECT_OUTLINE] = new RectOutlineRenderer();
        m_object_renderers[CIRCLE_FILLED] = new CircleFilledRenderer();
        m_object_renderers[BEZIER] = new BezierRenderer();
-       m_object_renderers[GROUP] = new GroupRenderer();
+       m_object_renderers[PATH] = new PathRenderer();
 
        // To add rendering for a new type of object;
        // 1. Add enum to ObjectType in ipdf.h

UCC git Repository :: git.ucc.asn.au