Compositing on CPU sort of kind of works if we ignore Alpha*
authorSam Moore <[email protected]>
Tue, 2 Sep 2014 10:43:40 +0000 (18:43 +0800)
committerSam Moore <[email protected]>
Tue, 2 Sep 2014 10:43:40 +0000 (18:43 +0800)
*Alpha is hard and I'm just going to ignore it.

Hacky fix to "overflood" problem where the fill point is outside the boundary;
since it can't be more than 1 pixel outside, check the neighbours before starting
the fill.

Unfortunately this means if the fill point is only one pixel *inside* the boundary,
there is no fill.

Tried brute force approach for low resolution paths, but that doesn't really work.
Path::PointInside doesn't seem to succeed where it should...

Other things might have happened.

Not much happened towards actually getting infinite precision,
starting to run out of time, panic mode engaged...

PANIC MODE ENGAGED

PANIC LEVELS AT 100%

EMERGENCY ANTIPROCRASTINATION MEASURES FAILED

PANIC LEVELS AT 200%

ENGAGE SHUT UP AND FIX EVERYTHING MODE

FAILED TO SHUT UP

PANIC LEVELS AT 300%

ENGAGE DINNER TIME

DINNER TIME SUCCESSFUL

PANIC LEVELS STILL AT 300%
apathy levels at 1000%

12 files changed:
src/bezier.h
src/controlpanel.cpp
src/controlpanel.h
src/document.cpp
src/document.h
src/main.cpp
src/objectrenderer.cpp
src/objectrenderer.h
src/path.cpp
src/path.h
src/view.cpp
src/view.h

index a7124af..5a773a7 100644 (file)
@@ -34,7 +34,7 @@ namespace IPDF
 
                }
                
-               const Type & GetType()
+               Type GetType()
                {
                        if (type != Bezier::UNKNOWN)
                                return type;
@@ -53,17 +53,17 @@ namespace IPDF
                        Real d2 = a3*b1 - a1*b3;
                        Real d3 = a1*b2 - a2*b1;
                        
-                       if (d1 == d2 && d2 == d3 && d3 == 0)
+                       if (fabs(d1+d2+d3) < 1e-6)
                        {
                                type = LINE;
                                //Debug("LINE %s", Str().c_str());
                                return type;
                        }
                        
-                       Real delta1 = -d1*d1;
+                       Real delta1 = -(d1*d1);
                        Real delta2 = d1*d2;
-                       Real delta3 = d1*d3 -d2*d2;
-                       if (delta1 == delta2 && delta2 == delta3 && delta3 == 0)
+                       Real delta3 = d1*d3 -(d2*d2);
+                       if (fabs(delta1+delta2+delta3) < 1e-6)
                        {
                                type = QUADRATIC;
                                
@@ -72,7 +72,7 @@ namespace IPDF
                        }
                        
                        Real discriminant = d1*d3*4 -d2*d2;
-                       if (discriminant == 0)
+                       if (fabs(discriminant) < 1e-6)
                        {
                                type = CUSP;
                                //Debug("CUSP %s", Str().c_str());
@@ -87,6 +87,7 @@ namespace IPDF
                                type = LOOP;
                                //Debug("LOOP %s", Str().c_str());
                        }
+                       //Debug("disc %.30f", discriminant);
                        return type;
                }
                
@@ -102,7 +103,7 @@ namespace IPDF
                 * Construct absolute control points using relative control points to a bounding rectangle
                 * ie: If cpy is relative to bounds rectangle, this will be absolute
                 */
-               Bezier(const Bezier & cpy, const Rect & t = Rect(0,0,1,1)) : x0(cpy.x0), y0(cpy.y0), x1(cpy.x1), y1(cpy.y1), x2(cpy.x2),y2(cpy.y2), x3(cpy.x3), y3(cpy.y3), type(UNKNOWN)
+               Bezier(const Bezier & cpy, const Rect & t = Rect(0,0,1,1)) : x0(cpy.x0), y0(cpy.y0), x1(cpy.x1), y1(cpy.y1), x2(cpy.x2),y2(cpy.y2), x3(cpy.x3), y3(cpy.y3), type(cpy.type)
                {
                        x0 *= t.w;
                        y0 *= t.h;
index 5b62e91..e4e68d6 100644 (file)
@@ -95,10 +95,25 @@ QMenu * ControlPanel::CreateViewMenu()
        view->addAction(m_view_set_bounds);
        connect(m_view_set_bounds, SIGNAL(triggered()), this, SLOT(SetViewBounds()));
        
-       m_view_show_object_bounds = new QAction("&Show Object Bounds", this);
-       m_view_show_object_bounds->setCheckable(true);
-       view->addAction(m_view_show_object_bounds);
-       connect(m_view_show_object_bounds, SIGNAL(triggered()), this, SLOT(ToggleShowObjectBounds()));
+       m_view_show_bezier_bounds = new QAction("&Show Bezier Bounds", this);
+       m_view_show_bezier_bounds->setCheckable(true);
+       view->addAction(m_view_show_bezier_bounds);
+       connect(m_view_show_bezier_bounds, SIGNAL(triggered()), this, SLOT(ToggleShowBezierBounds()));
+       
+       m_view_show_bezier_type = new QAction("&Show Bezier Type", this);
+       m_view_show_bezier_type->setCheckable(true);
+       view->addAction(m_view_show_bezier_type);
+       connect(m_view_show_bezier_type, SIGNAL(triggered()), this, SLOT(ToggleShowBezierType()));
+       
+       m_view_show_fill_bounds = new QAction("&Show Fill Bounds", this);
+       m_view_show_fill_bounds->setCheckable(true);
+       view->addAction(m_view_show_fill_bounds);
+       connect(m_view_show_fill_bounds, SIGNAL(triggered()), this, SLOT(ToggleShowFillBounds()));
+       
+       m_view_show_fill_points = new QAction("&Show Fill Points", this);
+       m_view_show_fill_points->setCheckable(true);
+       view->addAction(m_view_show_fill_points);
+       connect(m_view_show_fill_bounds, SIGNAL(triggered()), this, SLOT(ToggleShowFillPoints()));
        
        m_view_enable_shading = new QAction("&Enable Shading", this);
        m_view_enable_shading->setCheckable(true);
@@ -157,9 +172,13 @@ void ControlPanel::UpdateAll()
        m_screen_cpu_rendering->setChecked(!using_gpu_rendering);       
        m_screen_show_debug->setChecked(m_screen.DebugFontShown());
        
-       m_view_show_object_bounds->setChecked(m_view.ShowingObjectBounds());
+       m_view_show_bezier_bounds->setChecked(m_view.ShowingBezierBounds());
+       m_view_show_bezier_type->setChecked(m_view.ShowingBezierType());
+       m_view_show_fill_bounds->setChecked(m_view.ShowingFillBounds());
+       m_view_show_fill_points->setChecked(m_view.ShowingFillPoints());
        m_view_enable_shading->setChecked(m_view.PerformingShading());
        
+       
        // update things based on state
        const char * title;
        const char * tooltip;
@@ -200,10 +219,29 @@ void ControlPanel::UpdateAll()
        setToolTip(tooltip);
 }
 
