diff --git a/sandboxes/opencsg/CMakeLists.txt b/sandboxes/opencsg/CMakeLists.txt index a6256250d..600ef7884 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 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/I18N.hpp ${CMAKE_CURRENT_SOURCE_DIR}/../../src/slic3r/GUI/I18N.cpp) diff --git a/sandboxes/opencsg/GLScene.cpp b/sandboxes/opencsg/Engine.cpp similarity index 97% rename from sandboxes/opencsg/GLScene.cpp rename to sandboxes/opencsg/Engine.cpp index dcd121709..590faa296 100644 --- a/sandboxes/opencsg/GLScene.cpp +++ b/sandboxes/opencsg/Engine.cpp @@ -1,4 +1,4 @@ -#include "GLScene.hpp" +#include "Engine.hpp" #include #include #include @@ -48,7 +48,7 @@ namespace Slic3r { namespace GL { Scene::Scene() = default; Scene::~Scene() = default; -void Display::render_scene() +void CSGDisplay::render_scene() { GLfloat color[] = {1.f, 1.f, 0.f, 0.f}; glsafe(::glColor4fv(color)); @@ -95,14 +95,14 @@ BoundingBoxf3 Scene::get_bounding_box() const return m_print->model().bounding_box(); } -void Display::SceneCache::clear() +void CSGDisplay::SceneCache::clear() { primitives_csg.clear(); primitives_free.clear(); primitives.clear(); } -shptr Display::SceneCache::add_mesh(const TriangleMesh &mesh) +shptr CSGDisplay::SceneCache::add_mesh(const TriangleMesh &mesh) { auto p = std::make_shared(); p->load_mesh(mesh); @@ -111,9 +111,9 @@ shptr Display::SceneCache::add_mesh(const TriangleMesh &mesh) return p; } -shptr Display::SceneCache::add_mesh(const TriangleMesh &mesh, - OpenCSG::Operation o, - unsigned c) +shptr CSGDisplay::SceneCache::add_mesh(const TriangleMesh &mesh, + OpenCSG::Operation o, + unsigned c) { auto p = std::make_shared(o, c); p->load_mesh(mesh); @@ -388,7 +388,7 @@ void Controller::on_moved_to(long x, long y) m_mouse_pos = {x, y}; } -void Display::apply_csgsettings(const CSGSettings &settings) +void CSGDisplay::apply_csgsettings(const CSGSettings &settings) { using namespace OpenCSG; @@ -404,11 +404,9 @@ void Display::apply_csgsettings(const CSGSettings &settings) if (p->getConvexity() > 1) 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(); if (!print) return; diff --git a/sandboxes/opencsg/GLScene.hpp b/sandboxes/opencsg/Engine.hpp similarity index 98% rename from sandboxes/opencsg/GLScene.hpp rename to sandboxes/opencsg/Engine.hpp index d99652897..5e7030523 100644 --- a/sandboxes/opencsg/GLScene.hpp +++ b/sandboxes/opencsg/Engine.hpp @@ -1,5 +1,5 @@ -#ifndef GLSCENE_HPP -#define GLSCENE_HPP +#ifndef SLIC3R_OCSG_EXMP_ENGINE_HPP +#define SLIC3R_OCSG_EXMP_ENGINE_HPP_HPP #include #include @@ -322,21 +322,6 @@ protected: Vec2i m_size; bool m_initialized = false; - CSGSettings m_csgsettings; - - struct SceneCache { - vector> primitives; - vector primitives_free; - vector primitives_csg; - - void clear(); - - shptr add_mesh(const TriangleMesh &mesh); - shptr add_mesh(const TriangleMesh &mesh, - OpenCSG::Operation op, - unsigned covexity); - } m_scene_cache; - shptr m_camera; FpsCounter m_fps_counter; @@ -359,13 +344,8 @@ public: 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 render_scene(); + virtual void render_scene() {} template void set_fps_counter(_FpsCounter &&fpsc) { @@ -376,6 +356,33 @@ public: FpsCounter &get_fps_counter() { return m_fps_counter; } }; +class CSGDisplay : public Display { +protected: + CSGSettings m_csgsettings; + + struct SceneCache { + vector> primitives; + vector primitives_free; + vector primitives_csg; + + void clear(); + + shptr add_mesh(const TriangleMesh &mesh); + shptr 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, public MouseInput::Listener, public Scene::Listener @@ -425,4 +432,4 @@ public: }; }} // namespace Slic3r::GL -#endif // GLSCENE_HPP +#endif // SLIC3R_OCSG_EXMP_ENGINE_HPP diff --git a/sandboxes/opencsg/main.cpp b/sandboxes/opencsg/main.cpp index c7be06855..1352e1ba0 100644 --- a/sandboxes/opencsg/main.cpp +++ b/sandboxes/opencsg/main.cpp @@ -2,7 +2,7 @@ #include #include -#include "GLScene.hpp" +#include "Engine.hpp" #include @@ -19,6 +19,7 @@ #include #include #include +#include #include "libslic3r/Model.hpp" #include "libslic3r/Format/3mf.hpp" @@ -29,31 +30,47 @@ using namespace Slic3r::GL; -class Canvas: public wxGLCanvas, public Slic3r::GL::Display +class Canvas: public wxGLCanvas { - shptr m_context; + class OCSGRenderer: public Slic3r::GL::CSGDisplay { + Canvas *m_canvas; + shptr 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 m_ocsgdisplay = std::make_shared(this); + + shptr m_display = m_ocsgdisplay; + 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); - Bind(wxEVT_PAINT, [this](wxPaintEvent &) { // This is required even though dc is not used otherwise. wxPaintDC dc(this); @@ -67,16 +84,14 @@ public: // another canvas is repainted. const wxSize ClientSize = GetClientSize(); - set_screen_size(ClientSize.x, ClientSize.y); -// repaint(); + m_display->set_screen_size(ClientSize.x, ClientSize.y); }); } - - ~Canvas() override - { - m_scene_cache.clear(); - m_context.reset(); - } + + shptr get_display() const { return m_display; } + void set_display(shptr d) { m_display = d; } + + shptr get_ocsg_display() const { return m_ocsgdisplay; } }; enum EEvents { LCLK_U, RCLK_U, LCLK_D, RCLK_D, DDCLK, SCRL, MV }; @@ -204,7 +219,7 @@ class MyFrame: public wxFrame uqptr m_ui_job; 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) { m_ui_job = std::make_unique(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); }; +static const std::vector CSG_ALGS = {"Auto", "Goldfeather", "SCS"}; +static const std::vector CSG_DEPTH = {"Off", "OcclusionQuery", "On"}; +static const std::vector CSG_OPT = { "Default", "ForceOn", "On", "Off" }; + class App : public wxApp { - MyFrame *m_frame; + MyFrame *m_frame = nullptr; public: bool OnInit() override { - std::string fname; - std::string command; + wxCmdLineParser parser(argc, argv); - if (argc > 2) { - command = argv[1]; - fname = argv[2]; - } - - m_frame = new MyFrame("PrusaSlicer OpenCSG Demo", wxDefaultPosition, wxSize(1024, 768)); + parser.AddOption("p", "play", "play back file", wxCMD_LINE_VAL_STRING, wxCMD_LINE_PARAM_OPTIONAL); + parser.AddOption("a", "algorithm", "OpenCSG algorithm [Auto|Goldfeather|SCS]", wxCMD_LINE_VAL_STRING, wxCMD_LINE_PARAM_OPTIONAL); + 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); + 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 &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->play_back_mouse(fname); + m_frame->play_back_mouse(fname.ToStdString()); m_frame->Close( true ); + } else m_frame->Show( true ); return true; @@ -255,7 +317,8 @@ public: 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) { wxMenu *menuFile = new wxMenu; @@ -289,7 +352,10 @@ MyFrame::MyFrame(const wxString &title, const wxPoint &pos, const wxSize &size): m_canvas = std::make_shared(this, wxID_ANY, attribList, wxDefaultPosition, wxDefaultSize, 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); @@ -310,7 +376,7 @@ MyFrame::MyFrame(const wxString &title, const wxPoint &pos, const wxSize &size): console_sizer->Add(csg_toggle, 0, wxALL | wxEXPAND, 5); auto add_combobox = [control_panel, console_sizer] - (const wxString &label, std::vector &&list) + (const wxString &label, const std::vector &list) { auto widget = new wxComboBox(control_panel, wxID_ANY, list[0], 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 alg_select = add_combobox("Algorithm", {"Auto", "Goldfeather", "SCS"}); - auto depth_select = add_combobox("Depth Complexity", {"Off", "OcclusionQuery", "On"}); - auto optimization_select = add_combobox("Optimization", { "Default", "ForceOn", "On", "Off" }); + auto alg_select = add_combobox("Algorithm", CSG_ALGS); + auto depth_select = add_combobox("Depth Complexity", CSG_DEPTH); + auto optimization_select = add_combobox("Optimization", CSG_OPT); depth_select->Disable(); auto fpstext = new wxStaticText(control_panel, wxID_ANY, ""); 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) ); }); @@ -367,6 +433,13 @@ MyFrame::MyFrame(const wxString &title, const wxPoint &pos, const wxSize &size): sizer->Add(control_panel, 0, wxEXPAND); 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 &){ RemoveChild(m_canvas.get()); 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 &) { 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()); }); @@ -394,13 +467,13 @@ MyFrame::MyFrame(const wxString &title, const wxPoint &pos, const wxSize &size): ms_toggle->Bind(wxEVT_TOGGLEBUTTON, [this, ms_toggle](wxCommandEvent &){ enable_multisampling(ms_toggle->GetValue()); - m_canvas->repaint(); + m_canvas->get_display()->repaint(); }); 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()); - m_canvas->apply_csgsettings(settings); + m_canvas->get_ocsg_display()->apply_csgsettings(settings); }); 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(); 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)); - m_canvas->apply_csgsettings(settings); + m_canvas->get_ocsg_display()->apply_csgsettings(settings); }); depth_select->Bind(wxEVT_COMBOBOX, [this, depth_select](wxCommandEvent &) { 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)); - m_canvas->apply_csgsettings(settings); + m_canvas->get_ocsg_display()->apply_csgsettings(settings); }); optimization_select->Bind(wxEVT_COMBOBOX, [this, optimization_select](wxCommandEvent &) { 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)); - m_canvas->apply_csgsettings(settings); + m_canvas->get_ocsg_display()->apply_csgsettings(settings); }); 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(); if (c > 0) { 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 (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_mouse.record(true); } else { @@ -468,7 +541,7 @@ MyFrame::MyFrame(const wxString &title, const wxPoint &pos, const wxSize &size): // Do the repaint continuously 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(); });