Change to things to make performance testing easier
authorSam Moore <matches@ucc.asn.au>
Mon, 15 Sep 2014 17:26:00 +0000 (01:26 +0800)
committerSam Moore <matches@ucc.asn.au>
Tue, 16 Sep 2014 05:27:35 +0000 (13:27 +0800)
- Saving of CPU and GPU BMPs
  - OverlayBMP doesn't overlay a BMP which is good because we don't want it to...
- SVG loads in centre of view
  - This will break the Quad tree, probably
- tests/bmpdiff allows us to quantitatively compare output bmp images.
  - I didn't say it was a good metric, there's just a metric now.
- Arguments to set rendering and transform type, argument to set maximum number of frames to render,
argument to turn off the lazy rendering.

Will make some kind of ipython notebook next I guess.

.gitignore
src/Makefile
src/controlpanel.cpp
src/controlpanel.h
src/document.cpp
src/main.cpp
src/main.h
src/real.h
src/tests/bmpdiff.cpp [new file with mode: 0644]
src/view.cpp
src/view.h

index 7973e79..f415fe2 100644 (file)
@@ -13,3 +13,6 @@
 bin/ipdf
 data/*
 src/moc_controlpanel.cpp
+src/tests/*
+!src/tests/*.cpp
+!src/tests/*.h
index 38f69fd..03cf3aa 100644 (file)
@@ -104,7 +104,7 @@ movie : $(BIN) ../tools/stream_plot.py
 # 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/$@.o $(LIB) $(TESTRPATH)
+       $(CXX) $(CFLAGS) -o $@ $(LINKOBJ) ../obj/$@.o $(LIB) $(TESTRPATH)
 
 -include $(DEPS)
 
index e4e68d6..f27bc7a 100644 (file)
@@ -136,10 +136,16 @@ QMenu * ControlPanel::CreateScreenMenu()
        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()));
        
@@ -171,6 +177,7 @@ void ControlPanel::UpdateAll()
        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());
@@ -264,6 +271,13 @@ void ControlPanel::SetCPURendering()
        UpdateAll();
 }
 
+void ControlPanel::ToggleLazyRendering()
+{
+       bool state = m_view.UsingLazyRendering();
+       m_view.SetLazyRendering(!state);
+       UpdateAll();
+}
+
 void ControlPanel::ToggleScreenDebugFont()
 {
        bool state = m_screen.DebugFontShown();
@@ -303,6 +317,9 @@ void ControlPanel::InsertTextIntoDocument()
 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());
        
@@ -320,6 +337,9 @@ void ControlPanel::LoadSVGIntoDocument()
                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());
        
index 67eff64..ce7c3d9 100644 (file)
@@ -61,6 +61,7 @@ namespace IPDF
                private slots:
                        void SetGPURendering();
                        void SetCPURendering();
+                       void ToggleLazyRendering();
                        void ToggleShowBezierBounds();
                        void ToggleShowBezierType();
                        void ToggleShowFillBounds();
@@ -104,6 +105,7 @@ namespace IPDF
                        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;
@@ -116,7 +118,6 @@ namespace IPDF
                        QAction * m_view_show_fill_points;
                        QAction * m_view_enable_shading;
                        
-                       
                
                        QTextEdit * m_text_edit;
                        QPushButton * m_ok_button;
index 5890730..1558865 100644 (file)
@@ -392,12 +392,12 @@ static void GetXYPair(const string & d, Real & x, Real & y, unsigned & i,const s
 {
        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 = "()[],{}<>;:=")
@@ -460,11 +460,11 @@ void Document::ParseSVGTransform(const string & s, SVGMatrix & transform)
                }
                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
@@ -510,7 +510,7 @@ inline Colour ParseColourString(const string & colour_str)
                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];
@@ -518,7 +518,7 @@ inline Colour ParseColourString(const string & colour_str)
                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;
 }
@@ -527,7 +527,16 @@ void Document::ParseSVGNode(pugi::xml_node & root, SVGMatrix & parent_transform)
 {
        //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);  
@@ -709,7 +718,7 @@ void Document::LoadSVG(const string & filename, const Rect & bounds)
        
        input.close();
                                                // a c e, b d f
-       SVGMatrix transform = {bounds.w, 0,bounds.x, 0,bounds.h,bounds.y};
+       SVGMatrix transform = {bounds.w,,bounds.x, 0,bounds.h,bounds.y};
        ParseSVGNode(doc_xml, transform);
 }
 
@@ -755,9 +764,9 @@ pair<unsigned, unsigned> Document::ParseSVGPathData(const string & d, const SVGM
                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;
@@ -770,25 +779,25 @@ pair<unsigned, unsigned> Document::ParseSVGPathData(const string & d, const SVGM
                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;
                        }
@@ -821,12 +830,12 @@ pair<unsigned, unsigned> Document::ParseSVGPathData(const string & d, const SVGM
                {
                        //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")
                        {
index d65dc60..a2693d1 100644 (file)
@@ -7,10 +7,20 @@
 #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
@@ -31,11 +41,23 @@ int main(int argc, char ** argv)
        
        
        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)
        {
@@ -48,13 +70,10 @@ int main(int argc, char ** argv)
                {
                        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':
                        {
@@ -71,39 +90,113 @@ int main(int argc, char ** argv)
                                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;
@@ -113,5 +206,7 @@ int main(int argc, char ** argv)
                        Debug("ControlPanel thread returned %d", cp_return);
                }
        #endif //CONTROLPANEL_DISABLED
+       
+       ignore_sigfpe = true;
        return 0;
 }
index d20ea52..9929d69 100644 (file)
@@ -79,7 +79,7 @@ void RatCatcher(int x, int y, int buttons, int wheel, Screen * scr, View * view)
 }
 
 
-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 -_-
 
@@ -98,7 +98,8 @@ inline void MainLoop(Document & doc, Screen & scr, View & view)
        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;
index 9ea302d..5d4e133 100644 (file)
@@ -46,18 +46,23 @@ namespace IPDF
 
 #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
        
@@ -73,12 +78,14 @@ namespace IPDF
        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
@@ -137,6 +144,7 @@ namespace IPDF
        
        };
 
+       inline Real RealFromStr(const std::string & str) {return RealFromStr(str.c_str());}
 
 
 
diff --git a/src/tests/bmpdiff.cpp b/src/tests/bmpdiff.cpp
new file mode 100644 (file)
index 0000000..02ab568
--- /dev/null
@@ -0,0 +1,75 @@
+/**
+ * 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);
+}
index 52a4c6d..47d28c1 100644 (file)
@@ -160,7 +160,7 @@ void View::Render(int width, int height)
        }
 
        // 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();
@@ -171,7 +171,7 @@ void View::Render(int width, int height)
        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))
                {
@@ -363,7 +363,7 @@ void View::RenderRange(int width, int height, unsigned first_obj, unsigned last_
        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)
@@ -498,3 +498,12 @@ void View::PrepareRender()
        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);
+}
index d99db6e..e6b4dbb 100644 (file)
@@ -39,6 +39,7 @@ namespace IPDF
                        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;}
 
@@ -57,6 +58,11 @@ namespace IPDF
                        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
@@ -100,6 +106,8 @@ namespace IPDF
                        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

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