bin/ipdf
data/*
src/moc_controlpanel.cpp
+src/tests/*
+!src/tests/*.cpp
+!src/tests/*.h
# To change that you can run as `make DEFS="REALTYPE=X" tests/<target>` where X is your chosen type
# But remember to make clean first.
tests/% : tests/%.cpp ../obj/tests/%.o $(LINKOBJ)
- $(CXX) $(CFLAGS) -o $@
.test $(LINKOBJ) ../obj/
[email protected] $(LIB) $(TESTRPATH)
-include $(DEPS)
m_screen_cpu_rendering = new QAction("&CPU Rendering", this);
m_screen_cpu_rendering->setCheckable(true);
m_screen_gpu_rendering->setToolTip("Uses the CPU for Rendering");
+
+ m_screen_lazy_rendering = new QAction("&Lazy Rendering", this);
+ m_screen_lazy_rendering->setCheckable(true);
screen->addAction(m_screen_gpu_rendering);
screen->addAction(m_screen_cpu_rendering);
+ screen->addAction(m_screen_lazy_rendering);
+ connect(m_screen_lazy_rendering, SIGNAL(triggered()), this, SLOT(ToggleLazyRendering()));
+
connect(m_screen_gpu_rendering, SIGNAL(triggered()), this, SLOT(SetGPURendering()));
connect(m_screen_cpu_rendering, SIGNAL(triggered()), this, SLOT(SetCPURendering()));
m_screen_gpu_rendering->setChecked(using_gpu_rendering);
m_screen_cpu_rendering->setChecked(!using_gpu_rendering);
m_screen_show_debug->setChecked(m_screen.DebugFontShown());
+ m_screen_lazy_rendering->setChecked(m_view.UsingLazyRendering());
m_view_show_bezier_bounds->setChecked(m_view.ShowingBezierBounds());
m_view_show_bezier_type->setChecked(m_view.ShowingBezierType());
UpdateAll();
}
+void ControlPanel::ToggleLazyRendering()
+{
+ bool state = m_view.UsingLazyRendering();
+ m_view.SetLazyRendering(!state);
+ UpdateAll();
+}
+
void ControlPanel::ToggleScreenDebugFont()
{
bool state = m_screen.DebugFontShown();
void ControlPanel::InsertSVGIntoDocument()
{
Rect bounds(m_view.GetBounds());
+ bounds.x += bounds.w/Real(2);
+ bounds.y += bounds.h/Real(2);
+
bounds.w /= Real(m_screen.ViewportWidth());
bounds.h /= Real(m_screen.ViewportHeight());
return;
Rect bounds(m_view.GetBounds());
+ bounds.x += bounds.w/Real(2);
+ bounds.y += bounds.h/Real(2);
+
bounds.w /= Real(m_screen.ViewportWidth());
bounds.h /= Real(m_screen.ViewportHeight());
private slots:
void SetGPURendering();
void SetCPURendering();
+ void ToggleLazyRendering();
void ToggleShowBezierBounds();
void ToggleShowBezierType();
void ToggleShowFillBounds();
QAction * m_screen_gpu_rendering;
QAction * m_screen_cpu_rendering;
QAction * m_screen_show_debug;
+ QAction * m_screen_lazy_rendering;
QAction * m_document_set_font;
QAction * m_document_insert_text;
QAction * m_view_show_fill_points;
QAction * m_view_enable_shading;
-
QTextEdit * m_text_edit;
QPushButton * m_ok_button;
{
string token("");
while (GetToken(d, token, i, delims) == ",");
- x = strtod(token.c_str(),NULL);
+ x = RealFromStr(token);
if (GetToken(d, token, i, delims) != ",")
{
Fatal("Expected \",\" seperating x,y pair");
}
- y = strtod(GetToken(d, token, i, delims).c_str(),NULL);
+ y = RealFromStr(GetToken(d,token,i,delims));
}
static bool GetKeyValuePair(const string & d, string & key, string & value, unsigned & i, const string & delims = "()[],{}<>;:=")
}
else if (command == "scale")
{
- delta.a = (strtod(GetToken(s,token,i).c_str(), NULL));
+ delta.a = RealFromStr(GetToken(s,token,i));
GetToken(s, token, i);
if (token == ",")
{
- delta.d = (strtod(GetToken(s,token,i).c_str(), NULL));
+ delta.d = RealFromStr(GetToken(s,token,i));
assert(GetToken(s, token, i) == ")");
}
else
c = {255,255,255,255};
else if (colour_str.size() == 7 && colour_str[0] == '#')
{
- Debug("Parse colour string: \"%s\"", colour_str.c_str());
+ //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];
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);
+ //Debug("Colour is: %u, %u, %u, %u", c.r, c.g, c.b, c.a);
}
return c;
}
{
//Debug("Parse node <%s>", root.name());
-
+
+ // Centre the SVGs
+ if (strcmp(root.name(),"svg") == 0)
+ {
+ Real ww = RealFromStr(root.attribute("width").as_string());
+ Real hh = RealFromStr(root.attribute("height").as_string());
+ parent_transform.e -= parent_transform.a * ww/Real(2);
+ parent_transform.f -= parent_transform.d * hh/Real(2);
+ }
+
for (pugi::xml_node child = root.first_child(); child; child = child.next_sibling())
{
SVGMatrix transform(parent_transform);
input.close();
// a c e, b d f
- SVGMatrix transform = {bounds.w, 0,bounds.x, 0,bounds.h,bounds.y};
+ SVGMatrix transform = {bounds.w,0 ,bounds.x, 0,bounds.h,bounds.y};
ParseSVGNode(doc_xml, transform);
}
if (command == "m" || command == "M")
{
//Debug("Construct moveto command");
- Real dx = Real(strtod(GetToken(d,token,i,delims).c_str(),NULL));
+ Real dx = RealFromStr(GetToken(d,token,i,delims));
assert(GetToken(d,token,i,delims) == ",");
- Real dy = Real(strtod(GetToken(d,token,i,delims).c_str(),NULL));
+ Real dy = RealFromStr(GetToken(d,token,i,delims));
x[0] = (relative) ? x[0] + dx : dx;
y[0] = (relative) ? y[0] + dy : dy;
else if (command == "c" || command == "C" || command == "q" || command == "Q")
{
//Debug("Construct curveto command");
- Real dx = Real(strtod(GetToken(d,token,i,delims).c_str(),NULL));
+ Real dx = RealFromStr(GetToken(d,token,i,delims));
assert(GetToken(d,token,i,delims) == ",");
- Real dy = Real(strtod(GetToken(d,token,i,delims).c_str(),NULL));
+ Real dy = RealFromStr(GetToken(d,token,i,delims));
x[1] = (relative) ? x[0] + dx : dx;
y[1] = (relative) ? y[0] + dy : dy;
- dx = Real(strtod(GetToken(d,token,i,delims).c_str(),NULL));
+ dx = RealFromStr(GetToken(d,token,i,delims));
assert(GetToken(d,token,i,delims) == ",");
- dy = Real(strtod(GetToken(d,token,i,delims).c_str(),NULL));
+ dy = RealFromStr(GetToken(d,token,i,delims));
x[2] = (relative) ? x[0] + dx : dx;
y[2] = (relative) ? y[0] + dy : dy;
if (command != "q" && command != "Q")
{
- dx = Real(strtod(GetToken(d,token,i,delims).c_str(),NULL));
+ dx = RealFromStr(GetToken(d,token,i,delims));
assert(GetToken(d,token,i,delims) == ",");
- dy = Real(strtod(GetToken(d,token,i,delims).c_str(),NULL));
+ dy = RealFromStr(GetToken(d,token,i,delims));
x[3] = (relative) ? x[0] + dx : dx;
y[3] = (relative) ? y[0] + dy : dy;
}
{
//Debug("Construct lineto command, relative %d", relative);
- Real dx = Real(strtod(GetToken(d,token,i,delims).c_str(),NULL));
+ Real dx = RealFromStr(GetToken(d,token,i,delims));
Real dy;
if (command == "l" || command == "L")
{
assert(GetToken(d,token,i,delims) == ",");
- dy = Real(strtod(GetToken(d,token,i,delims).c_str(),NULL));
+ dy = RealFromStr(GetToken(d,token,i,delims));
}
else if (command == "v" || command == "V")
{
#define _GNU_SOURCE
#endif
#include <fenv.h>
+#include <signal.h>
+bool ignore_sigfpe = false;
+
+void sigfpe_handler(int sig)
+{
+ if (!ignore_sigfpe)
+ Fatal("Floating point exception!");
+ exit(EXIT_SUCCESS);
+}
int main(int argc, char ** argv)
{
+ signal(SIGFPE, sigfpe_handler);
#if REALTYPE == REAL_IRRAM
iRRAM_initialize(argc,argv);
#endif
Colour c(0,0,0,1);
- const char * input_bmp = NULL;
+
const char * output_bmp = NULL;
const char * input_filename = NULL;
+ const char * input_text = NULL;
float b[4] = {0,0,1,1};
+ int max_frames = -1;
+ bool hide_control_panel;
+ bool lazy_rendering = true;
+
+
+ Screen scr;
+ View view(doc,scr, {0,0,1,1});
+
+ if (!lazy_rendering)
+ view.SetLazyRendering(false);
+
int i = 0;
while (++i < argc)
{
{
case 'o':
mode = OUTPUT_TO_BMP;
- if (++i >= argc)
- Fatal("No input argument following -o switch");
- input_bmp = argv[i];
if (++i >= argc)
Fatal("No output argument following -o switch");
output_bmp = argv[i];
-
+ hide_control_panel = true;
break;
case 'b':
{
i += 4;
break;
}
+ case 't':
+ {
+ if (++i >= argc)
+ Fatal("No text input following -t switch");
+ input_text = argv[i];
+ Debug("Insert text: %s", input_text);
+ break;
+ }
+
+ case 'r':
+ {
+ if (++i >= argc)
+ Fatal("Expected \"gpu\" or \"cpu\" after -r switch");
+ if (strcmp(argv[i], "gpu") == 0)
+ {
+ view.SetGPURendering(true);
+ }
+ else if (strcmp(argv[i], "cpu") == 0)
+ {
+ view.SetGPURendering(false);
+ }
+ else
+ {
+ Fatal("Expected \"gpu\" or \"cpu\" after -r switch, not \"%s\"", argv[i]);
+ }
+ break;
+ }
+
+ case 'T':
+ {
+ if (++i >= argc)
+ Fatal("Expected \"gpu\" or \"cpu\" after -T switch");
+ if (strcmp(argv[i], "gpu") == 0)
+ {
+ view.SetGPUTransform(true);
+ }
+ else if (strcmp(argv[i], "cpu") == 0)
+ {
+ view.SetGPUTransform(false);
+ }
+ else
+ {
+ Fatal("Expected \"gpu\" or \"cpu\" after -T switch, not \"%s\"", argv[i]);
+ }
+ break;
+ }
+
+
+ case 'l':
+ view.SetLazyRendering(!view.UsingLazyRendering());
+ break;
+
+ case 'f':
+ if (++i >= argc)
+ Fatal("No frame number following -f switch");
+ max_frames = strtol(argv[i], NULL, 10);
+ hide_control_panel = true;
+ break;
+
+ case 'q':
+ hide_control_panel = true;
+ break;
+
}
}
+ Rect bounds(b[0],b[1],b[2],b[3]);
+ view.SetBounds(bounds);
if (input_filename != NULL)
{
- doc.LoadSVG(input_filename, Rect(0,0,Real(1)/Real(800),Real(1)/Real(600)));
+
+ doc.LoadSVG(input_filename, Rect(bounds.x+bounds.w/Real(2),bounds.y+bounds.h/Real(2),bounds.w/Real(800),bounds.h/Real(600)));
+ }
+ else if (input_text != NULL)
+ {
+ doc.AddText(input_text, bounds.h/Real(2), bounds.x, bounds.y+bounds.h/Real(2));
}
- else
+ else
{
doc.Add(RECT_OUTLINE, Rect(0,0,0,0),0); // hack to stop segfault if document is empty (:S)
}
- Debug("Start!");
- Rect bounds(b[0],b[1],b[2],b[3]);
-
- Screen scr;
- View view(doc,scr, bounds);
+
#ifndef CONTROLPANEL_DISABLED
+ SDL_Thread * cp_thread = NULL;
+ if (!hide_control_panel)
+ {
ControlPanel::RunArgs args = {argc, argv, view, doc, scr};
- SDL_Thread * cp_thread = SDL_CreateThread(ControlPanel::Run, "ControlPanel", &args);
+ cp_thread = SDL_CreateThread(ControlPanel::Run, "ControlPanel", &args);
if (cp_thread == NULL)
{
Error("Couldn't create ControlPanel thread: %s", SDL_GetError());
}
+ }
#endif //CONTROLPANEL_DISABLED
if (mode == LOOP)
- MainLoop(doc, scr, view);
+ MainLoop(doc, scr, view, max_frames);
else if (mode == OUTPUT_TO_BMP) //TODO: Remove this shit
- OverlayBMP(doc, input_bmp, output_bmp, bounds, c);
+ {
+ if (view.UsingGPURendering())
+ OverlayBMP(doc, output_bmp, output_bmp, bounds, c);
+ else
+ view.SaveCPUBMP(output_bmp);
+ }
#ifndef CONTROLPANEL_DISABLED
-
if (cp_thread != NULL)
{
int cp_return;
Debug("ControlPanel thread returned %d", cp_return);
}
#endif //CONTROLPANEL_DISABLED
+
+ ignore_sigfpe = true;
return 0;
}
}
-inline void MainLoop(Document & doc, Screen & scr, View & view)
+inline void MainLoop(Document & doc, Screen & scr, View & view, int max_frames = -1)
{
// order is important... segfaults occur when screen (which inits GL) is not constructed first -_-
double data_rate = 0; // period between data output to stdout (if <= 0 there will be no output)
uint64_t data_points = 0;
setbuf(stdout, NULL);
- while (scr.PumpEvents())
+ int frame_number = 0;
+ while (scr.PumpEvents() && (max_frames < 0 || frame_number++ < max_frames))
{
real_clock_prev = real_clock_now;
++frames;
#if REALTYPE == REAL_SINGLE
typedef float Real;
+ inline Real RealFromStr(const char * str) {return strtof(str, NULL);}
#elif REALTYPE == REAL_DOUBLE
typedef double Real;
+ inline Real RealFromStr(const char * str) {return strtod(str, NULL);}
#elif REALTYPE == REAL_LONG_DOUBLE
typedef long double Real;
+ inline Real RealFromStr(const char * str) {return strtold(str, NULL);}
#elif REALTYPE == REAL_VFPU
typedef VFPU::VFloat Real;
inline float Float(const Real & r) {return r.m_value;}
inline double Double(const Real & r) {return r.m_value;}
+ inline Real RealFromStr(const char * str) {return Real(strtod(str, NULL));}
#elif REALTYPE == REAL_RATIONAL
typedef Rational<int64_t> Real;
inline float Float(const Real & r) {return (float)r.ToDouble();}
inline double Double(const Real & r) {return r.ToDouble();}
+ inline Real RealFromStr(const char * str) {return Real(strtod(str, NULL));}
#elif REALTYPE == REAL_RATIONAL_ARBINT
#define ARBINT Gmpint // Set to Gmpint or Arbint here
inline int64_t Int64(const Real & r) {return r.toLong();}
inline Real Sqrt(const Real & r) {return mpfr::sqrt(r, mpfr::mpreal::get_default_rnd());}
inline Real Abs(const Real & r) {return mpfr::abs(r, mpfr::mpreal::get_default_rnd());}
+ inline Real RealFromStr(const char * str) {return Real(strtod(str, NULL));}
#elif REALTYPE == REAL_IRRAM
typedef iRRAM::REAL Real;
inline double Double(const Real & r) {return r.as_double(53);}
inline float Float(const Real & r) {return r.as_double(53);}
inline int64_t Int64(const Real & r) {return (int64_t)r.as_double(53);}
inline Real Sqrt(const Real & r) {return iRRAM::sqrt(r);}
+ inline Real RealFromStr(const char * str) {return Real(strtod(str, NULL));}
#else
#error "Type of Real unspecified."
#endif //REALTYPE
};
+ inline Real RealFromStr(const std::string & str) {return RealFromStr(str.c_str());}
--- /dev/null
+/**
+ * Get diff of bmps
+ */
+
+#include <SDL.h>
+#include <cassert>
+#include "ipdf.h"
+
+using namespace std;
+using namespace IPDF;
+
+
+int main(int argc, char ** argv)
+{
+ SDL_Surface * orig = SDL_LoadBMP(argv[1]);
+ SDL_Surface * diff = SDL_LoadBMP(argv[2]);
+
+ assert(orig->w == diff->w && orig->h == diff->h);
+ int w = diff->w;
+ int h = diff->h;
+
+ uint8_t * a = (uint8_t*)orig->pixels;
+ uint8_t * b = (uint8_t*)diff->pixels;
+
+ int total_diff = 0;
+
+ int mean_dist = 0;
+ int count_a = 0;
+ int count_b = 0;
+ for (int x = 0; x < w; ++x)
+ {
+ for (int y = 0; y < h; ++y)
+ {
+ if (a[4*(x + w*y)] == 0)
+ ++count_a;
+ if (b[4*(x + w*y)] == 0)
+ ++count_b;
+
+ if (a[4*(x + w*y)] != b[4*(x + w*y)] && b[4*(x+w*y)] == 0)
+ {
+ total_diff++;
+ //
+
+ int r = 1;
+ for (r=1; r+x < w; ++r)
+ {
+ if (a[4*(x+r + w*y)] == 0)
+ break;
+ }
+ int l = 1;
+ for (l=1; x-l >= 0; ++l)
+ {
+ if (a[4*(x-l + w*y)] == 0)
+ break;
+ }
+ int u = 1;
+ for (u=1; y-u >= 0; ++u)
+ {
+ if (a[4*(x + w*(y-u))] == 0)
+ break;
+ }
+
+ int d = 1;
+ for (d=1; y+d < h; ++d)
+ {
+ if (a[4*(x + w*(y+d))] == 0)
+ break;
+ }
+
+ mean_dist += min(min(d,u), min(r,l));
+ }
+ }
+ }
+ printf("%d\t%d\t%d\t%lf\n", count_a, count_b, total_diff, (double)mean_dist / (double)count_b);
+}
}
// View bounds have not changed; blit the FrameBuffer as it is
- if (!m_bounds_dirty)
+ if (!m_bounds_dirty && m_lazy_rendering)
{
m_cached_display.UnBind();
m_cached_display.Blit();
m_cached_display.Clear();
#ifndef QUADTREE_DISABLED
- if (m_bounds_dirty)
+ if (m_bounds_dirty || !m_lazy_rendering)
{
if ( false && (m_bounds.x > 1.0 || m_bounds.x < 0.0 || m_bounds.y > 1.0 || m_bounds.y < 0.0 || m_bounds.w > 1.0 || m_bounds.h > 1.0))
{
if (m_render_dirty) // document has changed
PrepareRender();
- if (m_buffer_dirty || m_bounds_dirty) // object bounds have changed
+ if (m_buffer_dirty || m_bounds_dirty || !m_lazy_rendering) // object bounds have changed
UpdateObjBoundsVBO(first_obj, last_obj);
if (m_use_gpu_transform)
dynamic_cast<BezierRenderer*>(m_object_renderers[BEZIER])->PrepareBezierGPUBuffer(m_document.m_objects);
m_render_dirty = false;
}
+
+void View::SaveCPUBMP(const char * filename)
+{
+ bool prev = UsingGPURendering();
+ SetGPURendering(false);
+ Render(800, 600);
+ ObjectRenderer::SaveBMP({m_cpu_rendering_pixels, 800, 600}, filename);
+ SetGPURendering(prev);
+}
const bool UsingGPURendering() const { return m_use_gpu_rendering; } // whether GPU shaders are used or CPU rendering
void ToggleGPUTransform() { m_use_gpu_transform = (!m_use_gpu_transform); m_bounds_dirty = true; m_buffer_dirty = true; }
void ToggleGPURendering() { m_use_gpu_rendering = (!m_use_gpu_rendering); m_bounds_dirty = true; m_buffer_dirty = true; }
+ void SetGPUTransform(bool state) {m_use_gpu_transform = state; m_bounds_dirty = true; m_buffer_dirty = true;}
void SetGPURendering(bool state) {m_use_gpu_rendering = state; m_bounds_dirty = true; m_buffer_dirty = true;}
void ForceBoundsDirty() {m_bounds_dirty = true;}
void ForceBufferDirty() {m_buffer_dirty = true;}
void ForceRenderDirty() {m_render_dirty = true;}
+
+ void SetLazyRendering(bool state = true) {m_lazy_rendering = state;}
+ bool UsingLazyRendering() const {return m_lazy_rendering;}
+
+ void SaveCPUBMP(const char * filename);
private:
struct GPUObjBounds
bool m_show_bezier_type;
bool m_show_fill_points;
bool m_show_fill_bounds;
+
+ bool m_lazy_rendering;// don't redraw frames unless we need to
#ifndef QUADTREE_DISABLED