-void ControlPanel::ToggleShowObjectBounds()
+void ControlPanel::ToggleShowBezierBounds()
+{
+       bool state = m_view.ShowingBezierBounds();
+       m_view.ShowBezierBounds(!state);
+       UpdateAll();
+}
+void ControlPanel::ToggleShowBezierType()
+{
+       bool state = m_view.ShowingBezierType();
+       m_view.ShowBezierType(!state);
+       UpdateAll();
+}
+void ControlPanel::ToggleShowFillBounds()
+{
+       bool state = m_view.ShowingFillBounds();
+       m_view.ShowFillBounds(!state);
+       UpdateAll();
+}
+
+void ControlPanel::ToggleShowFillPoints()
 {
-       bool state = m_view.ShowingObjectBounds();
-       m_view.ShowObjectBounds(!state);
+       bool state = m_view.ShowingFillPoints();
+       m_view.ShowFillPoints(!state);
        UpdateAll();
 }
 
index ea557d0..67eff64 100644 (file)
@@ -61,7 +61,10 @@ namespace IPDF
                private slots:
                        void SetGPURendering();
                        void SetCPURendering();
-                       void ToggleShowObjectBounds();
+                       void ToggleShowBezierBounds();
+                       void ToggleShowBezierType();
+                       void ToggleShowFillBounds();
+                       void ToggleShowFillPoints();
                        void ToggleScreenDebugFont();
                        void ToggleEnableShading();
                        void SetViewBounds();
@@ -107,9 +110,13 @@ namespace IPDF
                        QAction * m_document_parse_svg;
                        QAction * m_document_load_svg;
                        QAction * m_view_set_bounds;
-                       QAction * m_view_show_object_bounds;
+                       QAction * m_view_show_bezier_bounds;
+                       QAction * m_view_show_bezier_type;
+                       QAction * m_view_show_fill_bounds;
+                       QAction * m_view_show_fill_points;
                        QAction * m_view_enable_shading;
                        
+                       
                
                        QTextEdit * m_text_edit;
                        QPushButton * m_ok_button;
index 5ba166c..0aeee1d 100644 (file)
@@ -295,9 +295,9 @@ void Document::Load(const string & filename)
 #endif
 }
 
-unsigned Document::AddPath(unsigned start_index, unsigned end_index, const Colour & fill)
+unsigned Document::AddPath(unsigned start_index, unsigned end_index, const Colour & fill, const Colour & stroke)
 {
-       Path path(m_objects, start_index, end_index, fill);
+       Path path(m_objects, start_index, end_index, fill, stroke);
        unsigned data_index = AddPathData(path);
        Rect bounds = path.SolveBounds(m_objects);
        unsigned result = Add(PATH, bounds,data_index);
@@ -492,6 +492,34 @@ void Document::ParseSVGTransform(const string & s, SVGMatrix & transform)
        }
 }
 
