Merge branch 'tm_opencsg' into lm_tm_hollowing

This commit is contained in:
tamasmeszaros 2019-12-17 13:08:51 +01:00
commit 39fbb31db2
5 changed files with 245 additions and 214 deletions

View file

@ -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)

View file

@ -1,100 +0,0 @@
#ifndef CANVAS_HPP
#define CANVAS_HPP
#include <memory>
// For compilers that support precompilation, includes "wx/wx.h".
#include <wx/wxprec.h>
#ifndef WX_PRECOMP
#include <wx/wx.h>
#endif
#include <wx/glcanvas.h>
#include <wx/msgdlg.h>
#include "GLScene.hpp"
namespace Slic3r { namespace GL {
class Canvas: public wxGLCanvas, public Slic3r::GL::Display
{
std::unique_ptr<wxGLContext> 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<class...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_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());
}
};
}} // namespace Slic3r::GL
#endif // CANVAS_HPP

View file

@ -133,7 +133,7 @@ void Scene::set_print(uqptr<SLAPrint> &&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<float>());
repaint();
call_cameras(&Camera::rotate, (Vec2i{x, y} - m_mouse_pos).cast<float>());
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> scene)
{
m_scene = scene;
m_scene->add_display(shared_from_this());
}
void Camera::view()
{
glMatrixMode(GL_MODELVIEW);

View file

@ -21,16 +21,16 @@ template<class T> using uqptr = std::unique_ptr<T>;
template<class T> using wkptr = std::weak_ptr<T>;
template<class T, class A = std::allocator<T>>
using Collection = std::vector<T, A>;
using vector = std::vector<T, A>;
template<class L> void cleanup(Collection<std::weak_ptr<L>> &listeners) {
template<class L> void cleanup(vector<std::weak_ptr<L>> &listeners) {
auto it = std::remove_if(listeners.begin(), listeners.end(),
[](auto &l) { return !l.lock(); });
listeners.erase(it, listeners.end());
}
template<class F, class L, class...Args>
void call(F &&f, Collection<std::weak_ptr<L>> &listeners, Args&&... args) {
void call(F &&f, vector<std::weak_ptr<L>> &listeners, Args&&... args) {
for (auto &l : listeners)
if (auto p = l.lock()) ((p.get())->*f)(std::forward<Args>(args)...);
}
@ -57,7 +57,7 @@ public:
};
private:
Collection<wkptr<Listener>> m_listeners;
vector<wkptr<Listener>> 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<float> vertices_and_normals_interleaved;
Collection<int> triangle_indices;
Collection<int> quad_indices;
vector<float> vertices_and_normals_interleaved;
vector<int> triangle_indices;
vector<int> 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
@ -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,25 +244,48 @@ public:
unsigned get_convexity() const { return m_convexity; }
void set_convexity(unsigned c) { m_convexity = c; }
};
class Display : public std::enable_shared_from_this<Display>,
public MouseInput::Listener
class Scene
{
uqptr<SLAPrint> m_print;
public:
class Listener {
public:
virtual ~Listener() = default;
virtual void on_scene_updated(const Scene &scene) = 0;
};
Scene();
~Scene();
void set_print(uqptr<SLAPrint> &&print);
const SLAPrint * get_print() const { return m_print.get(); }
BoundingBoxf3 get_bounding_box() const;
void add_listener(shptr<Listener> listener)
{
m_listeners.emplace_back(listener);
cleanup(m_listeners);
}
private:
vector<wkptr<Listener>> m_listeners;
};
class Display : public Scene::Listener
{
protected:
shptr<Scene> 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<Camera> m_camera;
struct SceneCache {
Collection<shptr<Primitive>> primitives;
Collection<Primitive *> primitives_free;
Collection<OpenCSG::Primitive *> primitives_csg;
vector<shptr<Primitive>> primitives;
vector<Primitive *> primitives_free;
vector<OpenCSG::Primitive *> primitives_csg;
void clear();
@ -272,64 +295,80 @@ protected:
unsigned covexity);
} m_scene_cache;
shptr<Camera> m_camera;
public:
Display(shptr<Scene> scene = nullptr, shptr<Camera> camera = nullptr)
: m_scene(scene)
, m_camera(camera ? camera : std::make_shared<PerspectiveCamera>())
explicit Display(shptr<Camera> camera = nullptr)
: m_camera(camera ? camera : std::make_shared<PerspectiveCamera>())
{}
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> scene);
shptr<Scene> 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<Controller>,
public MouseInput::Listener,
public Scene::Listener
{
uqptr<SLAPrint> 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<Scene> m_scene;
vector<wkptr<Display>> m_displays;
// Call a method of Camera on all the cameras of the attached displays
template<class F, class...Args>
void call_cameras(F &&f, Args&&... args) {
for (wkptr<Display> &l : m_displays)
if (auto disp = l.lock()) if (disp->camera())
(disp->camera()->*f)(std::forward<Args>(args)...);
}
public:
Scene();
~Scene();
void set_scene(shptr<Scene> scene)
{
m_scene = scene;
m_scene->add_listener(shared_from_this());
}
const Scene * get_scene() const { return m_scene.get(); }
void add_display(shptr<Display> disp)
{
m_displays.emplace_back(disp);
cleanup(m_displays);
}
void set_print(uqptr<SLAPrint> &&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<wkptr<Display>> m_displays;
void move_clip_plane(double z) { call_cameras(&Camera::set_clip_z, z); }
};
}} // namespace Slic3r::GL
#endif // GLSCENE_HPP

View file

@ -15,9 +15,9 @@
#include <wx/tglbtn.h>
#include <wx/combobox.h>
#include <wx/spinctrl.h>
#include <wx/msgdlg.h>
#include <wx/glcanvas.h>
#include "Canvas.hpp"
#include "GLScene.hpp"
#include "libslic3r/Model.hpp"
@ -29,51 +29,60 @@
using namespace Slic3r::GL;
class Canvas: public wxGLCanvas, public Slic3r::GL::Display
{
std::unique_ptr<wxGLContext> 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<class...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);
}
};
class MyFrame: public wxFrame
{
std::shared_ptr<Canvas> m_canvas;
std::shared_ptr<Slic3r::GUI::ProgressStatusBar> m_stbar;
std::unique_ptr<Slic3r::GUI::Job> m_ui_job;
shptr<Scene> m_scene; // Model
shptr<Canvas> m_canvas; // View
shptr<Controller> m_ctl; // Controller
shptr<Slic3r::GUI::ProgressStatusBar> m_stbar;
uqptr<Slic3r::GUI::Job> m_ui_job;
class SLAJob: public Slic3r::GUI::Job {
MyFrame *m_parent;
std::unique_ptr<Slic3r::SLAPrint> 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<Slic3r::SLAPrint>();
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 +93,8 @@ public:
private:
void bind_canvas_events_to_controller();
void OnExit(wxCommandEvent& /*event*/)
{
RemoveChild(m_canvas.get());
@ -108,7 +119,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 +171,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<Scene>();
m_ctl = std::make_shared<Controller>();
m_ctl->set_scene(m_scene);
m_canvas = std::make_shared<Canvas>(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 +251,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 +300,73 @@ MyFrame::MyFrame(const wxString &title, const wxPoint &pos, const wxSize &size):
}
});
m_canvas->set_scene(std::make_shared<Slic3r::GL::Scene>());
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<Slic3r::SLAPrint>();
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();
}