endif
MAIN = main.o
- OBJ = log.o real.o bezier.o objectrenderer.o view.o screen.o graphicsbuffer.o framebuffer.o shaderprogram.o stb_truetype.o gl_core44.o path.o document.o debugscript.o paranoidnumber.o
+ OBJ = log.o profiler.o real.o bezier.o objectrenderer.o view.o screen.o graphicsbuffer.o framebuffer.o shaderprogram.o stb_truetype.o gl_core44.o path.o document.o debugscript.o paranoidnumber.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
QT_LIB := -L/usr/lib/x86_64-linux-gnu -lQtGui -lQtCore -lpthread
-LIB_x86_64 = ../contrib/lib/libSDL2-2.0.so.0 -lGL -lgmp
-LIB_i386 = ../contrib/lib32/libSDL2-2.0.so.0 -lGL -lgmp
+LIB_x86_64 = ../contrib/lib/libSDL2-2.0.so.0 -lGL -lgmp -lmpfr
+LIB_i386 = ../contrib/lib32/libSDL2-2.0.so.0 -lGL -lgmp -lmpfr
LIB_i686 = $(LIB_i386)
-LIB_win32 = -mwindows -lmingw32 -L../contrib/win32/lib/ -lSDL2main -lSDL2 -lgmp -static-libgcc -lopengl32 -static-libstdc++
+LIB_win32 = -mwindows -lmingw32 -L../contrib/win32/lib/ -lSDL2main -lSDL2 -lgmp -static-libgcc -lopengl32 -static-libstdc++ -lmpfr
MAINRPATH_x86_64 = -Wl,-rpath,'$$ORIGIN/../contrib/lib'
MAINRPATH_i386 = -Wl,-rpath,'$$ORIGIN/../contrib/lib32'
REALTYPE=1
CONTROLPANEL=enabled
QUADTREE=disabled
+TRANSFORMATIONS=direct
+MPFR_PRECISION=23
+PATHREAL=0
DEF = -DREALTYPE=$(REALTYPE)
ifeq ($(REALTYPE),6)
LIB := $(LIB) -lgmp -lmpfr
+ DEF := $(DEF) -DMPFR_PRECISION=$(MPFR_PRECISION)
+endif
+
+ifeq ($(TRANSFORMATIONS),cumulative)
+ DEF := $(DEF) -DTRANSFORM_OBJECTS_NOT_VIEW
+endif
+
+ifeq ($(TRANSFORMATIONS),path)
+ DEF := $(DEF) -DTRANSFORM_OBJECTS_NOT_VIEW -DTRANSFORM_BEZIERS_TO_PATH -DPATHREAL=$(PATHREAL)
+ ifeq ($(PATHREAL), mpfr)
+ LIB:= $(LIB) -lmpfr
+ endif
endif
ifeq ($(REALTYPE),7)
vector<BReal> SolveQuadratic(const BReal & a, const BReal & b, const BReal & c, const BReal & min, const BReal & max)
{
vector<BReal> roots; roots.reserve(2);
- if (a == 0 && b != 0)
+ if (a == BReal(0) && b != BReal(0))
{
roots.push_back(-c/b);
return roots;
}
BReal disc(b*b - BReal(4)*a*c);
- if (disc < 0)
+ if (disc < BReal(0))
{
return roots;
}
- else if (disc == 0)
+ else if (disc == BReal(0))
{
BReal x(-b/BReal(2)*a);
if (x >= min && x <= max)
{
BReal l = a*tl*tl*tl + b*tl*tl + c*tl + d;
BReal u = a*tu*tu*tu + b*tu*tu + c*tu + d;
- if ((l < 0 && u < 0) || (l > 0 && u > 0))
+ if ((l < BReal(0) && u < BReal(0)) || (l > BReal(0) && u > BReal(0)))
{
//Debug("Discarding segment (no roots) l = %f (%f), u = %f (%f)", Double(tl), Double(l), Double(tu), Double(u));
//return;
BReal t(tu+tl);
t /= 2;
BReal m = a*t*t*t + b*t*t + c*t + d;
- if (m > 0)
+ if (m > BReal(0))
{
if (negative)
tl = t;
vector<BReal> roots; roots.reserve(3);
BReal tu(max);
BReal tl(min);
- vector<BReal> turns(SolveQuadratic(a*3, b*2, c));
+ vector<BReal> turns(SolveQuadratic(a*BReal(3), b*BReal(2), c));
//Debug("%u turning points", turns.size());
for (unsigned i = 1; i < turns.size(); ++i)
{
- tu = turns[i];
+ if (tl > max) break;
+ tu = std::min(turns[i],tu);
CubicSolveSegment(roots, a, b, c, d, tl, tu,delta);
tl = turns[i];
}
- tu = max;
- CubicSolveSegment(roots, a, b, c, d, tl, tu,delta);
+ if (tu < max)
+ {
+ tu = max;
+ CubicSolveSegment(roots, a, b, c, d, tl, tu,delta);
+ }
return roots;
}
{
return pair<BReal,BReal>(0, 1);
}
- BReal a = ((p1-p2)*3 + p3 - p0);
- BReal b = (p2 - p1*2 + p0)*2;
+ BReal a = ((p1-p2)*BReal(3) + p3 - p0);
+ BReal b = (p2 - p1*BReal(2) + p0)*BReal(2);
BReal c = (p1-p0);
- if (a == 0)
+ if (a == BReal(0))
{
- if (b == 0)
+ if (b == BReal(0))
return pair<BReal, BReal>(0,1);
BReal t = -c/b;
- if (t > 1) t = 1;
- if (t < 0) t = 0;
+ if (t > BReal(1)) t = 1;
+ if (t < BReal(0)) t = 0;
return pair<BReal, BReal>(t, t);
}
//Debug("a, b, c are %f, %f, %f", Float(a), Float(b), Float(c));
- if (b*b - a*c*4 < 0)
+ if (b*b - a*c*BReal(4) < BReal(0))
{
//Debug("No real roots");
return pair<BReal, BReal>(0,1);
extern std::vector<BReal> SolveQuadratic(const BReal & a, const BReal & b, const BReal & c, const BReal & min = 0, const BReal & max = 1);
- extern std::vector<BReal> SolveCubic(const BReal & a, const BReal & b, const BReal & c, const BReal & d, const BReal & min = 0, const BReal & max = 1, const BReal & delta = 1e-9);
+ extern std::vector<BReal> SolveCubic(const BReal & a, const BReal & b, const BReal & c, const BReal & d, const BReal & min = 0, const BReal & max = 1, const BReal & delta = 1e-5);
/** A _cubic_ bezier. **/
struct Bezier
// (So can't just use the Copy constructor on the inverse of bounds)
// BRect inverse = {-bounds.x/bounds.w, -bounds.y/bounds.h, BReal(1)/bounds.w, BReal(1)/bounds.h};
Bezier result;
- if (bounds.w == 0)
+ if (bounds.w == BReal(0))
{
result.x0 = 0;
result.x1 = 0;
result.x3 = (x3 - bounds.x)/bounds.w;
}
- if (bounds.h == 0)
+ if (bounds.h == BReal(0))
{
result.y0 = 0;
result.y1 = 0;
#include "debugscript.h"
+ #include "profiler.h"
#include <string>
currentAction.type = AT_ScreenShot;
inp >> currentAction.textargs;
}
- else if (actionType == "printfps")
+ else if (actionType == "printspf")
{
- currentAction.type = AT_PrintFPS;
+ currentAction.type = AT_PrintSPF;
currentAction.iz = currentAction.loops;
- m_fps_cpu_mean = 0;
- m_fps_gpu_mean = 0;
- m_fps_cpu_stddev = 0;
- m_fps_gpu_stddev = 0;
+ m_spf_cpu_mean = 0;
+ m_spf_gpu_mean = 0;
+ m_spf_cpu_stddev = 0;
+ m_spf_gpu_stddev = 0;
}
else if (actionType == "printbounds")
{
currentAction.type = AT_PrintBounds;
}
+ else if (actionType == "profileon")
+ {
+ currentAction.type = AT_ProfileDisplay;
+ currentAction.iz = 1;
+ }
+ else if (actionType == "profileoff")
+ {
+ currentAction.type = AT_ProfileDisplay;
+ currentAction.iz = 0;
+ }
else
Fatal("Unknown action %s", actionType.c_str());
case AT_WaitFrame:
break;
case AT_Translate:
- view->Translate(currentAction.x, currentAction.y);
+ view->Translate(Double(currentAction.x), Double(currentAction.y));
break;
case AT_TranslatePx:
view->Translate(Real(currentAction.ix)/Real(scr->ViewportWidth()), Real(currentAction.iy)/Real(scr->ViewportHeight()));
break;
case AT_Zoom:
- view->ScaleAroundPoint(currentAction.x, currentAction.y, currentAction.z);
+ view->ScaleAroundPoint(Double(currentAction.x), Double(currentAction.y), Double(currentAction.z));
break;
case AT_ZoomPx:
- view->ScaleAroundPoint(Real(currentAction.ix)/Real(scr->ViewportWidth()),Real(currentAction.iy)/Real(scr->ViewportHeight()), Real(expf(-currentAction.iz/20.f)));
+ view->ScaleAroundPoint(Real(currentAction.ix)/Real(scr->ViewportWidth()),Real(currentAction.iy)/Real(scr->ViewportHeight()), exp(Real(-currentAction.iz)/Real(20)));
break;
case AT_SetGPURendering:
view->SetGPURendering(true);
break;
case AT_LoadSVG:
{
+ #ifndef QUADTREE_DISABLED
+ view->Doc().SetQuadtreeInsertNode(view->GetCurrentQuadtreeNode());
+ #endif
#ifdef TRANSFORM_OBJECTS_NOT_VIEW
view->Doc().LoadSVG(currentAction.textargs, Rect(Real(1)/Real(2),Real(1)/Real(2),Real(1)/Real(800),Real(1)/Real(600)));
#else
const Rect & bounds = view->GetBounds();
view->Doc().LoadSVG(currentAction.textargs, Rect(bounds.x+bounds.w/Real(2),bounds.y+bounds.h/Real(2),bounds.w/Real(800),bounds.h/Real(600)));
#endif
+ #ifndef QUADTREE_DISABLED
+ view->Doc().PropagateQuadChanges(view->GetCurrentQuadtreeNode());
+ view->Doc().PropagateQuadChanges(view->Doc().GetQuadTree().GetNeighbour(view->GetCurrentQuadtreeNode(), 0, 1, 0));
+ view->Doc().PropagateQuadChanges(view->Doc().GetQuadTree().GetNeighbour(view->GetCurrentQuadtreeNode(), 1, 0, 0));
+ view->Doc().PropagateQuadChanges(view->Doc().GetQuadTree().GetNeighbour(view->GetCurrentQuadtreeNode(), 1, 1, 0));
+ #endif
currentAction.type = AT_WaitFrame;
view->ForceRenderDirty();
view->ForceBufferDirty();
VReal s = target.w/(view->GetBounds().w);
- if (Real(s) != 1)
+ if (s != VReal(1))
{
VReal x0;
VReal y0;
x0 = (view->GetBounds().x - target.x)/((s - VReal(1))*view->GetBounds().w);
y0 = (view->GetBounds().y - target.y)/((s - VReal(1))*view->GetBounds().h);
- view->ScaleAroundPoint(x0, y0, s);
+ view->ScaleAroundPoint(Double(x0), Double(y0), Double(s));
currentAction.loops++;
}
else
target.w += view->GetBounds().w;
target.h += view->GetBounds().h;
VReal s = target.w/(view->GetBounds().w);
- if (Real(s) != 1)
+ if (s != VReal(1))
{
VReal x0;
VReal y0;
x0 = (view->GetBounds().x - target.x)/((s - VReal(1))*view->GetBounds().w);
y0 = (view->GetBounds().y - target.y)/((s - VReal(1))*view->GetBounds().h);
- view->ScaleAroundPoint(x0, y0, s);
+ view->ScaleAroundPoint(Double(x0), Double(y0), Double(s));
currentAction.loops++;
}
else
currentAction.loops = 1;
break;
}
- case AT_PrintFPS:
+ case AT_PrintSPF:
{
// Using a (apparently) Soviet trick to calculate the stddev in one pass
// This was my favourite algorithm in my Physics honours project
if (currentAction.loops <= 1)
{
double n = double(currentAction.iz);
- m_fps_cpu_mean /= n;
- m_fps_gpu_mean /= n;
+ m_spf_cpu_mean /= n;
+ m_spf_gpu_mean /= n;
- m_fps_cpu_stddev = sqrt(m_fps_cpu_stddev / n - m_fps_cpu_mean*m_fps_cpu_mean);
- m_fps_gpu_stddev = sqrt(m_fps_gpu_stddev / n - m_fps_gpu_mean*m_fps_gpu_mean);
+ m_spf_cpu_stddev = sqrt(m_spf_cpu_stddev / n - m_spf_cpu_mean*m_spf_cpu_mean);
+ m_spf_gpu_stddev = sqrt(m_spf_gpu_stddev / n - m_spf_gpu_mean*m_spf_gpu_mean);
printf("%d\t%f\t%f\t%f\t%f\n", currentAction.iz,
- m_fps_gpu_mean, m_fps_gpu_stddev,
- m_fps_cpu_mean, m_fps_cpu_stddev);
+ m_spf_gpu_mean, m_spf_gpu_stddev,
+ m_spf_cpu_mean, m_spf_cpu_stddev);
}
else
{
- double fps_cpu = 1.0/scr->GetLastFrameTimeCPU();
- double fps_gpu = 1.0/scr->GetLastFrameTimeGPU();
+ double spf_cpu = scr->GetLastFrameTimeCPU();
+ double spf_gpu = scr->GetLastFrameTimeGPU();
- m_fps_cpu_mean += fps_cpu;
- m_fps_gpu_mean += fps_gpu;
+ m_spf_cpu_mean += spf_cpu;
+ m_spf_gpu_mean += spf_gpu;
- m_fps_cpu_stddev += fps_cpu*fps_cpu;
- m_fps_gpu_stddev += fps_gpu*fps_gpu;
+ m_spf_cpu_stddev += spf_cpu*spf_cpu;
+ m_spf_gpu_stddev += spf_gpu*spf_gpu;
}
break;
}
case AT_PrintBounds:
{
- printf("%s\t%s\t%s\t%s\n", Str(view->GetBounds().x).c_str(), Str(view->GetBounds().y).c_str(), Str(view->GetBounds().w).c_str(), Str(view->GetBounds().h).c_str());
+ printf("%s\t%s\t%s\t%s\t%s\t%s\n", Str(view->GetBounds().x).c_str(), Str(view->GetBounds().y).c_str(), Str(view->GetBounds().w).c_str(), Str(view->GetBounds().h).c_str(), Str(Log10(view->GetBounds().w)).c_str(), Str(Log10(view->GetBounds().h)).c_str());
break;
}
+ case AT_ProfileDisplay:
+ {
+ g_profiler.Enable(currentAction.iz);
+ break;
+ }
default:
Fatal("Unknown script command in queue.");
}
AT_SetBounds,
AT_QueryGPUBounds, // query bounds of Beziers when transformed to GPU
AT_ScreenShot, // take screenshot
- AT_PrintFPS, // Print FPS statistics about the frames
+ AT_PrintSPF, // Print FPS statistics about the frames
AT_PrintBounds, // Print bounds
+ AT_ProfileDisplay,
AT_Quit
};
struct Action
{
ActionType type;
- Real x, y;
+ VReal x, y;
int ix, iy;
- Real z;
+ VReal z;
int iz;
int loops;
- Real w, h;
+ VReal w, h;
std::string textargs;
Action() : type(AT_WaitFrame), x(0), y(0), ix(0), iy(0), z(0), loops(0), textargs("") {}
};
std::map<std::string, int> m_labels;
unsigned m_index;
- double m_fps_cpu_mean;
- double m_fps_gpu_mean;
- double m_fps_cpu_stddev;
- double m_fps_gpu_stddev;
+ double m_spf_cpu_mean;
+ double m_spf_gpu_mean;
+ double m_spf_cpu_stddev;
+ double m_spf_gpu_stddev;
struct PerformanceData
{
bool ignore_sigfpe = false;
const char *script_filename;
+bool make_movie = false;
+const char * program_name;
void sigfpe_handler(int sig)
{
int main(int argc, char ** argv)
{
-
+ program_name = argv[0];
//Debug("Main!");
signal(SIGFPE, sigfpe_handler);
#endif
// We want to crash if we ever get a NaN.
-- // AH, so *this* is where that got enabled, I was looking for compiler flags
++ // Not any more
#ifndef __MINGW32__
- feenableexcept(FE_DIVBYZERO | FE_INVALID); // | FE_OVERFLOW);
- feenableexcept(FE_DIVBYZERO | FE_INVALID | FE_OVERFLOW);
++ //feenableexcept(FE_DIVBYZERO | FE_INVALID); // | FE_OVERFLOW);
#endif
#if REALTYPE == REAL_MPFRCPP
- mpfr_set_default_prec(6);
+
+ #ifdef MPFR_PRECISION
+ mpfr_set_default_prec(MPFR_PRECISION);
+ #else
+ mpfr_set_default_prec(23);
+ #endif
+
#endif
DebugRealInfo();
bool window_visible = true;
bool gpu_transform = USE_GPU_TRANSFORM;
bool gpu_rendering = USE_GPU_RENDERING;
-
+ #ifdef TRANSFORM_OBJECTS_NOT_VIEW
+ gpu_transform = true;
+ #endif
+ #ifdef TRANSFORM_BEZIERS_TO_PATH
+ gpu_transform = true;
+ #endif
int i = 0;
Fatal("Expected filename after -s switch");
script_filename = argv[i];
break;
+ case 'm':
+ make_movie = true;
+ break;
}
}
#include "view.h"
#include "screen.h"
#include "debugscript.h"
+ #include "profiler.h"
#include <unistd.h>
extern const char *script_filename;
+extern bool make_movie; // whyyy
+extern const char * program_name;
inline void OverlayBMP(Document & doc, const char * input, const char * output, const Rect & bounds = Rect(0,0,1,1), const Colour & c = Colour(0.f,0.f,0.f,1.f))
{
if (wheel)
{
- view->ScaleAroundPoint(Real(x)/Real(scr->ViewportWidth()),Real(y)/Real(scr->ViewportHeight()), Real(expf(-wheel/20.f)));
+ view->ScaleAroundPoint(Real(x)/Real(scr->ViewportWidth()),Real(y)/Real(scr->ViewportHeight()), exp(Real(-wheel)/Real(20)));
}
}
//scr.DebugFontInit("fonts/DejaVuSansMono.ttf", 12);
- scr.DebugFontInit("fonts/DejaVuSansMono.ttf", 18);
+ scr.DebugFontInit("fonts/DejaVuSansMono.ttf", 36);
scr.SetMouseHandler(RatCatcher);
ifstream tmp;
real_clock_prev = real_clock_now;
#endif
++frames;
+ g_profiler.BeginZone("scr.Clear()");
scr.Clear();
+ g_profiler.EndZone();
//view.ForceBoundsDirty();
//view.ForceBufferDirty();
//view.ForceRenderDirty();
return;
}
+ g_profiler.BeginZone("view.Render");
view.Render(scr.ViewportWidth(), scr.ViewportHeight());
+ g_profiler.EndZone();
double cpu_frame = scr.GetLastFrameTimeCPU();
double gpu_frame = scr.GetLastFrameTimeGPU();
-
+ scr.DebugFontPrintF("%s\n", program_name);
scr.DebugFontPrintF("Top Left: (%s,%s)\n", Str(view.GetBounds().x).c_str(),Str(view.GetBounds().y).c_str());
scr.DebugFontPrintF("Width: %s\n", Str(view.GetBounds().w).c_str());
- scr.DebugFontPrintF("Zoom: %s %%\n", Str(VReal(100)/VReal(view.GetBounds().w)).c_str());
- //scr.DebugFontPrintF("Similar size: %s\n", HumanScale(view.GetBounds().w * VReal(22e-3)));
+ Real zoom(100);
+ zoom = zoom/Real(view.GetBounds().w);
+ scr.DebugFontPrintF("Zoom: %s %%\n", Str(zoom).c_str());
+ scr.DebugFontPrintF("Similar size: %s\n", HumanScale(ClampFloat(Double(view.GetBounds().w))));
#if 0
scr.DebugFontPrintF("Rendered frame %lu\n", (uint64_t)frames);
scr.DebugFontPrint("Doing rendering using CPU.\n");
}
#endif // 0
-
+
- scr.Present();
-
+ if (make_movie)
+ {
+ std::stringstream s;
+ s << "frame" << frames << ".bmp";
+ scr.ScreenShot(s.str().c_str());
- }
++ }
++
++
+
+ g_profiler.BeginZone("scr.Present()");
+ scr.Present();
+ g_profiler.EndZone();
+ g_profiler.EndFrame();
++
++
}
}
}
SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 3);
- SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 1);
+ SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 3);
SDL_GL_SetAttribute(SDL_GL_CONTEXT_FLAGS, SDL_GL_CONTEXT_DEBUG_FLAG);
SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, SDL_GL_CONTEXT_PROFILE_CORE);
--
++ //SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 1);
m_gl_context = SDL_GL_CreateContext(m_window);
++ //SDL_GL_SetSwapInterval(1);
ogl_LoadFunctions();
// Why is this so horribly broken?
if (ogl_IsVersionGEQ(3,2))
{
- Fatal("We require OpenGL 3.3, but you have version %d.%d!",ogl_GetMajorVersion(), ogl_GetMinorVersion());
+ Error("We require OpenGL 3.3, but you have version %d.%d!",ogl_GetMajorVersion(), ogl_GetMinorVersion());
}
if (!SDL_GL_ExtensionSupported("GL_ARB_shading_language_420pack"))
{
- Fatal("Your system does not support the ARB_shading_language_420pack extension, which is required.");
+ Error("Your system does not support the ARB_shading_language_420pack extension, which is required.");
}
if (!SDL_GL_ExtensionSupported("GL_ARB_explicit_attrib_location"))
{
- Fatal("Your system does not support the ARB_explicit_attrib_location extension, which is required.");
+ Error("Your system does not support the ARB_explicit_attrib_location extension, which is required.");
}
m_frame_begin_time = SDL_GetPerformanceCounter();
{
if (!Valid())
return;
+
if (m_debug_font_atlas)
DebugFontFlush();
+
m_last_frame_time = SDL_GetPerformanceCounter() - m_frame_begin_time;
glEndQuery(GL_TIME_ELAPSED);
SDL_GL_SwapWindow(m_window);
m_last_frame_gpu_timer = m_frame_gpu_timer;
glGenQueries(1, &m_frame_gpu_timer);
glBeginQuery(GL_TIME_ELAPSED, m_frame_gpu_timer);
+
+
}
double Screen::GetLastFrameTimeGPU() const
-# BECAUSE I CAN
+# Script for the turtles video
gpu
lazy
-profileon
--#debugfont off
+
- loop 1000 wait
+# Wait to start video
++# loop 1000 wait
+
+#Load first turtle...
loadsvg svg-tests/turtle.svg
loop 50 pxzoom 430 170 1
loadsvg svg-tests/turtle.svg
loadsvg svg-tests/turtle.svg
loop 50 pxzoom 430 170 1
loadsvg svg-tests/turtle.svg
+
+# Wait near last visible turtle at float
+#loop 1000 wait
+# Zoom back out
+#loop 350 pxzoom 430 170 -1
+#loop 350 pxzoom 430 170 1
+
+# Continue
+loadsvg svg-tests/turtle.svg
loop 50 pxzoom 430 170 1
loadsvg svg-tests/turtle.svg
loop 50 pxzoom 430 170 1
clearperf
label start
printperf
-loop 3000 pxzoom 430 170 1
-loop 3000 pxzoom 430 170 -1
+loop 2000 pxzoom 430 170 1
+loop 2000 pxzoom 430 170 -1
goto start
wait
#include "view.h"
#include "bufferbuilder.h"
#include "screen.h"
+ #include "profiler.h"
#include "gl_core44.h"
#ifndef CONTROLPANEL_DISABLED
*/
void View::Translate(Real x, Real y)
{
+ PROFILE_SCOPE("View::Translate");
if (!m_use_gpu_transform)
m_buffer_dirty = true;
m_bounds_dirty = true;
*/
void View::ScaleAroundPoint(Real x, Real y, Real scale_amount)
{
-
+ PROFILE_SCOPE("View::ScaleAroundPoint");
// (x0, y0, w, h) -> (x*w - (x*w - x0)*s, y*h - (y*h - y0)*s, w*s, h*s)
// x and y are coordinates in the window
// Convert to local coords.
m_bounds.y = vy - top;
m_bounds.w *= scale_amount;
m_bounds.h *= scale_amount;
+ if (m_bounds.w == VReal(0))
+ {
+ Debug("Scaled to zero!!!");
+ }
//Debug("Scale at {%s, %s} by %s View Bounds => %s", x.Str().c_str(), y.Str().c_str(), scale_amount.Str().c_str(), m_bounds.Str().c_str());
*/
void View::Render(int width, int height)
{
+ PROFILE_SCOPE("View::Render()");
if (!m_screen.Valid()) return;
glPushDebugGroup(GL_DEBUG_SOURCE_APPLICATION,42,-1, "Beginning View::Render()");
// View dimensions have changed (ie: Window was resized)
// quadtree node).
if (m_bounds_dirty || !m_lazy_rendering)
{
+ g_profiler.BeginZone("View::Render -- Quadtree view bounds management");
// If we're too far zoomed out, become the parent of the current node.
- if ( m_bounds.w > 1.0 || m_bounds.h > 1.0)
+ while ( m_bounds.w > 1.0 || m_bounds.h > 1.0)
{
// If a parent node exists, we'll become it.
//TODO: Generate a new parent node if none exists, and work out when to change child_type
m_bounds = TransformFromQuadChild(m_bounds, m_document.GetQuadTree().nodes[m_current_quadtree_node].child_type);
m_current_quadtree_node = m_document.GetQuadTree().nodes[m_current_quadtree_node].parent;
}
+ else break;
}
// If we have a parent... (This prevents some crashes, but should disappear.)
// Otherwise, we'll arbitrarily select the bottom-right.
// TODO: Perhaps select based on greatest area?
- if (m_bounds.w < 0.5 || m_bounds.h < 0.5)
+ while (m_bounds.w < 0.5 || m_bounds.h < 0.5)
{
if (m_document.GetQuadTree().nodes[m_current_quadtree_node].bottom_right == QUADTREE_EMPTY)
{
m_bounds = TransformToQuadChild(m_bounds, QTC_BOTTOM_RIGHT);
m_current_quadtree_node = m_document.GetQuadTree().nodes[m_current_quadtree_node].bottom_right;
}
+ g_profiler.EndZone();
}
m_screen.DebugFontPrintF("Current View QuadTree");
#ifdef QUADTREE_DISABLED
RenderRange(width, height, 0, m_document.ObjectCount());
#else
+ // Make sure we update the gpu buffers properly.
+ if (m_document.m_document_dirty)
+ {
+ m_render_dirty = m_buffer_dirty = true;
+ m_document.m_document_dirty = false;
+ }
RenderQuadtreeNode(width, height, m_current_quadtree_node, m_quadtree_max_depth);
#endif
if (!m_use_gpu_rendering)
Rect old_bounds = m_bounds;
if (node == QUADTREE_EMPTY) return;
if (!remaining_depth) return;
- //Debug("Rendering QT node %d, (objs: %d -- %d)\n", node, m_document.GetQuadTree().nodes[node].object_begin, m_document.GetQuadTree().nodes[node].object_end);
m_bounds_dirty = true;
- m_render_dirty = m_buffer_dirty = true;
QuadTreeIndex overlay = node;
while(overlay != -1)
{
+ //Debug("Rendering QT node %d, (overlay %d, objs: %d -- %d)\n", node, overlay, m_document.GetQuadTree().nodes[overlay].object_begin, m_document.GetQuadTree().nodes[overlay].object_end);
+ if (m_document.GetQuadTree().nodes[overlay].render_dirty)
+ m_buffer_dirty = m_render_dirty = true;
RenderRange(width, height, m_document.GetQuadTree().nodes[overlay].object_begin, m_document.GetQuadTree().nodes[overlay].object_end);
+ const_cast<bool&>(m_document.GetQuadTree().nodes[overlay].render_dirty) = false;
overlay = m_document.GetQuadTree().nodes[overlay].next_overlay;
}
void View::RenderRange(int width, int height, unsigned first_obj, unsigned last_obj)
{
+ // We don't want to render an empty range,
+ // so don't waste time setting up everything.
+ if (first_obj == last_obj) return;
+ PROFILE_SCOPE("View::RenderRange");
glPushDebugGroup(GL_DEBUG_SOURCE_APPLICATION, 43, -1, "View::RenderRange()");
if (m_render_dirty) // document has changed
PrepareRender();
+
if (m_buffer_dirty || m_bounds_dirty || !m_lazy_rendering) // object bounds have changed
{
if (m_use_gpu_rendering)
UpdateObjBoundsVBO(first_obj, last_obj);
}
- if (m_use_gpu_transform)
- {
- #ifdef TRANSFORM_OBJECTS_NOT_VIEW
- //Debug("Transform objects, not view");
- GLfloat glbounds[] = {0.0f, 0.0f, 1.0f, 1.0f,
- 0.0f, 0.0f, float(width), float(height)};
- #else
- GLfloat glbounds[] = {static_cast<GLfloat>(Float(m_bounds.x)), static_cast<GLfloat>(Float(m_bounds.y)), static_cast<GLfloat>(Float(m_bounds.w)), static_cast<GLfloat>(Float(m_bounds.h)),
- 0.0, 0.0, static_cast<GLfloat>(width), static_cast<GLfloat>(height)};
- #endif
- m_bounds_ubo.Upload(sizeof(float)*8, glbounds);
- }
- else
- {
- GLfloat glbounds[] = {0.0f, 0.0f, 1.0f, 1.0f,
- 0.0f, 0.0f, float(width), float(height)};
- m_bounds_ubo.Upload(sizeof(float)*8, glbounds);
- }
- m_bounds_dirty = false;
-
// Render using GPU
if (m_use_gpu_rendering)
{
+
+ if (m_use_gpu_transform)
+ {
+ #ifdef TRANSFORM_OBJECTS_NOT_VIEW
+ //Debug("Transform objects, not view");
+ GLfloat glbounds[] = {0.0f, 0.0f, 1.0f, 1.0f,
+ 0.0f, 0.0f, float(width), float(height)};
+ #else
+ GLfloat glbounds[] = {static_cast<GLfloat>(Float(m_bounds.x)), static_cast<GLfloat>(Float(m_bounds.y)), static_cast<GLfloat>(Float(m_bounds.w)), static_cast<GLfloat>(Float(m_bounds.h)),
+ 0.0, 0.0, static_cast<GLfloat>(width), static_cast<GLfloat>(height)};
+ #endif
+ m_bounds_ubo.Upload(sizeof(float)*8, glbounds);
+ }
+ else
+ {
+ GLfloat glbounds[] = {0.0f, 0.0f, 1.0f, 1.0f,
+ 0.0f, 0.0f, float(width), float(height)};
+ m_bounds_ubo.Upload(sizeof(float)*8, glbounds);
+ }
+ m_bounds_dirty = false;
+
if (m_colour.a < 1.0f)
{
glEnable(GL_BLEND);
void View::UpdateObjBoundsVBO(unsigned first_obj, unsigned last_obj)
{
+ PROFILE_SCOPE("View::UpdateObjBoundsVBO");
if (m_query_gpu_bounds_on_next_frame != NULL)
{
- fprintf(m_query_gpu_bounds_on_next_frame,"# View: %s\t%s\t%s\t%s", Str(m_bounds.x).c_str(), Str(m_bounds.y).c_str(), Str(m_bounds.w).c_str(), Str(m_bounds.h).c_str());
+ fprintf(m_query_gpu_bounds_on_next_frame,"# View: %s\t%s\t%s\t%s\n", Str(m_bounds.x).c_str(), Str(m_bounds.y).c_str(), Str(m_bounds.w).c_str(), Str(m_bounds.h).c_str());
}
//m_objbounds_vbo.Invalidate();
continue;
Rect obj_bounds = m_document.m_objects.bounds[id];
-
obj_bounds.x *= pbounds.w;
obj_bounds.x += pbounds.x;
obj_bounds.y *= pbounds.h;
*/
void View::PrepareRender()
{
+ PROFILE_SCOPE("View::PrepareRender()");
Debug("Recreate buffers with %u objects", m_document.ObjectCount());
// Prepare bounds vbo
if (UsingGPURendering())
#include "path.h"
#include "transformationtype.h"
-#define USE_GPU_TRANSFORM true
+#define USE_GPU_TRANSFORM false
#define USE_GPU_RENDERING true
#define USE_SHADING !(USE_GPU_RENDERING) && true
namespace IPDF
{
- #ifdef TRANSFORM_BEZIERS_TO_PATH
- typedef Real VReal;
- #else
- typedef Real VReal;
- #endif
typedef TRect<VReal> VRect;
class Screen;
void SaveGPUBMP(const char * filename);
Document & Doc() {return m_document;}
+ #ifndef QUADTREE_DISABLED
+ QuadTreeIndex GetCurrentQuadtreeNode() { return m_current_quadtree_node; }
+ #endif
private:
struct GPUObjBounds