From bb3b39016fa9381506e1594cd46f361c6d348fd6 Mon Sep 17 00:00:00 2001 From: tamasmeszaros Date: Mon, 16 Dec 2019 18:49:44 +0100 Subject: [PATCH 1/2] Add ctl and fix applying opencsg params on the fly. --- sandboxes/opencsg/Canvas.hpp | 52 --------------- sandboxes/opencsg/GLScene.cpp | 63 ++++++++++-------- sandboxes/opencsg/GLScene.hpp | 122 ++++++++++++++++++++++------------ sandboxes/opencsg/main.cpp | 122 +++++++++++++++++++++++++--------- 4 files changed, 205 insertions(+), 154 deletions(-) diff --git a/sandboxes/opencsg/Canvas.hpp b/sandboxes/opencsg/Canvas.hpp index 17fd8f0440..4245799458 100644 --- a/sandboxes/opencsg/Canvas.hpp +++ b/sandboxes/opencsg/Canvas.hpp @@ -40,58 +40,6 @@ public: } m_context.reset(ctx); - - Bind( - wxEVT_MOUSEWHEEL, - [this](wxMouseEvent &evt) { - on_scroll(evt.GetWheelRotation(), evt.GetWheelDelta(), - evt.GetWheelAxis() == wxMOUSE_WHEEL_VERTICAL ? - Slic3r::GL::MouseInput::waVertical : - Slic3r::GL::MouseInput::waHorizontal); - }, - GetId()); - - Bind( - wxEVT_MOTION, - [this](wxMouseEvent &evt) { - on_moved_to(evt.GetPosition().x, evt.GetPosition().y); - }, - GetId()); - - Bind( - wxEVT_RIGHT_DOWN, - [this](wxMouseEvent & /*evt*/) { on_right_click_down(); }, - GetId()); - - Bind( - wxEVT_RIGHT_UP, - [this](wxMouseEvent & /*evt*/) { on_right_click_up(); }, - GetId()); - - Bind( - wxEVT_LEFT_DOWN, - [this](wxMouseEvent & /*evt*/) { on_left_click_down(); }, - GetId()); - - Bind( - wxEVT_LEFT_UP, - [this](wxMouseEvent & /*evt*/) { on_left_click_up(); }, - GetId()); - - Bind(wxEVT_PAINT, [this](wxPaintEvent &) { - // This is required even though dc is not used otherwise. - wxPaintDC dc(this); - - // Set the OpenGL viewport according to the client size of this - // canvas. This is done here rather than in a wxSizeEvent handler - // because our OpenGL rendering context (and thus viewport setting) is - // used with multiple canvases: If we updated the viewport in the - // wxSizeEvent handler, changing the size of one canvas causes a - // viewport setting that is wrong when next another canvas is - // repainted. - const wxSize ClientSize = GetClientSize(); - repaint(ClientSize.x, ClientSize.y); - }, GetId()); } }; diff --git a/sandboxes/opencsg/GLScene.cpp b/sandboxes/opencsg/GLScene.cpp index 02a4b79914..1cfccb3b19 100644 --- a/sandboxes/opencsg/GLScene.cpp +++ b/sandboxes/opencsg/GLScene.cpp @@ -133,7 +133,7 @@ void Scene::set_print(uqptr &&print) m_print = std::move(print); // Notify displays - call(&Display::on_scene_updated, m_displays); + call(&Listener::on_scene_updated, m_listeners, *this); } BoundingBoxf3 Scene::get_bounding_box() const @@ -383,13 +383,18 @@ void Display::set_active(long width, long height) m_camera->set_screen(width, height); } -void Display::repaint(long width, long height) +void Display::set_screen_size(long width, long height) { if (m_size.x() != width || m_size.y() != height) m_camera->set_screen(width, height); m_size = {width, height}; + repaint(); +} + +void Display::repaint() +{ clear_screen(); m_camera->view(); @@ -400,23 +405,34 @@ void Display::repaint(long width, long height) swap_buffers(); } -void Display::on_scroll(long v, long d, MouseInput::WheelAxis wa) +void Controller::on_scene_updated(const Scene &scene) +{ + const SLAPrint *print = scene.get_print(); + if (!print) return; + + auto bb = scene.get_bounding_box(); + double d = std::max(std::max(bb.size().x(), bb.size().y()), bb.size().z()); + m_wheel_pos = long(2 * d); + + call_cameras(&Camera::set_zoom, m_wheel_pos); + call(&Display::on_scene_updated, m_displays, scene); +} + +void Controller::on_scroll(long v, long d, MouseInput::WheelAxis /*wa*/) { m_wheel_pos += v / d; - m_camera->set_zoom(m_wheel_pos); - - m_scene->on_scroll(v, d, wa); - - repaint(m_size.x(), m_size.y()); + call_cameras(&Camera::set_zoom, m_wheel_pos); + call(&Display::repaint, m_displays); } -void Display::on_moved_to(long x, long y) +void Controller::on_moved_to(long x, long y) { if (m_left_btn) { - m_camera->rotate((Vec2i{x, y} - m_mouse_pos).cast()); - repaint(); + call_cameras(&Camera::rotate, (Vec2i{x, y} - m_mouse_pos).cast()); + call(&Display::repaint, m_displays); } + m_mouse_pos = {x, y}; } @@ -424,30 +440,27 @@ void Display::apply_csgsettings(const CSGSettings &settings) { using namespace OpenCSG; - bool update = m_csgsettings.get_convexity() != settings.get_convexity(); + bool needupdate = m_csgsettings.get_convexity() != settings.get_convexity(); m_csgsettings = settings; setOption(AlgorithmSetting, m_csgsettings.get_algo()); setOption(DepthComplexitySetting, m_csgsettings.get_depth_algo()); setOption(DepthBoundsOptimization, m_csgsettings.get_optimization()); - if (update) on_scene_updated(); + if (needupdate) { + for (OpenCSG::Primitive * p : m_scene_cache.primitives_csg) + if (p->getConvexity() > 1) + p->setConvexity(m_csgsettings.get_convexity()); + } repaint(); } -void Display::on_scene_updated() +void Display::on_scene_updated(const Scene &scene) { - const SLAPrint *print = m_scene->get_print(); + const SLAPrint *print = scene.get_print(); if (!print) return; - { - auto bb = m_scene->get_bounding_box(); - double d = std::max(std::max(bb.size().x(), bb.size().y()), bb.size().z()); - m_wheel_pos = long(2 * d); - m_camera->set_zoom(m_wheel_pos); - } - m_scene_cache.clear(); for (const SLAPrintObject *po : print->objects()) { @@ -499,12 +512,6 @@ void Display::on_scene_updated() repaint(); } -void Display::set_scene(shptr scene) -{ - m_scene = scene; - m_scene->add_display(shared_from_this()); -} - void Camera::view() { glMatrixMode(GL_MODELVIEW); diff --git a/sandboxes/opencsg/GLScene.hpp b/sandboxes/opencsg/GLScene.hpp index a127ab90be..5a4afb396b 100644 --- a/sandboxes/opencsg/GLScene.hpp +++ b/sandboxes/opencsg/GLScene.hpp @@ -223,8 +223,8 @@ public: private: OpenCSG::Algorithm m_csgalg = OpenCSG::Algorithm::Automatic; - OpenCSG::DepthComplexityAlgorithm m_depth_algo = OpenCSG::DepthComplexityAlgorithm::NoDepthComplexitySampling; - OpenCSG::Optimization m_optim = OpenCSG::Optimization::OptimizationDefault; + OpenCSG::DepthComplexityAlgorithm m_depth_algo = OpenCSG::NoDepthComplexitySampling; + OpenCSG::Optimization m_optim = OpenCSG::OptimizationDefault; bool m_enable = true; unsigned int m_convexity = DEFAULT_CONVEXITY; @@ -244,21 +244,44 @@ public: unsigned get_convexity() const { return m_convexity; } void set_convexity(unsigned c) { m_convexity = c; } }; - -class Display : public std::enable_shared_from_this, - public MouseInput::Listener + +class Scene +{ + uqptr m_print; +public: + + class Listener { + public: + virtual ~Listener() = default; + virtual void on_scene_updated(const Scene &scene) = 0; + }; + + Scene(); + ~Scene(); + + void set_print(uqptr &&print); + const SLAPrint * get_print() const { return m_print.get(); } + + BoundingBoxf3 get_bounding_box() const; + + void add_listener(shptr listener) + { + m_listeners.emplace_back(listener); + cleanup(m_listeners); + } + +private: + Collection> m_listeners; +}; + +class Display : public Scene::Listener { protected: - shptr m_scene; - long m_wheel_pos = 0; - Vec2i m_mouse_pos, m_mouse_pos_rprev, m_mouse_pos_lprev; Vec2i m_size; - bool m_initialized = false, m_left_btn = false, m_right_btn = false; + bool m_initialized = false; CSGSettings m_csgsettings; - shptr m_camera; - struct SceneCache { Collection> primitives; Collection primitives_free; @@ -272,64 +295,79 @@ protected: unsigned covexity); } m_scene_cache; + shptr m_camera; + public: - Display(shptr scene = nullptr, shptr camera = nullptr) - : m_scene(scene) - , m_camera(camera ? camera : std::make_shared()) + + explicit Display(shptr camera = nullptr) + : m_camera(camera ? camera : std::make_shared()) {} - + + Camera * camera() { return m_camera.get(); } + virtual void swap_buffers() = 0; - virtual void set_active(long width, long height); + virtual void set_screen_size(long width, long height); + Vec2i get_screen_size() const { return m_size; } - virtual void repaint(long width, long height); - void repaint() { repaint(m_size.x(), m_size.y()); } - - void set_scene(shptr scene); - shptr get_scene() { return m_scene; } + virtual void repaint(); bool is_initialized() const { return m_initialized; } - void on_scroll(long v, long d, MouseInput::WheelAxis wa) override; - void on_moved_to(long x, long y) override; - void on_left_click_down() override { m_left_btn = true; } - void on_left_click_up() override { m_left_btn = false; } - void on_right_click_down() override { m_right_btn = true; } - void on_right_click_up() override { m_right_btn = false; } - - void move_clip_plane(double z) { m_camera->set_clip_z(z); } - const CSGSettings & get_csgsettings() const { return m_csgsettings; } void apply_csgsettings(const CSGSettings &settings); - virtual void on_scene_updated(); + void on_scene_updated(const Scene &scene) override; + virtual void clear_screen(); virtual void render_scene(); }; -class Scene: public MouseInput::Listener +class Controller : public std::enable_shared_from_this, + public MouseInput::Listener, + public Scene::Listener { - uqptr m_print; + long m_wheel_pos = 0; + Vec2i m_mouse_pos, m_mouse_pos_rprev, m_mouse_pos_lprev; + bool m_left_btn = false, m_right_btn = false; + + shptr m_scene; + Collection> m_displays; + + template + void call_cameras(F &&f, Args&&... args) { + for (wkptr &l : m_displays) + if (auto disp = l.lock()) if (disp->camera()) + (disp->camera()->*f)(std::forward(args)...); + } + public: - Scene(); - ~Scene(); + void set_scene(shptr scene) + { + m_scene = scene; + m_scene->add_listener(shared_from_this()); + } + const Scene * get_scene() const { return m_scene.get(); } + void add_display(shptr disp) { m_displays.emplace_back(disp); cleanup(m_displays); } - void set_print(uqptr &&print); - const SLAPrint * get_print() const { return m_print.get(); } + void on_scene_updated(const Scene &scene) override; - BoundingBoxf3 get_bounding_box() const; + void on_left_click_down() override { m_left_btn = true; } + void on_left_click_up() override { m_left_btn = false; } + void on_right_click_down() override { m_right_btn = true; } + void on_right_click_up() override { m_right_btn = false; } + + void on_scroll(long v, long d, MouseInput::WheelAxis wa) override; + void on_moved_to(long x, long y) override; -private: - - Collection> m_displays; + void move_clip_plane(double z) { call_cameras(&Camera::set_clip_z, z); } }; - }} // namespace Slic3r::GL #endif // GLSCENE_HPP diff --git a/sandboxes/opencsg/main.cpp b/sandboxes/opencsg/main.cpp index ddd4bf33ef..d01687428e 100644 --- a/sandboxes/opencsg/main.cpp +++ b/sandboxes/opencsg/main.cpp @@ -31,49 +31,31 @@ using namespace Slic3r::GL; class MyFrame: public wxFrame { - std::shared_ptr m_canvas; - std::shared_ptr m_stbar; - std::unique_ptr m_ui_job; + shptr m_scene; // Model + shptr m_canvas; // View + shptr m_ctl; // Controller + + shptr m_stbar; + uqptr m_ui_job; class SLAJob: public Slic3r::GUI::Job { MyFrame *m_parent; std::unique_ptr m_print; std::string m_fname; public: - - SLAJob(MyFrame *frame, const std::string &fname) + SLAJob(MyFrame *frame, const std::string &fname) : Slic3r::GUI::Job{frame->m_stbar} , m_parent{frame} , m_fname{fname} - { - } - - void process() override - { - using Status = Slic3r::PrintBase::SlicingStatus; - - Slic3r::DynamicPrintConfig cfg; - auto model = Slic3r::Model::read_from_file(m_fname, &cfg); - - m_print = std::make_unique(); - m_print->apply(model, cfg); - - Slic3r::PrintBase::TaskParams params; - params.to_object_step = Slic3r::slaposHollowing; - m_print->set_task(params); - - m_print->set_status_callback([this](const Status &status) { - update_status(status.percent, status.text); - }); - - m_print->process(); - } + {} + + void process() override; protected: void finalize() override { - m_parent->m_canvas->get_scene()->set_print(std::move(m_print)); + m_parent->m_scene->set_print(std::move(m_print)); m_parent->m_stbar->set_status_text( wxString::Format("Model %s loaded.", m_fname)); } @@ -84,6 +66,8 @@ public: private: + void bind_canvas_events_to_controller(); + void OnExit(wxCommandEvent& /*event*/) { RemoveChild(m_canvas.get()); @@ -108,7 +92,8 @@ private: const wxSize ClientSize = GetClientSize(); m_canvas->set_active(ClientSize.x, ClientSize.y); - m_canvas->repaint(ClientSize.x, ClientSize.y); + m_canvas->set_screen_size(ClientSize.x, ClientSize.y); + m_canvas->repaint(); // Do the repaint continuously Bind(wxEVT_IDLE, [this](wxIdleEvent &evt) { @@ -159,9 +144,14 @@ MyFrame::MyFrame(const wxString &title, const wxPoint &pos, const wxSize &size): WX_GL_MIN_ALPHA, 8, WX_GL_DEPTH_SIZE, 8, WX_GL_STENCIL_SIZE, 8, WX_GL_SAMPLE_BUFFERS, GL_TRUE, WX_GL_SAMPLES, 4, 0}; + m_scene = std::make_shared(); + m_ctl = std::make_shared(); + m_ctl->set_scene(m_scene); + m_canvas = std::make_shared(this, wxID_ANY, attribList, wxDefaultPosition, wxDefaultSize, wxWANTS_CHARS | wxFULL_REPAINT_ON_RESIZE); + m_ctl->add_display(m_canvas); wxPanel *control_panel = new wxPanel(this); auto controlsizer = new wxBoxSizer(wxHORIZONTAL); @@ -234,7 +224,7 @@ MyFrame::MyFrame(const wxString &title, const wxPoint &pos, const wxSize &size): Bind(wxEVT_SHOW, &MyFrame::OnShown, this, GetId()); Bind(wxEVT_SLIDER, [this, slider](wxCommandEvent &) { - m_canvas->move_clip_plane(double(slider->GetValue())); + m_ctl->move_clip_plane(double(slider->GetValue())); }); ms_toggle->Bind(wxEVT_TOGGLEBUTTON, [this, ms_toggle](wxCommandEvent &){ @@ -283,5 +273,73 @@ MyFrame::MyFrame(const wxString &title, const wxPoint &pos, const wxSize &size): } }); - m_canvas->set_scene(std::make_shared()); + bind_canvas_events_to_controller(); +} + +void MyFrame::bind_canvas_events_to_controller() +{ + m_canvas->Bind(wxEVT_MOUSEWHEEL, [this](wxMouseEvent &evt) { + m_ctl->on_scroll(evt.GetWheelRotation(), evt.GetWheelDelta(), + evt.GetWheelAxis() == wxMOUSE_WHEEL_VERTICAL ? + Slic3r::GL::MouseInput::waVertical : + Slic3r::GL::MouseInput::waHorizontal); + }); + + m_canvas->Bind(wxEVT_MOTION, [this](wxMouseEvent &evt) { + m_ctl->on_moved_to(evt.GetPosition().x, evt.GetPosition().y); + }); + + m_canvas->Bind(wxEVT_RIGHT_DOWN, [this](wxMouseEvent & /*evt*/) { + m_ctl->on_right_click_down(); + }); + + m_canvas->Bind(wxEVT_RIGHT_UP, [this](wxMouseEvent & /*evt*/) { + m_ctl->on_right_click_up(); + }); + + m_canvas->Bind(wxEVT_LEFT_DOWN, [this](wxMouseEvent & /*evt*/) { + m_ctl->on_left_click_down(); + }); + + m_canvas->Bind(wxEVT_LEFT_UP, [this](wxMouseEvent & /*evt*/) { + m_ctl->on_left_click_up(); + }); + + m_canvas->Bind(wxEVT_PAINT, [this](wxPaintEvent &) { + // This is required even though dc is not used otherwise. + wxPaintDC dc(this); + + // Set the OpenGL viewport according to the client size of this + // canvas. This is done here rather than in a wxSizeEvent handler + // because our OpenGL rendering context (and thus viewport setting) is + // used with multiple canvases: If we updated the viewport in the + // wxSizeEvent handler, changing the size of one canvas causes a + // viewport setting that is wrong when next another canvas is + // repainted. + const wxSize ClientSize = m_canvas->GetClientSize(); + + m_canvas->set_screen_size(ClientSize.x, ClientSize.y); + m_canvas->repaint(); + }); +} + +void MyFrame::SLAJob::process() +{ + using Status = Slic3r::PrintBase::SlicingStatus; + + Slic3r::DynamicPrintConfig cfg; + auto model = Slic3r::Model::read_from_file(m_fname, &cfg); + + m_print = std::make_unique(); + m_print->apply(model, cfg); + + Slic3r::PrintBase::TaskParams params; + params.to_object_step = Slic3r::slaposHollowing; + m_print->set_task(params); + + m_print->set_status_callback([this](const Status &status) { + update_status(status.percent, status.text); + }); + + m_print->process(); } From 695950b2e6f9ae534c5568b52500c643d10cb257 Mon Sep 17 00:00:00 2001 From: tamasmeszaros Date: Tue, 17 Dec 2019 10:19:46 +0100 Subject: [PATCH 2/2] further simplification --- sandboxes/opencsg/CMakeLists.txt | 2 +- sandboxes/opencsg/Canvas.hpp | 48 -------------------------------- sandboxes/opencsg/GLScene.hpp | 25 +++++++++-------- sandboxes/opencsg/main.cpp | 29 ++++++++++++++++++- 4 files changed, 42 insertions(+), 62 deletions(-) delete mode 100644 sandboxes/opencsg/Canvas.hpp diff --git a/sandboxes/opencsg/CMakeLists.txt b/sandboxes/opencsg/CMakeLists.txt index 9a216a7dc1..651fbe82f7 100644 --- a/sandboxes/opencsg/CMakeLists.txt +++ b/sandboxes/opencsg/CMakeLists.txt @@ -2,7 +2,7 @@ cmake_minimum_required(VERSION 3.0) project(OpenCSG-example) -add_executable(opencsg_example main.cpp GLScene.hpp GLScene.cpp Canvas.hpp +add_executable(opencsg_example main.cpp GLScene.hpp GLScene.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.cpp) diff --git a/sandboxes/opencsg/Canvas.hpp b/sandboxes/opencsg/Canvas.hpp deleted file mode 100644 index 4245799458..0000000000 --- a/sandboxes/opencsg/Canvas.hpp +++ /dev/null @@ -1,48 +0,0 @@ -#ifndef CANVAS_HPP -#define CANVAS_HPP - -#include - -// For compilers that support precompilation, includes "wx/wx.h". -#include -#ifndef WX_PRECOMP -#include -#endif - -#include -#include - -#include "GLScene.hpp" - -namespace Slic3r { namespace GL { - -class Canvas: public wxGLCanvas, public Slic3r::GL::Display -{ - std::unique_ptr m_context; -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 - Canvas(Args &&...args): wxGLCanvas(std::forward(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); - } -}; - -}} // namespace Slic3r::GL - -#endif // CANVAS_HPP diff --git a/sandboxes/opencsg/GLScene.hpp b/sandboxes/opencsg/GLScene.hpp index 5a4afb396b..68cc59b01c 100644 --- a/sandboxes/opencsg/GLScene.hpp +++ b/sandboxes/opencsg/GLScene.hpp @@ -21,16 +21,16 @@ template using uqptr = std::unique_ptr; template using wkptr = std::weak_ptr; template> -using Collection = std::vector; +using vector = std::vector; -template void cleanup(Collection> &listeners) { +template void cleanup(vector> &listeners) { auto it = std::remove_if(listeners.begin(), listeners.end(), [](auto &l) { return !l.lock(); }); listeners.erase(it, listeners.end()); } template -void call(F &&f, Collection> &listeners, Args&&... args) { +void call(F &&f, vector> &listeners, Args&&... args) { for (auto &l : listeners) if (auto p = l.lock()) ((p.get())->*f)(std::forward(args)...); } @@ -57,7 +57,7 @@ public: }; private: - Collection> m_listeners; + vector> m_listeners; public: virtual ~MouseInput() = default; @@ -104,9 +104,9 @@ public: // Vertices and their normals, interleaved to be used by void // glInterleavedArrays(GL_N3F_V3F, 0, x) - Collection vertices_and_normals_interleaved; - Collection triangle_indices; - Collection quad_indices; + vector vertices_and_normals_interleaved; + vector triangle_indices; + vector quad_indices; // When the geometry data is loaded into the graphics card as Vertex // Buffer Objects, the above mentioned std::vectors are cleared and the @@ -271,7 +271,7 @@ public: } private: - Collection> m_listeners; + vector> m_listeners; }; class Display : public Scene::Listener @@ -283,9 +283,9 @@ protected: CSGSettings m_csgsettings; struct SceneCache { - Collection> primitives; - Collection primitives_free; - Collection primitives_csg; + vector> primitives; + vector primitives_free; + vector primitives_csg; void clear(); @@ -332,8 +332,9 @@ class Controller : public std::enable_shared_from_this, bool m_left_btn = false, m_right_btn = false; shptr m_scene; - Collection> m_displays; + vector> m_displays; + // Call a method of Camera on all the cameras of the attached displays template void call_cameras(F &&f, Args&&... args) { for (wkptr &l : m_displays) diff --git a/sandboxes/opencsg/main.cpp b/sandboxes/opencsg/main.cpp index d01687428e..c2f8a74aa1 100644 --- a/sandboxes/opencsg/main.cpp +++ b/sandboxes/opencsg/main.cpp @@ -15,9 +15,9 @@ #include #include #include +#include #include -#include "Canvas.hpp" #include "GLScene.hpp" #include "libslic3r/Model.hpp" @@ -29,6 +29,33 @@ using namespace Slic3r::GL; +class Canvas: public wxGLCanvas, public Slic3r::GL::Display +{ + std::unique_ptr m_context; +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 + Canvas(Args &&...args): wxGLCanvas(std::forward(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); + } +}; + class MyFrame: public wxFrame { shptr m_scene; // Model