Support colours in shading
authorSam Moore <[email protected]>
Sun, 24 Aug 2014 10:30:32 +0000 (18:30 +0800)
committerSam Moore <[email protected]>
Sun, 24 Aug 2014 10:30:32 +0000 (18:30 +0800)
Shading doesn't actually work still but that's of minor concern

src/controlpanel.cpp
src/controlpanel.h
src/document.cpp
src/document.h
src/ipdf.h
src/objectrenderer.cpp
src/view.cpp
src/view.h

index f2d0324..5b62e91 100644 (file)
@@ -95,6 +95,16 @@ 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_enable_shading = new QAction("&Enable Shading", this);
+       m_view_enable_shading->setCheckable(true);
+       view->addAction(m_view_enable_shading);
+       connect(m_view_enable_shading, SIGNAL(triggered()), this, SLOT(ToggleEnableShading()));
+       
        return view;
 }
 
@@ -147,6 +157,9 @@ 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_enable_shading->setChecked(m_view.PerformingShading());
+       
        // update things based on state
        const char * title;
        const char * tooltip;
@@ -187,6 +200,20 @@ void ControlPanel::UpdateAll()
        setToolTip(tooltip);
 }
 
+void ControlPanel::ToggleShowObjectBounds()
+{
+       bool state = m_view.ShowingObjectBounds();
+       m_view.ShowObjectBounds(!state);
+       UpdateAll();
+}
+
+void ControlPanel::ToggleEnableShading()
+{
+       bool state = m_view.PerformingShading();
+       m_view.PerformShading(!state);
+       UpdateAll();
+}
+
 void ControlPanel::SetGPURendering()
 {
        m_view.SetGPURendering(true);
index 90394f8..ea557d0 100644 (file)
@@ -61,7 +61,9 @@ namespace IPDF
                private slots:
                        void SetGPURendering();
                        void SetCPURendering();
+                       void ToggleShowObjectBounds();
                        void ToggleScreenDebugFont();
+                       void ToggleEnableShading();
                        void SetViewBounds();
                        void LoadSVGIntoDocument();
                        void SetDocumentFont();
@@ -105,6 +107,8 @@ 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_enable_shading;
                        
                
                        QTextEdit * m_text_edit;
index ead1b8e..8a5635c 100644 (file)
@@ -133,19 +133,12 @@ int Document::ClipObjectToQuadChild(int object_id, QuadTreeNodeChildren type)
        case BEZIER:
                {
                Rect child_node_bounds = TransformFromQuadChild({0,0,1,1}, type);
-               Rect clip_bezier_bounds;
-               clip_bezier_bounds.x = (child_node_bounds.x - m_objects.bounds[object_id].x) / m_objects.bounds[object_id].w;
-               clip_bezier_bounds.y = (child_node_bounds.y - m_objects.bounds[object_id].y) / m_objects.bounds[object_id].h;
-               clip_bezier_bounds.w = child_node_bounds.w / m_objects.bounds[object_id].w;
-               clip_bezier_bounds.h = child_node_bounds.h / m_objects.bounds[object_id].h;
-               std::vector<Bezier> new_curves = m_objects.beziers[m_objects.data_indices[object_id]].ClipToRectangle(clip_bezier_bounds);
+               std::vector<Bezier> new_curves = m_objects.beziers[m_objects.data_indices[object_id]].ClipToRectangle(child_node_bounds);
+               Rect obj_bounds = TransformToQuadChild(m_objects.bounds[object_id], type);
                for (size_t i = 0; i < new_curves.size(); ++i)
                {
-                       Rect new_bounds = TransformToQuadChild(m_objects.bounds[object_id], type);
-                       //new_bounds = TransformToQuadChild(new_bounds, type);
-                       //Bezier new_curve_data = new_curves[i].ToRelative(new_bounds);
                        unsigned index = AddBezierData(new_curves[i]);
-                       m_objects.bounds.push_back(new_bounds);
+                       m_objects.bounds.push_back(obj_bounds);
                        m_objects.types.push_back(BEZIER);
                        m_objects.data_indices.push_back(index);
                }
@@ -291,7 +284,7 @@ void Document::Load(const string & filename)
 #endif
 }
 
-unsigned Document::AddGroup(unsigned start_index, unsigned end_index)
+unsigned Document::AddGroup(unsigned start_index, unsigned end_index, const Colour & shading)
 {
        Real xmin = 0; Real ymin = 0; 
        Real xmax = 0; Real ymax = 0;
@@ -312,9 +305,11 @@ unsigned Document::AddGroup(unsigned start_index, unsigned end_index)
        }
        
        Rect bounds(xmin,ymin, xmax-xmin, ymax-ymin);
-       unsigned result = Add(GROUP, bounds,0);
-       m_objects.groups[m_count-1].first = start_index;
-       m_objects.groups[m_count-1].second = end_index;
+       
+       Group group = {start_index, end_index, shading};
+       
+       unsigned data_index = AddGroupData(group);
+       unsigned result = Add(GROUP, bounds,data_index);
        return result;
 }
 
