Add command line options. Rename GLScene to Engine

This commit is contained in:
tamasmeszaros 2019-12-19 14:51:38 +01:00
parent bf44da0e37
commit 8126cdd507
4 changed files with 175 additions and 97 deletions

View File

@ -2,7 +2,7 @@ cmake_minimum_required(VERSION 3.0)
project(OpenCSG-example) project(OpenCSG-example)
add_executable(opencsg_example WIN32 main.cpp GLScene.hpp GLScene.cpp add_executable(opencsg_example WIN32 main.cpp Engine.hpp Engine.cpp
${CMAKE_CURRENT_SOURCE_DIR}/../../src/slic3r/GUI/ProgressStatusBar.cpp ${CMAKE_CURRENT_SOURCE_DIR}/../../src/slic3r/GUI/ProgressStatusBar.cpp
${CMAKE_CURRENT_SOURCE_DIR}/../../src/slic3r/GUI/I18N.hpp ${CMAKE_CURRENT_SOURCE_DIR}/../../src/slic3r/GUI/I18N.hpp
${CMAKE_CURRENT_SOURCE_DIR}/../../src/slic3r/GUI/I18N.cpp) ${CMAKE_CURRENT_SOURCE_DIR}/../../src/slic3r/GUI/I18N.cpp)

View File

@ -1,4 +1,4 @@
#include "GLScene.hpp" #include "Engine.hpp"
#include <libslic3r/Utils.hpp> #include <libslic3r/Utils.hpp>
#include <libslic3r/SLAPrint.hpp> #include <libslic3r/SLAPrint.hpp>
#include <libslic3r/MTUtils.hpp> #include <libslic3r/MTUtils.hpp>
@ -48,7 +48,7 @@ namespace Slic3r { namespace GL {
Scene::Scene() = default; Scene::Scene() = default;
Scene::~Scene() = default; Scene::~Scene() = default;
void Display::render_scene() void CSGDisplay::render_scene()
{ {
GLfloat color[] = {1.f, 1.f, 0.f, 0.f}; GLfloat color[] = {1.f, 1.f, 0.f, 0.f};
glsafe(::glColor4fv(color)); glsafe(::glColor4fv(color));
@ -95,14 +95,14 @@ BoundingBoxf3 Scene::get_bounding_box() const
return m_print->model().bounding_box(); return m_print->model().bounding_box();
} }
void Display::SceneCache::clear() void CSGDisplay::SceneCache::clear()
{ {
primitives_csg.clear(); primitives_csg.clear();
primitives_free.clear(); primitives_free.clear();
primitives.clear(); primitives.clear();
} }
shptr<Primitive> Display::SceneCache::add_mesh(const TriangleMesh &mesh) shptr<Primitive> CSGDisplay::SceneCache::add_mesh(const TriangleMesh &mesh)
{ {
auto p = std::make_shared<Primitive>(); auto p = std::make_shared<Primitive>();
p->load_mesh(mesh); p->load_mesh(mesh);
@ -111,9 +111,9 @@ shptr<Primitive> Display::SceneCache::add_mesh(const TriangleMesh &mesh)
return p; return p;
} }
shptr<Primitive> Display::SceneCache::add_mesh(const TriangleMesh &mesh, shptr<Primitive> CSGDisplay::SceneCache::add_mesh(const TriangleMesh &mesh,
OpenCSG::Operation o, OpenCSG::Operation o,
unsigned c) unsigned c)
{ {
auto p = std::make_shared<Primitive>(o, c); auto p = std::make_shared<Primitive>(o, c);
p->load_mesh(mesh); p->load_mesh(mesh);
@ -388,7 +388,7 @@ void Controller::on_moved_to(long x, long y)
m_mouse_pos = {x, y}; m_mouse_pos = {x, y};
} }
void Display::apply_csgsettings(const CSGSettings &settings) void CSGDisplay::apply_csgsettings(const CSGSettings &settings)
{ {
using namespace OpenCSG; using namespace OpenCSG;
@ -404,11 +404,9 @@ void Display::apply_csgsettings(const CSGSettings &settings)
if (p->getConvexity() > 1) if (p->getConvexity() > 1)
p->setConvexity(m_csgsettings.get_convexity()); p->setConvexity(m_csgsettings.get_convexity());
} }
repaint();
} }
void Display::on_scene_updated(const Scene &scene) void CSGDisplay::on_scene_updated(const Scene &scene)
{ {
const SLAPrint *print = scene.get_print(); const SLAPrint *print = scene.get_print();
if (!print) return; if (!print) return;

View File

@ -1,5 +1,5 @@
#ifndef GLSCENE_HPP #ifndef SLIC3R_OCSG_EXMP_ENGINE_HPP
#define GLSCENE_HPP #define SLIC3R_OCSG_EXMP_ENGINE_HPP_HPP
#include <vector> #include <vector>
#include <memory> #include <memory>
@ -322,21 +322,6 @@ protected:
Vec2i m_size; Vec2i m_size;
bool m_initialized = false; bool m_initialized = false;
CSGSettings m_csgsettings;
struct SceneCache {
vector<shptr<Primitive>> primitives;
vector<Primitive *> primitives_free;
vector<OpenCSG::Primitive *> primitives_csg;
void clear();
shptr<Primitive> add_mesh(const TriangleMesh &mesh);
shptr<Primitive> add_mesh(const TriangleMesh &mesh,
OpenCSG::Operation op,
unsigned covexity);
} m_scene_cache;
shptr<Camera> m_camera; shptr<Camera> m_camera;
FpsCounter m_fps_counter; FpsCounter m_fps_counter;
@ -359,13 +344,8 @@ public:
bool is_initialized() const { return m_initialized; } bool is_initialized() const { return m_initialized; }
const CSGSettings & get_csgsettings() const { return m_csgsettings; }
void apply_csgsettings(const CSGSettings &settings);
void on_scene_updated(const Scene &scene) override;
virtual void clear_screen(); virtual void clear_screen();
virtual void render_scene(); virtual void render_scene() {}
template<class _FpsCounter> void set_fps_counter(_FpsCounter &&fpsc) template<class _FpsCounter> void set_fps_counter(_FpsCounter &&fpsc)
{ {
@ -376,6 +356,33 @@ public:
FpsCounter &get_fps_counter() { return m_fps_counter; } FpsCounter &get_fps_counter() { return m_fps_counter; }
}; };
class CSGDisplay : public Display {
protected:
CSGSettings m_csgsettings;
struct SceneCache {
vector<shptr<Primitive>> primitives;
vector<Primitive *> primitives_free;
vector<OpenCSG::Primitive *> primitives_csg;
void clear();
shptr<Primitive> add_mesh(const TriangleMesh &mesh);
shptr<Primitive> add_mesh(const TriangleMesh &mesh,
OpenCSG::Operation op,
unsigned covexity);
} m_scene_cache;
public:
const CSGSettings & get_csgsettings() const { return m_csgsettings; }
void apply_csgsettings(const CSGSettings &settings);
void render_scene() override;
void on_scene_updated(const Scene &scene) override;
};
class Controller : public std::enable_shared_from_this<Controller>, class Controller : public std::enable_shared_from_this<Controller>,
public MouseInput::Listener, public MouseInput::Listener,
public Scene::Listener public Scene::Listener
@ -425,4 +432,4 @@ public:
}; };
}} // namespace Slic3r::GL }} // namespace Slic3r::GL
#endif // GLSCENE_HPP #endif // SLIC3R_OCSG_EXMP_ENGINE_HPP