+inline Colour ParseColourString(const string & colour_str)
+{
+       Colour c(0,0,0,0);
+       if (colour_str == "red")
+               c = {255,0,0,255};
+       else if (colour_str == "blue")
+               c = {0,0,255,255};
+       else if (colour_str == "green")
+               c = {0,255,0,255};
+       else if (colour_str == "black")
+               c = {0,0,0,255};
+       else if (colour_str == "white")
+               c = {255,255,255,255};
+       else if (colour_str.size() == 7 && colour_str[0] == '#')
+       {
+               Debug("Parse colour string: \"%s\"", colour_str.c_str());
+               char comp[3] = {colour_str[1], colour_str[2], '\0'};
+               c.r = strtoul(comp, NULL, 16);
+               comp[0] = colour_str[3]; comp[1] = colour_str[4];
+               c.g = strtoul(comp, NULL, 16);
+               comp[0] = colour_str[5]; comp[1] = colour_str[6];
+               c.b = strtoul(comp, NULL, 16);
+               c.a = 255;
+               Debug("Colour is: %u, %u, %u, %u", c.r, c.g, c.b, c.a);
+       }
+       return c;
+}
+
 void Document::ParseSVGNode(pugi::xml_node & root, SVGMatrix & parent_transform)
 {
        //Debug("Parse node <%s>", root.name());
@@ -521,9 +549,9 @@ void Document::ParseSVGNode(pugi::xml_node & root, SVGMatrix & parent_transform)
                        //Debug("Path data attribute is \"%s\"", d.c_str());
                        bool closed = false;
                        pair<unsigned, unsigned> range = ParseSVGPathData(d, transform, closed);
-                       if (closed)
+                       if (true)//(closed)
                        {
-                               Colour c(0,0,0,0);
+                               
                                string colour_str("");
                                map<string, string> style;
                                if (child.attribute("style"))
@@ -540,41 +568,39 @@ void Document::ParseSVGNode(pugi::xml_node & root, SVGMatrix & parent_transform)
                                {
                                        colour_str = style["fill"];
                                }
-                               if (colour_str == "red")
-                                       c = {1,0,0,1};
-                               else if (colour_str == "blue")
-                                       c = {0,0,1,1};
-                               else if (colour_str == "green")
-                                       c = {0,1,0,1};
-                               else if (colour_str == "black")
-                                       c = {0,0,0,1};
-                               else if (colour_str == "white")
-                                       c = {1,1,1,1};
-                               else if (colour_str.size() == 7 && colour_str[0] == '#')
+                               Colour fill = ParseColourString(colour_str);
+                               Colour stroke = fill;
+                       
+                               if (child.attribute("stroke"))
                                {
-                                       Debug("Parse colour string: \"%s\"", colour_str.c_str());
-                                       char comp[2] = {colour_str[1], colour_str[2]};
-                                       c.r = Real(strtoul(comp, NULL, 16))/Real(255);
-                                       comp[0] = colour_str[3]; comp[1] = colour_str[4];
-                                       c.g = Real(strtoul(comp, NULL, 16))/Real(255);
-                                       comp[0] = colour_str[5]; comp[1] = colour_str[6];
-                                       c.b = Real(strtoul(comp, NULL, 16))/Real(255);
-                                       c.a = 1;
-                                       Debug("Colour is: %f, %f, %f, %f", Float(c.r), Float(c.g), Float(c.b), Float(c.a));
+                                       colour_str = child.attribute("stroke").as_string();
+                                       stroke = ParseColourString(colour_str);
                                }
+                               else if (style.find("stroke") != style.end())
+                               {
+                                       colour_str = style["stroke"];
+                                       stroke = ParseColourString(colour_str);
+                               }
+                               
                                
                                // Determin shading alpha
                                if (child.attribute("fill-opacity"))
                                {
-                                       c.a = child.attribute("fill-opacity").as_float();
+                                       fill.a = 255*child.attribute("fill-opacity").as_float();
                                }
                                else if (style.find("fill-opacity") != style.end())
                                {
-                                       c.a = strtod(style["fill-opacity"].c_str(), NULL);
+                                       fill.a = 255*strtod(style["fill-opacity"].c_str(), NULL);
                                }
-                               
-                                       Debug("fill-opacity is %f", Float(c.a));
-                               AddPath(range.first, range.second, c);
+                               if (child.attribute("stroke-opacity"))
+                               {
+                                       stroke.a = 255*child.attribute("stroke-opacity").as_float();
+                               }
+                               else if (style.find("stroke-opacity") != style.end())
+                               {
+                                       stroke.a = 255*strtod(style["stroke-opacity"].c_str(), NULL);
+                               }
+                               AddPath(range.first, range.second, fill, stroke);
                        }
                        
                }
index 9169d8a..eb8710e 100644 (file)
@@ -52,7 +52,7 @@ namespace IPDF
                        bool operator==(const Document & equ) const;
                        bool operator!=(const Document & equ) const {return !(this->operator==(equ));}
 
-                       unsigned AddPath(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), const Colour & stroke=Colour(0,0,0,0));
                        unsigned AddBezier(const Bezier & bezier);
                        unsigned Add(ObjectType type, const Rect & bounds, unsigned data_index = 0);
                        unsigned AddBezierData(const Bezier & bezier);
index f183303..dc20d75 100644 (file)
@@ -52,22 +52,6 @@ int main(int argc, char ** argv)
                                output_bmp = argv[i];
 
                                break;