@@ -334,7 +329,6 @@ unsigned Document::Add(ObjectType type, const Rect & bounds, unsigned data_index
        m_objects.types.push_back(type);
        m_objects.bounds.push_back(bounds);
        m_objects.data_indices.push_back(data_index);
-       m_objects.groups.push_back(pair<unsigned, unsigned>(data_index, data_index));
        return (m_count++); // Why can't we just use the size of types or something?
 }
 
@@ -344,6 +338,11 @@ unsigned Document::AddBezierData(const Bezier & bezier)
        return m_objects.beziers.size()-1;
 }
 
+unsigned Document::AddGroupData(const Group & group)
+{
+       m_objects.groups.push_back(group);
+       return m_objects.groups.size()-1;
+}
 
 void Document::DebugDumpObjects()
 {
@@ -401,6 +400,22 @@ static void GetXYPair(const string & d, Real & x, Real & y, unsigned & i,const s
        y = strtod(GetToken(d, token, i, delims).c_str(),NULL);
 }
 
+static bool GetKeyValuePair(const string & d, string & key, string & value, unsigned & i, const string & delims = "()[],{}<>;:=")
+{
+       key = "";
+       string token;
+       while (GetToken(d, token, i, delims) == ":" || token == ";");
+       key = token;
+       if (GetToken(d, token, i, delims) != ":")
+       {
+               Error("Expected \":\" seperating key:value pair");
+               return false;
+       }
+       value = "";
+       GetToken(d, value, i, delims);
+       return true;
+}
+
 static void TransformXYPair(Real & x, Real & y, const SVGMatrix & transform)
 {
        Real x0(x);
@@ -494,6 +509,8 @@ void Document::ParseSVGNode(pugi::xml_node & root, SVGMatrix & parent_transform)
                        ParseSVGTransform(attrib_trans.as_string(), transform);
                }
                
+               
+               
                if (strcmp(child.name(), "svg") == 0 || strcmp(child.name(),"g") == 0
                        || strcmp(child.name(), "group") == 0)
                {
@@ -504,9 +521,64 @@ void Document::ParseSVGNode(pugi::xml_node & root, SVGMatrix & parent_transform)
                else if (strcmp(child.name(), "path") == 0)
                {
                        string d = child.attribute("d").as_string();
-                       Debug("Path data attribute is \"%s\"", d.c_str());
-                       pair<unsigned, unsigned> range = ParseSVGPathData(d, transform);
-                       AddGroup(range.first, range.second);
+                       //Debug("Path data attribute is \"%s\"", d.c_str());
+                       bool closed = false;
+                       pair<unsigned, unsigned> range = ParseSVGPathData(d, transform, closed);
+                       if (closed)
+                       {
+                               Colour c(0,0,0,0);
+                               string colour_str("");
+                               map<string, string> style;
+                               if (child.attribute("style"))
+                               {
+                                       ParseSVGStyleData(child.attribute("style").as_string(), style);
+                               }
+                               
+                               // Determine shading colour
+                               if (child.attribute("fill"))
+                               {
+                                       colour_str = child.attribute("fill").as_string();
+                               }
+                               else if (style.find("fill") != style.end())
+                               {
+                                       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] == '#')
+                               {
+                                       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));
+                               }
+                               
+                               // Determin shading alpha
+                               if (child.attribute("fill-opacity"))
+                               {
+                                       c.a = child.attribute("fill-opacity").as_float();
+                               }
+                               else if (style.find("fill-opacity") != style.end())
+                               {
+                                       c.a = strtod(style["fill-opacity"].c_str(), NULL);
+                               }
+                               
+                                       Debug("fill-opacity is %f", Float(c.a));
+                               AddGroup(range.first, range.second, c);
+                       }
                        
                }
                else if (strcmp(child.name(), "line") == 0)
@@ -564,6 +636,17 @@ void Document::ParseSVGNode(pugi::xml_node & root, SVGMatrix & parent_transform)
        }
 }
 