View File

@ -2,7 +2,7 @@
#include <utility> #include <utility>
#include <memory> #include <memory>
#include "GLScene.hpp" #include "Engine.hpp"
#include <GL/glew.h> #include <GL/glew.h>
@ -19,6 +19,7 @@
#include <wx/spinctrl.h> #include <wx/spinctrl.h>
#include <wx/msgdlg.h> #include <wx/msgdlg.h>
#include <wx/glcanvas.h> #include <wx/glcanvas.h>
#include <wx/cmdline.h>
#include "libslic3r/Model.hpp" #include "libslic3r/Model.hpp"
#include "libslic3r/Format/3mf.hpp" #include "libslic3r/Format/3mf.hpp"
@ -29,31 +30,47 @@
using namespace Slic3r::GL; using namespace Slic3r::GL;
class Canvas: public wxGLCanvas, public Slic3r::GL::Display class Canvas: public wxGLCanvas
{ {
shptr<wxGLContext> m_context; class OCSGRenderer: public Slic3r::GL::CSGDisplay {
Canvas *m_canvas;
shptr<wxGLContext> m_context;
public:
OCSGRenderer(Canvas *c): m_canvas{c} {
auto ctx = new wxGLContext(m_canvas);
if (!ctx || !ctx->IsOK()) {
wxMessageBox("Could not create OpenGL context.", "Error",
wxOK | wxICON_ERROR);
return;
}
m_context.reset(ctx);
}
void set_active(long w, long h) override
{
m_canvas->SetCurrent(*m_context);
Slic3r::GL::Display::set_active(w, h);
}
wxGLContext * context() { return m_context.get(); }
const wxGLContext * context() const { return m_context.get(); }
void swap_buffers() override { m_canvas->SwapBuffers(); }
~OCSGRenderer() override { m_scene_cache.clear(); }
};
shptr<OCSGRenderer> m_ocsgdisplay = std::make_shared<OCSGRenderer>(this);
shptr<Slic3r::GL::Display> m_display = m_ocsgdisplay;
public: public:
void set_active(long w, long h) override
{
SetCurrent(*m_context);
Slic3r::GL::Display::set_active(w, h);
}
void swap_buffers() override { SwapBuffers(); }
template<class...Args> template<class...Args>
Canvas(Args &&...args): wxGLCanvas(std::forward<Args>(args)...) Canvas(Args &&...args): wxGLCanvas(std::forward<Args>(args)...)
{ {
auto ctx = new wxGLContext(this);
if (!ctx || !ctx->IsOK()) {
wxMessageBox("Could not create OpenGL context.", "Error",
wxOK | wxICON_ERROR);
return;
}
m_context.reset(ctx);
Bind(wxEVT_PAINT, [this](wxPaintEvent &) { Bind(wxEVT_PAINT, [this](wxPaintEvent &) {
// This is required even though dc is not used otherwise. // This is required even though dc is not used otherwise.
wxPaintDC dc(this); wxPaintDC dc(this);
@ -67,16 +84,14 @@ public:
// another canvas is repainted. // another canvas is repainted.
const wxSize ClientSize = GetClientSize(); const wxSize ClientSize = GetClientSize();
set_screen_size(ClientSize.x, ClientSize.y); m_display->set_screen_size(ClientSize.x, ClientSize.y);
// repaint();
}); });
} }
~Canvas() override shptr<Slic3r::GL::Display> get_display() const { return m_display; }
{ void set_display(shptr<Slic3r::GL::Display> d) { m_display = d; }
m_scene_cache.clear();
m_context.reset(); shptr<Slic3r::GL::CSGDisplay> get_ocsg_display() const { return m_ocsgdisplay; }
}
}; };
enum EEvents { LCLK_U, RCLK_U, LCLK_D, RCLK_D, DDCLK, SCRL, MV }; enum EEvents { LCLK_U, RCLK_U, LCLK_D, RCLK_D, DDCLK, SCRL, MV };
@ -204,7 +219,7 @@ class MyFrame: public wxFrame
uqptr<SLAJob> m_ui_job; uqptr<SLAJob> m_ui_job;
public: public:
MyFrame(const wxString& title, const wxPoint& pos, const wxSize& size); MyFrame(const wxString& title, const wxPoint& pos, const wxSize& size, const Slic3r::GL::CSGSettings &settings);
void load_model(const std::string &fname) { void load_model(const std::string &fname) {
m_ui_job = std::make_unique<SLAJob>(this, fname); m_ui_job = std::make_unique<SLAJob>(this, fname);
@ -224,29 +239,76 @@ public:
} }
} }
Canvas * canvas() { return m_canvas.get(); }
const Canvas * canvas() const { return m_canvas.get(); }
void bind_canvas_events(MouseInput &msinput); void bind_canvas_events(MouseInput &msinput);
}; };
static const std::vector<wxString> CSG_ALGS = {"Auto", "Goldfeather", "SCS"};
static const std::vector<wxString> CSG_DEPTH = {"Off", "OcclusionQuery", "On"};
static const std::vector<wxString> CSG_OPT = { "Default", "ForceOn", "On", "Off" };
class App : public wxApp { class App : public wxApp {
MyFrame *m_frame; MyFrame *m_frame = nullptr;
public: public:
bool OnInit() override { bool OnInit() override {
std::string fname; wxCmdLineParser parser(argc, argv);
std::string command;
if (argc > 2) { parser.AddOption("p", "play", "play back file", wxCMD_LINE_VAL_STRING, wxCMD_LINE_PARAM_OPTIONAL);
command = argv[1]; parser.AddOption("a", "algorithm", "OpenCSG algorithm [Auto|Goldfeather|SCS]", wxCMD_LINE_VAL_STRING, wxCMD_LINE_PARAM_OPTIONAL);
fname = argv[2]; parser.AddOption("d", "depth", "OpenCSG depth strategy [Off|OcclusionQuery|On]", wxCMD_LINE_VAL_STRING, wxCMD_LINE_PARAM_OPTIONAL);
} parser.AddOption("o", "optimization", "OpenCSG optimization strategy [Default|ForceOn|On|Off]", wxCMD_LINE_VAL_STRING, wxCMD_LINE_PARAM_OPTIONAL);
parser.AddOption("c", "convexity", "OpenCSG convexity parameter for generic meshes", wxCMD_LINE_VAL_NUMBER, wxCMD_LINE_PARAM_OPTIONAL);
m_frame = new MyFrame("PrusaSlicer OpenCSG Demo", wxDefaultPosition, wxSize(1024, 768)); parser.AddSwitch("", "disable-csg", "Disable csg rendering", wxCMD_LINE_PARAM_OPTIONAL);
if (command == "play") { parser.Parse();
wxString fname;
bool is_play = parser.Found("play", &fname);
wxString alg;
parser.Found("algorithm", &alg);
wxString depth;
parser.Found("depth", &depth);
wxString opt;
parser.Found("optimization", &opt);
long convexity = 1;
parser.Found("convexity", &convexity);
bool csg_off = parser.Found("disable-csg");
auto get_idx = [](const wxString &a, const std::vector<wxString> &v) {
auto it = std::find(v.begin(), v.end(), a.ToStdString());
return it - v.begin();
};
Slic3r::GL::CSGSettings settings;
if (auto a = get_idx(alg, CSG_ALGS) < OpenCSG::AlgorithmUnused)
settings.set_algo(OpenCSG::Algorithm(a));
if (auto a = get_idx(depth, CSG_DEPTH) < OpenCSG::DepthComplexityAlgorithmUnused)
settings.set_depth_algo(OpenCSG::DepthComplexityAlgorithm(a));
if (auto a = get_idx(opt, CSG_OPT) < OpenCSG::OptimizationUnused)
settings.set_optimization(OpenCSG::Optimization(a));
settings.set_convexity(unsigned(convexity));
settings.enable_csg(!csg_off);
m_frame = new MyFrame("PrusaSlicer OpenCSG Demo", wxDefaultPosition, wxSize(1024, 768), settings);
if (is_play) {
m_frame->Show( true ); m_frame->Show( true );
m_frame->play_back_mouse(fname); m_frame->play_back_mouse(fname.ToStdString());
m_frame->Close( true ); m_frame->Close( true );
} else m_frame->Show( true ); } else m_frame->Show( true );
return true; return true;
@ -255,7 +317,8 @@ public:
wxIMPLEMENT_APP(App); wxIMPLEMENT_APP(App);
MyFrame::MyFrame(const wxString &title, const wxPoint &pos, const wxSize &size): MyFrame::MyFrame(const wxString &title, const wxPoint &pos, const wxSize &size,
const Slic3r::GL::CSGSettings &settings):
wxFrame(nullptr, wxID_ANY, title, pos, size) wxFrame(nullptr, wxID_ANY, title, pos, size)
{ {
wxMenu *menuFile = new wxMenu; wxMenu *menuFile = new wxMenu;
@ -289,7 +352,10 @@ MyFrame::MyFrame(const wxString &title, const wxPoint &pos, const wxSize &size):
m_canvas = std::make_shared<Canvas>(this, wxID_ANY, attribList, m_canvas = std::make_shared<Canvas>(this, wxID_ANY, attribList,
wxDefaultPosition, wxDefaultSize, wxDefaultPosition, wxDefaultSize,
wxWANTS_CHARS | wxFULL_REPAINT_ON_RESIZE); wxWANTS_CHARS | wxFULL_REPAINT_ON_RESIZE);
m_ctl->add_display(m_canvas);
m_canvas->get_ocsg_display()->apply_csgsettings(settings);
m_ctl->add_display(m_canvas->get_display());
wxPanel *control_panel = new wxPanel(this); wxPanel *control_panel = new wxPanel(this);
@ -310,7 +376,7 @@ MyFrame::MyFrame(const wxString &title, const wxPoint &pos, const wxSize &size):
console_sizer->Add(csg_toggle, 0, wxALL | wxEXPAND, 5); console_sizer->Add(csg_toggle, 0, wxALL | wxEXPAND, 5);
auto add_combobox = [control_panel, console_sizer] auto add_combobox = [control_panel, console_sizer]
(const wxString &label, std::vector<wxString> &&list) (const wxString &label, const std::vector<wxString> &list)
{ {
auto widget = new wxComboBox(control_panel, wxID_ANY, list[0], auto widget = new wxComboBox(control_panel, wxID_ANY, list[0],
wxDefaultPosition, wxDefaultSize, wxDefaultPosition, wxDefaultSize,
@ -343,14 +409,14 @@ MyFrame::MyFrame(const wxString &title, const wxPoint &pos, const wxSize &size):
auto convexity_spin = add_spinctl("Convexity", CSGSettings::DEFAULT_CONVEXITY, 0, 100); auto convexity_spin = add_spinctl("Convexity", CSGSettings::DEFAULT_CONVEXITY, 0, 100);
auto alg_select = add_combobox("Algorithm", {"Auto", "Goldfeather", "SCS"}); auto alg_select = add_combobox("Algorithm", CSG_ALGS);
auto depth_select = add_combobox("Depth Complexity", {"Off", "OcclusionQuery", "On"}); auto depth_select = add_combobox("Depth Complexity", CSG_DEPTH);
auto optimization_select = add_combobox("Optimization", { "Default", "ForceOn", "On", "Off" }); auto optimization_select = add_combobox("Optimization", CSG_OPT);
depth_select->Disable(); depth_select->Disable();
auto fpstext = new wxStaticText(control_panel, wxID_ANY, ""); auto fpstext = new wxStaticText(control_panel, wxID_ANY, "");
console_sizer->Add(fpstext, 0, wxALL, 5); console_sizer->Add(fpstext, 0, wxALL, 5);
m_canvas->get_fps_counter().add_listener([fpstext](double fps) { m_canvas->get_ocsg_display()->get_fps_counter().add_listener([fpstext](double fps) {
fpstext->SetLabel(wxString::Format("fps: %.2f", fps) ); fpstext->SetLabel(wxString::Format("fps: %.2f", fps) );
}); });
@ -367,6 +433,13 @@ MyFrame::MyFrame(const wxString &title, const wxPoint &pos, const wxSize &size):
sizer->Add(control_panel, 0, wxEXPAND); sizer->Add(control_panel, 0, wxEXPAND);
SetSizer(sizer); SetSizer(sizer);
if (settings.get_algo() > 0) depth_select->Enable(true);
alg_select->SetSelection(settings.get_algo());
depth_select->SetSelection(settings.get_depth_algo());
optimization_select->SetSelection(settings.get_optimization());
convexity_spin->SetValue(int(settings.get_convexity()));
csg_toggle->SetValue(settings.is_enabled());
Bind(wxEVT_CLOSE_WINDOW, [this](wxCloseEvent &){ Bind(wxEVT_CLOSE_WINDOW, [this](wxCloseEvent &){
RemoveChild(m_canvas.get()); RemoveChild(m_canvas.get());
m_canvas.reset(); m_canvas.reset();
@ -384,7 +457,7 @@ MyFrame::MyFrame(const wxString &title, const wxPoint &pos, const wxSize &size):
Bind(wxEVT_SHOW, [this, ms_toggle](wxShowEvent &) { Bind(wxEVT_SHOW, [this, ms_toggle](wxShowEvent &) {
const wxSize ClientSize = GetClientSize(); const wxSize ClientSize = GetClientSize();
m_canvas->set_active(ClientSize.x, ClientSize.y); m_canvas->get_display()->set_active(ClientSize.x, ClientSize.y);
enable_multisampling(ms_toggle->GetValue()); enable_multisampling(ms_toggle->GetValue());
}); });
@ -394,13 +467,13 @@ MyFrame::MyFrame(const wxString &title, const wxPoint &pos, const wxSize &size):
ms_toggle->Bind(wxEVT_TOGGLEBUTTON, [this, ms_toggle](wxCommandEvent &){ ms_toggle->Bind(wxEVT_TOGGLEBUTTON, [this, ms_toggle](wxCommandEvent &){
enable_multisampling(ms_toggle->GetValue()); enable_multisampling(ms_toggle->GetValue());
m_canvas->repaint(); m_canvas->get_display()->repaint();
}); });
csg_toggle->Bind(wxEVT_TOGGLEBUTTON, [this, csg_toggle](wxCommandEvent &){ csg_toggle->Bind(wxEVT_TOGGLEBUTTON, [this, csg_toggle](wxCommandEvent &){
CSGSettings settings = m_canvas->get_csgsettings(); CSGSettings settings = m_canvas->get_ocsg_display()->get_csgsettings();
settings.enable_csg(csg_toggle->GetValue()); settings.enable_csg(csg_toggle->GetValue());
m_canvas->apply_csgsettings(settings); m_canvas->get_ocsg_display()->apply_csgsettings(settings);
}); });
alg_select->Bind(wxEVT_COMBOBOX, alg_select->Bind(wxEVT_COMBOBOX,
@ -408,33 +481,33 @@ MyFrame::MyFrame(const wxString &title, const wxPoint &pos, const wxSize &size):
{ {
int sel = alg_select->GetSelection(); int sel = alg_select->GetSelection();
depth_select->Enable(sel > 0); depth_select->Enable(sel > 0);
CSGSettings settings = m_canvas->get_csgsettings(); CSGSettings settings = m_canvas->get_ocsg_display()->get_csgsettings();
settings.set_algo(OpenCSG::Algorithm(sel)); settings.set_algo(OpenCSG::Algorithm(sel));
m_canvas->apply_csgsettings(settings); m_canvas->get_ocsg_display()->apply_csgsettings(settings);
}); });
depth_select->Bind(wxEVT_COMBOBOX, [this, depth_select](wxCommandEvent &) { depth_select->Bind(wxEVT_COMBOBOX, [this, depth_select](wxCommandEvent &) {
int sel = depth_select->GetSelection(); int sel = depth_select->GetSelection();
CSGSettings settings = m_canvas->get_csgsettings(); CSGSettings settings = m_canvas->get_ocsg_display()->get_csgsettings();
settings.set_depth_algo(OpenCSG::DepthComplexityAlgorithm(sel)); settings.set_depth_algo(OpenCSG::DepthComplexityAlgorithm(sel));
m_canvas->apply_csgsettings(settings); m_canvas->get_ocsg_display()->apply_csgsettings(settings);
}); });
optimization_select->Bind(wxEVT_COMBOBOX, optimization_select->Bind(wxEVT_COMBOBOX,
[this, optimization_select](wxCommandEvent &) { [this, optimization_select](wxCommandEvent &) {
int sel = optimization_select->GetSelection(); int sel = optimization_select->GetSelection();
CSGSettings settings = m_canvas->get_csgsettings(); CSGSettings settings = m_canvas->get_ocsg_display()->get_csgsettings();
settings.set_optimization(OpenCSG::Optimization(sel)); settings.set_optimization(OpenCSG::Optimization(sel));
m_canvas->apply_csgsettings(settings); m_canvas->get_ocsg_display()->apply_csgsettings(settings);
}); });
convexity_spin->Bind(wxEVT_SPINCTRL, [this, convexity_spin](wxSpinEvent &) { convexity_spin->Bind(wxEVT_SPINCTRL, [this, convexity_spin](wxSpinEvent &) {
CSGSettings settings = m_canvas->get_csgsettings(); CSGSettings settings = m_canvas->get_ocsg_display()->get_csgsettings();
int c = convexity_spin->GetValue(); int c = convexity_spin->GetValue();
if (c > 0) { if (c > 0) {
settings.set_convexity(unsigned(c)); settings.set_convexity(unsigned(c));
m_canvas->apply_csgsettings(settings); m_canvas->get_ocsg_display()->apply_csgsettings(settings);
} }
}); });
@ -445,7 +518,7 @@ MyFrame::MyFrame(const wxString &title, const wxPoint &pos, const wxSize &size):
} }
if (record_btn->GetValue()) { if (record_btn->GetValue()) {
if (m_canvas->camera()) reset(*m_canvas->camera()); if (auto c = m_canvas->get_display()->camera()) reset(*c);
m_ctl->on_scene_updated(*m_scene); m_ctl->on_scene_updated(*m_scene);
m_mouse.record(true); m_mouse.record(true);
} else { } else {
@ -468,7 +541,7 @@ MyFrame::MyFrame(const wxString &title, const wxPoint &pos, const wxSize &size):
// Do the repaint continuously // Do the repaint continuously
m_canvas->Bind(wxEVT_IDLE, [this](wxIdleEvent &evt) { m_canvas->Bind(wxEVT_IDLE, [this](wxIdleEvent &evt) {
if (m_canvas->IsShown()) m_canvas->repaint(); if (m_canvas->IsShown()) m_canvas->get_display()->repaint();
evt.RequestMore(); evt.RequestMore();
}); });