-                       case 'c':
-                       {
-                               Debug("Reading paint colour");
-                               for (int j = 1; j <= 4; ++j)
-                               {
-                                       if (i+j >= argc)
-                                               Fatal("No %d colour component following -c switch", j);
-                                       char * e;
-                                       float * comp = (j == 1) ? (&c.r) : ((j == 2) ? (&c.g) : ((j == 3) ? (&c.b) : &(c.a)));
-                                       *comp = strtof(argv[i+j], &e);
-                                       if (*e != '\0')
-                                               Fatal("Colour component %d not a valid float", j); 
-                               }
-                               i += 4;
-                               break;
-                       }
                        case 'b':
                        {
                                Debug("Reading view bounds");
index 4e59cd0..f2f0fdd 100644 (file)
@@ -52,7 +52,7 @@ void ObjectRenderer::RenderUsingGPU(unsigned first_obj_id, unsigned last_obj_id)
 /**
  * Default implementation for rendering using CPU
  */
-void ObjectRenderer::RenderUsingCPU(const Objects & objects, const View & view, const CPURenderTarget & target, unsigned first_obj_id, unsigned last_obj_id)
+void ObjectRenderer::RenderUsingCPU(Objects & objects, const View & view, const CPURenderTarget & target, unsigned first_obj_id, unsigned last_obj_id)
 {
        Error("Cannot render objects of type %d on CPU", m_type);
        //TODO: Render a rect or something instead?
@@ -117,7 +117,7 @@ void ObjectRenderer::FinaliseBuffers()
 /**
  * Rectangle (filled)
  */
-void RectFilledRenderer::RenderUsingCPU(const Objects & objects, const View & view, const CPURenderTarget & target, unsigned first_obj_id, unsigned last_obj_id)
+void RectFilledRenderer::RenderUsingCPU(Objects & objects, const View & view, const CPURenderTarget & target, unsigned first_obj_id, unsigned last_obj_id)
 {
        for (unsigned i = 0; i < m_indexes.size(); ++i)
        {
@@ -144,7 +144,7 @@ void RectFilledRenderer::RenderUsingCPU(const Objects & objects, const View & vi
 /**
  * Rectangle (outine)
  */
-void RectOutlineRenderer::RenderUsingCPU(const Objects & objects, const View & view, const CPURenderTarget & target, unsigned first_obj_id, unsigned last_obj_id)
+void RectOutlineRenderer::RenderUsingCPU(Objects & objects, const View & view, const CPURenderTarget & target, unsigned first_obj_id, unsigned last_obj_id)
 {
        //Debug("Render %u outlined rectangles on CPU", m_indexes.size());
        for (unsigned i = 0; i < m_indexes.size(); ++i)
@@ -172,7 +172,7 @@ void RectOutlineRenderer::RenderUsingCPU(const Objects & objects, const View & v
 /**
  * Circle (filled)
  */
-void CircleFilledRenderer::RenderUsingCPU(const Objects & objects, const View & view, const CPURenderTarget & target, unsigned first_obj_id, unsigned last_obj_id)
+void CircleFilledRenderer::RenderUsingCPU(Objects & objects, const View & view, const CPURenderTarget & target, unsigned first_obj_id, unsigned last_obj_id)
 {
        for (unsigned i = 0; i < m_indexes.size(); ++i)
        {
@@ -224,85 +224,92 @@ ObjectRenderer::PixelPoint ObjectRenderer::CPUPointLocation(const Vec2 & point,
        return PixelPoint(x,y);
 }
        
+       
+void BezierRenderer::RenderBezierOnCPU(unsigned i, Objects & objects, const View & view, const CPURenderTarget & target, const Colour & c)
+{
+       const Rect & bounds = objects.bounds[i];
+       PixelBounds pix_bounds(CPURenderBounds(bounds,view,target));
+       Bezier control(objects.beziers[objects.data_indices[i]].ToAbsolute(bounds),CPURenderBounds(Rect(0,0,1,1), view, target));
+
+       if (view.ShowingBezierBounds())
+       {
+               ObjectRenderer::RenderLineOnCPU(pix_bounds.x, pix_bounds.y, pix_bounds.x+pix_bounds.w, pix_bounds.y, target, Colour(255,0,0,0));
+               ObjectRenderer::RenderLineOnCPU(pix_bounds.x, pix_bounds.y+pix_bounds.h, pix_bounds.x+pix_bounds.w, pix_bounds.y+pix_bounds.h, target, Colour(0,255,0,0));
+               ObjectRenderer::RenderLineOnCPU(pix_bounds.x, pix_bounds.y, pix_bounds.x, pix_bounds.y+pix_bounds.h, target, Colour(255,0,0,0));
+               ObjectRenderer::RenderLineOnCPU(pix_bounds.x+pix_bounds.w, pix_bounds.y, pix_bounds.x+pix_bounds.w, pix_bounds.y+pix_bounds.h, target, Colour(0,255,0,0));
+       }
+       
+       unsigned blen = min(max(2U, (unsigned)(target.w/view.GetBounds().w)), 
+                       min((unsigned)(pix_bounds.w+pix_bounds.h)/4 + 1, 100U));
+               
+               // DeCasteljau Divide the Bezier
+       queue<Bezier> divisions;
+       divisions.push(control);
+       while(divisions.size() < blen)
+       {
+               Bezier & current = divisions.front();
+               if (current.GetType() == Bezier::LINE)
+               {
+                       --blen;
+                       continue;
+               }
+               divisions.push(current.DeCasteljauSubdivideRight(Real(1)/Real(2)));     
+               divisions.push(current.DeCasteljauSubdivideLeft(Real(1)/Real(2)));
+               divisions.pop();
+       }
+       while (divisions.size() > 0)
+       {
+               Bezier & current = divisions.front();
+               RenderLineOnCPU(current.x0, current.y0, current.x3, current.y3, target, c);
+               divisions.pop();
+       }               
+}
 
 /**
  * Bezier curve
  * Not sure how to apply De'Casteljau, will just use a bunch of Bresnham lines for now.
  */
-void BezierRenderer::RenderUsingCPU(const Objects & objects, const View & view, const CPURenderTarget & target, unsigned first_obj_id, unsigned last_obj_id)
+void BezierRenderer::RenderUsingCPU(Objects & objects, const View & view, const CPURenderTarget & target, unsigned first_obj_id, unsigned last_obj_id)
 {
+       if (view.PerformingShading())
+               return;
+               
        //Warn("Rendering Beziers on CPU. Things may explode.");
        for (unsigned i = 0; i < m_indexes.size(); ++i)
        {
                if (m_indexes[i] < first_obj_id) continue;
                if (m_indexes[i] >= last_obj_id) continue;
-               const Rect & bounds = objects.bounds[m_indexes[i]];
-               PixelBounds pix_bounds(CPURenderBounds(bounds,view,target));
-
-               Bezier control(objects.beziers[objects.data_indices[m_indexes[i]]].ToAbsolute(bounds),CPURenderBounds(Rect(0,0,1,1), view, target));
-               //Debug("%s -> %s via %s", objects.beziers[objects.data_indices[m_indexes[i]]].Str().c_str(), control.Str().c_str(), bounds.Str().c_str());
-               // Draw a rectangle around the bezier for debugging the bounds rectangle calculations
-               if (view.ShowingObjectBounds())
+               Colour c(0,0,0,255);
+               if (view.ShowingBezierType())
                {
-                       ObjectRenderer::RenderLineOnCPU(pix_bounds.x, pix_bounds.y, pix_bounds.x+pix_bounds.w, pix_bounds.y, target, Colour(1,0,0,1));
-                       ObjectRenderer::RenderLineOnCPU(pix_bounds.x, pix_bounds.y+pix_bounds.h, pix_bounds.x+pix_bounds.w, pix_bounds.y+pix_bounds.h, target, Colour(0,1,0,1));
-                       ObjectRenderer::RenderLineOnCPU(pix_bounds.x, pix_bounds.y, pix_bounds.x, pix_bounds.y+pix_bounds.h, target, Colour(1,0,0,1));
-                       ObjectRenderer::RenderLineOnCPU(pix_bounds.x+pix_bounds.w, pix_bounds.y, pix_bounds.x+pix_bounds.w, pix_bounds.y+pix_bounds.h, target, Colour(0,1,0,1));
-               }
-               // Draw lines between the control points for debugging
-               //ObjectRenderer::RenderLineOnCPU((int64_t)control.x0, (int64_t)control.y0, (int64_t)control.x1, (int64_t)control.y1,target);
-               //ObjectRenderer::RenderLineOnCPU((int64_t)control.x1, (int64_t)control.y1, (int64_t)control.x2, (int64_t)control.y2,target);
-                                                                               
-
-               
-       
-               unsigned blen = min(max(2U, (unsigned)(target.w/view.GetBounds().w)), min((unsigned)(pix_bounds.w+pix_bounds.h)/4 + 1, 100U));
-               
-               // DeCasteljau Divide the Bezier
-               queue<Bezier> divisions;
-               divisions.push(control);
-               while(divisions.size() < blen)
-               {
-                       Bezier & current = divisions.front();
-                       if (current.GetType() == Bezier::LINE)
+                       switch (objects.beziers[objects.data_indices[m_indexes[i]]].GetType())
                        {
-                               --blen;
-                               continue;
+                               case Bezier::LINE:
+                                       break;
+                               case Bezier::QUADRATIC:
+                                       c.b = 255;
+                                       break;
+                               case Bezier::SERPENTINE:
+                                       c.r = 255;
+                                       break;
+                               case Bezier::CUSP:
+                                       c.g = 255;
+                                       break;
+                               case Bezier::LOOP:
+                                       c.r = 128;
+                                       c.b = 128;
+                                       break;
+                               default:
+                                       c.r = 128;
+                                       c.g = 128;
+                                       break;
                        }
-                       divisions.push(current.DeCasteljauSubdivideRight(Real(1)/Real(2)));     
-                       divisions.push(current.DeCasteljauSubdivideLeft(Real(1)/Real(2)));
-                       divisions.pop();
-                       
-                       //Debug("divisions %u", divisions.size());
                }
-               while (divisions.size() > 0)
-               {
-                       Bezier & current = divisions.front();
-                       RenderLineOnCPU(current.x0, current.y0, current.x3, current.y3, target, Colour(0,0,0,!view.PerformingShading()));
-                       divisions.pop();
-               }
-               
-               /* Draw the Bezier by sampling
-               Real invblen(1); invblen /= blen;
-               Real t(invblen);
-               Vec2 v0;
-               Vec2 v1;
-               control.Evaluate(v0.x, v0.y, 0);
-               for (int64_t j = 1; j <= blen; ++j)
-               {
-                       control.Evaluate(v1.x, v1.y, t);
-                       
-                       ObjectRenderer::RenderLineOnCPU(v0.x, v0.y, v1.x, v1.y, target, Colour(0,0,0,!view.PerformingShading()));
-                       //ObjectRenderer::SetColour(target, x[0], y[0], Colour(1,0,0,1));
-                       //ObjectRenderer::SetColour(target, x[1], y[1], Colour(0,0,1,1));
-                       t += invblen;
-                       v0 = v1;
-               }
-               */
+               RenderBezierOnCPU(m_indexes[i], objects, view, target, c);
        }
 }
 
-void BezierRenderer::PrepareBezierGPUBuffer(const Objects& objects)
+void BezierRenderer::PrepareBezierGPUBuffer(Objects & objects)
 {
        m_bezier_coeffs.SetType(GraphicsBuffer::BufferTypeTexture);
        m_bezier_coeffs.SetUsage(GraphicsBuffer::BufferUsageDynamicDraw);
@@ -365,10 +372,9 @@ void BezierRenderer::RenderUsingGPU(unsigned first_obj_id, unsigned last_obj_id)
 /**
  * Render Path (shading)
  */
-void PathRenderer::RenderUsingCPU(const Objects & objects, const View & view, const CPURenderTarget & target, unsigned first_obj_id, unsigned last_obj_id)
+void PathRenderer::RenderUsingCPU(Objects & objects, const View & view, const CPURenderTarget & target, unsigned first_obj_id, unsigned last_obj_id)
 {
-       if (!view.ShowingObjectBounds() && !view.PerformingShading())
-               return;
+
                
        for (unsigned i = 0; i < m_indexes.size(); ++i)
        {
@@ -379,27 +385,57 @@ void PathRenderer::RenderUsingCPU(const Objects & objects, const View & view, co
                Rect bounds(CPURenderBounds(objects.bounds[m_indexes[i]], view, target));
                PixelBounds pix_bounds(bounds);
                const Path & path = objects.paths[objects.data_indices[m_indexes[i]]];
-               if (path.m_fill.a == 0 || !view.PerformingShading())
+               
+               if (view.ShowingFillPoints())
+               {
+                       
+                       PixelPoint start(CPUPointLocation((path.m_top+path.m_left+path.m_right+path.m_bottom)/4, view, target));
+                       for (unsigned f = 0; f < path.m_fill_points.size(); ++f)
+                       {
+                               PixelPoint end(CPUPointLocation(path.m_fill_points[f], view, target));
+                               RenderLineOnCPU(start.first, start.second, end.first, end.second, target, Colour(0,0,255,0));
+                       }
+               }
+               
+               if (!view.PerformingShading())
                        continue;
                
-               for (unsigned f = 0; f < path.m_fill_points.size(); ++f)
+               for (unsigned b = path.m_start; b <= path.m_end; ++b)
                {
-                       PixelPoint fill_point(CPUPointLocation(path.m_fill_points[f], view, target));
-                       FloodFillOnCPU(fill_point.first, fill_point.second, pix_bounds, target, path.m_fill);
+                       BezierRenderer::RenderBezierOnCPU(b,objects,view,target,path.m_stroke);
                }
                
-               /*if (true)//(view.ShowingObjectBounds())
+               if (pix_bounds.w*pix_bounds.h > 100)
                {
-                       
-                       PixelPoint start(CPUPointLocation((path.m_top+path.m_left+path.m_right+path.m_bottom)/4, view, target));
+                       Debug("High resolution; use fill points %u,%u", pix_bounds.w, pix_bounds.h);
                        for (unsigned f = 0; f < path.m_fill_points.size(); ++f)
                        {
-                               PixelPoint end(CPUPointLocation(path.m_fill_points[f], view, target));
-                               RenderLineOnCPU(start.first, start.second, end.first, end.second, target, Colour(0,0,1,1));
+                               PixelPoint fill_point(CPUPointLocation(path.m_fill_points[f], view, target));
+                               
+                               FloodFillOnCPU(fill_point.first, fill_point.second, pix_bounds, target, path.m_fill, path.m_stroke);
+                       }
+               }
+               else
+               {
+                       Debug("Low resolution; use brute force %u,%u",pix_bounds.w, pix_bounds.h);
+                       int64_t y_min = max((int64_t)0, pix_bounds.y);
+                       int64_t y_max = min(pix_bounds.y+pix_bounds.h, target.h);
+                       int64_t x_min = max((int64_t)0, pix_bounds.x);
+                       int64_t x_max = min(pix_bounds.x+pix_bounds.w, target.w);
+                       for (int64_t y = y_min; y < y_max; ++y)
+                       {
+                               for (int64_t x = x_min; x < x_max; ++x)
+                               {
+                                       Rect pb(path.SolveBounds(objects));
+                                       Vec2 pt(pb.x + (Real(x-pix_bounds.x)/Real(pix_bounds.w))*pb.w, 
+                                                       pb.y + (Real(y-pix_bounds.y)/Real(pix_bounds.h))*pb.h);
+                                       if (path.PointInside(objects, pt))
+                                       {
+                                               FloodFillOnCPU(x, y, pix_bounds, target, path.m_fill, path.m_stroke);
+                                       }
+                               }
                        }
                }
-               */
-       
        }       
 }
 
@@ -449,12 +485,6 @@ void ObjectRenderer::RenderLineOnCPU(int64_t x0, int64_t y0, int64_t x1, int64_t
        int64_t width = (transpose ? target.h : target.w);
        int64_t height = (transpose ? target.w : target.h);
 
-       uint8_t rgba[4];
-       rgba[0] = 255*colour.r;
-       rgba[1] = 255*colour.g;
-       rgba[2] = 255*colour.b;
-       rgba[3] = 255*colour.a;
-
        if (x0 > x1)
        {
                x = x1;
@@ -487,8 +517,10 @@ void ObjectRenderer::RenderLineOnCPU(int64_t x0, int64_t y0, int64_t x1, int64_t
                if (x >= 0 && x < width && y >= 0 && y < height)
                {
                        int64_t index = (transpose ? (y + x*target.w)*4 : (x + y*target.w)*4);
-                       for (int i = 0; i < 4; ++i)
-                               target.pixels[index+i] = rgba[i];
+                       target.pixels[index+0] = colour.r;
+                       target.pixels[index+1] = colour.g;
+                       target.pixels[index+2] = colour.b;
+                       target.pixels[index+3] = colour.a;
                }
                if (p < 0)
                        p += two_dy;
@@ -500,10 +532,27 @@ 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)
+
+void ObjectRenderer::FloodFillOnCPU(int64_t x, int64_t y, const PixelBounds & bounds, const CPURenderTarget & target, const Colour & fill, const Colour & stroke)
 {
-       if (fill == Colour(1,1,1,1))
+       // HACK to prevent overflooding (when the fill points for a path round to the pixel outside the boundary)
+       // (I totally just made that term up...)
+       Colour c = GetColour(target, x+1, y);
+       if (c == fill || c == stroke)
+               return;
+       c = GetColour(target, x-1, y);
+       if (c == fill || c == stroke)
+               return;
+       c = GetColour(target, x, y+1);
+       if (c == fill || c == stroke)
+               return;
+       c = GetColour(target, x, y-1);
+       if (c == fill || c == stroke)
                return;
+               
+       // The hack works but now we get underflooding, or, "droughts".
+       
+               
        queue<PixelPoint > traverse;
        traverse.push(PixelPoint(x,y));
        // now with 100% less stack overflows!
@@ -514,10 +563,14 @@ void ObjectRenderer::FloodFillOnCPU(int64_t x, int64_t y, const PixelBounds & bo
                if (cur.first < 0 || cur.first < bounds.x || cur.first >= bounds.x+bounds.w || cur.first >= target.w ||
                        cur.second < 0 || cur.second < bounds.y || cur.second >= bounds.y+bounds.h || cur.second >= target.h)
                        continue;
-               if (GetColour(target, cur.first, cur.second) != Colour(1,1,1,1))
+               c = GetColour(target, cur.first, cur.second);
+               if (c == fill || c == stroke)
                        continue;
+
                SetColour(target, cur.first, cur.second, fill);
                
+               //Debug("c is {%u,%u,%u,%u} fill is {%u,%u,%u,%u}, stroke is {%u,%u,%u,%u}",
+               //      c.r,c.g,c.b,c.a, fill.r,fill.g,fill.b,fill.a, stroke.r,stroke.g,stroke.b,stroke.a);
 
                traverse.push(PixelPoint(cur.first+1, cur.second));
                traverse.push(PixelPoint(cur.first-1, cur.second));
index e43e3b9..841040f 100644 (file)
@@ -55,19 +55,21 @@ namespace IPDF
                        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));
+                               if (index < 0 || index >= 4*(target.w*target.h))
+                                       return Colour(0,0,0,0);
+                               return Colour(target.pixels[index+0],target.pixels[index+1],target.pixels[index+2],target.pixels[index+3]);
                        }
                        
                        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;
+                               if (index < 0 || index >= 4*(target.w*target.h))
+                                       return;
+                               
+                               target.pixels[index+0] = c.r;
+                               target.pixels[index+1] = c.g;
+                               target.pixels[index+2] = c.b;
+                               target.pixels[index+3] = c.a;
                        }
                        
                        struct PixelBounds
@@ -84,7 +86,7 @@ namespace IPDF
                        static void SaveBMP(const CPURenderTarget & target, const char * filename);
 
 
-                       virtual void RenderUsingCPU(const Objects & objects, const View & view, const CPURenderTarget & target, unsigned first_obj_id, unsigned last_obj_id) = 0;
+                       virtual void RenderUsingCPU(Objects & objects, const View & view, const CPURenderTarget & target, unsigned first_obj_id, unsigned last_obj_id) = 0;
                        
                        
                        
@@ -98,7 +100,7 @@ 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);
+                       static void FloodFillOnCPU(int64_t x0, int64_t y0, const PixelBounds & bounds, const CPURenderTarget & target, const Colour & fill, const Colour & stroke=Colour(0,0,0,0));
 
                        ShaderProgram m_shader_program; /** GLSL shaders for GPU **/
                        GraphicsBuffer m_ibo; /** Index Buffer Object for GPU rendering **/
@@ -112,7 +114,7 @@ namespace IPDF
                public:
                        RectFilledRenderer() : ObjectRenderer(RECT_FILLED, "shaders/rect_vert.glsl", "shaders/rect_frag.glsl","shaders/rect_filled_geom.glsl") {}
                        virtual ~RectFilledRenderer() {}
-                       virtual void RenderUsingCPU(const Objects & objects, const View & view, const CPURenderTarget & target, unsigned first_obj_id, unsigned last_obj_id);
+                       virtual void RenderUsingCPU(Objects & objects, const View & view, const CPURenderTarget & target, unsigned first_obj_id, unsigned last_obj_id);
        };
        /** Renderer for outlined rectangles **/
        class RectOutlineRenderer : public ObjectRenderer
@@ -120,7 +122,7 @@ namespace IPDF
                public:
                        RectOutlineRenderer() : ObjectRenderer(RECT_OUTLINE, "shaders/rect_vert.glsl", "shaders/rect_frag.glsl", "shaders/rect_outline_geom.glsl") {}
                        virtual ~RectOutlineRenderer() {}
-                       virtual void RenderUsingCPU(const Objects & objects, const View & view, const CPURenderTarget & target, unsigned first_obj_id, unsigned last_obj_id);
+                       virtual void RenderUsingCPU(Objects & objects, const View & view, const CPURenderTarget & target, unsigned first_obj_id, unsigned last_obj_id);
        };
        /** Renderer for filled circles **/
        class CircleFilledRenderer : public ObjectRenderer
@@ -128,7 +130,7 @@ namespace IPDF
                public:
                        CircleFilledRenderer() : ObjectRenderer(CIRCLE_FILLED, "shaders/rect_vert.glsl", "shaders/circle_frag.glsl", "shaders/circle_filled_geom.glsl") {}
                        virtual ~CircleFilledRenderer() {}
-                       virtual void RenderUsingCPU(const Objects & objects, const View & view, const CPURenderTarget & target, unsigned first_obj_id, unsigned last_obj_id);
+                       virtual void RenderUsingCPU(Objects & objects, const View & view, const CPURenderTarget & target, unsigned first_obj_id, unsigned last_obj_id);
        };
 
        /** Renderer for bezier curves **/
@@ -138,8 +140,11 @@ namespace IPDF
                        BezierRenderer() : ObjectRenderer(BEZIER, "shaders/rect_vert.glsl", "shaders/rect_frag.glsl", "shaders/bezier_texbuf_geom.glsl") {}
                        virtual ~BezierRenderer() {}
                        virtual void RenderUsingGPU(unsigned first_obj_id, unsigned last_obj_id); 
-                       virtual void RenderUsingCPU(const Objects & objects, const View & view, const CPURenderTarget & target, unsigned first_obj_id, unsigned last_obj_id);
-                       void PrepareBezierGPUBuffer(const Objects & objects);
+                       virtual void RenderUsingCPU(Objects & objects, const View & view, const CPURenderTarget & target, unsigned first_obj_id, unsigned last_obj_id);
+                       void PrepareBezierGPUBuffer(Objects & objects);
+                       
+                       static void RenderBezierOnCPU(unsigned index, Objects & objects, const View & view, const CPURenderTarget & target, const Colour & c=Colour(0,0,0,255));
+                       
                private:
                        GraphicsBuffer m_bezier_coeffs;
                        GraphicsBuffer m_bezier_ids;
@@ -162,7 +167,7 @@ namespace IPDF
                public:
                        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);
+                       virtual void RenderUsingCPU(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) {}
        };
index e0eca4a..3f93822 100644 (file)
@@ -5,8 +5,8 @@ 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)
+Path::Path(const Objects & objects, unsigned start, unsigned end, const Colour & fill, const Colour & stroke)
+       : m_start(start), m_end(end), m_fill(fill), m_stroke(stroke)
 {
        Real xmin = 0; Real ymin = 0; 
        Real xmax = 0; Real ymax = 0;
index b08c146..1a0ed53 100644 (file)
@@ -11,9 +11,9 @@ namespace IPDF
        
        struct Colour
        {
-               float r; float g; float b; float a;
+               uint8_t r; uint8_t g; uint8_t b; uint8_t a;
                Colour() = default;
-               Colour(float _r, float _g, float _b, float _a) : r(_r), g(_g), b(_b), a(_a) {}
+               Colour(uint8_t _r, uint8_t _g, uint8_t _b, uint8_t _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);
@@ -25,7 +25,7 @@ namespace IPDF
        
        struct Path
        {
-               Path(const Objects & objects, unsigned _start, unsigned _end, const Colour & _fill = Colour(0.8,0.8,0.8,1));
+               Path(const Objects & objects, unsigned _start, unsigned _end, const Colour & _fill = Colour(128,128,128,255), const Colour & _stroke = Colour(0,0,0,0));
                
                Rect SolveBounds(const Objects & objects) const;
                
@@ -44,6 +44,7 @@ namespace IPDF
                std::vector<Vec2> m_fill_points;
                
                Colour m_fill;  // colour to fill with  
+               Colour m_stroke; // colour to outline with
        };
 
 }
index 2caaadc..94064ad 100644 (file)
@@ -21,7 +21,8 @@ View::View(Document & document, Screen & screen, const Rect & bounds, const Colo
        : m_use_gpu_transform(USE_GPU_TRANSFORM), m_use_gpu_rendering(USE_GPU_RENDERING), m_bounds_dirty(true), m_buffer_dirty(true), 
                m_render_dirty(true), m_document(document), m_screen(screen), m_cached_display(), m_bounds(bounds), m_colour(colour), m_bounds_ubo(), 
                m_objbounds_vbo(), m_object_renderers(NUMBER_OF_OBJECT_TYPES), m_cpu_rendering_pixels(NULL),
-               m_show_object_bounds(false), m_perform_shading(USE_SHADING)
+               m_perform_shading(USE_SHADING), m_show_bezier_bounds(false), m_show_bezier_type(false),
+               m_show_fill_points(false), m_show_fill_bounds(false)
 {
        Debug("View Created - Bounds => {%s}", m_bounds.Str().c_str());
 
index abfbefe..d99db6e 100644 (file)
@@ -42,8 +42,14 @@ namespace IPDF
                        
                        void SetGPURendering(bool state) {m_use_gpu_rendering = state; m_bounds_dirty = true; m_buffer_dirty = true;}
 
-                       bool ShowingObjectBounds() const {return m_show_object_bounds;} // render bounds rectangles
-                       void ShowObjectBounds(bool state) {m_show_object_bounds = state; m_bounds_dirty = true; m_buffer_dirty = true;}
+                       bool ShowingBezierBounds() const {return m_show_bezier_bounds;} // render bounds rectangles
+                       void ShowBezierBounds(bool state) {m_show_bezier_bounds = state; m_bounds_dirty = true; m_buffer_dirty = true;}
+                       bool ShowingBezierType() const {return m_show_bezier_type;}
+                       void ShowBezierType(bool state) {m_show_bezier_type = state; m_bounds_dirty = true; m_buffer_dirty = true;}
+                       bool ShowingFillPoints() const {return m_show_fill_points;}
+                       void ShowFillPoints(bool state) {m_show_fill_points = state; m_bounds_dirty = true; m_buffer_dirty = true;}
+                       bool ShowingFillBounds() const {return m_show_fill_bounds;}
+                       void ShowFillBounds(bool state) {m_show_fill_bounds = true;}
                        
                        bool PerformingShading() const {return m_perform_shading;}
                        void PerformShading(bool state) {m_perform_shading = state; m_bounds_dirty = true; m_buffer_dirty = true;}
@@ -84,10 +90,17 @@ namespace IPDF
                        // Trust me it will be easier to generalise things this way. Even though there are pointers.
                        std::vector<ObjectRenderer*> m_object_renderers; 
                        uint8_t * m_cpu_rendering_pixels; // pixels to be used for CPU rendering
+
                        
-                       // Debug rendering
-                       bool m_show_object_bounds;
+                       // shading
                        bool m_perform_shading;
+                       
+                       // Debug rendering
+                       bool m_show_bezier_bounds;
+                       bool m_show_bezier_type;
+                       bool m_show_fill_points;
+                       bool m_show_fill_bounds;
+
 
 #ifndef QUADTREE_DISABLED
                        QuadTreeIndex m_current_quadtree_node;  // The highest node we will traverse.

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