+void Document::ParseSVGStyleData(const string & style, map<string, string> & results)
+{
+       unsigned i = 0;
+       string key;
+       string value;
+       while (i < style.size() && GetKeyValuePair(style, key, value, i))
+       {
+               results[key] = value;
+       }
+}
+
 /**
  * Parse an SVG string into a rectangle
  */
@@ -608,8 +691,9 @@ void Document::LoadSVG(const string & filename, const Rect & bounds)
 
 // Fear the wrath of the tokenizing svg data
 // Seriously this isn't really very DOM-like at all is it?
-pair<unsigned, unsigned> Document::ParseSVGPathData(const string & d, const SVGMatrix & transform)
+pair<unsigned, unsigned> Document::ParseSVGPathData(const string & d, const SVGMatrix & transform, bool & closed)
 {
+       closed = false;
        Real x[4] = {0,0,0,0};
        Real y[4] = {0,0,0,0};
        
@@ -709,7 +793,7 @@ pair<unsigned, unsigned> Document::ParseSVGPathData(const string & d, const SVGM
                }
                else if (command == "l" || command == "L" || command == "h" || command == "H" || command == "v" || command == "V")
                {
-                       Debug("Construct lineto command, relative %d", relative);
+                       //Debug("Construct lineto command, relative %d", relative);
                
                        Real dx = Real(strtod(GetToken(d,token,i,delims).c_str(),NULL));
                        Real dy;
@@ -770,6 +854,7 @@ pair<unsigned, unsigned> Document::ParseSVGPathData(const string & d, const SVGM
                        x[0] = x3;
                        y[0] = y3;
                        command = "m";
+                       closed = true;
                }
                else
                {
index 3ff607b..df818f2 100644 (file)
@@ -4,6 +4,8 @@
 #include "ipdf.h"
 #include "quadtree.h"
 
+#include <map>
+
 #include "../contrib/pugixml-1.4/src/pugixml.hpp"
 #include "stb_truetype.h"
 
@@ -50,17 +52,13 @@ 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);
+                       unsigned AddGroup(unsigned start_index, unsigned end_index, const Colour & shading=Colour(0.1,0.1,0.1,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);
 
 
-                       
-
-                       
-                       
                        /** SVG Related functions **/
                        
                        /** Load an SVG text file and add to the document **/
@@ -70,10 +68,13 @@ namespace IPDF
                        /** Parse an SVG node or SVG-group node, adding children to the document **/
                        void ParseSVGNode(pugi::xml_node & root, SVGMatrix & transform);
                        /** Parse an SVG path with string **/
-                       std::pair<unsigned, unsigned> ParseSVGPathData(const std::string & d, const SVGMatrix & transform);
+                       std::pair<unsigned, unsigned> ParseSVGPathData(const std::string & d, const SVGMatrix & transform, bool & closed);
                        
                        /** Modify an SVG transformation matrix **/
                        static void ParseSVGTransform(const std::string & s, SVGMatrix & transform);
+                       
+                       /** Extract CSS values (shudder) from style **/
+                       static void ParseSVGStyleData(const std::string & style, std::map<std::string, std::string> & results);
 
                        /** Font related functions **/
                        void SetFont(const std::string & font_filename);
index ff31533..968a3ed 100644 (file)
@@ -56,6 +56,8 @@ namespace IPDF
        
        struct Group
        {
+               unsigned start;
+               unsigned end;
                Colour shading;
        };
 
@@ -64,14 +66,12 @@ namespace IPDF
                /** Used by all objects **/
                std::vector<ObjectType> types; // types of objects
                std::vector<Rect> bounds; // rectangle bounds of objects
-               
-               /** Used by BEZIER to identify data position in relevant vector **/
+               /** Used by BEZIER and GROUP to identify data position in relevant vector **/
                std::vector<unsigned> data_indices;
-
                /** Used by BEZIER only **/
                std::vector<Bezier> beziers; // bezier curves - look up by data_indices
-               
-               std::vector<std::pair<unsigned, unsigned> > groups;
+               /** Used by GROUP only **/
+               std::vector<Group> groups;
        };
 
        class View;
index 8349bc1..967f7e1 100644 (file)
@@ -227,12 +227,13 @@ void BezierRenderer::RenderUsingCPU(const Objects & objects, const View & view,
                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
-               /*
-               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));
-               */
+               if (view.ShowingObjectBounds())
+               {
+                       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);
@@ -242,8 +243,7 @@ void BezierRenderer::RenderUsingCPU(const Objects & objects, const View & view,
                Real x[2]; Real y[2];
                control.Evaluate(x[0], y[0], Real(0));
                //Debug("target is (%lu, %lu)", target.w, target.h);
-               int64_t blen = 100;
-               //blen = min(max((int64_t)2, (int64_t)(target.w/view.GetBounds().w)), (int64_t)100);
+               int64_t blen = min(max((int64_t)2, (int64_t)(target.w/view.GetBounds().w)), (int64_t)100);
                
                Real invblen(1); invblen /= blen;
                //Debug("Using %li lines, inverse %f", blen, Double(invblen));
@@ -336,6 +336,9 @@ void BezierRenderer::RenderUsingGPU(unsigned first_obj_id, unsigned last_obj_id)
  */
 void GroupRenderer::RenderUsingCPU(const 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)
        {
                if (m_indexes[i] < first_obj_id) continue;
@@ -344,22 +347,21 @@ 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]]];
+               const Colour & c = group.shading;
+               if (c.a == 0 || !view.PerformingShading())
+                       continue;
 
-               Colour c(0.5,0.5,1,1);
                // make the bounds just a little bit bigger
                pix_bounds.x--;
                pix_bounds.w++;
                pix_bounds.y--;
                pix_bounds.h++;
-               /*
-               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);
-               ObjectRenderer::RenderLineOnCPU(pix_bounds.x+pix_bounds.w, pix_bounds.y, pix_bounds.x+pix_bounds.w, pix_bounds.y+pix_bounds.h, target, c);
-               */
+               
                // 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)
                {
                        bool inside = false;
@@ -387,6 +389,15 @@ void GroupRenderer::RenderUsingCPU(const Objects & objects, const View & view, c
                                }
                        }
                }
+               //#endif //SHADING_DUMB
+               if (view.ShowingObjectBounds())
+               {
+                       
+                       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);
+                       ObjectRenderer::RenderLineOnCPU(pix_bounds.x+pix_bounds.w, pix_bounds.y, pix_bounds.x+pix_bounds.w, pix_bounds.y+pix_bounds.h, target, c);
+               }
                
        
        }       
