mirror of
https://github.com/OrcaSlicer/OrcaSlicer.git
synced 2026-10-14 19:31:14 +00:00
The texture-displacement gizmo pushes pane state to the UV editor from the preview rebuild that runs on every frame of a slider drag. Tile size is the only one of the layer card's sliders whose value appears in that pane state, so dragging it changes the "N.N mm tile" label, the panel relays out, and the UV canvas receives a synchronous wxEVT_SIZE. Its on_size() flushes a paint with Update(), and render() then makes the app's single shared wxGLContext current on the UV drawable in the middle of the 3D canvas's frame. On X11/GLX that out-of-turn context activation is fatal: the drawable the 3D canvas later swaps no longer belongs to the current context, the server returns BadMatch, and GDK turns the unhandled X error into g_error(). EGL on Wayland reports only a status, so the same theft silently corrupts the frame instead of aborting - which is why the guard is not conditioned on the display backend. Add GLCanvas3D::is_frame_in_progress(), backed by a counter that _render_frame() maintains through its existing scope guard, and let the UV canvas skip the synchronous paint while a frame is on the stack, re-queueing it with Refresh() so nothing is dropped. Rebind the context with _set_current() before SwapBuffers() as well, so a surface that steals it by some other route - a modal GL dialog a gizmo opens from its panel - cannot turn the swap into the same fatal error.
1665 lines
71 KiB
C++
1665 lines
71 KiB
C++
#ifndef slic3r_GLCanvas3D_hpp_
|
|
#define slic3r_GLCanvas3D_hpp_
|
|
|
|
#include "libslic3r/Point.hpp"
|
|
#include "libslic3r/ConnectedBodies.hpp"
|
|
#include "libslic3r/GCode/GCodeProcessor.hpp"
|
|
#include "libslic3r/TriangleMesh.hpp"
|
|
#include "slic3r/GUI/3DScene.hpp"
|
|
#include <cstdlib>
|
|
#include <imgui.h>
|
|
#include <map>
|
|
#include <cmath>
|
|
#include "libslic3r/Geometry.hpp"
|
|
#include "libslic3r/BoundingBox.hpp"
|
|
#include <array>
|
|
#include "libslic3r/Config.hpp"
|
|
#include "libslic3r/Polygon.hpp"
|
|
#include "libslic3r/Technologies.hpp"
|
|
#include "libslic3r/Model.hpp"
|
|
#include "libvgcode/include/Types.hpp"
|
|
#include "libslic3r/libslic3r.h"
|
|
#include "libslic3r/Line.hpp"
|
|
#include <stddef.h>
|
|
#include <functional>
|
|
#include <memory>
|
|
#include <chrono>
|
|
#include <cstdint>
|
|
#include <optional>
|
|
|
|
#include "GLToolbar.hpp"
|
|
#include "Event.hpp"
|
|
#include "Selection.hpp"
|
|
#include "Gizmos/GLGizmosManager.hpp"
|
|
#include "GUI_ObjectLayers.hpp"
|
|
#include "GLSelectionRectangle.hpp"
|
|
#include "GLModel.hpp"
|
|
#include "MeshUtils.hpp"
|
|
#include "GCodeViewer.hpp"
|
|
#include "Camera.hpp"
|
|
#include "SceneRaycaster.hpp"
|
|
#include "SceneCache.hpp"
|
|
#include "FrameProfiler.hpp"
|
|
#include "IMToolbar.hpp"
|
|
#include "slic3r/GUI/3DBed.hpp"
|
|
#include "libslic3r/Slicing.hpp"
|
|
|
|
#include <float.h>
|
|
|
|
#include <wx/setup.h>
|
|
#include <wx/event.h>
|
|
#include <utility>
|
|
#include <vector>
|
|
#include <string>
|
|
#include <wx/string.h>
|
|
#include <wx/colour.h>
|
|
#include <wx/time.h>
|
|
#include <wx/timer.h>
|
|
|
|
namespace Slic3r { class ColorRGBA; }
|
|
namespace Slic3r { class DynamicPrintConfig; }
|
|
namespace Slic3r { class GLShaderProgram; }
|
|
namespace Slic3r { struct GCodeProcessorResult; }
|
|
namespace Slic3r::GUI { class ImGuiWrapper; }
|
|
namespace libvgcode { struct PathVertex; }
|
|
struct ImVec2;
|
|
|
|
class wxSizeEvent;
|
|
class wxIdleEvent;
|
|
class wxKeyEvent;
|
|
class wxMouseEvent;
|
|
class wxTimerEvent;
|
|
class wxPaintEvent;
|
|
class wxGLCanvas;
|
|
class wxGLContext;
|
|
struct ImDrawData;
|
|
|
|
// Support for Retina OpenGL on Mac OS.
|
|
// wxGTK3 seems to simulate OSX behavior in regard to HiDPI scaling support, enable it as well.
|
|
#define ENABLE_RETINA_GL (__APPLE__ || __WXGTK3__)
|
|
|
|
namespace Slic3r {
|
|
|
|
class BackgroundSlicingProcess;
|
|
class BuildVolume;
|
|
struct ThumbnailData;
|
|
struct ThumbnailsParams;
|
|
class ModelObject;
|
|
class ModelInstance;
|
|
struct TextInfo;
|
|
class PrintObject;
|
|
class Print;
|
|
class SLAPrint;
|
|
class PresetBundle;
|
|
namespace CustomGCode { struct Item; }
|
|
|
|
namespace GUI {
|
|
|
|
class Bed3D;
|
|
class PartPlateList;
|
|
#ifdef SLIC3R_CAD
|
|
class DesignSketchTool; // Design tab: interactive 2D sketch tool
|
|
#endif
|
|
struct KeyChord;
|
|
|
|
#if ENABLE_RETINA_GL
|
|
class RetinaHelper;
|
|
#endif
|
|
|
|
class Size
|
|
{
|
|
int m_width{ 0 };
|
|
int m_height{ 0 };
|
|
float m_scale_factor{ 1.0f };
|
|
|
|
public:
|
|
Size() = default;
|
|
Size(int width, int height, float scale_factor = 1.0f) : m_width(width), m_height(height), m_scale_factor(scale_factor) {}
|
|
|
|
int get_width() const { return m_width; }
|
|
void set_width(int width) { m_width = width; }
|
|
|
|
int get_height() const { return m_height; }
|
|
void set_height(int height) { m_height = height; }
|
|
|
|
float get_scale_factor() const { return m_scale_factor; }
|
|
void set_scale_factor(float factor) { m_scale_factor = factor; }
|
|
};
|
|
|
|
class RenderTimerEvent : public wxEvent
|
|
{
|
|
public:
|
|
RenderTimerEvent(wxEventType type, wxTimer& timer)
|
|
: wxEvent(timer.GetId(), type),
|
|
m_timer(&timer)
|
|
{
|
|
SetEventObject(timer.GetOwner());
|
|
}
|
|
int GetInterval() const { return m_timer->GetInterval(); }
|
|
wxTimer& GetTimer() const { return *m_timer; }
|
|
|
|
virtual wxEvent* Clone() const { return new RenderTimerEvent(*this); }
|
|
virtual wxEventCategory GetEventCategory() const { return wxEVT_CATEGORY_TIMER; }
|
|
private:
|
|
wxTimer* m_timer;
|
|
};
|
|
|
|
class ToolbarHighlighterTimerEvent : public wxEvent
|
|
{
|
|
public:
|
|
ToolbarHighlighterTimerEvent(wxEventType type, wxTimer& timer)
|
|
: wxEvent(timer.GetId(), type),
|
|
m_timer(&timer)
|
|
{
|
|
SetEventObject(timer.GetOwner());
|
|
}
|
|
int GetInterval() const { return m_timer->GetInterval(); }
|
|
wxTimer& GetTimer() const { return *m_timer; }
|
|
|
|
virtual wxEvent* Clone() const { return new ToolbarHighlighterTimerEvent(*this); }
|
|
virtual wxEventCategory GetEventCategory() const { return wxEVT_CATEGORY_TIMER; }
|
|
private:
|
|
wxTimer* m_timer;
|
|
};
|
|
|
|
|
|
class GizmoHighlighterTimerEvent : public wxEvent
|
|
{
|
|
public:
|
|
GizmoHighlighterTimerEvent(wxEventType type, wxTimer& timer)
|
|
: wxEvent(timer.GetId(), type),
|
|
m_timer(&timer)
|
|
{
|
|
SetEventObject(timer.GetOwner());
|
|
}
|
|
int GetInterval() const { return m_timer->GetInterval(); }
|
|
wxTimer& GetTimer() const { return *m_timer; }
|
|
|
|
virtual wxEvent* Clone() const { return new GizmoHighlighterTimerEvent(*this); }
|
|
virtual wxEventCategory GetEventCategory() const { return wxEVT_CATEGORY_TIMER; }
|
|
private:
|
|
wxTimer* m_timer;
|
|
};
|
|
|
|
|
|
wxDECLARE_EVENT(EVT_GLCANVAS_OBJECT_SELECT, SimpleEvent);
|
|
wxDECLARE_EVENT(EVT_GLCANVAS_PLATE_NAME_CHANGE, SimpleEvent);
|
|
//BBS: declare EVT_GLCANVAS_PLATE_SELECT
|
|
wxDECLARE_EVENT(EVT_GLCANVAS_PLATE_SELECT, SimpleEvent);
|
|
|
|
// _bool_ value is used as a indicator of selection in the 3DScene
|
|
using RBtnEvent = Event<std::pair<Vec2d, bool>>;
|
|
using RBtnPlateEvent = Event<std::pair<Vec2d, int>>;
|
|
|
|
template <size_t N> using Vec3dsEvent = ArrayEvent<Vec3d, N>;
|
|
|
|
using HeightProfileSmoothEvent = Event<HeightProfileSmoothingParams>;
|
|
|
|
wxDECLARE_EVENT(EVT_GLCANVAS_SCHEDULE_BACKGROUND_PROCESS, SimpleEvent);
|
|
wxDECLARE_EVENT(EVT_GLCANVAS_RIGHT_CLICK, RBtnEvent);
|
|
wxDECLARE_EVENT(EVT_GLCANVAS_PLATE_RIGHT_CLICK, RBtnPlateEvent);
|
|
wxDECLARE_EVENT(EVT_GLCANVAS_REMOVE_OBJECT, SimpleEvent);
|
|
wxDECLARE_EVENT(EVT_GLCANVAS_ARRANGE, SimpleEvent);
|
|
//BBS: add arrange and orient event
|
|
wxDECLARE_EVENT(EVT_GLCANVAS_ARRANGE_PARTPLATE, SimpleEvent);
|
|
wxDECLARE_EVENT(EVT_GLCANVAS_ORIENT, SimpleEvent);
|
|
wxDECLARE_EVENT(EVT_GLCANVAS_ORIENT_PARTPLATE, SimpleEvent);
|
|
wxDECLARE_EVENT(EVT_GLCANVAS_SELECT_CURR_PLATE_ALL, SimpleEvent);
|
|
wxDECLARE_EVENT(EVT_GLCANVAS_SELECT_ALL, SimpleEvent);
|
|
wxDECLARE_EVENT(EVT_GLCANVAS_QUESTION_MARK, SimpleEvent);
|
|
wxDECLARE_EVENT(EVT_GLCANVAS_INCREASE_INSTANCES, Event<int>); // data: +1 => increase, -1 => decrease
|
|
wxDECLARE_EVENT(EVT_GLCANVAS_INSTANCE_MOVED, SimpleEvent);
|
|
wxDECLARE_EVENT(EVT_GLCANVAS_FORCE_UPDATE, SimpleEvent);
|
|
wxDECLARE_EVENT(EVT_GLCANVAS_INSTANCE_ROTATED, SimpleEvent);
|
|
wxDECLARE_EVENT(EVT_GLCANVAS_INSTANCE_SCALED, SimpleEvent);
|
|
wxDECLARE_EVENT(EVT_GLCANVAS_ENABLE_ACTION_BUTTONS, Event<bool>);
|
|
wxDECLARE_EVENT(EVT_GLCANVAS_UPDATE_GEOMETRY, Vec3dsEvent<2>);
|
|
wxDECLARE_EVENT(EVT_GLCANVAS_MOUSE_DRAGGING_STARTED, SimpleEvent);
|
|
wxDECLARE_EVENT(EVT_GLCANVAS_MOUSE_DRAGGING_FINISHED, SimpleEvent);
|
|
wxDECLARE_EVENT(EVT_GLCANVAS_UPDATE_BED_SHAPE, SimpleEvent);
|
|
wxDECLARE_EVENT(EVT_GLCANVAS_TAB, SimpleEvent);
|
|
wxDECLARE_EVENT(EVT_GLCANVAS_RESETGIZMOS, SimpleEvent);
|
|
wxDECLARE_EVENT(EVT_GLCANVAS_UNDO, SimpleEvent);
|
|
wxDECLARE_EVENT(EVT_GLCANVAS_REDO, SimpleEvent);
|
|
wxDECLARE_EVENT(EVT_GLCANVAS_SWITCH_TO_OBJECT, SimpleEvent);
|
|
wxDECLARE_EVENT(EVT_GLCANVAS_SWITCH_TO_GLOBAL, SimpleEvent);
|
|
wxDECLARE_EVENT(EVT_GLCANVAS_COLLAPSE_SIDEBAR, SimpleEvent);
|
|
wxDECLARE_EVENT(EVT_GLCANVAS_RELOAD_FROM_DISK, SimpleEvent);
|
|
wxDECLARE_EVENT(EVT_GLCANVAS_RENDER_TIMER, wxTimerEvent/*RenderTimerEvent*/);
|
|
wxDECLARE_EVENT(EVT_GLCANVAS_TOOLBAR_HIGHLIGHTER_TIMER, wxTimerEvent);
|
|
wxDECLARE_EVENT(EVT_GLCANVAS_GIZMO_HIGHLIGHTER_TIMER, wxTimerEvent);
|
|
wxDECLARE_EVENT(EVT_GLCANVAS_UPDATE, SimpleEvent);
|
|
wxDECLARE_EVENT(EVT_CUSTOMEVT_TICKSCHANGED, wxCommandEvent);
|
|
wxDECLARE_EVENT(EVT_GLCANVAS_RESET_LAYER_HEIGHT_PROFILE, SimpleEvent);
|
|
wxDECLARE_EVENT(EVT_GLCANVAS_ADAPTIVE_LAYER_HEIGHT_PROFILE, Event<float>);
|
|
wxDECLARE_EVENT(EVT_GLCANVAS_SMOOTH_LAYER_HEIGHT_PROFILE, HeightProfileSmoothEvent);
|
|
wxDECLARE_EVENT(EVT_GLCANVAS_PRINTABLE, SimpleEvent);
|
|
|
|
class GLCanvas3D
|
|
{
|
|
static const double DefaultCameraZoomToBoxMarginFactor;
|
|
static const double DefaultCameraZoomToBedMarginFactor;
|
|
static const double DefaultCameraZoomToPlateMarginFactor;
|
|
|
|
static void update_render_colors();
|
|
static void load_render_colors();
|
|
|
|
class LayersEditing
|
|
{
|
|
public:
|
|
enum EState : unsigned char
|
|
{
|
|
Unknown,
|
|
Editing,
|
|
Completed,
|
|
Num_States
|
|
};
|
|
|
|
static const float THICKNESS_BAR_WIDTH;
|
|
|
|
// Orca: Shrinkage compensation
|
|
void set_shrinkage_compensation(const Vec3d &shrinkage_compensation) { m_shrinkage_compensation = shrinkage_compensation; };
|
|
|
|
private:
|
|
bool m_enabled{ false };
|
|
unsigned int m_z_texture_id{ 0 };
|
|
// Not owned by LayersEditing.
|
|
const DynamicPrintConfig* m_config{ nullptr };
|
|
// ModelObject for the currently selected object (Model::objects[last_object_id]).
|
|
const ModelObject* m_model_object{ nullptr };
|
|
// Maximum z of the currently selected object (Model::objects[last_object_id]).
|
|
float m_object_max_z{ 0.0f };
|
|
// Owned by LayersEditing.
|
|
SlicingParameters* m_slicing_parameters{ nullptr };
|
|
std::vector<double> m_layer_height_profile;
|
|
|
|
// Orca: Shrinkage compensation to apply when we need to use object_max_z with Z compensation.
|
|
Vec3d m_shrinkage_compensation{ Vec3d::Ones() };
|
|
|
|
mutable float m_adaptive_quality{ 0.5f };
|
|
mutable HeightProfileSmoothingParams m_smooth_params;
|
|
|
|
static float s_overlay_window_width;
|
|
|
|
struct LayersTexture
|
|
{
|
|
// Texture data
|
|
std::vector<char> data;
|
|
// Width of the texture, top level.
|
|
size_t width{ 0 };
|
|
// Height of the texture, top level.
|
|
size_t height{ 0 };
|
|
// For how many levels of detail is the data allocated?
|
|
size_t levels{ 0 };
|
|
// Number of texture cells allocated for the height texture.
|
|
size_t cells{ 0 };
|
|
// Does it need to be refreshed?
|
|
bool valid{ false };
|
|
};
|
|
LayersTexture m_layers_texture;
|
|
|
|
public:
|
|
EState state{ Unknown };
|
|
float band_width{ 2.0f };
|
|
float strength{ 0.005f };
|
|
int last_object_id{ -1 };
|
|
float last_z{ 0.0f };
|
|
LayerHeightEditActionType last_action{ LAYER_HEIGHT_EDIT_ACTION_INCREASE };
|
|
struct Profile
|
|
{
|
|
GLModel baseline;
|
|
GLModel profile;
|
|
GLModel background;
|
|
float old_canvas_width{ 0.0f };
|
|
std::vector<double> old_layer_height_profile;
|
|
};
|
|
Profile m_profile;
|
|
|
|
LayersEditing() = default;
|
|
~LayersEditing();
|
|
|
|
void init();
|
|
|
|
void set_config(const DynamicPrintConfig* config);
|
|
void select_object(const Model& model, int object_id);
|
|
|
|
bool is_allowed() const;
|
|
|
|
bool is_enabled() const { return m_enabled; }
|
|
void set_enabled(bool enabled) { m_enabled = is_allowed() && enabled; }
|
|
|
|
void render_variable_layer_height_dialog(GLCanvas3D& canvas);
|
|
void render_overlay(GLCanvas3D& canvas);
|
|
void render_volumes(const GLCanvas3D& canvas, const GLVolumeCollection& volumes);
|
|
|
|
void adjust_layer_height_profile();
|
|
void accept_changes(GLCanvas3D& canvas);
|
|
void reset_layer_height_profile(GLCanvas3D& canvas);
|
|
void adaptive_layer_height_profile(GLCanvas3D& canvas, float quality_factor);
|
|
void smooth_layer_height_profile(GLCanvas3D& canvas, const HeightProfileSmoothingParams& smoothing_params);
|
|
|
|
static float get_cursor_z_relative(const GLCanvas3D& canvas);
|
|
static bool bar_rect_contains(const GLCanvas3D& canvas, float x, float y);
|
|
static Rect get_bar_rect_screen(const GLCanvas3D& canvas);
|
|
static float get_overlay_window_width() { return LayersEditing::s_overlay_window_width; }
|
|
|
|
float object_max_z() const { return m_object_max_z; }
|
|
|
|
std::string get_tooltip(const GLCanvas3D& canvas) const;
|
|
|
|
private:
|
|
bool is_initialized() const;
|
|
void generate_layer_height_texture();
|
|
void render_active_object_annotations(const GLCanvas3D& canvas);
|
|
void render_profile(const GLCanvas3D& canvas);
|
|
void update_slicing_parameters();
|
|
|
|
static float thickness_bar_width(const GLCanvas3D& canvas);
|
|
};
|
|
|
|
struct Mouse
|
|
{
|
|
struct Drag
|
|
{
|
|
static const Point Invalid_2D_Point;
|
|
static const Vec3d Invalid_3D_Point;
|
|
static const int MoveThresholdPx;
|
|
|
|
Point start_position_2D{ Invalid_2D_Point };
|
|
Vec3d start_position_3D{ Invalid_3D_Point };
|
|
int move_volume_idx{ -1 };
|
|
bool move_requires_threshold{ false };
|
|
Point move_start_threshold_position_2D{ Invalid_2D_Point };
|
|
// Orca: Keep the world-space point selected at the start of a mouse pan.
|
|
std::optional<Vec3d> camera_pan_anchor;
|
|
};
|
|
|
|
bool dragging{ false };
|
|
Vec2d position{ DBL_MAX, DBL_MAX };
|
|
bool ignore_left_up{ false };
|
|
Drag drag;
|
|
bool ignore_right_up;
|
|
|
|
// Orca: The screen-space start and world-space anchor describe the same pan session.
|
|
// Invalidating one must invalidate the other so a new drag cannot reuse stale depth.
|
|
void set_start_position_2D_as_invalid() {
|
|
drag.start_position_2D = Drag::Invalid_2D_Point;
|
|
drag.camera_pan_anchor.reset();
|
|
}
|
|
void set_start_position_3D_as_invalid() { drag.start_position_3D = Drag::Invalid_3D_Point; }
|
|
void set_move_start_threshold_position_2D_as_invalid() { drag.move_start_threshold_position_2D = Drag::Invalid_2D_Point; }
|
|
|
|
bool is_start_position_2D_defined() const { return (drag.start_position_2D != Drag::Invalid_2D_Point); }
|
|
bool is_start_position_3D_defined() const { return (drag.start_position_3D != Drag::Invalid_3D_Point); }
|
|
bool is_move_start_threshold_position_2D_defined() const { return (drag.move_start_threshold_position_2D != Drag::Invalid_2D_Point); }
|
|
bool is_move_threshold_met(const Point& mouse_pos) const {
|
|
return (std::abs(mouse_pos(0) - drag.move_start_threshold_position_2D(0)) > Drag::MoveThresholdPx)
|
|
|| (std::abs(mouse_pos(1) - drag.move_start_threshold_position_2D(1)) > Drag::MoveThresholdPx);
|
|
}
|
|
};
|
|
|
|
struct SlaCap
|
|
{
|
|
struct Triangles
|
|
{
|
|
GLModel object;
|
|
GLModel supports;
|
|
};
|
|
typedef std::map<unsigned int, Triangles> ObjectIdToModelsMap;
|
|
double z;
|
|
ObjectIdToModelsMap triangles;
|
|
|
|
SlaCap() { reset(); }
|
|
void reset() { z = DBL_MAX; triangles.clear(); }
|
|
bool matches(double z) const { return this->z == z; }
|
|
};
|
|
|
|
enum class EWarning {
|
|
ObjectOutside,
|
|
ToolpathOutside,
|
|
SlaSupportsOutside,
|
|
SomethingNotShown,
|
|
ObjectClashed,
|
|
ObjectLimited,
|
|
GCodeConflict,
|
|
ToolHeightOutside,
|
|
TPUPrintableError,
|
|
FilamentPrintableError,
|
|
LeftExtruderPrintableError, // before slice
|
|
RightExtruderPrintableError, // before slice
|
|
MultiExtruderPrintableError, // after slice
|
|
MultiExtruderHeightOutside, // after slice
|
|
FilamentUnPrintableOnFirstLayer,
|
|
MixUsePLAAndPETG,
|
|
PrimeTowerOutside,
|
|
NozzleFilamentIncompatible,
|
|
MixtureFilamentIncompatible,
|
|
SingleExtruderMixedFilament,
|
|
FlushingVolumeZero
|
|
};
|
|
|
|
class RenderStats
|
|
{
|
|
private:
|
|
std::chrono::time_point<std::chrono::high_resolution_clock> m_measuring_start;
|
|
int m_fps_out = -1;
|
|
int m_fps_running = 0;
|
|
// Frames that redrew the 3D scene rather than reusing the cached one.
|
|
int m_scene_fps_out = 0;
|
|
int m_scene_fps_running = 0;
|
|
public:
|
|
void increment_fps_counter() { ++m_fps_running; }
|
|
void increment_scene_fps_counter() { ++m_scene_fps_running; }
|
|
int get_fps() { return m_fps_out; }
|
|
int get_scene_fps() const { return m_scene_fps_out; }
|
|
int get_fps_and_reset_if_needed() {
|
|
auto cur_time = std::chrono::high_resolution_clock::now();
|
|
int elapsed_ms = std::chrono::duration_cast<std::chrono::milliseconds>(cur_time-m_measuring_start).count();
|
|
if (elapsed_ms > 1000 || m_fps_out == -1) {
|
|
m_measuring_start = cur_time;
|
|
m_fps_out = int (1000. * m_fps_running / elapsed_ms);
|
|
m_scene_fps_out = int (1000. * m_scene_fps_running / elapsed_ms);
|
|
m_fps_running = 0;
|
|
m_scene_fps_running = 0;
|
|
}
|
|
return m_fps_out;
|
|
}
|
|
|
|
};
|
|
|
|
class Labels
|
|
{
|
|
bool m_enabled{ false };
|
|
bool m_shown{ false };
|
|
GLCanvas3D& m_canvas;
|
|
|
|
public:
|
|
explicit Labels(GLCanvas3D& canvas) : m_canvas(canvas) {}
|
|
void enable(bool enable) { m_enabled = enable; }
|
|
void show(bool show) { m_shown = m_enabled ? show : false; }
|
|
bool is_shown() const { return m_shown; }
|
|
void render(const std::vector<const ModelInstance*>& sorted_instances) const;
|
|
};
|
|
|
|
class CenterOfMass
|
|
{
|
|
using Sum = GCodeProcessorResult::ObjectMass::Sum;
|
|
enum MarkerKind : size_t { mkPlate, mkObject, mkSupport, mkBody, mkCount };
|
|
// A marker's mass and the box of what it stands for.
|
|
struct Marker
|
|
{
|
|
Sum sum;
|
|
BoundingBoxf3 box;
|
|
// Of an object, whether it is an assembly.
|
|
bool assembly{ false };
|
|
|
|
Vec3d center() const { return sum.moment / sum.mass; }
|
|
};
|
|
// The plates', each object instance's, its supports' and each body of an assembly's.
|
|
using Markers = std::array<std::vector<Marker>, mkCount>;
|
|
|
|
// The marker's two colors of alternating octants.
|
|
std::array<GLModel, 2> m_octants;
|
|
// Mass properties at unit density of each ModelVolume's mesh, by ModelVolume id, which a new mesh changes.
|
|
std::map<size_t, MassProperties> m_meshes;
|
|
// The connected bodies of each assembly in its own coordinates, by ModelObject id, with the volumes they were sliced from.
|
|
struct Bodies
|
|
{
|
|
struct Volume
|
|
{
|
|
size_t id;
|
|
bool negative;
|
|
double density;
|
|
Transform3d trafo;
|
|
|
|
bool operator==(const Volume& other) const
|
|
{
|
|
return id == other.id && negative == other.negative && density == other.density && trafo.matrix() == other.trafo.matrix();
|
|
}
|
|
};
|
|
std::vector<Volume> volumes;
|
|
size_t slabs{ 0 };
|
|
std::vector<SolidBody> bodies;
|
|
};
|
|
std::map<size_t, Bodies> m_bodies;
|
|
// The markers drawn last: of the finished print and, in Preview, of what is printed up to the top layer shown.
|
|
std::array<Markers, 2> m_drawn;
|
|
size_t m_top_layer{ 0 };
|
|
// The marker whose details are shown, with the number of its kind then.
|
|
struct Pick
|
|
{
|
|
size_t set;
|
|
size_t kind;
|
|
size_t index;
|
|
size_t count;
|
|
};
|
|
std::optional<Pick> m_picked;
|
|
|
|
Markers model_markers(const GLCanvas3D& canvas);
|
|
|
|
public:
|
|
void render(GLCanvas3D& canvas);
|
|
// Shows the details of the marker under the mouse, else hides them; whether it hit one.
|
|
bool on_left_down(GLCanvas3D& canvas, const Vec2d& mouse);
|
|
void render_details(GLCanvas3D& canvas);
|
|
};
|
|
|
|
class Tooltip
|
|
{
|
|
std::string m_text;
|
|
std::chrono::steady_clock::time_point m_start_time;
|
|
// Indicator that the mouse is inside an ImGUI dialog, therefore the tooltip should be suppressed.
|
|
bool m_in_imgui = false;
|
|
|
|
public:
|
|
bool is_empty() const { return m_text.empty(); }
|
|
void set_text(const std::string& text);
|
|
void render(const Vec2d& mouse_position, GLCanvas3D& canvas);
|
|
// Indicates that the mouse is inside an ImGUI dialog, therefore the tooltip should be suppressed.
|
|
void set_in_imgui(bool b) { m_in_imgui = b; }
|
|
bool is_in_imgui() const { return m_in_imgui; }
|
|
};
|
|
|
|
class Slope
|
|
{
|
|
bool m_enabled{ false };
|
|
GLVolumeCollection& m_volumes;
|
|
public:
|
|
Slope(GLVolumeCollection& volumes) : m_volumes(volumes) {}
|
|
|
|
void enable(bool enable) { m_enabled = enable; }
|
|
bool is_enabled() const { return m_enabled; }
|
|
void use(bool use) { m_volumes.set_slope_active(m_enabled ? use : false); }
|
|
bool is_used() const { return m_volumes.is_slope_active(); }
|
|
void globalUse(bool use) { m_volumes.set_slope_GlobalActive(m_enabled ? use : false); }
|
|
bool is_GlobalUsed() const { return m_volumes.is_slope_GlobalActive(); }
|
|
void set_normal_angle(float angle_in_deg) const {
|
|
m_volumes.set_slope_normal_z(-::cos(Geometry::deg2rad(90.0f - angle_in_deg)));
|
|
}
|
|
};
|
|
|
|
class RenderTimer : public wxTimer {
|
|
private:
|
|
virtual void Notify() override;
|
|
};
|
|
|
|
class ToolbarHighlighterTimer : public wxTimer {
|
|
private:
|
|
virtual void Notify() override;
|
|
};
|
|
|
|
class GizmoHighlighterTimer : public wxTimer {
|
|
private:
|
|
virtual void Notify() override;
|
|
};
|
|
|
|
public:
|
|
enum ECursorType : unsigned char
|
|
{
|
|
Standard,
|
|
Cross
|
|
};
|
|
|
|
struct ArrangeSettings
|
|
{
|
|
float distance = 0.f;
|
|
// float distance_sla = 6.;
|
|
float accuracy = 0.65f; // Unused currently
|
|
bool enable_rotation = false;
|
|
bool allow_multi_materials_on_same_plate = true;
|
|
bool avoid_extrusion_cali_region = true;
|
|
//BBS: add more arrangeSettings
|
|
bool is_seq_print = false;
|
|
bool align_to_y_axis = false;
|
|
};
|
|
|
|
struct OrientSettings
|
|
{
|
|
float overhang_angle = 60.f;
|
|
bool enable_rotation = false;
|
|
bool min_area = true;
|
|
};
|
|
|
|
//BBS: add canvas type for assemble view usage
|
|
enum ECanvasType
|
|
{
|
|
CanvasView3D = 0,
|
|
CanvasPreview = 1,
|
|
CanvasAssembleView = 2,
|
|
};
|
|
|
|
int GetHoverId();
|
|
|
|
private:
|
|
bool m_is_dark = false;
|
|
wxGLCanvas* m_canvas;
|
|
wxGLContext* m_context;
|
|
SceneRaycaster m_scene_raycaster;
|
|
Bed3D &m_bed;
|
|
// Contains all shortcuts in the format of {shortcut, description}, e.g. {alt + _L("Left mouse button"), _L("Part_selection")}
|
|
std::vector<std::pair<wxString, wxString>> m_shortcuts_assembly_view;
|
|
#if ENABLE_RETINA_GL
|
|
std::unique_ptr<RetinaHelper> m_retina_helper;
|
|
#endif
|
|
unsigned int m_last_w, m_last_h;
|
|
bool m_in_render;
|
|
// How many canvases are inside _render_frame() right now - see is_frame_in_progress().
|
|
static int s_frames_in_progress;
|
|
wxTimer m_timer;
|
|
wxTimer m_timer_set_color;
|
|
// Armed by each frame that draws the FPS overlay; its tick requests an overlay-only frame.
|
|
wxTimer m_fps_overlay_timer;
|
|
// True during the frame the timer requested, which is not counted.
|
|
bool m_fps_overlay_tick{ false };
|
|
LayersEditing m_layers_editing;
|
|
Mouse m_mouse;
|
|
// Orca: Gesture pans have their own lifecycle and stable world-space anchor.
|
|
std::optional<Vec3d> m_gesture_pan_anchor;
|
|
GLGizmosManager m_gizmos;
|
|
//BBS: GUI refactor: GLToolbar
|
|
mutable GLToolbar m_main_toolbar;
|
|
mutable GLToolbar m_separator_toolbar;
|
|
mutable IMToolbar m_sel_plate_toolbar;
|
|
mutable GLToolbar m_assemble_view_toolbar;
|
|
mutable IMReturnToolbar m_return_toolbar;
|
|
mutable Vec2i32 m_canvas_toolbar_pos = {140, 5};
|
|
mutable float m_sc{1};
|
|
mutable float m_paint_toolbar_width;
|
|
bool m_collapse_toolbar_enabled{true};
|
|
// The collapse button of a sidebar other than Prepare's, from set_collapse_toolbar().
|
|
GLToolbar* m_collapse_toolbar{nullptr};
|
|
std::function<CollapseSide()> m_collapse_side;
|
|
bool m_plate_chrome_enabled{true};
|
|
// This canvas is the Design tab's. Its bed stays at the printer bed's home whichever plate is
|
|
// current, with the world-axis triad and a CAD grid at the bed centre (= modeling origin) in
|
|
// place of the corner triad and the plate grid, and the plate data it reads (exclude areas,
|
|
// the current plate's box) moved onto that bed. Default false leaves the editor tabs untouched.
|
|
bool m_design_canvas{false};
|
|
// Design tab: draw the printer bed and its plate grid at all. Default true, so the
|
|
// main editor is untouched; the Design tab lets the user hide it to model without a bed.
|
|
bool m_show_bed{true};
|
|
// Design tab: draw the outline where a volume crosses the bed. GLVolume::SinkingContours slices
|
|
// the plater model's mesh by the volume's ids, so a canvas over its own Model must turn it off.
|
|
bool m_sinking_contours_enabled{true};
|
|
// Design tab: CAD grid drawn on the bed plane in place of the plate's corner-origin grid.
|
|
// Two GLModels (10 mm minor / 50 mm major) generated from the bed centre so a line passes
|
|
// exactly through the modeling origin; built once and rebuilt only when the bed shape changes.
|
|
GLModel m_cad_grid_minor;
|
|
GLModel m_cad_grid_major;
|
|
// Geometry the CAD grid models were last built from, so they are rebuilt on bed-shape change
|
|
// rather than every frame.
|
|
BoundingBoxf m_cad_grid_bb;
|
|
Vec2d m_cad_grid_center;
|
|
bool m_cad_grid_valid{false};
|
|
#ifdef SLIC3R_CAD
|
|
DesignSketchTool* m_design_sketch_tool{nullptr};
|
|
#endif
|
|
|
|
//BBS: add canvas type for assemble view usage
|
|
ECanvasType m_canvas_type;
|
|
// Objects drawn with the phong shader's studio lighting whatever the realistic-view settings
|
|
// (the Design tab's canvas). Off for every canvas of the slicer, which render as before.
|
|
bool m_studio_lighting{false};
|
|
std::array<ClippingPlane, 2> m_clipping_planes;
|
|
ClippingPlane m_camera_clipping_plane;
|
|
bool m_use_clipping_planes;
|
|
struct SectionView
|
|
{
|
|
explicit SectionView(const GLCanvas3D* owner) : owner(owner) {}
|
|
double ratio{ 0. }; // 0 = off
|
|
double last_ratio{ 0. }; // before it was switched off
|
|
Vec3d normal{ Vec3d::Zero() }; // zero until first aimed
|
|
bool panel_open{ false };
|
|
const GLCanvas3D* owner; // whose objects place the plane
|
|
};
|
|
std::shared_ptr<SectionView> m_section_view{ std::make_shared<SectionView>(this) };
|
|
std::map<const GLVolume*, MeshClipper> m_section_view_caps;
|
|
// Its release would open the hidden window menu on Windows.
|
|
bool m_alt_wheel_used{ false };
|
|
std::array<SlaCap, 2> m_sla_caps;
|
|
std::string m_sidebar_field;
|
|
// when true renders an extra frame by not resetting m_dirty to false
|
|
// see request_extra_frame()
|
|
bool m_extra_frame_requested;
|
|
bool m_event_handlers_bound{ false };
|
|
|
|
GLVolumeCollection m_volumes;
|
|
GCodeViewer m_gcode_viewer;
|
|
|
|
RenderTimer m_render_timer;
|
|
|
|
Selection m_selection;
|
|
const DynamicPrintConfig* m_config;
|
|
Model* m_model;
|
|
BackgroundSlicingProcess *m_process;
|
|
bool m_requires_check_outside_state{ false };
|
|
|
|
std::array<unsigned int, 2> m_old_size{ 0, 0 };
|
|
|
|
bool m_is_touchpad_navigation{ false };
|
|
// Screen is only refreshed from the OnIdle handler if it is dirty.
|
|
bool m_dirty;
|
|
// A frame is needed, and only for the overlay.
|
|
bool m_overlay_dirty{ false };
|
|
bool m_initialized;
|
|
//BBS: add flag to controll rendering
|
|
bool m_render_preview{ true };
|
|
bool m_enable_render { true };
|
|
bool m_apply_zoom_to_volumes_filter;
|
|
bool m_picking_enabled;
|
|
bool m_moving_enabled;
|
|
bool m_dynamic_background_enabled;
|
|
bool m_multisample_allowed;
|
|
bool m_moving;
|
|
// The key-down being dispatched, kept for the char event that may follow it.
|
|
struct KeyDown
|
|
{
|
|
int code = WXK_NONE;
|
|
bool repeat = false;
|
|
};
|
|
KeyDown m_key_down;
|
|
// A keyboard move or rotation of the selection runs from the key-down that started it to
|
|
// that key's release, so a held key becomes one undo step.
|
|
struct SelectionEdit
|
|
{
|
|
enum Kind { None, Move, Rotate };
|
|
Kind kind = None;
|
|
int key = WXK_NONE; // raw key code of the key-down, matched against the key-up
|
|
Vec3d direction{ Vec3d::UnitX() };
|
|
};
|
|
SelectionEdit m_selection_edit;
|
|
bool m_camera_movement;
|
|
//BBS: add toolpath outside
|
|
bool m_toolpath_outside{ false };
|
|
ECursorType m_cursor_type;
|
|
GLSelectionRectangle m_rectangle_selection;
|
|
bool m_navigator_dragging{ false };
|
|
|
|
//BBS:add plate related logic
|
|
mutable std::vector<int> m_hover_volume_idxs;
|
|
std::vector<int> m_hover_plate_idxs;
|
|
// IMEX ghost hover state (plate-owned transparent ghost volumes).
|
|
int m_hover_ghost_head { -1 }; // physical head index, -1 when not hovering a ghost
|
|
int m_hover_ghost_plate { -1 }; // plate index for the hovered ghost, -1 when none
|
|
//BBS if explosion_ratio is changed, need to update volume bounding box
|
|
mutable float m_explosion_ratio = 1.0;
|
|
mutable Vec3d m_rotation_center{ 0.0, 0.0, 0.0};
|
|
//BBS store camera view
|
|
Camera camera;
|
|
|
|
// Following variable is obsolete and it should be safe to remove it.
|
|
// I just don't want to do it now before a release (Lukas Matena 24.3.2019)
|
|
bool m_render_sla_auxiliaries;
|
|
|
|
std::string m_color_by;
|
|
|
|
bool m_reload_delayed;
|
|
|
|
RenderStats m_render_stats;
|
|
FrameProfiler m_frame_profiler;
|
|
bool m_benchmarking{ false };
|
|
std::chrono::time_point<std::chrono::steady_clock> m_last_frame_start_time{ std::chrono::steady_clock::now() };
|
|
|
|
int m_imgui_undo_redo_hovered_pos{ -1 };
|
|
int m_mouse_wheel{ 0 };
|
|
int m_selected_extruder;
|
|
|
|
Labels m_labels;
|
|
CenterOfMass m_center_of_mass;
|
|
Tooltip m_tooltip;
|
|
bool m_tooltip_enabled{ true };
|
|
Slope m_slope;
|
|
|
|
OrientSettings m_orient_settings_fff, m_orient_settings_sla;
|
|
|
|
ArrangeSettings m_arrange_settings_fff, m_arrange_settings_sla,
|
|
m_arrange_settings_fff_seq_print;
|
|
|
|
PrinterTechnology current_printer_technology() const;
|
|
|
|
bool m_show_world_axes{true};
|
|
Bed3D::Axes m_axes;
|
|
//BBS:record key botton frequency
|
|
int auto_orient_count = 0;
|
|
int auto_arrange_count = 0;
|
|
int split_to_objects_count = 0;
|
|
int split_to_part_count = 0;
|
|
int custom_height_count = 0;
|
|
int assembly_view_count = 0;
|
|
|
|
// used to show layers times on the layers slider when pre-gcode view is active
|
|
std::vector<float> m_gcode_layers_times_cache;
|
|
|
|
public:
|
|
OrientSettings& get_orient_settings()
|
|
{
|
|
PrinterTechnology ptech = this->current_printer_technology();
|
|
|
|
auto* ptr = &this->m_orient_settings_fff;
|
|
|
|
if (ptech == ptSLA) {
|
|
ptr = &this->m_orient_settings_sla;
|
|
}
|
|
|
|
return *ptr;
|
|
}
|
|
|
|
void load_arrange_settings();
|
|
ArrangeSettings& get_arrange_settings();
|
|
|
|
class SequentialPrintClearance
|
|
{
|
|
//BBS: add the height logic
|
|
GLModel m_height_limit;
|
|
GLModel m_fill;
|
|
GLModel m_perimeter;
|
|
bool m_render_fill{ true };
|
|
bool m_visible{ false };
|
|
|
|
std::vector<Pointf3s> m_hull_2d_cache;
|
|
|
|
public:
|
|
//BBS: add the height logic
|
|
void set_polygons(const Polygons& polygons, const std::vector<std::pair<Polygon, float>>& height_polygons);
|
|
void set_render_fill(bool render_fill) { m_render_fill = render_fill; }
|
|
void set_visible(bool visible) { m_visible = visible; }
|
|
void render();
|
|
|
|
friend class GLCanvas3D;
|
|
};
|
|
|
|
SequentialPrintClearance m_sequential_print_clearance;
|
|
bool m_sequential_print_clearance_first_displacement{ true };
|
|
|
|
struct ToolbarHighlighter
|
|
{
|
|
void set_timer_owner(wxEvtHandler* owner, int timerid = wxID_ANY) { m_timer.SetOwner(owner, timerid); }
|
|
void init(GLToolbarItem* toolbar_item, GLCanvas3D* canvas);
|
|
void blink();
|
|
void invalidate();
|
|
bool m_render_arrow{ false };
|
|
GLToolbarItem* m_toolbar_item{ nullptr };
|
|
private:
|
|
GLCanvas3D* m_canvas{ nullptr };
|
|
int m_blink_counter{ 0 };
|
|
ToolbarHighlighterTimer m_timer;
|
|
}
|
|
m_toolbar_highlighter;
|
|
|
|
struct GizmoHighlighter
|
|
{
|
|
void set_timer_owner(wxEvtHandler* owner, int timerid = wxID_ANY) { m_timer.SetOwner(owner, timerid); }
|
|
void init(GLGizmosManager* manager, GLGizmosManager::EType gizmo, GLCanvas3D* canvas);
|
|
void blink();
|
|
void invalidate();
|
|
bool m_render_arrow{ false };
|
|
GLGizmosManager::EType m_gizmo_type;
|
|
private:
|
|
GLGizmosManager* m_gizmo_manager{ nullptr };
|
|
GLCanvas3D* m_canvas{ nullptr };
|
|
int m_blink_counter{ 0 };
|
|
GizmoHighlighterTimer m_timer;
|
|
|
|
}
|
|
m_gizmo_highlighter;
|
|
|
|
#if ENABLE_SHOW_CAMERA_TARGET
|
|
struct CameraTarget
|
|
{
|
|
std::array<GLModel, 3> axis;
|
|
Vec3d target{ Vec3d::Zero() };
|
|
};
|
|
|
|
CameraTarget m_camera_target;
|
|
#endif // ENABLE_SHOW_CAMERA_TARGET
|
|
GLModel m_background;
|
|
unsigned int m_fxaa_texture_id{ 0 };
|
|
std::array<unsigned int, 2> m_fxaa_texture_size{ 0, 0 };
|
|
unsigned int m_ssao_color_texture_id{ 0 };
|
|
unsigned int m_ssao_depth_texture_id{ 0 };
|
|
std::array<unsigned int, 2> m_ssao_texture_size{ { 0, 0 } };
|
|
// The last scene pass, for frames that only rebuild the overlay.
|
|
SceneCache m_scene_cache;
|
|
// Signature of the overlay on screen; empty after render(), a paint request or a frame drawn but
|
|
// not shown, so the next frame is presented regardless.
|
|
std::optional<size_t> m_presented_signature;
|
|
GLModel m_plate_shadow_mask;
|
|
std::string m_plate_shadow_mask_key;
|
|
// Depth-based shadow map used to cast object shadows onto other objects and themselves.
|
|
unsigned int m_shadow_map_fbo{ 0 };
|
|
unsigned int m_shadow_map_texture_id{ 0 };
|
|
unsigned int m_shadow_map_size{ 0 };
|
|
Transform3d m_shadow_light_vp{ Transform3d::Identity() };
|
|
bool m_shadow_map_valid{ false };
|
|
// Casters and light frustum the map was last rendered for, under a static light. 0 when none.
|
|
size_t m_shadow_map_key{ 0 };
|
|
// Plate rectangle a shadow can reach, min xy then max xy.
|
|
std::array<float, 4> m_shadow_plate_bounds{ { 0.0f, 0.0f, 0.0f, 0.0f } };
|
|
public:
|
|
explicit GLCanvas3D(wxGLCanvas* canvas, Bed3D &bed);
|
|
~GLCanvas3D();
|
|
|
|
bool is_initialized() const { return m_initialized; }
|
|
|
|
void set_context(wxGLContext* context) { m_context = context; }
|
|
void set_type(ECanvasType type) { m_canvas_type = type; }
|
|
void set_studio_lighting(bool on) { m_studio_lighting = on; }
|
|
ECanvasType get_canvas_type() { return m_canvas_type; }
|
|
|
|
wxGLCanvas* get_wxglcanvas() { return m_canvas; }
|
|
const wxGLCanvas* get_wxglcanvas() const { return m_canvas; }
|
|
|
|
bool init();
|
|
void post_event(wxEvent &&event);
|
|
|
|
std::shared_ptr<SceneRaycasterItem> add_raycaster_for_picking(SceneRaycaster::EType type, int id, const MeshRaycaster& raycaster,
|
|
const Transform3d& trafo = Transform3d::Identity(), bool use_back_faces = false) {
|
|
return m_scene_raycaster.add_raycaster(type, id, raycaster, trafo, use_back_faces);
|
|
}
|
|
void remove_raycasters_for_picking(SceneRaycaster::EType type, int id) {
|
|
m_scene_raycaster.remove_raycasters(type, id);
|
|
}
|
|
void remove_raycasters_for_picking(SceneRaycaster::EType type) {
|
|
m_scene_raycaster.remove_raycasters(type);
|
|
}
|
|
|
|
std::vector<std::shared_ptr<SceneRaycasterItem>>* get_raycasters_for_picking(SceneRaycaster::EType type) {
|
|
return m_scene_raycaster.get_raycasters(type);
|
|
}
|
|
|
|
void set_raycaster_gizmos_on_top(bool value) {
|
|
m_scene_raycaster.set_gizmos_on_top(value);
|
|
}
|
|
|
|
float get_explosion_ratio() { return m_explosion_ratio; }
|
|
void reset_explosion_ratio() { m_explosion_ratio = 1.0; }
|
|
void on_change_color_mode(bool is_dark, bool reinit = true);
|
|
const bool get_dark_mode_status() { return m_is_dark; }
|
|
void set_as_dirty() { m_dirty = true; }
|
|
// True while any GLCanvas3D is inside _render_frame(). The other surfaces that share the app's one
|
|
// GL context (the UV editor canvas) check this before making themselves current: a frame interrupted
|
|
// by another surface finishes drawing into that surface and then presents a window the context no
|
|
// longer belongs to, which on Mesa/X11 is a fatal X error (BadMatch) rather than a no-op.
|
|
static bool is_frame_in_progress() { return s_frames_in_progress > 0; }
|
|
void requires_check_outside_state() { m_requires_check_outside_state = true; }
|
|
|
|
unsigned int get_volumes_count() const { return (unsigned int)m_volumes.volumes.size(); }
|
|
const GLVolumeCollection& get_volumes() const { return m_volumes; }
|
|
void reset_volumes();
|
|
ModelInstanceEPrintVolumeState check_volumes_outside_state(ObjectFilamentResults* object_results = nullptr) const;
|
|
void check_volumes_outside_state(GLVolumeCollection& volumes) const { check_volumes_outside_state(volumes, nullptr, false); }
|
|
bool is_all_plates_selected() { return m_sel_plate_toolbar.m_all_plates_stats_item && m_sel_plate_toolbar.m_all_plates_stats_item->selected; }
|
|
const float get_scale() const;
|
|
|
|
private:
|
|
// returns true if all the volumes are completely contained in the print volume
|
|
// returns the containment state in the given out_state, if non-null
|
|
bool check_volumes_outside_state(GLVolumeCollection& volumes, ModelInstanceEPrintVolumeState* out_state, bool selection_only = true) const;
|
|
|
|
public:
|
|
//BBS
|
|
GCodeViewer& get_gcode_viewer() { return m_gcode_viewer; }
|
|
void init_gcode_viewer(ConfigOptionMode mode, Slic3r::PresetBundle* preset_bundle) { m_gcode_viewer.init(mode, preset_bundle); }
|
|
void reset_gcode_toolpaths() { _set_shown_canvas_current(); m_gcode_viewer.reset(); }
|
|
const GCodeViewer::SequentialView& get_gcode_sequential_view() const { return m_gcode_viewer.get_sequential_view(); }
|
|
void update_gcode_sequential_view_current(unsigned int first, unsigned int last) { m_gcode_viewer.update_sequential_view_current(first, last); }
|
|
const libvgcode::Interval& get_gcode_view_full_range() const { return m_gcode_viewer.get_gcode_view_full_range(); }
|
|
const libvgcode::Interval& get_gcode_view_enabled_range() const { return m_gcode_viewer.get_gcode_view_enabled_range(); }
|
|
const libvgcode::Interval& get_gcode_view_visible_range() const { return m_gcode_viewer.get_gcode_view_visible_range(); }
|
|
const libvgcode::PathVertex& get_gcode_vertex_at(size_t id) const { return m_gcode_viewer.get_gcode_vertex_at(id); }
|
|
|
|
void toggle_selected_volume_visibility(bool selected_visible);
|
|
void toggle_sla_auxiliaries_visibility(bool visible, const ModelObject* mo = nullptr, int instance_idx = -1);
|
|
void toggle_model_objects_visibility(bool visible, const ModelObject* mo = nullptr, int instance_idx = -1, const ModelVolume* mv = nullptr);
|
|
void update_instance_printable_state_for_object(size_t obj_idx);
|
|
void update_instance_printable_state_for_objects(const std::vector<size_t>& object_idxs);
|
|
|
|
void set_config(const DynamicPrintConfig* config);
|
|
void set_process(BackgroundSlicingProcess* process) { m_process = process; }
|
|
void set_model(Model* model);
|
|
const Model* get_model() const { return m_model; }
|
|
|
|
const Selection& get_selection() const { return m_selection; }
|
|
Selection& get_selection() { return m_selection; }
|
|
|
|
const GLGizmosManager& get_gizmos_manager() const { return m_gizmos; }
|
|
GLGizmosManager& get_gizmos_manager() { return m_gizmos; }
|
|
|
|
void bed_shape_changed();
|
|
|
|
//BBS: add part plate related logic
|
|
void plates_count_changed();
|
|
|
|
//BBS get camera
|
|
Camera& get_camera();
|
|
|
|
void set_clipping_plane(unsigned int id, const ClippingPlane& plane)
|
|
{
|
|
if (id < 2)
|
|
{
|
|
m_clipping_planes[id] = plane;
|
|
m_sla_caps[id].reset();
|
|
}
|
|
}
|
|
void reset_clipping_planes_cache() { m_sla_caps[0].triangles.clear(); m_sla_caps[1].triangles.clear(); }
|
|
void set_use_clipping_planes(bool use) { m_use_clipping_planes = use; }
|
|
|
|
bool get_use_clipping_planes() const { return m_use_clipping_planes; }
|
|
const std::array<ClippingPlane, 2> &get_clipping_planes() const { return m_clipping_planes; };
|
|
|
|
void set_use_color_clip_plane(bool use) { m_volumes.set_use_color_clip_plane(use); }
|
|
void set_color_clip_plane(const Vec3d& cp_normal, double offset) { m_volumes.set_color_clip_plane(cp_normal, offset); }
|
|
void set_color_clip_plane_colors(const std::array<ColorRGBA, 2>& colors) { m_volumes.set_color_clip_plane_colors(colors); }
|
|
|
|
bool is_section_view_active() const { return m_section_view->ratio > 0.; }
|
|
double get_section_view_ratio() const { return m_section_view->ratio; }
|
|
const Vec3d& get_section_view_normal() const { return m_section_view->normal; }
|
|
void set_section_view_ratio(double ratio);
|
|
void toggle_section_view();
|
|
void align_section_view_to_camera();
|
|
void share_section_view(const GLCanvas3D& owner) { m_section_view = owner.m_section_view; }
|
|
|
|
void toggle_world_axes_visibility(bool force_show = false);
|
|
void refresh_camera_scene_box();
|
|
void set_color_by(const std::string& value);
|
|
|
|
BoundingBoxf3 volumes_bounding_box(bool current_plate_only = false) const;
|
|
BoundingBoxf3 scene_bounding_box() const;
|
|
BoundingBoxf3 plate_scene_bounding_box(int plate_idx) const;
|
|
|
|
bool is_layers_editing_enabled() const { return m_layers_editing.is_enabled(); }
|
|
bool is_layers_editing_allowed() const { return m_layers_editing.is_allowed(); }
|
|
|
|
void reset_layer_height_profile();
|
|
void adaptive_layer_height_profile(float quality_factor);
|
|
void smooth_layer_height_profile(const HeightProfileSmoothingParams& smoothing_params);
|
|
|
|
bool is_reload_delayed() const { return m_reload_delayed; }
|
|
|
|
void enable_layers_editing(bool enable);
|
|
void enable_picking(bool enable)
|
|
{
|
|
m_picking_enabled = enable;
|
|
// Orca: invalidate hover state when dragging is toggled, otherwise if we turned off dragging
|
|
// while hovering above a volume, the hovering state won't update even if mouse has moved away.
|
|
// Fixes https://github.com/OrcaSlicer/OrcaSlicer/pull/9979#issuecomment-3065575889
|
|
m_hover_volume_idxs.clear();
|
|
}
|
|
void enable_moving(bool enable) { m_moving_enabled = enable; }
|
|
void enable_gizmos(bool enable) { m_gizmos.set_enabled(enable); }
|
|
void enable_selection(bool enable) { m_selection.set_enabled(enable); }
|
|
void enable_main_toolbar(bool enable) { m_main_toolbar.set_enabled(enable); }
|
|
//BBS: GUI refactor: GLToolbar
|
|
void _update_select_plate_toolbar_stats_item(bool force_selected = false);
|
|
void reset_select_plate_toolbar_selection();
|
|
void enable_select_plate_toolbar(bool enable);
|
|
void enable_assemble_view_toolbar(bool enable);
|
|
void enable_return_toolbar(bool enable);
|
|
void enable_separator_toolbar(bool enable);
|
|
void enable_collapse_toolbar(bool enable);
|
|
// A canvas beside a sidebar other than Prepare's shows that sidebar's collapse button: `toolbar`,
|
|
// set up with setup_collapse_toolbar(), on the edge `side` reports. Call before the canvas is
|
|
// initialized, which loads the toolbar's background.
|
|
void set_collapse_toolbar(GLToolbar* toolbar, std::function<CollapseSide()> side);
|
|
void enable_plate_chrome(bool enable);
|
|
void set_design_canvas(bool b) { m_design_canvas = b; }
|
|
void set_show_bed(bool b) { m_show_bed = b; }
|
|
bool get_show_bed() const { return m_show_bed; }
|
|
void enable_sinking_contours(bool enable) { m_sinking_contours_enabled = enable; }
|
|
#ifdef SLIC3R_CAD
|
|
void set_design_sketch_tool(DesignSketchTool* tool) { m_design_sketch_tool = tool; }
|
|
DesignSketchTool* get_design_sketch_tool() const { return m_design_sketch_tool; }
|
|
// The Design tab frames what it selects itself (DesignCanvas::zoom_to_box), as the Fit button does.
|
|
void zoom_to_box(const BoundingBoxf3& box) { _zoom_to_box(box); }
|
|
#endif
|
|
void enable_dynamic_background(bool enable) { m_dynamic_background_enabled = enable; }
|
|
void enable_labels(bool enable) { m_labels.enable(enable); }
|
|
void enable_slope(bool enable) { m_slope.enable(enable); }
|
|
void allow_multisample(bool allow) { m_multisample_allowed = allow; }
|
|
|
|
void zoom_to_bed();
|
|
void zoom_to_volumes();
|
|
void zoom_to_selection();
|
|
void zoom_to_gcode();
|
|
//BBS -1 for current plate
|
|
void zoom_to_plate(int plate_idx = -1);
|
|
void select_view(const std::string& direction);
|
|
//BBS: add part plate related logic
|
|
void select_plate();
|
|
//BBS: GUI refactor: GLToolbar&&gizmo
|
|
int get_main_toolbar_offset() const;
|
|
int get_main_toolbar_height() const { return m_main_toolbar.get_height(); }
|
|
int get_main_toolbar_width() const { return m_main_toolbar.get_width(); }
|
|
float get_assemble_view_toolbar_width() const { return m_assemble_view_toolbar.get_width(); }
|
|
float get_assemble_view_toolbar_height() const { return m_assemble_view_toolbar.get_height(); }
|
|
float get_assembly_paint_toolbar_width() const { return m_paint_toolbar_width; }
|
|
float get_separator_toolbar_width() const { return m_separator_toolbar.get_width(); }
|
|
float get_separator_toolbar_height() const { return m_separator_toolbar.get_height(); }
|
|
bool is_collapse_toolbar_on_left() const;
|
|
float get_collapse_toolbar_width() const;
|
|
float get_collapse_toolbar_height() const;
|
|
// Right edge, in canvas pixels, of the bottom-left corner the 3D navigator and the round
|
|
// canvas buttons own. An overlay along the bottom edge starts past it.
|
|
float get_canvas_toolbar_right() const;
|
|
|
|
void update_volumes_colors_by_extruder();
|
|
|
|
bool is_dragging() const { return m_gizmos.is_dragging() || m_moving; }
|
|
bool has_mouse_capture() const;
|
|
|
|
void render(bool only_init = false);
|
|
bool is_rendering_enabled()
|
|
{
|
|
return m_enable_render;
|
|
}
|
|
void enable_render(bool enabled)
|
|
{
|
|
m_enable_render = enabled;
|
|
}
|
|
|
|
// printable_only == false -> render also non printable volumes as grayed
|
|
// parts_only == false -> render also sla support and pad
|
|
void render_thumbnail(ThumbnailData& thumbnail_data, unsigned int w, unsigned int h, const ThumbnailsParams& thumbnail_params,
|
|
Camera::EType camera_type,
|
|
Camera::ViewAngleType camera_view_angle_type = Camera::ViewAngleType::Iso,
|
|
bool for_picking = false,
|
|
bool ban_light = false);
|
|
void render_thumbnail(ThumbnailData & thumbnail_data,
|
|
unsigned int w,
|
|
unsigned int h,
|
|
const ThumbnailsParams & thumbnail_params,
|
|
ModelObjectPtrs & model_objects,
|
|
const GLVolumeCollection &volumes,
|
|
Camera::EType camera_type,
|
|
Camera::ViewAngleType camera_view_angle_type = Camera::ViewAngleType::Iso,
|
|
bool for_picking = false,
|
|
bool ban_light = false);
|
|
void render_thumbnail(ThumbnailData & thumbnail_data,
|
|
std::vector<ColorRGBA> & extruder_colors,
|
|
unsigned int w,
|
|
unsigned int h,
|
|
const ThumbnailsParams & thumbnail_params,
|
|
ModelObjectPtrs & model_objects,
|
|
const GLVolumeCollection &volumes,
|
|
Camera::EType camera_type,
|
|
Camera::ViewAngleType camera_view_angle_type = Camera::ViewAngleType::Iso,
|
|
bool for_picking = false,
|
|
bool ban_light = false);
|
|
static void render_thumbnail_internal(ThumbnailData& thumbnail_data, const ThumbnailsParams& thumbnail_params, PartPlateList& partplate_list, ModelObjectPtrs& model_objects,
|
|
const GLVolumeCollection& volumes, std::vector<ColorRGBA>& extruder_colors,
|
|
GLShaderProgram * shader,
|
|
Camera::EType camera_type,
|
|
Camera::ViewAngleType camera_view_angle_type = Camera::ViewAngleType::Iso,
|
|
bool for_picking = false,
|
|
bool ban_light = false);
|
|
// render thumbnail using an off-screen framebuffer
|
|
static void render_thumbnail_framebuffer(ThumbnailData& thumbnail_data, unsigned int w, unsigned int h, const ThumbnailsParams& thumbnail_params,
|
|
PartPlateList& partplate_list, ModelObjectPtrs& model_objects, const GLVolumeCollection& volumes, std::vector<ColorRGBA>& extruder_colors,
|
|
GLShaderProgram * shader,
|
|
Camera::EType camera_type,
|
|
Camera::ViewAngleType camera_view_angle_type = Camera::ViewAngleType::Iso,
|
|
bool for_picking = false,
|
|
bool ban_light = false);
|
|
// render thumbnail using an off-screen framebuffer when GL_EXT_framebuffer_object is supported
|
|
static void render_thumbnail_framebuffer_ext(ThumbnailData& thumbnail_data, unsigned int w, unsigned int h, const ThumbnailsParams& thumbnail_params,
|
|
PartPlateList& partplate_list, ModelObjectPtrs& model_objects, const GLVolumeCollection& volumes, std::vector<ColorRGBA>& extruder_colors,
|
|
GLShaderProgram * shader,
|
|
Camera::EType camera_type,
|
|
Camera::ViewAngleType camera_view_angle_type = Camera::ViewAngleType::Iso,
|
|
bool for_picking = false,
|
|
bool ban_light = false);
|
|
|
|
// render thumbnail using the default framebuffer
|
|
static void render_thumbnail_legacy(ThumbnailData & thumbnail_data,
|
|
unsigned int w,
|
|
unsigned int h,
|
|
const ThumbnailsParams & thumbnail_params,
|
|
PartPlateList & partplate_list,
|
|
ModelObjectPtrs & model_objects,
|
|
const GLVolumeCollection & volumes,
|
|
std::vector<ColorRGBA> & extruder_colors,
|
|
GLShaderProgram * shader,
|
|
Camera::EType camera_type,
|
|
Camera::ViewAngleType camera_view_angle_type = Camera::ViewAngleType::Iso,
|
|
bool for_picking = false,
|
|
bool ban_light = false);
|
|
|
|
//BBS
|
|
void select_curr_plate_all();
|
|
void select_object_from_idx(std::vector<int>& object_idxs);
|
|
void remove_curr_plate_all();
|
|
|
|
void select_all();
|
|
void deselect_all();
|
|
void exit_gizmo();
|
|
void set_selected_visible(bool visible);
|
|
void delete_selected() { m_selection.erase(); }
|
|
void ensure_on_bed(unsigned int object_idx, bool allow_negative_z);
|
|
|
|
std::vector<double> get_gcode_layers_zs() const { return m_gcode_viewer.get_layers_zs(); }
|
|
std::vector<float> get_gcode_layers_times() const { return m_gcode_viewer.get_layers_times(); }
|
|
const std::vector<float>& get_gcode_layers_times_cache() const { return m_gcode_layers_times_cache; }
|
|
void reset_gcode_layers_times_cache() { m_gcode_layers_times_cache.clear(); }
|
|
void set_volumes_z_range(const std::array<double, 2>& range) { m_volumes.set_range(range[0] - 1e-6, range[1] + 1e-6); }
|
|
size_t get_gcode_extruders_count() { return m_gcode_viewer.get_extruders_count(); }
|
|
|
|
std::vector<int> load_object(const ModelObject& model_object, int obj_idx, std::vector<int> instance_idxs);
|
|
std::vector<int> load_object(const Model& model, int obj_idx);
|
|
|
|
void mirror_selection(Axis axis);
|
|
|
|
void reload_scene(bool refresh_immediately, bool force_full_scene_refresh = false);
|
|
//Orca: shell preview improvement
|
|
void set_shell_transparence(float alpha = 0.2f);
|
|
void load_shells(const Print& print, bool force_previewing = false);
|
|
void reset_shells() { m_gcode_viewer.reset_shell(); }
|
|
void set_shells_on_previewing(bool is_preview) { m_gcode_viewer.set_shells_on_preview(is_preview); }
|
|
|
|
//BBS: add only gcode mode
|
|
void load_gcode_preview(const GCodeProcessorResult& gcode_result, const std::vector<std::string>& str_tool_colors,
|
|
const std::vector<std::string>& str_color_print_colors, bool only_gcode);
|
|
void set_gcode_view_type(libvgcode::EViewType type) { return m_gcode_viewer.set_view_type(type); }
|
|
libvgcode::EViewType get_gcode_view_type() const { return m_gcode_viewer.get_view_type(); }
|
|
|
|
void load_sla_preview();
|
|
void bind_event_handlers();
|
|
void unbind_event_handlers();
|
|
|
|
void on_size(wxSizeEvent& evt) { m_dirty = true; }
|
|
void on_idle(wxIdleEvent& evt);
|
|
void on_char(wxKeyEvent& evt);
|
|
void on_key(wxKeyEvent& evt);
|
|
// Runs the Plater/Preview shortcut bound to chord, swallowing auto-repeats of one-shot
|
|
// shortcuts; false when nothing is bound.
|
|
bool handle_shortcut(const KeyChord& chord);
|
|
void apply_selection_move(bool slow, bool camera_space);
|
|
void apply_selection_rotate(double angle_z_rad);
|
|
void finish_selection_edit();
|
|
void update_shortcut_tooltips();
|
|
void on_mouse_wheel(wxMouseEvent& evt);
|
|
void on_timer(wxTimerEvent& evt);
|
|
void on_render_timer(wxTimerEvent& evt);
|
|
void on_set_color_timer(wxTimerEvent& evt);
|
|
void on_fps_overlay_timer(wxTimerEvent& evt);
|
|
void on_mouse(wxMouseEvent& evt);
|
|
void on_gesture(wxGestureEvent& evt);
|
|
void on_paint(wxPaintEvent& evt);
|
|
void on_set_focus(wxFocusEvent& evt);
|
|
void force_set_focus();
|
|
|
|
enum class MouseButton { None, Left, Middle, Right };
|
|
enum class MouseAction { None, Pan, Rotation };
|
|
bool clicked_button_matches_action(const wxMouseEvent& evt, MouseAction action, const std::map<MouseButton, MouseAction>& mappings) const;
|
|
bool is_camera_rotate(const wxMouseEvent& evt, const std::map<MouseButton, MouseAction>& mappings) const;
|
|
bool is_camera_pan(const wxMouseEvent& evt, const std::map<MouseButton, MouseAction>& mappings) const;
|
|
|
|
Size get_canvas_size() const;
|
|
Vec2d get_local_mouse_position() const;
|
|
|
|
// store opening position of menu
|
|
std::optional<Vec2d> m_popup_menu_positon; // position of mouse right click
|
|
void set_popup_menu_position(const Vec2d &position) { m_popup_menu_positon = position; }
|
|
const std::optional<Vec2d>& get_popup_menu_position() const { return m_popup_menu_positon; }
|
|
void clear_popup_menu_position() { m_popup_menu_positon.reset(); }
|
|
|
|
void set_tooltip(const std::string& tooltip);
|
|
|
|
// the following methods add a snapshot to the undo/redo stack, unless the given string is empty
|
|
void do_move(const std::string& snapshot_type);
|
|
void do_rotate(const std::string& snapshot_type);
|
|
void do_scale(const std::string& snapshot_type);
|
|
void do_center();
|
|
void do_drop();
|
|
void do_center_plate(const int plate_idx);
|
|
void do_mirror(const std::string& snapshot_type);
|
|
|
|
void update_gizmos_on_off_state();
|
|
void reset_all_gizmos() { m_gizmos.reset_all_states(); }
|
|
|
|
void handle_sidebar_focus_event(const std::string& opt_key, bool focus_on);
|
|
void handle_layers_data_focus_event(const t_layer_height_range range, const EditorType type);
|
|
|
|
void update_ui_from_settings();
|
|
|
|
int get_move_volume_id() const { return m_mouse.drag.move_volume_idx; }
|
|
int get_first_hover_volume_idx() const { return m_hover_volume_idxs.empty() ? -1 : m_hover_volume_idxs.front(); }
|
|
int get_hover_ghost_head() const { return m_hover_ghost_head; }
|
|
int get_hover_ghost_plate() const { return m_hover_ghost_plate; }
|
|
void set_selected_extruder(int extruder) { m_selected_extruder = extruder;}
|
|
|
|
class WipeTowerInfo {
|
|
protected:
|
|
Vec2d m_pos = {std::nan(""), std::nan("")};
|
|
double m_rotation = 0.;
|
|
BoundingBoxf m_bb;
|
|
// BBS: add partplate logic
|
|
int m_plate_idx = -1;
|
|
friend class GLCanvas3D;
|
|
|
|
public:
|
|
inline operator bool() const {
|
|
return !std::isnan(m_pos.x()) && !std::isnan(m_pos.y());
|
|
}
|
|
|
|
inline const Vec2d& pos() const { return m_pos; }
|
|
inline double rotation() const { return m_rotation; }
|
|
inline const Vec2d bb_size() const { return m_bb.size(); }
|
|
|
|
void apply_wipe_tower() const { apply_wipe_tower(m_pos, m_rotation); }
|
|
void apply_wipe_tower(Vec2d pos, double rot) const;
|
|
};
|
|
|
|
// BBS: add partplate logic
|
|
WipeTowerInfo get_wipe_tower_info(int plate_idx) const;
|
|
|
|
// Returns the view ray line, in world coordinate, at the given mouse position.
|
|
Linef3 mouse_ray(const Point& mouse_pos);
|
|
|
|
void set_mouse_as_dragging() { m_mouse.dragging = true; }
|
|
bool is_mouse_dragging() const { return m_mouse.dragging; }
|
|
// True when the current left up event comes from an ImGui window and was not processed by it
|
|
// (e.g. a drag that started on a gizmo floating window and was released over the 3D scene).
|
|
// Such a release is the end of an ImGui interaction, not a click on the scene.
|
|
bool is_mouse_left_up_ignored() const { return m_mouse.ignore_left_up; }
|
|
|
|
double get_size_proportional_to_max_bed_size(double factor) const;
|
|
|
|
// BBS: get empty cells to put new object
|
|
// start_point={-1,-1} means sort from bed center, step is the unscaled x,y stride
|
|
std::vector<Vec2f> get_empty_cells(const Vec2f start_point, const Vec2f step = {10, 10});
|
|
// BBS: get the nearest empty cell
|
|
// start_point={-1,-1} means sort from bed center
|
|
Vec2f get_nearest_empty_cell(const Vec2f start_point, const Vec2f step = {10, 10});
|
|
|
|
void set_cursor(ECursorType type);
|
|
void msw_rescale() { m_gcode_viewer.invalidate_legend(); }
|
|
|
|
void request_extra_frame() { m_extra_frame_requested = true; }
|
|
|
|
void schedule_extra_frame(int milliseconds);
|
|
|
|
// The scene benchmark draws every frame itself, without picking or the FPS and timings overlays.
|
|
void set_benchmarking(bool benchmarking) { m_benchmarking = benchmarking; }
|
|
FrameProfiler& get_frame_profiler() { return m_frame_profiler; }
|
|
|
|
int get_main_toolbar_item_id(const std::string& name) const { return m_main_toolbar.get_item_id(name); }
|
|
void force_main_toolbar_left_action(int item_id) { m_main_toolbar.force_left_action(item_id, *this); }
|
|
void force_main_toolbar_right_action(int item_id) { m_main_toolbar.force_right_action(item_id, *this); }
|
|
|
|
bool has_toolpaths_to_export() const { return m_gcode_viewer.can_export_toolpaths(); }
|
|
void export_toolpaths_to_obj(const char* filename) const { m_gcode_viewer.export_toolpaths_to_obj(filename); }
|
|
|
|
void mouse_up_cleanup();
|
|
|
|
bool are_labels_shown() const { return m_labels.is_shown(); }
|
|
void show_labels(bool show) { m_labels.show(show); }
|
|
|
|
bool is_overhang_shown() const { return m_slope.is_GlobalUsed(); }
|
|
void show_overhang(bool show) { m_slope.globalUse(show); }
|
|
|
|
bool is_using_slope() const { return m_slope.is_used(); }
|
|
void use_slope(bool use) { m_slope.use(use); }
|
|
void set_slope_normal_angle(float angle_in_deg) { m_slope.set_normal_angle(angle_in_deg); }
|
|
|
|
void highlight_toolbar_item(const std::string& item_name);
|
|
void highlight_gizmo(const std::string& gizmo_name);
|
|
|
|
// Timestamp for FPS calculation and notification fade-outs.
|
|
static int64_t timestamp_now() {
|
|
#ifdef _WIN32
|
|
// Cheaper on Windows, calls GetSystemTimeAsFileTime()
|
|
return wxGetUTCTimeMillis().GetValue();
|
|
#else
|
|
// calls clock()
|
|
return wxGetLocalTimeMillis().GetValue();
|
|
#endif
|
|
}
|
|
|
|
void reset_sequential_print_clearance() {
|
|
m_sequential_print_clearance.set_visible(false);
|
|
m_sequential_print_clearance.set_render_fill(false);
|
|
//BBS: add the height logic
|
|
m_sequential_print_clearance.set_polygons(Polygons(), std::vector<std::pair<Polygon, float>>());
|
|
}
|
|
|
|
void set_sequential_print_clearance_visible(bool visible) {
|
|
m_sequential_print_clearance.set_visible(visible);
|
|
}
|
|
|
|
void set_sequential_print_clearance_render_fill(bool render_fill) {
|
|
m_sequential_print_clearance.set_render_fill(render_fill);
|
|
}
|
|
|
|
//BBS: add the height logic
|
|
void set_sequential_print_clearance_polygons(const Polygons& polygons, const std::vector<std::pair<Polygon, float>>& height_polygons) {
|
|
m_sequential_print_clearance.set_polygons(polygons, height_polygons);
|
|
}
|
|
|
|
bool can_sequential_clearance_show_in_gizmo();
|
|
void update_sequential_clearance();
|
|
// Orca: by-layer counterpart, for a prime tower compacted by "No sparse layers".
|
|
void update_compacted_wipe_tower_clearance();
|
|
|
|
const Print* fff_print() const;
|
|
const SLAPrint* sla_print() const;
|
|
|
|
void reset_old_size() { m_old_size = { 0, 0 }; }
|
|
|
|
bool is_object_sinking(int object_idx) const;
|
|
|
|
void apply_retina_scale(Vec2d &screen_coordinate) const;
|
|
|
|
void _perform_layer_editing_action(wxMouseEvent* evt = nullptr);
|
|
|
|
// Convert the screen space coordinate to an object space coordinate.
|
|
// If the Z screen space coordinate is not provided, a depth buffer value is substituted.
|
|
Vec3d _mouse_to_3d(const Point& mouse_pos, float* z = nullptr);
|
|
|
|
bool make_current_for_postinit();
|
|
// Sizes ImGui's fonts and style for this canvas; the fonts are rebuilt when the size changes.
|
|
void set_imgui_scaling();
|
|
|
|
private:
|
|
bool _is_shown_on_screen() const;
|
|
|
|
void _update_slice_error_status();
|
|
|
|
void _switch_toolbars_icon_filename();
|
|
bool _init_toolbars();
|
|
bool _init_main_toolbar();
|
|
bool _init_select_plate_toolbar();
|
|
bool _update_imgui_select_plate_toolbar();
|
|
bool _init_assemble_view_toolbar();
|
|
bool _init_return_toolbar();
|
|
bool _init_separator_toolbar();
|
|
// BBS
|
|
//bool _init_view_toolbar();
|
|
bool _init_collapse_toolbar();
|
|
GLToolbar& collapse_toolbar() const;
|
|
CollapseSide collapse_side() const;
|
|
|
|
bool _set_current();
|
|
bool _set_shown_canvas_current();
|
|
void _resize(unsigned int w, unsigned int h);
|
|
|
|
//BBS: add part plate related logic
|
|
BoundingBoxf3 _max_bounding_box(bool include_gizmos, bool include_bed_model, bool include_plates) const;
|
|
|
|
void _zoom_to_box(const BoundingBoxf3& box, double margin_factor = DefaultCameraZoomToBoxMarginFactor);
|
|
void _update_camera_zoom(double zoom);
|
|
|
|
void _refresh_if_shown_on_screen(bool scene_dirty = true);
|
|
|
|
void _picking_pass();
|
|
void _rectangular_selection_picking_pass();
|
|
// IMEX ghost picking (ray vs. ghost bbox). Runs at the end of _picking_pass.
|
|
void _picking_pass_imex_ghosts();
|
|
bool _is_fxaa_enabled() const;
|
|
bool _is_realistic_view_enabled() const;
|
|
bool _is_ssao_enabled() const;
|
|
int _get_effective_fps_cap() const;
|
|
bool _is_fps_overlay_enabled() const;
|
|
bool _is_render_timings_enabled() const;
|
|
enum class EShadowMode { Off, Static, Orbit };
|
|
EShadowMode _shadow_mode() const;
|
|
// Direction to the static shadow light in eye space, when it lights the scene.
|
|
std::optional<Vec3d> _static_light_dir_eye() const;
|
|
size_t _shadow_casters_signature(bool toolpath_casters) const;
|
|
bool _is_scene_cache_enabled() const;
|
|
bool _is_scene_cacheable() const;
|
|
bool _is_frame_skipping_enabled() const;
|
|
void _render_fps_overlay(int fps) const;
|
|
void _render_fxaa_pass(unsigned int width, unsigned int height);
|
|
void _render_ssao_pass(unsigned int width, unsigned int height);
|
|
// scene_dirty is false only for a frame that its requester knows to be overlay-only.
|
|
void _render_frame(bool scene_dirty, bool only_init = false);
|
|
void _render_scene(const Camera& camera, const Size& cnv_size);
|
|
// Request a frame that only rebuilds the overlay.
|
|
void _set_overlay_as_dirty() { m_overlay_dirty = true; }
|
|
// These read the hover state _picking_pass() sets.
|
|
SceneCache::Key _scene_cache_key(const Camera& camera) const;
|
|
bool _can_reuse_cached_scene(const Camera& camera) const;
|
|
void _capture_scene_cache(const Camera& camera);
|
|
void _render_background();
|
|
void _render_bed(const Transform3d& view_matrix, const Transform3d& projection_matrix, bool bottom, bool show_axes);
|
|
// Build the light-space depth shadow map (consumed by gouraud/phong for object & self shadows)
|
|
// and cast it onto the build plate. Realistic view only.
|
|
void _render_shadows(const Transform3d& view_matrix, const Transform3d& projection_matrix);
|
|
//BBS: add part plate related logic
|
|
void _render_platelist(const Transform3d& view_matrix, const Transform3d& projection_matrix, bool bottom, bool only_current, bool only_body = false, int hover_id = -1, bool render_cali = false, bool show_grid = true);
|
|
// The current plate's box (XY, at z = 0); in the Design tab, its own bed's.
|
|
BoundingBoxf3 _current_plate_box() const;
|
|
// Design tab: draw the CAD grid (minor 10 mm + major 50 mm) in place of the plate's
|
|
// corner-origin grid, centred on the modeling origin. Rebuilds its GLModels lazily, only
|
|
// when the bed shape changed.
|
|
void _render_cad_grid(const Transform3d& view_matrix, const Transform3d& projection_matrix);
|
|
//BBS: add outline drawing logic
|
|
void _render_objects(GLVolumeCollection::ERenderType type, bool with_outline = true);
|
|
// IMEX ghost volumes owned by PartPlate, drawn through the shader the caller bound:
|
|
// the shaded pass's transparent half, or the X-Ray pass below.
|
|
void _render_imex_ghosts(bool xray_pass = false);
|
|
void _render_imex_ghosts_xray();
|
|
// IMEX ghost hover tooltip: filament swatch + label drawn as an ImGui overlay.
|
|
void _render_imex_ghost_tooltip();
|
|
void _render_section_view_caps();
|
|
void _render_wireframe_overlay();
|
|
bool _is_xray_view_active() const;
|
|
void _render_xray_volumes();
|
|
//BBS: GUI refactor: add canvas size as parameters
|
|
void _render_gcode(int canvas_width, int canvas_height);
|
|
void _render_gcode_overlay(int canvas_width, int canvas_height);
|
|
//BBS: render a plane for assemble
|
|
void _render_plane() const;
|
|
void _render_selection();
|
|
void _render_sequential_clearance();
|
|
#if ENABLE_RENDER_SELECTION_CENTER
|
|
void _render_selection_center() { m_selection.render_center(m_gizmos.is_dragging()); }
|
|
#endif // ENABLE_RENDER_SELECTION_CENTER
|
|
void _check_and_update_toolbar_icon_scale();
|
|
void _render_overlays();
|
|
void _render_overlay_toolbars();
|
|
size_t _overlay_signature(const ImDrawData* draw_data) const;
|
|
void _render_style_editor();
|
|
void _render_volumes_for_picking(const Camera& camera) const;
|
|
void _render_current_gizmo() const;
|
|
void _render_gizmos_overlay();
|
|
void _render_main_toolbar();
|
|
void _render_imgui_select_plate_toolbar();
|
|
void _render_assemble_view_toolbar() const;
|
|
void _render_return_toolbar() const;
|
|
void _render_canvas_toolbar();
|
|
void _render_section_view_panel(const ImVec2& bottom_left);
|
|
void _render_separator_toolbar_right() const;
|
|
void _render_separator_toolbar_left() const;
|
|
void _render_collapse_toolbar() const;
|
|
// BBS
|
|
//void _render_view_toolbar() const;
|
|
void _render_paint_toolbar() const;
|
|
float _render_assembly_tooltip_button(ImGuiWrapper* imgui_wrapper) const;
|
|
void _render_assemble_control();
|
|
void _render_assemble_info() const;
|
|
#if ENABLE_SHOW_CAMERA_TARGET
|
|
void _render_camera_target();
|
|
#endif // ENABLE_SHOW_CAMERA_TARGET
|
|
void _render_sla_slices();
|
|
void _render_selection_sidebar_hints() { m_selection.render_sidebar_hints(m_sidebar_field, m_gizmos.get_uniform_scaling()); }
|
|
//BBS: GUI refactor: adjust main toolbar position
|
|
bool _render_orient_menu(float left, float right, float bottom, float top);
|
|
void _render_arrange_menu(float left, float right, float bottom, float top);
|
|
void _render_3d_navigator();
|
|
|
|
void _update_volumes_hover_state();
|
|
|
|
// Convert the screen space coordinate to world coordinate on the bed.
|
|
Vec3d _mouse_to_bed_3d(const Point& mouse_pos);
|
|
|
|
// Orca: Navigation type selects the legacy pivot policy used when no visible surface is hit.
|
|
enum class ECameraNavigationType : unsigned char
|
|
{
|
|
Mouse,
|
|
Gesture
|
|
};
|
|
|
|
void _on_section_view_changed();
|
|
// In the ClippingPlane::is_point_clipped() convention.
|
|
ClippingPlane _get_section_view_plane() const;
|
|
// In the volume shaders' convention: the open gizmo's own plane, else the section view's.
|
|
ClippingPlane _get_volumes_clipping_plane() const;
|
|
// Orca: These helpers keep clipping, orbit pivots, and perspective-pan depth selection consistent.
|
|
ClippingPlane get_raycaster_clipping_plane() const;
|
|
bool is_bed_visible() const;
|
|
std::optional<Vec3d> get_camera_orbit_target(ECameraNavigationType navigation_type) const;
|
|
Vec3d get_camera_pan_anchor(Camera& camera, ECameraNavigationType navigation_type,
|
|
const Vec2d& screen_position) const;
|
|
|
|
void _start_timer() { m_timer.Start(100, wxTIMER_CONTINUOUS); }
|
|
void _stop_timer() { m_timer.Stop(); }
|
|
|
|
// Load SLA objects and support structures for objects, for which the slaposSliceSupports step has been finished.
|
|
void _load_sla_shells();
|
|
void _update_sla_shells_outside_state() { check_volumes_outside_state(); }
|
|
void _set_warning_notification_if_needed(EWarning warning);
|
|
|
|
//BBS: add partplate print volume get function
|
|
BoundingBoxf3 _get_current_partplate_print_volume();
|
|
|
|
// generates a warning notification containing the given message
|
|
void _set_warning_notification(EWarning warning, bool state);
|
|
|
|
bool is_flushing_matrix_error();
|
|
bool _is_any_volume_outside() const;
|
|
|
|
// updates the selection from the content of m_hover_volume_idxs
|
|
void _update_selection_from_hover();
|
|
|
|
bool _deactivate_collapse_toolbar_items();
|
|
bool _deactivate_arrange_menu();
|
|
//BBS: add deactivate_orient_menu
|
|
bool _deactivate_orient_menu();
|
|
//BBS: add _deactivate_layersediting_menu
|
|
bool _deactivate_layersediting_menu();
|
|
|
|
// BBS FIXME
|
|
float get_overlay_window_width() { return 0; /*LayersEditing::get_overlay_window_width();*/ }
|
|
};
|
|
|
|
const ModelVolume *get_model_volume(const GLVolume &v, const Model &model);
|
|
ModelVolume *get_model_volume(const ObjectID &volume_id, const ModelObjectPtrs &objects);
|
|
ModelVolume *get_model_volume(const GLVolume &v, const ModelObjectPtrs &objects);
|
|
ModelVolume *get_model_volume(const GLVolume &v, const ModelObject &object);
|
|
|
|
GLVolume *get_first_hovered_gl_volume(const GLCanvas3D &canvas);
|
|
GLVolume *get_selected_gl_volume(const GLCanvas3D &canvas);
|
|
|
|
ModelObject *get_model_object(const GLVolume &gl_volume, const Model &model);
|
|
ModelObject *get_model_object(const GLVolume &gl_volume, const ModelObjectPtrs &objects);
|
|
|
|
ModelInstance *get_model_instance(const GLVolume &gl_volume, const Model &model);
|
|
ModelInstance *get_model_instance(const GLVolume &gl_volume, const ModelObjectPtrs &objects);
|
|
ModelInstance *get_model_instance(const GLVolume &gl_volume, const ModelObject &object);
|
|
|
|
} // namespace GUI
|
|
} // namespace Slic3r
|
|
|
|
#endif // slic3r_GLCanvas3D_hpp_
|