Add some comments.
This commit is contained in:
parent
9363344a6f
commit
d3925abb13
@ -17,33 +17,36 @@ class SLAPrint;
|
|||||||
|
|
||||||
namespace GL {
|
namespace GL {
|
||||||
|
|
||||||
|
// Simple shorthands for smart pointers
|
||||||
template<class T> using shptr = std::shared_ptr<T>;
|
template<class T> using shptr = std::shared_ptr<T>;
|
||||||
template<class T> using uqptr = std::unique_ptr<T>;
|
template<class T> using uqptr = std::unique_ptr<T>;
|
||||||
template<class T> using wkptr = std::weak_ptr<T>;
|
template<class T> using wkptr = std::weak_ptr<T>;
|
||||||
|
|
||||||
template<class T, class A = std::allocator<T>>
|
template<class T, class A = std::allocator<T>> using vector = std::vector<T, A>;
|
||||||
using vector = std::vector<T, A>;
|
|
||||||
|
|
||||||
|
// remove empty weak pointers from a vector
|
||||||
template<class L> void cleanup(vector<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 it = std::remove_if(listeners.begin(), listeners.end(),
|
||||||
[](auto &l) { return !l.lock(); });
|
[](auto &l) { return !l.lock(); });
|
||||||
listeners.erase(it, listeners.end());
|
listeners.erase(it, listeners.end());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Call a class method on each element of a vector of objects (weak pointers)
|
||||||
|
// of the same type.
|
||||||
template<class F, class L, class...Args>
|
template<class F, class L, class...Args>
|
||||||
void call(F &&f, vector<std::weak_ptr<L>> &listeners, Args&&... args) {
|
void call(F &&f, vector<std::weak_ptr<L>> &listeners, Args&&... args) {
|
||||||
for (auto &l : listeners)
|
for (auto &l : listeners)
|
||||||
if (auto p = l.lock()) ((p.get())->*f)(std::forward<Args>(args)...);
|
if (auto p = l.lock()) ((p.get())->*f)(std::forward<Args>(args)...);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// A representation of a mouse input for the engine.
|
||||||
class MouseInput
|
class MouseInput
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
enum WheelAxis { waVertical, waHorizontal };
|
||||||
|
|
||||||
enum WheelAxis {
|
// Interface to implement if an object wants to receive notifications
|
||||||
waVertical, waHorizontal
|
// about mouse events.
|
||||||
};
|
|
||||||
|
|
||||||
class Listener {
|
class Listener {
|
||||||
public:
|
public:
|
||||||
virtual ~Listener();
|
virtual ~Listener();
|
||||||
@ -99,6 +102,7 @@ public:
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// This is a stripped down version of Slic3r::IndexedVertexArray
|
||||||
class IndexedVertexArray {
|
class IndexedVertexArray {
|
||||||
public:
|
public:
|
||||||
~IndexedVertexArray() { release_geometry(); }
|
~IndexedVertexArray() { release_geometry(); }
|
||||||
@ -164,8 +168,11 @@ public:
|
|||||||
void shrink_to_fit();
|
void shrink_to_fit();
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// Try to enable or disable multisampling.
|
||||||
bool enable_multisampling(bool e = true);
|
bool enable_multisampling(bool e = true);
|
||||||
|
|
||||||
|
// A primitive that can be used with OpenCSG rendering algorithms.
|
||||||
|
// Does a similar job to GLVolume.
|
||||||
class Primitive : public OpenCSG::Primitive
|
class Primitive : public OpenCSG::Primitive
|
||||||
{
|
{
|
||||||
IndexedVertexArray m_geom;
|
IndexedVertexArray m_geom;
|
||||||
@ -176,19 +183,21 @@ public:
|
|||||||
|
|
||||||
Primitive() : OpenCSG::Primitive(OpenCSG::Intersection, 1) {}
|
Primitive() : OpenCSG::Primitive(OpenCSG::Intersection, 1) {}
|
||||||
|
|
||||||
void render();
|
void render() override;
|
||||||
|
|
||||||
void translation(const Vec3d &offset) { m_trafo.set_offset(offset); }
|
void translation(const Vec3d &offset) { m_trafo.set_offset(offset); }
|
||||||
void rotation(const Vec3d &rot) { m_trafo.set_rotation(rot); }
|
void rotation(const Vec3d &rot) { m_trafo.set_rotation(rot); }
|
||||||
void scale(const Vec3d &scaleing) { m_trafo.set_scaling_factor(scaleing); }
|
void scale(const Vec3d &scaleing) { m_trafo.set_scaling_factor(scaleing); }
|
||||||
void scale(double s) { scale({s, s, s}); }
|
void scale(double s) { scale({s, s, s}); }
|
||||||
|
|
||||||
inline void load_mesh(const TriangleMesh &mesh) {
|
inline void load_mesh(const TriangleMesh &mesh)
|
||||||
|
{
|
||||||
m_geom.load_mesh(mesh);
|
m_geom.load_mesh(mesh);
|
||||||
m_geom.finalize_geometry();
|
m_geom.finalize_geometry();
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// A simple representation of a camera in a 3D scene
|
||||||
class Camera {
|
class Camera {
|
||||||
protected:
|
protected:
|
||||||
Vec2f m_rot = {0., 0.};
|
Vec2f m_rot = {0., 0.};
|
||||||
@ -209,6 +218,7 @@ public:
|
|||||||
void set_clip_z(double z) { m_clip_z = z; }
|
void set_clip_z(double z) { m_clip_z = z; }
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// Reset a camera object
|
||||||
inline void reset(Camera &cam)
|
inline void reset(Camera &cam)
|
||||||
{
|
{
|
||||||
cam.set_rotation({0., 0.});
|
cam.set_rotation({0., 0.});
|
||||||
@ -217,12 +227,15 @@ inline void reset(Camera &cam)
|
|||||||
cam.set_clip_z(0.);
|
cam.set_clip_z(0.);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Specialization of a camera which shows in perspective projection
|
||||||
class PerspectiveCamera: public Camera {
|
class PerspectiveCamera: public Camera {
|
||||||
public:
|
public:
|
||||||
|
|
||||||
void set_screen(long width, long height) override;
|
void set_screen(long width, long height) override;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// A simple counter of FPS. Subscribed objects will receive updates of the
|
||||||
|
// current fps.
|
||||||
class FpsCounter {
|
class FpsCounter {
|
||||||
vector<std::function<void(double)>> m_listeners;
|
vector<std::function<void(double)>> m_listeners;
|
||||||
|
|
||||||
@ -259,6 +272,7 @@ public:
|
|||||||
double get_mesure_window_size() const { return m_window_size; }
|
double get_mesure_window_size() const { return m_window_size; }
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// Collection of the used OpenCSG library settings.
|
||||||
class CSGSettings {
|
class CSGSettings {
|
||||||
public:
|
public:
|
||||||
static const constexpr unsigned DEFAULT_CONVEXITY = 10;
|
static const constexpr unsigned DEFAULT_CONVEXITY = 10;
|
||||||
@ -287,11 +301,18 @@ public:
|
|||||||
void set_convexity(unsigned c) { m_convexity = c; }
|
void set_convexity(unsigned c) { m_convexity = c; }
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// The scene is a wrapper around SLAPrint which holds the data to be visualized.
|
||||||
class Scene
|
class Scene
|
||||||
{
|
{
|
||||||
uqptr<SLAPrint> m_print;
|
uqptr<SLAPrint> m_print;
|
||||||
public:
|
public:
|
||||||
|
|
||||||
|
// Subscribers will be notified if the model is changed. This might be a
|
||||||
|
// display which will have to load the meshes and repaint itself when
|
||||||
|
// the scene data changes.
|
||||||
|
// eg. We load a new 3mf through the UI, this will notify the controller
|
||||||
|
// associated with the scene and all the displays that the controller is
|
||||||
|
// connected with.
|
||||||
class Listener {
|
class Listener {
|
||||||
public:
|
public:
|
||||||
virtual ~Listener() = default;
|
virtual ~Listener() = default;
|
||||||
@ -316,6 +337,11 @@ private:
|
|||||||
vector<wkptr<Listener>> m_listeners;
|
vector<wkptr<Listener>> m_listeners;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// The basic Display. This is almost just an interface but will do all the
|
||||||
|
// initialization and show the fps values. Overriding the render_scene is
|
||||||
|
// needed to show the scene content. The specific method of displaying the
|
||||||
|
// scene is up the the particular implementation (OpenCSG or other screen space
|
||||||
|
// boolean algorithms)
|
||||||
class Display : public Scene::Listener
|
class Display : public Scene::Listener
|
||||||
{
|
{
|
||||||
protected:
|
protected:
|
||||||
@ -356,10 +382,13 @@ public:
|
|||||||
FpsCounter &get_fps_counter() { return m_fps_counter; }
|
FpsCounter &get_fps_counter() { return m_fps_counter; }
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// Special dispaly using OpenCSG for rendering the scene.
|
||||||
class CSGDisplay : public Display {
|
class CSGDisplay : public Display {
|
||||||
protected:
|
protected:
|
||||||
CSGSettings m_csgsettings;
|
CSGSettings m_csgsettings;
|
||||||
|
|
||||||
|
// Cache the renderable primitives. These will be fetched when the scene
|
||||||
|
// is modified.
|
||||||
struct SceneCache {
|
struct SceneCache {
|
||||||
vector<shptr<Primitive>> primitives;
|
vector<shptr<Primitive>> primitives;
|
||||||
vector<Primitive *> primitives_free;
|
vector<Primitive *> primitives_free;
|
||||||
@ -375,6 +404,7 @@ protected:
|
|||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
||||||
|
// Receive or apply the new settings.
|
||||||
const CSGSettings & get_csgsettings() const { return m_csgsettings; }
|
const CSGSettings & get_csgsettings() const { return m_csgsettings; }
|
||||||
void apply_csgsettings(const CSGSettings &settings);
|
void apply_csgsettings(const CSGSettings &settings);
|
||||||
|
|
||||||
@ -383,6 +413,11 @@ public:
|
|||||||
void on_scene_updated(const Scene &scene) override;
|
void on_scene_updated(const Scene &scene) override;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
// The controller is a hub which dispatches mouse events to the connected
|
||||||
|
// displays. It keeps track of the mouse wheel position, the states whether
|
||||||
|
// the mouse is being held, dragged, etc... All the connected displays will
|
||||||
|
// mirror the camera movement (if there is more than one display).
|
||||||
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
|
||||||
@ -404,6 +439,7 @@ class Controller : public std::enable_shared_from_this<Controller>,
|
|||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
||||||
|
// Set the scene that will be controlled.
|
||||||
void set_scene(shptr<Scene> scene)
|
void set_scene(shptr<Scene> scene)
|
||||||
{
|
{
|
||||||
m_scene = scene;
|
m_scene = scene;
|
||||||
|
@ -30,8 +30,11 @@
|
|||||||
|
|
||||||
using namespace Slic3r::GL;
|
using namespace Slic3r::GL;
|
||||||
|
|
||||||
|
// The opengl rendering facility. Here we implement the rendering objects.
|
||||||
class Canvas: public wxGLCanvas
|
class Canvas: public wxGLCanvas
|
||||||
{
|
{
|
||||||
|
|
||||||
|
// Tell the CSGDisplay how to swap buffers and set the gl context.
|
||||||
class OCSGRenderer: public Slic3r::GL::CSGDisplay {
|
class OCSGRenderer: public Slic3r::GL::CSGDisplay {
|
||||||
Canvas *m_canvas;
|
Canvas *m_canvas;
|
||||||
shptr<wxGLContext> m_context;
|
shptr<wxGLContext> m_context;
|
||||||
@ -62,8 +65,10 @@ class Canvas: public wxGLCanvas
|
|||||||
~OCSGRenderer() override { m_scene_cache.clear(); }
|
~OCSGRenderer() override { m_scene_cache.clear(); }
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// Create the OCSGDisplay for rendering with OpenCSG algorithms
|
||||||
shptr<OCSGRenderer> m_ocsgdisplay = std::make_shared<OCSGRenderer>(this);
|
shptr<OCSGRenderer> m_ocsgdisplay = std::make_shared<OCSGRenderer>(this);
|
||||||
|
|
||||||
|
// One display is active at a time, the OCSGRenderer by default.
|
||||||
shptr<Slic3r::GL::Display> m_display = m_ocsgdisplay;
|
shptr<Slic3r::GL::Display> m_display = m_ocsgdisplay;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
@ -94,6 +99,7 @@ public:
|
|||||||
shptr<Slic3r::GL::CSGDisplay> get_ocsg_display() const { return m_ocsgdisplay; }
|
shptr<Slic3r::GL::CSGDisplay> get_ocsg_display() const { return m_ocsgdisplay; }
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// Enumerate possible mouse events, we will record them.
|
||||||
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 };
|
||||||
struct Event
|
struct Event
|
||||||
{
|
{
|
||||||
@ -102,6 +108,8 @@ struct Event
|
|||||||
Event(EEvents t, long x = 0, long y = 0) : type{t}, a{x}, b{y} {}
|
Event(EEvents t, long x = 0, long y = 0) : type{t}, a{x}, b{y} {}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// Create a special mouse input adapter, which can store (record) the received
|
||||||
|
// mouse signals into a file and play back the stored events later.
|
||||||
class RecorderMouseInput: public MouseInput {
|
class RecorderMouseInput: public MouseInput {
|
||||||
std::vector<Event> m_events;
|
std::vector<Event> m_events;
|
||||||
bool m_recording = false, m_playing = false;
|
bool m_recording = false, m_playing = false;
|
||||||
@ -181,16 +189,20 @@ public:
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// The top level frame of the application.
|
||||||
class MyFrame: public wxFrame
|
class MyFrame: public wxFrame
|
||||||
{
|
{
|
||||||
|
// Instantiate the 3D engine.
|
||||||
shptr<Scene> m_scene; // Model
|
shptr<Scene> m_scene; // Model
|
||||||
shptr<Canvas> m_canvas; // View
|
shptr<Canvas> m_canvas; // View
|
||||||
shptr<Controller> m_ctl; // Controller
|
shptr<Controller> m_ctl; // Controller
|
||||||
|
|
||||||
|
// Add a status bar with progress indication.
|
||||||
shptr<Slic3r::GUI::ProgressStatusBar> m_stbar;
|
shptr<Slic3r::GUI::ProgressStatusBar> m_stbar;
|
||||||
|
|
||||||
RecorderMouseInput m_mouse;
|
RecorderMouseInput m_mouse;
|
||||||
|
|
||||||
|
// When loading a Model from 3mf and preparing it, we use a separate thread.
|
||||||
class SLAJob: public Slic3r::GUI::Job {
|
class SLAJob: public Slic3r::GUI::Job {
|
||||||
MyFrame *m_parent;
|
MyFrame *m_parent;
|
||||||
std::unique_ptr<Slic3r::SLAPrint> m_print;
|
std::unique_ptr<Slic3r::SLAPrint> m_print;
|
||||||
@ -203,11 +215,14 @@ class MyFrame: public wxFrame
|
|||||||
, m_fname{fname}
|
, m_fname{fname}
|
||||||
{}
|
{}
|
||||||
|
|
||||||
|
// Runs in separate thread
|
||||||
void process() override;
|
void process() override;
|
||||||
|
|
||||||
const std::string & get_project_fname() const { return m_fname; }
|
const std::string & get_project_fname() const { return m_fname; }
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
|
|
||||||
|
// Runs in the UI thread.
|
||||||
void finalize() override
|
void finalize() override
|
||||||
{
|
{
|
||||||
m_parent->m_scene->set_print(std::move(m_print));
|
m_parent->m_scene->set_print(std::move(m_print));
|
||||||
@ -218,16 +233,22 @@ class MyFrame: public wxFrame
|
|||||||
|
|
||||||
uqptr<SLAJob> m_ui_job;
|
uqptr<SLAJob> m_ui_job;
|
||||||
|
|
||||||
|
// To keep track of the running average of measured fps values.
|
||||||
double m_fps_avg = 0.;
|
double m_fps_avg = 0.;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
MyFrame(const wxString& title, const wxPoint& pos, const wxSize& size, const Slic3r::GL::CSGSettings &settings);
|
MyFrame(const wxString & title,
|
||||||
|
const wxPoint & pos,
|
||||||
|
const wxSize & size,
|
||||||
|
const Slic3r::GL::CSGSettings &settings);
|
||||||
|
|
||||||
|
// Grab a 3mf and load (hollow it out) within the UI job.
|
||||||
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);
|
||||||
m_ui_job->start();
|
m_ui_job->start();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Load a previously stored mouse event log and play it back.
|
||||||
void play_back_mouse(const std::string &events_fname)
|
void play_back_mouse(const std::string &events_fname)
|
||||||
{
|
{
|
||||||
std::fstream stream(events_fname, std::fstream::in);
|
std::fstream stream(events_fname, std::fstream::in);
|
||||||
@ -249,11 +270,14 @@ public:
|
|||||||
Canvas * canvas() { return m_canvas.get(); }
|
Canvas * canvas() { return m_canvas.get(); }
|
||||||
const Canvas * canvas() const { return m_canvas.get(); }
|
const Canvas * canvas() const { return m_canvas.get(); }
|
||||||
|
|
||||||
|
// Bind the canvas mouse events to a class implementing MouseInput interface
|
||||||
void bind_canvas_events(MouseInput &msinput);
|
void bind_canvas_events(MouseInput &msinput);
|
||||||
|
|
||||||
double get_fps_average() const { return m_fps_avg; }
|
double get_fps_average() const { return m_fps_avg; }
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// Possible OpenCSG configuration values. Will be used on the command line and
|
||||||
|
// on the UI widgets.
|
||||||
static const std::vector<wxString> CSG_ALGS = {"Auto", "Goldfeather", "SCS"};
|
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_DEPTH = {"Off", "OcclusionQuery", "On"};
|
||||||
static const std::vector<wxString> CSG_OPT = { "Default", "ForceOn", "On", "Off" };
|
static const std::vector<wxString> CSG_OPT = { "Default", "ForceOn", "On", "Off" };
|
||||||
@ -482,9 +506,9 @@ MyFrame::MyFrame(const wxString &title, const wxPoint &pos, const wxSize &size,
|
|||||||
});
|
});
|
||||||
|
|
||||||
csg_toggle->Bind(wxEVT_TOGGLEBUTTON, [this, csg_toggle](wxCommandEvent &){
|
csg_toggle->Bind(wxEVT_TOGGLEBUTTON, [this, csg_toggle](wxCommandEvent &){
|
||||||
CSGSettings settings = m_canvas->get_ocsg_display()->get_csgsettings();
|
CSGSettings stt = m_canvas->get_ocsg_display()->get_csgsettings();
|
||||||
settings.enable_csg(csg_toggle->GetValue());
|
stt.enable_csg(csg_toggle->GetValue());
|
||||||
m_canvas->get_ocsg_display()->apply_csgsettings(settings);
|
m_canvas->get_ocsg_display()->apply_csgsettings(stt);
|
||||||
});
|
});
|
||||||
|
|
||||||
alg_select->Bind(wxEVT_COMBOBOX,
|
alg_select->Bind(wxEVT_COMBOBOX,
|
||||||
@ -492,33 +516,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_ocsg_display()->get_csgsettings();
|
CSGSettings stt = m_canvas->get_ocsg_display()->get_csgsettings();
|
||||||
settings.set_algo(OpenCSG::Algorithm(sel));
|
stt.set_algo(OpenCSG::Algorithm(sel));
|
||||||
m_canvas->get_ocsg_display()->apply_csgsettings(settings);
|
m_canvas->get_ocsg_display()->apply_csgsettings(stt);
|
||||||
});
|
});
|
||||||
|
|
||||||
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_ocsg_display()->get_csgsettings();
|
CSGSettings stt = m_canvas->get_ocsg_display()->get_csgsettings();
|
||||||
settings.set_depth_algo(OpenCSG::DepthComplexityAlgorithm(sel));
|
stt.set_depth_algo(OpenCSG::DepthComplexityAlgorithm(sel));
|
||||||
m_canvas->get_ocsg_display()->apply_csgsettings(settings);
|
m_canvas->get_ocsg_display()->apply_csgsettings(stt);
|
||||||
});
|
});
|
||||||
|
|
||||||
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_ocsg_display()->get_csgsettings();
|
CSGSettings stt = m_canvas->get_ocsg_display()->get_csgsettings();
|
||||||
settings.set_optimization(OpenCSG::Optimization(sel));
|
stt.set_optimization(OpenCSG::Optimization(sel));
|
||||||
m_canvas->get_ocsg_display()->apply_csgsettings(settings);
|
m_canvas->get_ocsg_display()->apply_csgsettings(stt);
|
||||||
});
|
});
|
||||||
|
|
||||||
convexity_spin->Bind(wxEVT_SPINCTRL, [this, convexity_spin](wxSpinEvent &) {
|
convexity_spin->Bind(wxEVT_SPINCTRL, [this, convexity_spin](wxSpinEvent &) {
|
||||||
CSGSettings settings = m_canvas->get_ocsg_display()->get_csgsettings();
|
CSGSettings stt = 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));
|
stt.set_convexity(unsigned(c));
|
||||||
m_canvas->get_ocsg_display()->apply_csgsettings(settings);
|
m_canvas->get_ocsg_display()->apply_csgsettings(stt);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user