@@ -472,14 +483,13 @@ void ObjectRenderer::RenderLineOnCPU(int64_t x0, int64_t y0, int64_t x1, int64_t
 
        // TODO: Avoid extra inner conditionals
        do
-       {
+       {       
                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];
                }
-               
                if (p < 0)
                        p += two_dy;
                else
index d7d1e34..48e0a5a 100644 (file)
@@ -20,7 +20,8 @@ using namespace std;
 View::View(Document & document, Screen & screen, const Rect & bounds, const Colour & colour)
        : 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_objbounds_vbo(), m_object_renderers(NUMBER_OF_OBJECT_TYPES), m_cpu_rendering_pixels(NULL),
+               m_show_object_bounds(false), m_perform_shading(USE_SHADING)
 {
        Debug("View Created - Bounds => {%s}", m_bounds.Str().c_str());
 
@@ -71,7 +72,7 @@ void View::Translate(Real x, Real y)
        y *= m_bounds.h;
        m_bounds.x += x;
        m_bounds.y += y;
-       Debug("View Bounds => %s", m_bounds.Str().c_str());
+       //Debug("View Bounds => %s", m_bounds.Str().c_str());
        if (!m_use_gpu_transform)
                m_buffer_dirty = true;
        m_bounds_dirty = true;
index fe93e6c..56e80a3 100644 (file)
@@ -6,8 +6,9 @@
 #include "framebuffer.h"
 #include "objectrenderer.h"
 
-#define USE_GPU_TRANSFORM true
-#define USE_GPU_RENDERING true
+#define USE_GPU_TRANSFORM false
+#define USE_GPU_RENDERING false
+#define USE_SHADING !(USE_GPU_RENDERING) && true
 
 namespace IPDF
 {
@@ -41,6 +42,11 @@ 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 PerformingShading() const {return m_perform_shading;}
+                       void PerformShading(bool state) {m_perform_shading = state; m_bounds_dirty = true; m_buffer_dirty = true;}
 
                        void ForceBoundsDirty() {m_bounds_dirty = true;}                
                        void ForceBufferDirty() {m_buffer_dirty = true;}                
@@ -78,6 +84,10 @@ 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;
+                       bool m_perform_shading;
 
 #ifndef QUADTREE_DISABLED
                        QuadTreeIndex m_current_quadtree_node;  // The highest node we will traverse.

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