Merge branch terrible and branch awful
authorSam Moore <[email protected]>
Thu, 23 Oct 2014 11:49:35 +0000 (19:49 +0800)
committerSam Moore <[email protected]>
Thu, 23 Oct 2014 11:49:35 +0000 (19:49 +0800)
scr.Present was in wrong place
Merging sucks
Everything sucks
GPUs suck
fglrx sucks
professionalism sucks
I hope no one looking to hire me ever reads these.

Conflicts:
src/main.h

1  2 
src/Makefile
src/bezier.cpp
src/bezier.h
src/debugscript.cpp
src/debugscript.h
src/main.cpp
src/main.h
src/screen.cpp
src/turtles_all_the_way_down.script
src/view.cpp
src/view.h

diff --combined src/Makefile
@@@ -10,16 -10,16 +10,16 @@@ els
  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'
@@@ -48,9 -48,6 +48,9 @@@ BIN = ../bin/ipd
  REALTYPE=1
  CONTROLPANEL=enabled
  QUADTREE=disabled
 +TRANSFORMATIONS=direct
 +MPFR_PRECISION=23
 +PATHREAL=0
  DEF = -DREALTYPE=$(REALTYPE)
  
  
@@@ -83,18 -80,6 +83,18 @@@ endi
  
  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)
diff --combined src/bezier.cpp
@@@ -14,17 -14,17 +14,17 @@@ namespace IPD
  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)
@@@ -55,7 -55,7 +55,7 @@@ static void CubicSolveSegment(vector<BR
  {
        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;
@@@ -68,7 -68,7 +68,7 @@@
                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;
@@@ -92,16 -92,20 +92,20 @@@ vector<BReal> SolveCubic(const BReal & 
        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;
  }
  
@@@ -155,20 -159,20 +159,20 @@@ pair<BReal, BReal> BezierTurningPoints(
        {
                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);
diff --combined src/bezier.h
@@@ -20,7 -20,7 +20,7 @@@ namespace IPD
        
        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;
diff --combined src/debugscript.cpp
@@@ -1,4 -1,5 +1,5 @@@
  #include "debugscript.h"
+ #include "profiler.h"
  
  #include <string>
  
@@@ -172,19 -173,29 +173,29 @@@ void DebugScript::ParseAction(View * vi
                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());
  
@@@ -215,16 -226,16 +226,16 @@@ bool DebugScript::Execute(View *view, S
        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.");
        }
diff --combined src/debugscript.h
@@@ -43,20 -43,21 +43,21 @@@ private
                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
        {
diff --combined src/main.cpp
@@@ -11,8 -11,6 +11,8 @@@
  
  bool ignore_sigfpe = false;
  const char *script_filename;
 +bool make_movie = false;
 +const char * program_name;
  
  void sigfpe_handler(int sig)
  {
@@@ -23,7 -21,7 +23,7 @@@
  
  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;
                }       
        }
  
diff --combined src/main.h
@@@ -4,6 -4,7 +4,7 @@@
  #include "view.h"
  #include "screen.h"
  #include "debugscript.h"
+ #include "profiler.h"
  #include <unistd.h>
  
  
@@@ -12,8 -13,6 +13,8 @@@ using namespace IPDF
  
  
  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))
  {
@@@ -71,7 -70,7 +72,7 @@@ void RatCatcher(int x, int y, int butto
                
        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)));
        }
  }
  
@@@ -82,7 -81,7 +83,7 @@@ void MainLoop(Document & doc, Screen & 
        
  
        //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();
++              
++              
        }
  }
diff --combined src/screen.cpp
@@@ -45,28 -45,28 +45,29 @@@ Screen::Screen(bool visible
        }
  
        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();
@@@ -227,10 -227,8 +228,10 @@@ void Screen::Present(
  {
        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
@@@ -1,12 -1,10 +1,12 @@@
 -# 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
@@@ -20,15 -18,6 +20,15 @@@ loop 50 pxzoom 430 170 
  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
@@@ -104,7 -93,7 +104,7 @@@ loop 50 pxzoom 430 170 -
  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
diff --combined src/view.cpp
@@@ -1,6 -1,7 +1,7 @@@
  #include "view.h"
  #include "bufferbuilder.h"
  #include "screen.h"
+ #include "profiler.h"
  #include "gl_core44.h"
  
  #ifndef CONTROLPANEL_DISABLED
@@@ -87,6 -88,7 +88,7 @@@ View::~View(
   */
  void View::Translate(Real x, Real y)
  {
+       PROFILE_SCOPE("View::Translate");       
        if (!m_use_gpu_transform)
                m_buffer_dirty = true;
        m_bounds_dirty = true;
@@@ -134,7 -136,7 +136,7 @@@ void View::SetBounds(const Rect & bound
   */
  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());
        
        
@@@ -197,6 -195,7 +199,7 @@@ Rect View::TransformToViewCoords(const 
   */
  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)
@@@ -403,13 -411,15 +415,15 @@@ void View::RenderQuadtreeNode(int width
        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())
diff --combined src/view.h
@@@ -8,7 -8,7 +8,7 @@@
  #include "path.h"
  #include "transformationtype.h"
  
 -#define USE_GPU_TRANSFORM tru
 +#define USE_GPU_TRANSFORM fals
  #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;
@@@ -78,6 -83,9 +78,9 @@@
                        void SaveGPUBMP(const char * filename);
  
                        Document & Doc() {return m_document;}
+ #ifndef QUADTREE_DISABLED
+                       QuadTreeIndex GetCurrentQuadtreeNode() { return m_current_quadtree_node; }
+ #endif
  
                private:
                        struct GPUObjBounds

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