# 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
+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
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
Real x1; Real y1;
Real x2; Real y2;
Real x3; Real y3;
+
+ typedef enum {LINE, QUADRATIC, CUSP, LOOP, SERPENTINE} Type;
+ Type type;
+
Bezier() = default; // Needed so we can fread/fwrite this struct... for now.
Bezier(Real _x0, Real _y0, Real _x1, Real _y1, Real _x2, Real _y2, Real _x3, Real _y3) : x0(_x0), y0(_y0), x1(_x1), y1(_y1), x2(_x2), y2(_y2), x3(_x3), y3(_y3)
{
-
+ //TODO: classify the curve
+ type = SERPENTINE;
}
- Bezier(Real _x0, Real _y0, Real _x1, Real _y1, Real _x2, Real _y2) : x0(_x0), y0(_y0), x1(_x1), y1(_y1), x2(_x2), y2(_y2), x3(_x2), y3(_y2) {}
-
std::string Str() const
{
std::stringstream s;
* 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)
+ 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;
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;
}
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;
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);
private slots:
void SetGPURendering();
void SetCPURendering();
+ void ToggleShowObjectBounds();
void ToggleScreenDebugFont();
+ void ToggleEnableShading();
void SetViewBounds();
void LoadSVGIntoDocument();
void SetDocumentFont();
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;
#endif
}
-unsigned Document::AddGroup(unsigned start_index, unsigned end_index)
+unsigned Document::AddGroup(unsigned start_index, unsigned end_index, const Colour & fill)
{
Real xmin = 0; Real ymin = 0;
Real xmax = 0; Real ymax = 0;
}
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, 0U, fill);
+
+ unsigned data_index = AddGroupData(group);
+ unsigned result = Add(GROUP, bounds,data_index);
return result;
}
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?
}
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()
{
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);
ParseSVGTransform(attrib_trans.as_string(), transform);
}
+
+
if (strcmp(child.name(), "svg") == 0 || strcmp(child.name(),"g") == 0
|| strcmp(child.name(), "group") == 0)
{
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)
}
}
+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
*/
// 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};
}
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;
x[0] = x3;
y[0] = y3;
command = "m";
+ closed = true;
}
else
{
#include "ipdf.h"
#include "quadtree.h"
+#include <map>
+
#include "../contrib/pugixml-1.4/src/pugixml.hpp"
#include "stb_truetype.h"
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.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);
-
-
-
-
/** SVG Related functions **/
/** Load an SVG text file and add to the document **/
/** 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);
--- /dev/null
+#include "group.h"
+using namespace std;
+
+namespace IPDF
+{
+
+
+}
--- /dev/null
+#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
#include "bezier.h"
#include "rect.h"
-#define C_RED Colour(1,0,0,1)
-#define C_GREEN Colour(0,1,0,1)
-#define C_BLUE Colour(0,0,1,1)
-#define C_BLACK Colour(0,0,0,1);
+#include "group.h"
namespace IPDF
{
CT_OBJGROUPS
};
-
-
-
-
- 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) {}
- };
-
- struct Group
- {
- Colour shading;
- };
-
struct Objects
{
/** 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;
#include "objectrenderer.h"
#include "view.h"
+#include <list>
using namespace std;
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);
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));
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)
*/
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;
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;
- 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);
- */
+ 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)
{
- bool inside = false;
- bool online = false;
- for (int64_t x = max((int64_t)0, pix_bounds.x); x <= min(pix_bounds.x+pix_bounds.w, target.w-1); ++x)
+ struct Segment
{
- int64_t index = (x+target.w*y)*4;
- if (target.pixels[index+0] == 0 && target.pixels[index+1] == 0 && target.pixels[index+2] == 0 && target.pixels[index+3] == 255)
+ 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;
+
+ 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)
{
- online = true;
- continue;
+ black = IsBlack(target.pixels, 4*(x+yy));
}
- else if (online)
+ 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)
{
- inside = !inside;
- online = false;
+ c.r = 1;//1; // Change to debug the outline scanning
+ c.g = 0;
+ c.b = 0;
+ c.a = 1;
}
-
- if (inside)
+ for (x = max(min_x, j->first); x <= min(max_x, j->second); ++x)
{
- 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;
+ 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
+ if (view.ShowingObjectBounds())
+ {
+ const Colour & c = group.m_fill;
+ 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);
+ }
}
// 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
#include "shaderprogram.h"
#include "bufferbuilder.h"
+
namespace IPDF
{
class View;
--- /dev/null
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN"
+"http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
+
+<svg xmlns="http://www.w3.org/2000/svg"
+ xmlns:xlink="http://www.w3.org/1999/xlink"
+ width="100" height="100"
+
+ >
+ <path
+ d = "M 0,0 0,100 100,100 100,0 Z M 25,25 25,75 75,75 75,25 25,25"
+ fill="#f0f0f0"
+ />
+
+
+ </svg>
+
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());
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;
#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
{
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;}
// 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.