mirror of
https://github.com/SoftFever/OrcaSlicer.git
synced 2025-07-14 10:17:55 -06:00
Sync most of the gizmos with latest PrusaSlicer
This commit is contained in:
parent
049dfd3e08
commit
1561d65712
33 changed files with 843 additions and 760 deletions
|
@ -17,6 +17,8 @@
|
|||
|
||||
#include <imgui/imgui_internal.h>
|
||||
|
||||
#include "slic3r/GUI/CameraUtils.hpp"
|
||||
|
||||
namespace Slic3r {
|
||||
namespace GUI {
|
||||
|
||||
|
@ -111,9 +113,9 @@ GLGizmoAdvancedCut::GLGizmoAdvancedCut(GLCanvas3D& parent, const std::string& ic
|
|||
m_buffered_rotation.setZero();
|
||||
}
|
||||
|
||||
void GLGizmoAdvancedCut::data_changed()
|
||||
void GLGizmoAdvancedCut::data_changed(bool is_serializing)
|
||||
{
|
||||
GLGizmoRotate3D::data_changed();
|
||||
GLGizmoRotate3D::data_changed(is_serializing);
|
||||
finish_rotation();
|
||||
}
|
||||
|
||||
|
@ -227,7 +229,7 @@ bool GLGizmoAdvancedCut::unproject_on_cut_plane(const Vec2d &mouse_pos, Vec3d &p
|
|||
Vec3d point;
|
||||
Vec3d direction;
|
||||
Vec3d hit;
|
||||
MeshRaycaster::line_from_mouse_pos_static(mouse_pos, Transform3d::Identity(), camera, point, direction);
|
||||
CameraUtils::ray_from_screen_pos(camera, mouse_pos, point, direction);
|
||||
Vec3d normal = -cp->get_normal().cast<double>();
|
||||
double den = normal.dot(direction);
|
||||
if (den != 0.) {
|
||||
|
@ -1876,7 +1878,7 @@ bool GLGizmoAdvancedCut::process_cut_line(SLAGizmoEventType action, const Vec2d
|
|||
|
||||
Vec3d pt;
|
||||
Vec3d dir;
|
||||
MeshRaycaster::line_from_mouse_pos_static(mouse_position, Transform3d::Identity(), camera, pt, dir);
|
||||
CameraUtils::ray_from_screen_pos(camera, mouse_position, pt, dir);
|
||||
dir.normalize();
|
||||
pt += dir; // Move the pt along dir so it is not clipped.
|
||||
|
||||
|
|
|
@ -138,7 +138,7 @@ public:
|
|||
|
||||
virtual bool apply_clipping_plane() { return m_connectors_editing; }
|
||||
|
||||
void data_changed() override;
|
||||
void data_changed(bool is_serializing) override;
|
||||
|
||||
protected:
|
||||
bool on_init() override;
|
||||
|
|
|
@ -1,3 +1,7 @@
|
|||
///|/ Copyright (c) Prusa Research 2019 - 2023 Oleksandra Iushchenko @YuSanka, Enrico Turri @enricoturri1966, Lukáš Matěna @lukasmatena, Filip Sykala @Jony01, Vojtěch Bubník @bubnikv
|
||||
///|/
|
||||
///|/ PrusaSlicer is released under the terms of the AGPLv3 or higher
|
||||
///|/
|
||||
#include "GLGizmoBase.hpp"
|
||||
#include "slic3r/GUI/GLCanvas3D.hpp"
|
||||
|
||||
|
@ -196,12 +200,21 @@ void GLGizmoBase::Grabber::render(float size, const ColorRGBA& render_color)
|
|||
|
||||
GLGizmoBase::GLGizmoBase(GLCanvas3D& parent, const std::string& icon_filename, unsigned int sprite_id)
|
||||
: m_parent(parent)
|
||||
, m_group_id(-1)
|
||||
, m_state(Off)
|
||||
, m_shortcut_key(NO_SHORTCUT_KEY_VALUE)
|
||||
, m_icon_filename(icon_filename)
|
||||
, m_sprite_id(sprite_id)
|
||||
, m_imgui(wxGetApp().imgui())
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
std::string GLGizmoBase::get_action_snapshot_name() const
|
||||
{
|
||||
return "Gizmo action";
|
||||
}
|
||||
|
||||
void GLGizmoBase::set_icon_filename(const std::string &filename) {
|
||||
m_icon_filename = filename;
|
||||
}
|
||||
|
@ -212,8 +225,8 @@ void GLGizmoBase::set_hover_id(int id)
|
|||
assert(!m_dragging);
|
||||
|
||||
// allow empty grabbers when not using grabbers but use hover_id - flatten, rotate
|
||||
if (!m_grabbers.empty() && id >= (int) m_grabbers.size())
|
||||
return;
|
||||
// if (!m_grabbers.empty() && id >= (int) m_grabbers.size())
|
||||
// return;
|
||||
|
||||
m_hover_id = id;
|
||||
on_set_hover_id();
|
||||
|
@ -266,15 +279,6 @@ void GLGizmoBase::unregister_grabbers_for_picking()
|
|||
}
|
||||
}
|
||||
|
||||
ColorRGBA GLGizmoBase::picking_color_component(unsigned int id) const
|
||||
{
|
||||
id = BASE_ID - id;
|
||||
if (m_group_id > -1)
|
||||
id -= m_group_id;
|
||||
|
||||
return picking_decode(id);
|
||||
}
|
||||
|
||||
void GLGizmoBase::render_grabbers(const BoundingBoxf3& box) const
|
||||
{
|
||||
#if ENABLE_FIXED_GRABBER
|
||||
|
@ -285,16 +289,23 @@ void GLGizmoBase::render_grabbers(const BoundingBoxf3& box) const
|
|||
}
|
||||
|
||||
void GLGizmoBase::render_grabbers(float size) const
|
||||
{
|
||||
render_grabbers(0, m_grabbers.size() - 1, size, false);
|
||||
}
|
||||
|
||||
void GLGizmoBase::render_grabbers(size_t first, size_t last, float size, bool force_hover) const
|
||||
{
|
||||
GLShaderProgram* shader = wxGetApp().get_shader("gouraud_light");
|
||||
if (shader == nullptr)
|
||||
return;
|
||||
shader->start_using();
|
||||
shader->set_uniform("emission_factor", 0.1f);
|
||||
for (int i = 0; i < (int)m_grabbers.size(); ++i) {
|
||||
glsafe(::glDisable(GL_CULL_FACE));
|
||||
for (size_t i = first; i <= last; ++i) {
|
||||
if (m_grabbers[i].enabled)
|
||||
m_grabbers[i].render(m_hover_id == i, size);
|
||||
m_grabbers[i].render(force_hover ? true : m_hover_id == (int)i, size);
|
||||
}
|
||||
glsafe(::glEnable(GL_CULL_FACE));
|
||||
shader->stop_using();
|
||||
}
|
||||
|
||||
|
@ -310,18 +321,16 @@ bool GLGizmoBase::use_grabbers(const wxMouseEvent &mouse_event) {
|
|||
}
|
||||
|
||||
if (mouse_event.LeftDown()) {
|
||||
Selection &selection = m_parent.get_selection();
|
||||
if (!selection.is_empty() && m_hover_id != -1 &&
|
||||
(m_grabbers.empty() || m_hover_id < static_cast<int>(m_grabbers.size()))) {
|
||||
Selection &selection = m_parent.get_selection();
|
||||
if (!selection.is_empty() && m_hover_id != -1 /* &&
|
||||
(m_grabbers.empty() || m_hover_id < static_cast<int>(m_grabbers.size()))*/) {
|
||||
selection.setup_cache();
|
||||
|
||||
m_dragging = true;
|
||||
for (auto &grabber : m_grabbers) grabber.dragging = false;
|
||||
if (!m_grabbers.empty() && m_hover_id < int(m_grabbers.size()))
|
||||
m_grabbers[m_hover_id].dragging = true;
|
||||
// if (!m_grabbers.empty() && m_hover_id < int(m_grabbers.size()))
|
||||
// m_grabbers[m_hover_id].dragging = true;
|
||||
|
||||
// prevent change of hover_id during dragging
|
||||
m_parent.set_mouse_as_dragging();
|
||||
on_start_dragging();
|
||||
|
||||
// Let the plater know that the dragging started
|
||||
|
@ -333,7 +342,6 @@ bool GLGizmoBase::use_grabbers(const wxMouseEvent &mouse_event) {
|
|||
// when mouse cursor leave window than finish actual dragging operation
|
||||
bool is_leaving = mouse_event.Leaving();
|
||||
if (mouse_event.Dragging()) {
|
||||
m_parent.set_mouse_as_dragging();
|
||||
Point mouse_coord(mouse_event.GetX(), mouse_event.GetY());
|
||||
auto ray = m_parent.mouse_ray(mouse_coord);
|
||||
UpdateData data(ray, mouse_coord);
|
||||
|
@ -343,35 +351,41 @@ bool GLGizmoBase::use_grabbers(const wxMouseEvent &mouse_event) {
|
|||
wxGetApp().obj_manipul()->set_dirty();
|
||||
m_parent.set_as_dirty();
|
||||
return true;
|
||||
} else if (mouse_event.LeftUp() || is_leaving || is_dragging_finished) {
|
||||
for (auto &grabber : m_grabbers) grabber.dragging = false;
|
||||
m_dragging = false;
|
||||
|
||||
// NOTE: This should be part of GLCanvas3D
|
||||
// Reset hover_id when leave window
|
||||
if (is_leaving) m_parent.mouse_up_cleanup();
|
||||
|
||||
on_stop_dragging();
|
||||
|
||||
// There is prediction that after draggign, data are changed
|
||||
// Data are updated twice also by canvas3D::reload_scene.
|
||||
// Should be fixed.
|
||||
m_parent.get_gizmos_manager().update_data();
|
||||
|
||||
wxGetApp().obj_manipul()->set_dirty();
|
||||
|
||||
// Let the plater know that the dragging finished, so a delayed
|
||||
// refresh of the scene with the background processing data should
|
||||
// be performed.
|
||||
m_parent.post_event(SimpleEvent(EVT_GLCANVAS_MOUSE_DRAGGING_FINISHED));
|
||||
// updates camera target constraints
|
||||
m_parent.refresh_camera_scene_box();
|
||||
}
|
||||
else if (mouse_event.LeftUp() || is_leaving || is_dragging_finished) {
|
||||
do_stop_dragging(is_leaving);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void GLGizmoBase::do_stop_dragging(bool perform_mouse_cleanup)
|
||||
{
|
||||
for (auto& grabber : m_grabbers) grabber.dragging = false;
|
||||
m_dragging = false;
|
||||
|
||||
// NOTE: This should be part of GLCanvas3D
|
||||
// Reset hover_id when leave window
|
||||
if (perform_mouse_cleanup) m_parent.mouse_up_cleanup();
|
||||
|
||||
on_stop_dragging();
|
||||
|
||||
// There is prediction that after draggign, data are changed
|
||||
// Data are updated twice also by canvas3D::reload_scene.
|
||||
// Should be fixed.
|
||||
m_parent.get_gizmos_manager().update_data();
|
||||
|
||||
wxGetApp().obj_manipul()->set_dirty();
|
||||
|
||||
// Let the plater know that the dragging finished, so a delayed
|
||||
// refresh of the scene with the background processing data should
|
||||
// be performed.
|
||||
m_parent.post_event(SimpleEvent(EVT_GLCANVAS_MOUSE_DRAGGING_FINISHED));
|
||||
// updates camera target constraints
|
||||
m_parent.refresh_camera_scene_box();
|
||||
}
|
||||
|
||||
std::string GLGizmoBase::format(float value, unsigned int decimals) const
|
||||
{
|
||||
return Slic3r::string_printf("%.*f", decimals, value);
|
||||
|
@ -385,9 +399,12 @@ void GLGizmoBase::render_input_window(float x, float y, float bottom_limit)
|
|||
{
|
||||
on_render_input_window(x, y, bottom_limit);
|
||||
if (m_first_input_window_render) {
|
||||
// for some reason, the imgui dialogs are not shown on screen in the 1st frame where they are rendered, but show up only with the 2nd rendered frame
|
||||
// so, we forces another frame rendering the first time the imgui window is shown
|
||||
// imgui windows that don't have an initial size needs to be processed once to get one
|
||||
// and are not rendered in the first frame
|
||||
// so, we forces to render another frame the first time the imgui window is shown
|
||||
// https://github.com/ocornut/imgui/issues/2949
|
||||
m_parent.set_as_dirty();
|
||||
m_parent.request_extra_frame();
|
||||
m_first_input_window_render = false;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,3 +1,7 @@
|
|||
///|/ Copyright (c) Prusa Research 2019 - 2023 Oleksandra Iushchenko @YuSanka, Lukáš Matěna @lukasmatena, Enrico Turri @enricoturri1966, Filip Sykala @Jony01, Vojtěch Bubník @bubnikv
|
||||
///|/
|
||||
///|/ PrusaSlicer is released under the terms of the AGPLv3 or higher
|
||||
///|/
|
||||
#ifndef slic3r_GLGizmoBase_hpp_
|
||||
#define slic3r_GLGizmoBase_hpp_
|
||||
|
||||
|
@ -68,6 +72,9 @@ public:
|
|||
NegZ = 1 << 5,
|
||||
};
|
||||
|
||||
// Represents NO key(button on keyboard) value
|
||||
static const int NO_SHORTCUT_KEY_VALUE = 0;
|
||||
|
||||
protected:
|
||||
struct Grabber
|
||||
{
|
||||
|
@ -129,9 +136,9 @@ public:
|
|||
protected:
|
||||
GLCanvas3D& m_parent;
|
||||
|
||||
int m_group_id{ -1 }; // TODO: remove only for rotate
|
||||
EState m_state{ Off };
|
||||
int m_shortcut_key{ 0 };
|
||||
int m_group_id; // TODO: remove only for rotate
|
||||
EState m_state;
|
||||
int m_shortcut_key;
|
||||
std::string m_icon_filename;
|
||||
unsigned int m_sprite_id;
|
||||
int m_hover_id{ -1 };
|
||||
|
@ -171,7 +178,7 @@ public:
|
|||
virtual bool wants_enter_leave_snapshots() const { return false; }
|
||||
virtual std::string get_gizmo_entering_text() const { assert(false); return ""; }
|
||||
virtual std::string get_gizmo_leaving_text() const { assert(false); return ""; }
|
||||
virtual std::string get_action_snapshot_name() { return "Gizmo action"; }
|
||||
virtual std::string get_action_snapshot_name() const;
|
||||
void set_common_data_pool(CommonGizmosDataPool* ptr) { m_c = ptr; }
|
||||
|
||||
virtual bool apply_clipping_plane() { return true; }
|
||||
|
@ -202,7 +209,7 @@ public:
|
|||
/// <summary>
|
||||
/// Is called when data (Selection) is changed
|
||||
/// </summary>
|
||||
virtual void data_changed(){};
|
||||
virtual void data_changed(bool is_serializing){};
|
||||
|
||||
/// <summary>
|
||||
/// Implement when want to process mouse events in gizmo
|
||||
|
@ -246,11 +253,9 @@ protected:
|
|||
virtual void on_register_raycasters_for_picking() {}
|
||||
virtual void on_unregister_raycasters_for_picking() {}
|
||||
|
||||
// Returns the picking color for the given id, based on the BASE_ID constant
|
||||
// No check is made for clashing with other picking color (i.e. GLVolumes)
|
||||
ColorRGBA picking_color_component(unsigned int id) const;
|
||||
void render_grabbers(const BoundingBoxf3& box) const;
|
||||
void render_grabbers(float size) const;
|
||||
void render_grabbers(size_t first, size_t last, float size, bool force_hover) const;
|
||||
|
||||
std::string format(float value, unsigned int decimals) const;
|
||||
|
||||
|
@ -265,6 +270,9 @@ protected:
|
|||
/// <param name="mouse_event">Keep information about mouse click</param>
|
||||
/// <returns>same as on_mouse</returns>
|
||||
bool use_grabbers(const wxMouseEvent &mouse_event);
|
||||
|
||||
void do_stop_dragging(bool perform_mouse_cleanup);
|
||||
|
||||
private:
|
||||
// Flag for dirty visible state of Gizmo
|
||||
// When True then need new rendering
|
||||
|
|
|
@ -430,7 +430,7 @@ void GLGizmoFdmSupports::on_render_input_window(float x, float y, float bottom_l
|
|||
else {
|
||||
if (m_imgui->button(m_desc.at("reset_direction"))) {
|
||||
wxGetApp().CallAfter([this]() {
|
||||
m_c->object_clipper()->set_position(-1., false);
|
||||
m_c->object_clipper()->set_position_by_ratio(-1., false);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
@ -444,7 +444,7 @@ void GLGizmoFdmSupports::on_render_input_window(float x, float y, float bottom_l
|
|||
ImGui::PushItemWidth(1.5 * slider_icon_width);
|
||||
bool b_drag_input = ImGui::BBLDragFloat("##clp_dist_input", &clp_dist, 0.05f, 0.0f, 0.0f, "%.2f");
|
||||
|
||||
if (b_bbl_slider_float || b_drag_input) m_c->object_clipper()->set_position(clp_dist, true);
|
||||
if (b_bbl_slider_float || b_drag_input) m_c->object_clipper()->set_position_by_ratio(clp_dist, true);
|
||||
}
|
||||
|
||||
ImGui::Separator();
|
||||
|
|
|
@ -40,7 +40,7 @@ protected:
|
|||
|
||||
std::string get_gizmo_entering_text() const override { return "Entering Paint-on supports"; }
|
||||
std::string get_gizmo_leaving_text() const override { return "Leaving Paint-on supports"; }
|
||||
std::string get_action_snapshot_name() override { return "Paint-on supports editing"; }
|
||||
std::string get_action_snapshot_name() const override { return "Paint-on supports editing"; }
|
||||
|
||||
// BBS
|
||||
wchar_t m_current_tool = 0;
|
||||
|
|
|
@ -1,4 +1,7 @@
|
|||
// Include GLGizmoBase.hpp before I18N.hpp as it includes some libigl code, which overrides our localization "L" macro.
|
||||
///|/ Copyright (c) Prusa Research 2019 - 2023 Oleksandra Iushchenko @YuSanka, Lukáš Matěna @lukasmatena, Enrico Turri @enricoturri1966, Filip Sykala @Jony01, Vojtěch Bubník @bubnikv
|
||||
///|/
|
||||
///|/ PrusaSlicer is released under the terms of the AGPLv3 or higher
|
||||
///|/
|
||||
#include "GLGizmoFlatten.hpp"
|
||||
#include "slic3r/GUI/GLCanvas3D.hpp"
|
||||
#include "slic3r/GUI/GUI_App.hpp"
|
||||
|
@ -22,53 +25,39 @@ GLGizmoFlatten::GLGizmoFlatten(GLCanvas3D& parent, const std::string& icon_filen
|
|||
|
||||
bool GLGizmoFlatten::on_mouse(const wxMouseEvent &mouse_event)
|
||||
{
|
||||
if (mouse_event.Moving()) {
|
||||
// only for sure
|
||||
m_mouse_left_down = false;
|
||||
return false;
|
||||
}
|
||||
if (mouse_event.LeftDown()) {
|
||||
if (m_hover_id != -1) {
|
||||
m_mouse_left_down = true;
|
||||
Selection &selection = m_parent.get_selection();
|
||||
if (selection.is_single_full_instance()) {
|
||||
// Rotate the object so the normal points downward:
|
||||
selection.flattening_rotate(m_planes[m_hover_id].normal);
|
||||
m_parent.do_rotate(L("Gizmo-Place on Face"));
|
||||
wxGetApp().obj_manipul()->set_dirty();
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
// fix: prevent restart gizmo when reselect object
|
||||
// take responsibility for left up
|
||||
if (m_parent.get_first_hover_volume_idx() >= 0) m_mouse_left_down = true;
|
||||
|
||||
} else if (mouse_event.LeftUp()) {
|
||||
if (m_mouse_left_down) {
|
||||
// responsible for mouse left up after selecting plane
|
||||
m_mouse_left_down = false;
|
||||
return true;
|
||||
}
|
||||
} else if (mouse_event.Leaving()) {
|
||||
m_mouse_left_down = false;
|
||||
}
|
||||
else if (mouse_event.LeftUp())
|
||||
return m_hover_id != -1;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
void GLGizmoFlatten::data_changed()
|
||||
void GLGizmoFlatten::data_changed(bool is_serializing)
|
||||
{
|
||||
const Selection & selection = m_parent.get_selection();
|
||||
const ModelObject *model_object = nullptr;
|
||||
int instance_id = -1;
|
||||
if (selection.is_single_full_instance() ||
|
||||
selection.is_from_single_object() ) {
|
||||
model_object = selection.get_model()->objects[selection.get_object_idx()];
|
||||
instance_id = selection.get_instance_idx();
|
||||
}
|
||||
set_flattening_data(model_object);
|
||||
set_flattening_data(model_object, instance_id);
|
||||
}
|
||||
|
||||
bool GLGizmoFlatten::on_init()
|
||||
{
|
||||
// BBS
|
||||
m_shortcut_key = WXK_CONTROL_F;
|
||||
return true;
|
||||
}
|
||||
|
@ -111,7 +100,7 @@ void GLGizmoFlatten::on_render()
|
|||
if (selection.is_single_full_instance()) {
|
||||
const Transform3d& inst_matrix = selection.get_first_volume()->get_instance_transformation().get_matrix();
|
||||
const Camera& camera = wxGetApp().plater()->get_camera();
|
||||
const Transform3d model_matrix = Geometry::assemble_transform(selection.get_first_volume()->get_sla_shift_z() * Vec3d::UnitZ()) * inst_matrix;
|
||||
const Transform3d model_matrix = Geometry::translation_transform(selection.get_first_volume()->get_sla_shift_z() * Vec3d::UnitZ()) * inst_matrix;
|
||||
const Transform3d view_model_matrix = camera.get_view_matrix() * model_matrix;
|
||||
|
||||
shader->set_uniform("view_model_matrix", view_model_matrix);
|
||||
|
@ -119,7 +108,6 @@ void GLGizmoFlatten::on_render()
|
|||
if (this->is_plane_update_necessary())
|
||||
update_planes();
|
||||
for (int i = 0; i < (int)m_planes.size(); ++i) {
|
||||
m_planes_casters[i]->set_transform(model_matrix);
|
||||
m_planes[i].vbo.model.set_color(i == m_hover_id ? GLGizmoBase::FLATTEN_HOVER_COLOR : GLGizmoBase::FLATTEN_COLOR);
|
||||
m_planes[i].vbo.model.render();
|
||||
}
|
||||
|
@ -139,7 +127,7 @@ void GLGizmoFlatten::on_register_raycasters_for_picking()
|
|||
|
||||
if (!m_planes.empty()) {
|
||||
const Selection& selection = m_parent.get_selection();
|
||||
const Transform3d matrix = Geometry::assemble_transform(selection.get_first_volume()->get_sla_shift_z() * Vec3d::UnitZ()) *
|
||||
const Transform3d matrix = Geometry::translation_transform(selection.get_first_volume()->get_sla_shift_z() * Vec3d::UnitZ()) *
|
||||
selection.get_first_volume()->get_instance_transformation().get_matrix();
|
||||
|
||||
for (int i = 0; i < (int)m_planes.size(); ++i) {
|
||||
|
@ -155,9 +143,9 @@ void GLGizmoFlatten::on_unregister_raycasters_for_picking()
|
|||
m_planes_casters.clear();
|
||||
}
|
||||
|
||||
void GLGizmoFlatten::set_flattening_data(const ModelObject* model_object)
|
||||
void GLGizmoFlatten::set_flattening_data(const ModelObject* model_object, int instance_id)
|
||||
{
|
||||
if (model_object != m_old_model_object) {
|
||||
if (model_object != m_old_model_object || instance_id != m_old_instance_id) {
|
||||
m_planes.clear();
|
||||
on_unregister_raycasters_for_picking();
|
||||
}
|
||||
|
@ -237,9 +225,7 @@ void GLGizmoFlatten::update_planes()
|
|||
}
|
||||
|
||||
// Let's prepare transformation of the normal vector from mesh to instance coordinates.
|
||||
Geometry::Transformation t(inst_matrix);
|
||||
Vec3d scaling = t.get_scaling_factor();
|
||||
t.set_scaling_factor(Vec3d(1./scaling(0), 1./scaling(1), 1./scaling(2)));
|
||||
const Matrix3d normal_matrix = inst_matrix.matrix().block(0, 0, 3, 3).inverse().transpose();
|
||||
|
||||
// Now we'll go through all the polygons, transform the points into xy plane to process them:
|
||||
for (unsigned int polygon_id=0; polygon_id < m_planes.size(); ++polygon_id) {
|
||||
|
@ -247,7 +233,7 @@ void GLGizmoFlatten::update_planes()
|
|||
const Vec3d& normal = m_planes[polygon_id].normal;
|
||||
|
||||
// transform the normal according to the instance matrix:
|
||||
Vec3d normal_transformed = t.get_matrix() * normal;
|
||||
const Vec3d normal_transformed = normal_matrix * normal;
|
||||
|
||||
// We are going to rotate about z and y to flatten the plane
|
||||
Eigen::Quaterniond q;
|
||||
|
@ -260,7 +246,7 @@ void GLGizmoFlatten::update_planes()
|
|||
// And yes, it is a nasty thing to do. Whoever has time is free to refactor.
|
||||
Vec3d bb_size = BoundingBoxf3(polygon).size();
|
||||
float sf = std::min(1./bb_size(0), 1./bb_size(1));
|
||||
Transform3d tr = Geometry::assemble_transform(Vec3d::Zero(), Vec3d::Zero(), Vec3d(sf, sf, 1.f));
|
||||
Transform3d tr = Geometry::scale_transform({ sf, sf, 1.f });
|
||||
polygon = transform(polygon, tr);
|
||||
polygon = Slic3r::Geometry::convex_hull(polygon);
|
||||
polygon = transform(polygon, tr.inverse());
|
||||
|
@ -365,6 +351,7 @@ void GLGizmoFlatten::update_planes()
|
|||
m_first_instance_scale = mo->instances.front()->get_scaling_factor();
|
||||
m_first_instance_mirror = mo->instances.front()->get_mirror();
|
||||
m_old_model_object = mo;
|
||||
m_old_instance_id = m_c->selection_info()->get_active_instance();
|
||||
|
||||
// And finally create respective VBOs. The polygon is convex with
|
||||
// the vertices in order, so triangulation is trivial.
|
||||
|
@ -378,18 +365,24 @@ void GLGizmoFlatten::update_planes()
|
|||
for (size_t i = 1; i < plane.vertices.size() - 1; ++i) {
|
||||
its.indices.emplace_back(0, i, i + 1); // triangle fan
|
||||
}
|
||||
|
||||
plane.vbo.model.init_from(its);
|
||||
if (Geometry::Transformation(inst_matrix).is_left_handed()) {
|
||||
// we need to swap face normals in case the object is mirrored
|
||||
// for the raycaster to work properly
|
||||
for (stl_triangle_vertex_indices& face : its.indices) {
|
||||
if (its_face_normal(its, face).cast<double>().dot(plane.normal) < 0.0)
|
||||
std::swap(face[1], face[2]);
|
||||
}
|
||||
}
|
||||
plane.vbo.mesh_raycaster = std::make_unique<MeshRaycaster>(std::make_shared<const TriangleMesh>(std::move(its)));
|
||||
// FIXME: vertices should really be local, they need not
|
||||
// persist now when we use VBOs
|
||||
plane.vertices.clear();
|
||||
plane.vertices.shrink_to_fit();
|
||||
// vertices are no more needed, clear memory
|
||||
plane.vertices = std::vector<Vec3d>();
|
||||
}
|
||||
|
||||
on_register_raycasters_for_picking();
|
||||
}
|
||||
|
||||
|
||||
bool GLGizmoFlatten::is_plane_update_necessary() const
|
||||
{
|
||||
const ModelObject* mo = m_c->selection_info()->model_object();
|
||||
|
|
|
@ -1,3 +1,7 @@
|
|||
///|/ Copyright (c) Prusa Research 2019 - 2023 Oleksandra Iushchenko @YuSanka, Lukáš Matěna @lukasmatena, Enrico Turri @enricoturri1966, Filip Sykala @Jony01
|
||||
///|/
|
||||
///|/ PrusaSlicer is released under the terms of the AGPLv3 or higher
|
||||
///|/
|
||||
#ifndef slic3r_GLGizmoFlatten_hpp_
|
||||
#define slic3r_GLGizmoFlatten_hpp_
|
||||
|
||||
|
@ -35,9 +39,8 @@ private:
|
|||
|
||||
std::vector<PlaneData> m_planes;
|
||||
std::vector<std::shared_ptr<SceneRaycasterItem>> m_planes_casters;
|
||||
bool m_mouse_left_down = false; // for detection left_up of this gizmo
|
||||
const ModelObject* m_old_model_object = nullptr;
|
||||
std::vector<const Transform3d*> instances_matrices;
|
||||
int m_old_instance_id{ -1 };
|
||||
|
||||
void update_planes();
|
||||
bool is_plane_update_necessary() const;
|
||||
|
@ -45,7 +48,7 @@ private:
|
|||
public:
|
||||
GLGizmoFlatten(GLCanvas3D& parent, const std::string& icon_filename, unsigned int sprite_id);
|
||||
|
||||
void set_flattening_data(const ModelObject* model_object);
|
||||
void set_flattening_data(const ModelObject* model_object, int instance_id);
|
||||
|
||||
/// <summary>
|
||||
/// Apply rotation on select plane
|
||||
|
@ -54,7 +57,7 @@ public:
|
|||
/// <returns>Return True when use the information otherwise False.</returns>
|
||||
bool on_mouse(const wxMouseEvent &mouse_event) override;
|
||||
|
||||
void data_changed() override;
|
||||
void data_changed(bool is_serializing) override;
|
||||
protected:
|
||||
bool on_init() override;
|
||||
std::string on_get_name() const override;
|
||||
|
|
|
@ -1,3 +1,8 @@
|
|||
///|/ Copyright (c) Prusa Research 2019 - 2023 Oleksandra Iushchenko @YuSanka, Lukáš Matěna @lukasmatena, Enrico Turri @enricoturri1966, Filip Sykala @Jony01, Lukáš Hejl @hejllukas, David Kocík @kocikdav, Vojtěch Bubník @bubnikv
|
||||
///|/ Copyright (c) 2021 Justin Schuh @jschuh
|
||||
///|/
|
||||
///|/ PrusaSlicer is released under the terms of the AGPLv3 or higher
|
||||
///|/
|
||||
#include "GLGizmoMmuSegmentation.hpp"
|
||||
|
||||
#include "slic3r/GUI/GLCanvas3D.hpp"
|
||||
|
@ -162,9 +167,9 @@ void GLGizmoMmuSegmentation::render_painter_gizmo()
|
|||
glsafe(::glDisable(GL_BLEND));
|
||||
}
|
||||
|
||||
void GLGizmoMmuSegmentation::data_changed()
|
||||
void GLGizmoMmuSegmentation::data_changed(bool is_serializing)
|
||||
{
|
||||
GLGizmoPainterBase::data_changed();
|
||||
GLGizmoPainterBase::data_changed(is_serializing);
|
||||
if (m_state != On || wxGetApp().preset_bundle->printers.get_edited_preset().printer_technology() != ptFFF || wxGetApp().extruders_edited_cnt() <= 1)
|
||||
return;
|
||||
|
||||
|
@ -571,7 +576,7 @@ void GLGizmoMmuSegmentation::on_render_input_window(float x, float y, float bott
|
|||
else {
|
||||
if (m_imgui->button(m_desc.at("reset_direction"))) {
|
||||
wxGetApp().CallAfter([this]() {
|
||||
m_c->object_clipper()->set_position(-1., false);
|
||||
m_c->object_clipper()->set_position_by_ratio(-1., false);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
@ -584,7 +589,7 @@ void GLGizmoMmuSegmentation::on_render_input_window(float x, float y, float bott
|
|||
ImGui::PushItemWidth(1.5 * slider_icon_width);
|
||||
bool b_clp_dist_input = ImGui::BBLDragFloat("##clp_dist_input", &clp_dist, 0.05f, 0.0f, 0.0f, "%.2f");
|
||||
|
||||
if (slider_clp_dist || b_clp_dist_input) { m_c->object_clipper()->set_position(clp_dist, true); }
|
||||
if (slider_clp_dist || b_clp_dist_input) { m_c->object_clipper()->set_position_by_ratio(clp_dist, true); }
|
||||
|
||||
} else if (m_current_tool == ImGui::TriangleButtonIcon) {
|
||||
m_cursor_type = TriangleSelector::CursorType::POINTER;
|
||||
|
@ -597,7 +602,7 @@ void GLGizmoMmuSegmentation::on_render_input_window(float x, float y, float bott
|
|||
else {
|
||||
if (m_imgui->button(m_desc.at("reset_direction"))) {
|
||||
wxGetApp().CallAfter([this]() {
|
||||
m_c->object_clipper()->set_position(-1., false);
|
||||
m_c->object_clipper()->set_position_by_ratio(-1., false);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
@ -610,7 +615,7 @@ void GLGizmoMmuSegmentation::on_render_input_window(float x, float y, float bott
|
|||
ImGui::PushItemWidth(1.5 * slider_icon_width);
|
||||
bool b_clp_dist_input = ImGui::BBLDragFloat("##clp_dist_input", &clp_dist, 0.05f, 0.0f, 0.0f, "%.2f");
|
||||
|
||||
if (slider_clp_dist || b_clp_dist_input) { m_c->object_clipper()->set_position(clp_dist, true); }
|
||||
if (slider_clp_dist || b_clp_dist_input) { m_c->object_clipper()->set_position_by_ratio(clp_dist, true); }
|
||||
|
||||
} else if (m_current_tool == ImGui::FillButtonIcon) {
|
||||
m_cursor_type = TriangleSelector::CursorType::POINTER;
|
||||
|
@ -644,7 +649,7 @@ void GLGizmoMmuSegmentation::on_render_input_window(float x, float y, float bott
|
|||
else {
|
||||
if (m_imgui->button(m_desc.at("reset_direction"))) {
|
||||
wxGetApp().CallAfter([this]() {
|
||||
m_c->object_clipper()->set_position(-1., false);
|
||||
m_c->object_clipper()->set_position_by_ratio(-1., false);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
@ -657,7 +662,7 @@ void GLGizmoMmuSegmentation::on_render_input_window(float x, float y, float bott
|
|||
ImGui::PushItemWidth(1.5 * slider_icon_width);
|
||||
bool b_clp_dist_input = ImGui::BBLDragFloat("##clp_dist_input", &clp_dist, 0.05f, 0.0f, 0.0f, "%.2f");
|
||||
|
||||
if (slider_clp_dist || b_clp_dist_input) { m_c->object_clipper()->set_position(clp_dist, true);}
|
||||
if (slider_clp_dist || b_clp_dist_input) { m_c->object_clipper()->set_position_by_ratio(clp_dist, true);}
|
||||
|
||||
} else if (m_current_tool == ImGui::HeightRangeIcon) {
|
||||
m_tool_type = ToolType::BRUSH;
|
||||
|
@ -680,7 +685,7 @@ void GLGizmoMmuSegmentation::on_render_input_window(float x, float y, float bott
|
|||
else {
|
||||
if (m_imgui->button(m_desc.at("reset_direction"))) {
|
||||
wxGetApp().CallAfter([this]() {
|
||||
m_c->object_clipper()->set_position(-1., false);
|
||||
m_c->object_clipper()->set_position_by_ratio(-1., false);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
@ -693,7 +698,7 @@ void GLGizmoMmuSegmentation::on_render_input_window(float x, float y, float bott
|
|||
ImGui::PushItemWidth(1.5 * slider_icon_width);
|
||||
bool b_clp_dist_input = ImGui::BBLDragFloat("##clp_dist_input", &clp_dist, 0.05f, 0.0f, 0.0f, "%.2f");
|
||||
|
||||
if (slider_clp_dist || b_clp_dist_input) { m_c->object_clipper()->set_position(clp_dist, true); }
|
||||
if (slider_clp_dist || b_clp_dist_input) { m_c->object_clipper()->set_position_by_ratio(clp_dist, true); }
|
||||
}
|
||||
else if (m_current_tool == ImGui::GapFillIcon) {
|
||||
m_tool_type = ToolType::GAP_FILL;
|
||||
|
|
|
@ -70,7 +70,7 @@ public:
|
|||
|
||||
void render_painter_gizmo() override;
|
||||
|
||||
void data_changed() override;
|
||||
void data_changed(bool is_serializing) override;
|
||||
|
||||
void render_triangles(const Selection& selection) const override;
|
||||
|
||||
|
@ -104,7 +104,7 @@ protected:
|
|||
|
||||
std::string get_gizmo_entering_text() const override { return "Entering color painting"; }
|
||||
std::string get_gizmo_leaving_text() const override { return "Leaving color painting"; }
|
||||
std::string get_action_snapshot_name() override { return "Color painting editing"; }
|
||||
std::string get_action_snapshot_name() const override { return "Color painting editing"; }
|
||||
|
||||
// BBS
|
||||
size_t m_selected_extruder_idx = 0;
|
||||
|
|
|
@ -1,4 +1,7 @@
|
|||
// Include GLGizmoBase.hpp before I18N.hpp as it includes some libigl code, which overrides our localization "L" macro.
|
||||
///|/ Copyright (c) Prusa Research 2019 - 2023 Enrico Turri @enricoturri1966, Oleksandra Iushchenko @YuSanka, Lukáš Matěna @lukasmatena, Filip Sykala @Jony01, Vojtěch Bubník @bubnikv
|
||||
///|/
|
||||
///|/ PrusaSlicer is released under the terms of the AGPLv3 or higher
|
||||
///|/
|
||||
#include "GLGizmoMove.hpp"
|
||||
#include "slic3r/GUI/GLCanvas3D.hpp"
|
||||
#include "slic3r/GUI/GUI_App.hpp"
|
||||
|
@ -47,10 +50,8 @@ bool GLGizmoMove3D::on_mouse(const wxMouseEvent &mouse_event) {
|
|||
return use_grabbers(mouse_event);
|
||||
}
|
||||
|
||||
void GLGizmoMove3D::data_changed() {
|
||||
const Selection &selection = m_parent.get_selection();
|
||||
bool is_wipe_tower = selection.is_wipe_tower();
|
||||
m_grabbers[2].enabled = !is_wipe_tower;
|
||||
void GLGizmoMove3D::data_changed(bool is_serializing) {
|
||||
m_grabbers[2].enabled = !m_parent.get_selection().is_wipe_tower();
|
||||
}
|
||||
|
||||
bool GLGizmoMove3D::on_init()
|
||||
|
@ -219,17 +220,17 @@ double GLGizmoMove3D::calc_projection(const UpdateData& data) const
|
|||
{
|
||||
double projection = 0.0;
|
||||
|
||||
Vec3d starting_vec = m_starting_drag_position - m_starting_box_center;
|
||||
double len_starting_vec = starting_vec.norm();
|
||||
const Vec3d starting_vec = m_starting_drag_position - m_starting_box_center;
|
||||
const double len_starting_vec = starting_vec.norm();
|
||||
if (len_starting_vec != 0.0) {
|
||||
Vec3d mouse_dir = data.mouse_ray.unit_vector();
|
||||
const Vec3d mouse_dir = data.mouse_ray.unit_vector();
|
||||
// finds the intersection of the mouse ray with the plane parallel to the camera viewport and passing throught the starting position
|
||||
// use ray-plane intersection see i.e. https://en.wikipedia.org/wiki/Line%E2%80%93plane_intersection algebric form
|
||||
// in our case plane normal and ray direction are the same (orthogonal view)
|
||||
// when moving to perspective camera the negative z unit axis of the camera needs to be transformed in world space and used as plane normal
|
||||
Vec3d inters = data.mouse_ray.a + (m_starting_drag_position - data.mouse_ray.a).dot(mouse_dir) / mouse_dir.squaredNorm() * mouse_dir;
|
||||
const Vec3d inters = data.mouse_ray.a + (m_starting_drag_position - data.mouse_ray.a).dot(mouse_dir) * mouse_dir;
|
||||
// vector from the starting position to the found intersection
|
||||
Vec3d inters_vec = inters - m_starting_drag_position;
|
||||
const Vec3d inters_vec = inters - m_starting_drag_position;
|
||||
|
||||
// finds projection of the vector along the staring direction
|
||||
projection = inters_vec.dot(starting_vec.normalized());
|
||||
|
|
|
@ -1,3 +1,7 @@
|
|||
///|/ Copyright (c) Prusa Research 2019 - 2023 Lukáš Matěna @lukasmatena, Enrico Turri @enricoturri1966, Oleksandra Iushchenko @YuSanka, Filip Sykala @Jony01
|
||||
///|/
|
||||
///|/ PrusaSlicer is released under the terms of the AGPLv3 or higher
|
||||
///|/
|
||||
#ifndef slic3r_GLGizmoMove_hpp_
|
||||
#define slic3r_GLGizmoMove_hpp_
|
||||
|
||||
|
@ -52,7 +56,7 @@ public:
|
|||
/// <summary>
|
||||
/// Detect reduction of move for wipetover on selection change
|
||||
/// </summary>
|
||||
void data_changed() override;
|
||||
void data_changed(bool is_serializing) override;
|
||||
protected:
|
||||
bool on_init() override;
|
||||
std::string on_get_name() const override;
|
||||
|
|
|
@ -1,4 +1,7 @@
|
|||
// Include GLGizmoBase.hpp before I18N.hpp as it includes some libigl code, which overrides our localization "L" macro.
|
||||
///|/ Copyright (c) Prusa Research 2019 - 2023 Oleksandra Iushchenko @YuSanka, Lukáš Matěna @lukasmatena, Enrico Turri @enricoturri1966, Vojtěch Bubník @bubnikv, Filip Sykala @Jony01, Lukáš Hejl @hejllukas
|
||||
///|/
|
||||
///|/ PrusaSlicer is released under the terms of the AGPLv3 or higher
|
||||
///|/
|
||||
#include "GLGizmoPainterBase.hpp"
|
||||
#include "slic3r/GUI/GLCanvas3D.hpp"
|
||||
#include "slic3r/GUI/Gizmos/GLGizmosCommon.hpp"
|
||||
|
@ -34,7 +37,7 @@ GLGizmoPainterBase::~GLGizmoPainterBase()
|
|||
s_sphere.reset();
|
||||
}
|
||||
|
||||
void GLGizmoPainterBase::data_changed()
|
||||
void GLGizmoPainterBase::data_changed(bool is_serializing)
|
||||
{
|
||||
if (m_state != On)
|
||||
return;
|
||||
|
@ -120,13 +123,11 @@ void GLGizmoPainterBase::render_triangles(const Selection& selection) const
|
|||
shader->set_uniform("volume_world_matrix", trafo_matrix);
|
||||
|
||||
m_triangle_selectors[mesh_id]->render(m_imgui, trafo_matrix);
|
||||
|
||||
if (is_left_handed)
|
||||
glsafe(::glFrontFace(GL_CCW));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void GLGizmoPainterBase::render_cursor()
|
||||
{
|
||||
// First check that the mouse pointer is on an object.
|
||||
|
@ -165,11 +166,9 @@ void GLGizmoPainterBase::render_cursor()
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
void GLGizmoPainterBase::render_cursor_circle()
|
||||
{
|
||||
const Size cnv_size = m_parent.get_canvas_size();
|
||||
const Size cnv_size = m_parent.get_canvas_size();
|
||||
const float cnv_width = float(cnv_size.get_width());
|
||||
const float cnv_height = float(cnv_size.get_height());
|
||||
if (cnv_width == 0.0f || cnv_height == 0.0f)
|
||||
|
@ -202,7 +201,7 @@ void GLGizmoPainterBase::render_cursor_circle()
|
|||
init_data.reserve_indices(StepsCount);
|
||||
|
||||
// vertices + indices
|
||||
for (unsigned short i = 0; i < StepsCount; ++i) {
|
||||
for (unsigned int i = 0; i < StepsCount; ++i) {
|
||||
const float angle = float(i * StepSize);
|
||||
init_data.add_vertex(Vec2f(2.0f * ((center.x() + ::cos(angle) * radius) * cnv_inv_width - 0.5f),
|
||||
-2.0f * ((center.y() + ::sin(angle) * radius) * cnv_inv_height - 0.5f)));
|
||||
|
@ -220,8 +219,8 @@ void GLGizmoPainterBase::render_cursor_circle()
|
|||
render_color = this->get_cursor_sphere_right_button_color();
|
||||
|
||||
m_circle.set_color(render_color);
|
||||
|
||||
GLShaderProgram* shader = wxGetApp().get_shader("flat");
|
||||
|
||||
GLShaderProgram* shader = GUI::wxGetApp().get_shader("flat");
|
||||
if (shader != nullptr) {
|
||||
shader->start_using();
|
||||
shader->set_uniform("view_model_matrix", Transform3d::Identity());
|
||||
|
@ -247,10 +246,6 @@ void GLGizmoPainterBase::render_cursor_sphere(const Transform3d& trafo) const
|
|||
return;
|
||||
|
||||
const Transform3d complete_scaling_matrix_inverse = Geometry::Transformation(trafo).get_matrix(true, true, false, true).inverse();
|
||||
const bool is_left_handed = Geometry::Transformation(trafo).is_left_handed();
|
||||
|
||||
if (is_left_handed)
|
||||
glFrontFace(GL_CW);
|
||||
|
||||
// BBS
|
||||
ColorRGBA render_color = this->get_cursor_hover_color();
|
||||
|
@ -258,6 +253,7 @@ void GLGizmoPainterBase::render_cursor_sphere(const Transform3d& trafo) const
|
|||
render_color = this->get_cursor_sphere_left_button_color();
|
||||
else if (m_button_down == Button::Right)
|
||||
render_color = this->get_cursor_sphere_right_button_color();
|
||||
|
||||
shader->start_using();
|
||||
|
||||
const Camera& camera = wxGetApp().plater()->get_camera();
|
||||
|
@ -268,13 +264,18 @@ void GLGizmoPainterBase::render_cursor_sphere(const Transform3d& trafo) const
|
|||
shader->set_uniform("view_model_matrix", view_model_matrix);
|
||||
shader->set_uniform("projection_matrix", camera.get_projection_matrix());
|
||||
|
||||
const bool is_left_handed = Geometry::Transformation(view_model_matrix).is_left_handed();
|
||||
if (is_left_handed)
|
||||
glsafe(::glFrontFace(GL_CW));
|
||||
|
||||
assert(s_sphere != nullptr);
|
||||
s_sphere->set_color(render_color);
|
||||
s_sphere->render();
|
||||
|
||||
shader->stop_using();
|
||||
if (is_left_handed)
|
||||
glFrontFace(GL_CCW);
|
||||
glsafe(::glFrontFace(GL_CCW));
|
||||
|
||||
shader->stop_using();
|
||||
}
|
||||
|
||||
// BBS
|
||||
|
@ -631,13 +632,13 @@ bool GLGizmoPainterBase::gizmo_event(SLAGizmoEventType action, const Vec2d& mous
|
|||
pos = action == SLAGizmoEventType::MouseWheelDown
|
||||
? std::max(0., pos - 0.01)
|
||||
: std::min(1., pos + 0.01);
|
||||
m_c->object_clipper()->set_position(pos, true);
|
||||
m_c->object_clipper()->set_position_by_ratio(pos, true);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
if (action == SLAGizmoEventType::ResetClippingPlane) {
|
||||
m_c->object_clipper()->set_position(-1., false);
|
||||
m_c->object_clipper()->set_position_by_ratio(-1., false);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -788,14 +789,13 @@ bool GLGizmoPainterBase::gizmo_event(SLAGizmoEventType action, const Vec2d& mous
|
|||
assert(m_cursor_type == TriangleSelector::CursorType::CIRCLE || m_cursor_type == TriangleSelector::CursorType::SPHERE);
|
||||
|
||||
if (projected_mouse_positions.size() == 1) {
|
||||
const ProjectedMousePosition& first_position = projected_mouse_positions.front();
|
||||
std::unique_ptr<TriangleSelector::Cursor> cursor = TriangleSelector::SinglePointCursor::cursor_factory(first_position.mesh_hit,
|
||||
camera_pos, m_cursor_radius,
|
||||
m_cursor_type, trafo_matrix, clp);
|
||||
const ProjectedMousePosition &first_position = projected_mouse_positions.front();
|
||||
std::unique_ptr<TriangleSelector::Cursor> cursor = TriangleSelector::SinglePointCursor::cursor_factory(first_position.mesh_hit,
|
||||
camera_pos, m_cursor_radius,
|
||||
m_cursor_type, trafo_matrix, clp);
|
||||
m_triangle_selectors[mesh_idx]->select_patch(int(first_position.facet_idx), std::move(cursor), new_state, trafo_matrix_not_translate,
|
||||
m_triangle_splitting_enabled, m_paint_on_overhangs_only ? m_highlight_by_angle_threshold_deg : 0.f);
|
||||
}
|
||||
else {
|
||||
m_triangle_splitting_enabled, m_paint_on_overhangs_only ? m_highlight_by_angle_threshold_deg : 0.f);
|
||||
} else {
|
||||
for (auto first_position_it = projected_mouse_positions.cbegin(); first_position_it != projected_mouse_positions.cend() - 1; ++first_position_it) {
|
||||
auto second_position_it = first_position_it + 1;
|
||||
std::unique_ptr<TriangleSelector::Cursor> cursor = TriangleSelector::DoublePointCursor::cursor_factory(first_position_it->mesh_hit, second_position_it->mesh_hit, camera_pos, m_cursor_radius, m_cursor_type, trafo_matrix, clp);
|
||||
|
@ -1190,10 +1190,6 @@ void TriangleSelectorGUI::update_render_data()
|
|||
static const float offset = 0.001f;
|
||||
|
||||
for (const Triangle &tr : m_triangles) {
|
||||
bool is_valid = tr.valid();
|
||||
bool is_split = tr.is_split();
|
||||
EnforcerBlockerType type = tr.get_state();
|
||||
bool is_select_by_seed_fill = tr.is_selected_by_seed_fill();
|
||||
if (!tr.valid() || tr.is_split() || (tr.get_state() == EnforcerBlockerType::NONE && !tr.is_selected_by_seed_fill()))
|
||||
continue;
|
||||
|
||||
|
|
|
@ -1,3 +1,7 @@
|
|||
///|/ Copyright (c) Prusa Research 2019 - 2023 Pavel Mikuš @Godrak, Lukáš Matěna @lukasmatena, Enrico Turri @enricoturri1966, Vojtěch Bubník @bubnikv, Lukáš Hejl @hejllukas, Filip Sykala @Jony01
|
||||
///|/
|
||||
///|/ PrusaSlicer is released under the terms of the AGPLv3 or higher
|
||||
///|/
|
||||
#ifndef slic3r_GLGizmoPainterBase_hpp_
|
||||
#define slic3r_GLGizmoPainterBase_hpp_
|
||||
|
||||
|
@ -186,10 +190,11 @@ private:
|
|||
ObjectID m_old_mo_id;
|
||||
size_t m_old_volumes_size = 0;
|
||||
void on_render() override {}
|
||||
|
||||
public:
|
||||
GLGizmoPainterBase(GLCanvas3D& parent, const std::string& icon_filename, unsigned int sprite_id);
|
||||
virtual ~GLGizmoPainterBase() override;
|
||||
void data_changed() override;
|
||||
~GLGizmoPainterBase() override;
|
||||
void data_changed(bool is_serializing) override;
|
||||
virtual bool gizmo_event(SLAGizmoEventType action, const Vec2d& mouse_position, bool shift_down, bool alt_down, bool control_down);
|
||||
|
||||
// Following function renders the triangles and cursor. Having this separated
|
||||
|
@ -227,8 +232,8 @@ protected:
|
|||
virtual void update_model_object() = 0;
|
||||
virtual void update_from_model_object(bool first_update) = 0;
|
||||
|
||||
virtual ColorRGBA get_cursor_sphere_left_button_color() const { return {0.f, 0.f, 1.f, 0.25f}; }
|
||||
virtual ColorRGBA get_cursor_sphere_right_button_color() const { return {1.f, 0.f, 0.f, 0.25f}; }
|
||||
virtual ColorRGBA get_cursor_sphere_left_button_color() const { return { 0.0f, 0.0f, 1.0f, 0.25f }; }
|
||||
virtual ColorRGBA get_cursor_sphere_right_button_color() const { return { 1.0f, 0.0f, 0.0f, 0.25f }; }
|
||||
// BBS
|
||||
virtual ColorRGBA get_cursor_hover_color() const { return { 0.f, 0.f, 0.f, 0.25f }; }
|
||||
|
||||
|
@ -339,7 +344,7 @@ private:
|
|||
Vec3f hit;
|
||||
size_t facet;
|
||||
};
|
||||
mutable RaycastResult m_rr;
|
||||
mutable RaycastResult m_rr = {Vec2d::Zero(), -1, Vec3f::Zero(), 0};
|
||||
|
||||
// BBS
|
||||
struct CutContours
|
||||
|
|
|
@ -1,4 +1,7 @@
|
|||
// Include GLGizmoBase.hpp before I18N.hpp as it includes some libigl code, which overrides our localization "L" macro.
|
||||
///|/ Copyright (c) Prusa Research 2019 - 2023 Oleksandra Iushchenko @YuSanka, Lukáš Matěna @lukasmatena, Enrico Turri @enricoturri1966, Tomáš Mészáros @tamasmeszaros, Filip Sykala @Jony01, Vojtěch Bubník @bubnikv
|
||||
///|/
|
||||
///|/ PrusaSlicer is released under the terms of the AGPLv3 or higher
|
||||
///|/
|
||||
#include "GLGizmoRotate.hpp"
|
||||
#include "slic3r/GUI/GLCanvas3D.hpp"
|
||||
#include "slic3r/GUI/ImGuiWrapper.hpp"
|
||||
|
@ -235,7 +238,7 @@ void GLGizmoRotate::render_circle(const ColorRGBA& color, bool radius_changed)
|
|||
init_data.reserve_indices(ScaleStepsCount);
|
||||
|
||||
// vertices + indices
|
||||
for (unsigned short i = 0; i < ScaleStepsCount; ++i) {
|
||||
for (unsigned int i = 0; i < ScaleStepsCount; ++i) {
|
||||
const float angle = float(i * ScaleStepRad);
|
||||
init_data.add_vertex(Vec3f(::cos(angle) * m_radius, ::sin(angle) * m_radius, 0.0f));
|
||||
init_data.add_index(i);
|
||||
|
@ -262,7 +265,7 @@ void GLGizmoRotate::render_scale(const ColorRGBA& color, bool radius_changed)
|
|||
init_data.reserve_indices(2 * ScaleStepsCount);
|
||||
|
||||
// vertices + indices
|
||||
for (unsigned short i = 0; i < ScaleStepsCount; ++i) {
|
||||
for (unsigned int i = 0; i < ScaleStepsCount; ++i) {
|
||||
const float angle = float(i * ScaleStepRad);
|
||||
const float cosa = ::cos(angle);
|
||||
const float sina = ::sin(angle);
|
||||
|
@ -271,10 +274,12 @@ void GLGizmoRotate::render_scale(const ColorRGBA& color, bool radius_changed)
|
|||
const float out_x = (i % ScaleLongEvery == 0) ? cosa * out_radius_long : cosa * out_radius_short;
|
||||
const float out_y = (i % ScaleLongEvery == 0) ? sina * out_radius_long : sina * out_radius_short;
|
||||
|
||||
// vertices
|
||||
init_data.add_vertex(Vec3f(in_x, in_y, 0.0f));
|
||||
init_data.add_vertex(Vec3f(out_x, out_y, 0.0f));
|
||||
init_data.add_index(i * 2);
|
||||
init_data.add_index(i * 2 + 1);
|
||||
|
||||
// indices
|
||||
init_data.add_line(i * 2, i * 2 + 1);
|
||||
}
|
||||
|
||||
m_scale.init_from(std::move(init_data));
|
||||
|
@ -299,7 +304,7 @@ void GLGizmoRotate::render_snap_radii(const ColorRGBA& color, bool radius_change
|
|||
init_data.reserve_indices(2 * ScaleStepsCount);
|
||||
|
||||
// vertices + indices
|
||||
for (unsigned short i = 0; i < ScaleStepsCount; ++i) {
|
||||
for (unsigned int i = 0; i < ScaleStepsCount; ++i) {
|
||||
const float angle = float(i * step);
|
||||
const float cosa = ::cos(angle);
|
||||
const float sina = ::sin(angle);
|
||||
|
@ -308,10 +313,12 @@ void GLGizmoRotate::render_snap_radii(const ColorRGBA& color, bool radius_change
|
|||
const float out_x = cosa * out_radius;
|
||||
const float out_y = sina * out_radius;
|
||||
|
||||
// vertices
|
||||
init_data.add_vertex(Vec3f(in_x, in_y, 0.0f));
|
||||
init_data.add_vertex(Vec3f(out_x, out_y, 0.0f));
|
||||
init_data.add_index(i * 2);
|
||||
init_data.add_index(i * 2 + 1);
|
||||
|
||||
// indices
|
||||
init_data.add_line(i * 2, i * 2 + 1);
|
||||
}
|
||||
|
||||
m_snap_radii.init_from(std::move(init_data));
|
||||
|
@ -362,7 +369,7 @@ void GLGizmoRotate::render_angle_arc(const ColorRGBA& color, bool radius_changed
|
|||
init_data.reserve_indices(1 + AngleResolution);
|
||||
|
||||
// vertices + indices
|
||||
for (unsigned short i = 0; i <= AngleResolution; ++i) {
|
||||
for (unsigned int i = 0; i <= AngleResolution; ++i) {
|
||||
const float angle = float(i) * step_angle;
|
||||
init_data.add_vertex(Vec3f(::cos(angle) * ex_radius, ::sin(angle) * ex_radius, 0.0f));
|
||||
init_data.add_index(i);
|
||||
|
@ -439,7 +446,7 @@ Transform3d GLGizmoRotate::local_transform(const Selection& selection) const
|
|||
|
||||
Vec3d GLGizmoRotate::mouse_position_in_local_plane(const Linef3& mouse_ray, const Selection& selection) const
|
||||
{
|
||||
double half_pi = 0.5 * double(PI);
|
||||
const double half_pi = 0.5 * double(PI);
|
||||
|
||||
Transform3d m = Transform3d::Identity();
|
||||
|
||||
|
@ -470,7 +477,20 @@ Vec3d GLGizmoRotate::mouse_position_in_local_plane(const Linef3& mouse_ray, cons
|
|||
|
||||
m.translate(-m_center);
|
||||
|
||||
return transform(mouse_ray, m).intersect_plane(0.0);
|
||||
const Linef3 local_mouse_ray = transform(mouse_ray, m);
|
||||
if (std::abs(local_mouse_ray.vector().dot(Vec3d::UnitZ())) < EPSILON) {
|
||||
// if the ray is parallel to the plane containing the circle
|
||||
if (std::abs(local_mouse_ray.vector().dot(Vec3d::UnitY())) > 1.0 - EPSILON)
|
||||
// if the ray is parallel to grabber direction
|
||||
return Vec3d::UnitX();
|
||||
else {
|
||||
const Vec3d world_pos = (local_mouse_ray.a.x() >= 0.0) ? mouse_ray.a - m_center : mouse_ray.b - m_center;
|
||||
m.translate(m_center);
|
||||
return m * world_pos;
|
||||
}
|
||||
}
|
||||
else
|
||||
return local_mouse_ray.intersect_plane(0.0);
|
||||
}
|
||||
|
||||
//BBS: GUI refactor: add obj manipulation
|
||||
|
@ -489,13 +509,14 @@ bool GLGizmoRotate3D::on_mouse(const wxMouseEvent &mouse_event) {
|
|||
// Apply new temporary rotations
|
||||
TransformationType transformation_type(
|
||||
TransformationType::World_Relative_Joint);
|
||||
if (mouse_event.AltDown()) transformation_type.set_independent();
|
||||
if (mouse_event.AltDown())
|
||||
transformation_type.set_independent();
|
||||
m_parent.get_selection().rotate(get_rotation(), transformation_type);
|
||||
}
|
||||
return use_grabbers(mouse_event);
|
||||
}
|
||||
|
||||
void GLGizmoRotate3D::data_changed() {
|
||||
void GLGizmoRotate3D::data_changed(bool is_serializing) {
|
||||
const Selection &selection = m_parent.get_selection();
|
||||
bool is_wipe_tower = selection.is_wipe_tower();
|
||||
if (is_wipe_tower) {
|
||||
|
|
|
@ -1,3 +1,7 @@
|
|||
///|/ Copyright (c) Prusa Research 2019 - 2023 Lukáš Matěna @lukasmatena, Enrico Turri @enricoturri1966, Oleksandra Iushchenko @YuSanka, Filip Sykala @Jony01, Tomáš Mészáros @tamasmeszaros
|
||||
///|/
|
||||
///|/ PrusaSlicer is released under the terms of the AGPLv3 or higher
|
||||
///|/
|
||||
#ifndef slic3r_GLGizmoRotate_hpp_
|
||||
#define slic3r_GLGizmoRotate_hpp_
|
||||
|
||||
|
@ -85,6 +89,7 @@ public:
|
|||
/// <returns>Return True when use the information otherwise False.</returns>
|
||||
bool on_mouse(const wxMouseEvent &mouse_event) override;
|
||||
void dragging(const UpdateData &data);
|
||||
|
||||
protected:
|
||||
bool on_init() override;
|
||||
std::string on_get_name() const override { return ""; }
|
||||
|
@ -122,7 +127,7 @@ public:
|
|||
GLGizmoRotate3D(GLCanvas3D& parent, const std::string& icon_filename, unsigned int sprite_id, GizmoObjectManipulation* obj_manipulation);
|
||||
|
||||
Vec3d get_rotation() const { return Vec3d(m_gizmos[X].get_angle(), m_gizmos[Y].get_angle(), m_gizmos[Z].get_angle()); }
|
||||
void set_rotation(const Vec3d& rotation) { m_gizmos[X].set_angle(rotation(0)); m_gizmos[Y].set_angle(rotation(1)); m_gizmos[Z].set_angle(rotation(2)); }
|
||||
void set_rotation(const Vec3d& rotation) { m_gizmos[X].set_angle(rotation.x()); m_gizmos[Y].set_angle(rotation.y()); m_gizmos[Z].set_angle(rotation.z()); }
|
||||
|
||||
std::string get_tooltip() const override {
|
||||
std::string tooltip = m_gizmos[X].get_tooltip();
|
||||
|
@ -147,7 +152,7 @@ public:
|
|||
/// <returns>Return True when use the information otherwise False.</returns>
|
||||
bool on_mouse(const wxMouseEvent &mouse_event) override;
|
||||
|
||||
void data_changed() override;
|
||||
void data_changed(bool is_serializing) override;
|
||||
protected:
|
||||
bool on_init() override;
|
||||
std::string on_get_name() const override;
|
||||
|
|
|
@ -1,4 +1,7 @@
|
|||
// Include GLGizmoBase.hpp before I18N.hpp as it includes some libigl code, which overrides our localization "L" macro.
|
||||
///|/ Copyright (c) Prusa Research 2019 - 2023 Oleksandra Iushchenko @YuSanka, Lukáš Matěna @lukasmatena, Enrico Turri @enricoturri1966, Filip Sykala @Jony01, Vojtěch Bubník @bubnikv
|
||||
///|/
|
||||
///|/ PrusaSlicer is released under the terms of the AGPLv3 or higher
|
||||
///|/
|
||||
#include "GLGizmoScale.hpp"
|
||||
#include "slic3r/GUI/GLCanvas3D.hpp"
|
||||
#include "slic3r/GUI/GUI_App.hpp"
|
||||
|
@ -83,18 +86,18 @@ bool GLGizmoScale3D::on_mouse(const wxMouseEvent &mouse_event)
|
|||
if (m_dragging) {
|
||||
// Apply new temporary scale factors
|
||||
TransformationType transformation_type(TransformationType::Local_Absolute_Joint);
|
||||
if (mouse_event.AltDown()) transformation_type.set_independent();
|
||||
if (mouse_event.AltDown())
|
||||
transformation_type.set_independent();
|
||||
|
||||
Selection &selection = m_parent.get_selection();
|
||||
selection.scale(get_scale(), transformation_type);
|
||||
Selection& selection = m_parent.get_selection();
|
||||
selection.scale(m_scale, transformation_type);
|
||||
if (mouse_event.CmdDown()) selection.translate(m_offset, true);
|
||||
}
|
||||
}
|
||||
return use_grabbers(mouse_event);
|
||||
}
|
||||
|
||||
void GLGizmoScale3D::data_changed()
|
||||
{
|
||||
void GLGizmoScale3D::data_changed(bool is_serializing) {
|
||||
const Selection &selection = m_parent.get_selection();
|
||||
bool enable_scale_xyz = selection.is_single_full_instance() ||
|
||||
selection.is_single_volume() ||
|
||||
|
@ -298,7 +301,13 @@ void GLGizmoScale3D::on_render()
|
|||
}
|
||||
|
||||
// draw grabbers
|
||||
render_grabbers(grabber_mean_size);
|
||||
shader = wxGetApp().get_shader("gouraud_light");
|
||||
if (shader != nullptr) {
|
||||
shader->start_using();
|
||||
shader->set_uniform("emission_factor", 0.1f);
|
||||
render_grabbers(grabber_mean_size);
|
||||
shader->stop_using();
|
||||
}
|
||||
}
|
||||
|
||||
void GLGizmoScale3D::on_register_raycasters_for_picking()
|
||||
|
@ -388,9 +397,9 @@ void GLGizmoScale3D::do_scale_along_axis(Axis axis, const UpdateData& data)
|
|||
}
|
||||
}
|
||||
|
||||
void GLGizmoScale3D::do_scale_uniform(const UpdateData& data)
|
||||
void GLGizmoScale3D::do_scale_uniform(const UpdateData & data)
|
||||
{
|
||||
double ratio = calc_ratio(data);
|
||||
const double ratio = calc_ratio(data);
|
||||
if (ratio > 0.0) {
|
||||
m_scale = m_starting.scale * ratio;
|
||||
m_offset = Vec3d::Zero();
|
||||
|
|
|
@ -1,3 +1,7 @@
|
|||
///|/ Copyright (c) Prusa Research 2019 - 2023 Oleksandra Iushchenko @YuSanka, Lukáš Matěna @lukasmatena, Enrico Turri @enricoturri1966, Filip Sykala @Jony01
|
||||
///|/
|
||||
///|/ PrusaSlicer is released under the terms of the AGPLv3 or higher
|
||||
///|/
|
||||
#ifndef slic3r_GLGizmoScale_hpp_
|
||||
#define slic3r_GLGizmoScale_hpp_
|
||||
|
||||
|
@ -28,10 +32,10 @@ class GLGizmoScale3D : public GLGizmoBase
|
|||
StartingData() : scale(Vec3d::Ones()), drag_position(Vec3d::Zero()), ctrl_down(false) { for (int i = 0; i < 5; ++i) { pivots[i] = Vec3d::Zero(); } }
|
||||
};
|
||||
|
||||
mutable BoundingBoxf3 m_box;
|
||||
mutable Transform3d m_transform;
|
||||
BoundingBoxf3 m_box;
|
||||
Transform3d m_transform;
|
||||
// Transforms grabbers offsets to the proper reference system (world for instances, instance for volumes)
|
||||
mutable Transform3d m_offsets_transform;
|
||||
Transform3d m_offsets_transform;
|
||||
Vec3d m_scale{ Vec3d::Ones() };
|
||||
Vec3d m_offset{ Vec3d::Zero() };
|
||||
double m_snap_step{ 0.05 };
|
||||
|
@ -41,7 +45,7 @@ class GLGizmoScale3D : public GLGizmoBase
|
|||
ColorRGBA m_drag_color;
|
||||
ColorRGBA m_highlight_color;
|
||||
|
||||
struct GrabberConnection
|
||||
struct GrabberConnection
|
||||
{
|
||||
GLModel model;
|
||||
std::pair<unsigned int, unsigned int> grabber_indices;
|
||||
|
@ -66,8 +70,6 @@ public:
|
|||
|
||||
std::string get_tooltip() const override;
|
||||
|
||||
void enable_ununiversal_scale(bool enable);
|
||||
|
||||
/// <summary>
|
||||
/// Postpone to Grabber for scale
|
||||
/// </summary>
|
||||
|
@ -75,7 +77,8 @@ public:
|
|||
/// <returns>Return True when use the information otherwise False.</returns>
|
||||
bool on_mouse(const wxMouseEvent &mouse_event) override;
|
||||
|
||||
void data_changed() override;
|
||||
void data_changed(bool is_serializing) override;
|
||||
void enable_ununiversal_scale(bool enable);
|
||||
protected:
|
||||
virtual bool on_init() override;
|
||||
virtual std::string on_get_name() const override;
|
||||
|
|
|
@ -1,3 +1,7 @@
|
|||
///|/ Copyright (c) Prusa Research 2020 - 2022 Enrico Turri @enricoturri1966, Lukáš Matěna @lukasmatena, Lukáš Hejl @hejllukas, Oleksandra Iushchenko @YuSanka, Vojtěch Bubník @bubnikv
|
||||
///|/
|
||||
///|/ PrusaSlicer is released under the terms of the AGPLv3 or higher
|
||||
///|/
|
||||
#include "GLGizmoSeam.hpp"
|
||||
|
||||
#include "libslic3r/Model.hpp"
|
||||
|
@ -298,8 +302,8 @@ void GLGizmoSeam::on_render_input_window(float x, float y, float bottom_limit)
|
|||
}
|
||||
else {
|
||||
if (m_imgui->button(m_desc.at("reset_direction"))) {
|
||||
wxGetApp().CallAfter([this]() {
|
||||
m_c->object_clipper()->set_position(-1., false);
|
||||
wxGetApp().CallAfter([this](){
|
||||
m_c->object_clipper()->set_position_by_ratio(-1., false);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
@ -313,7 +317,7 @@ void GLGizmoSeam::on_render_input_window(float x, float y, float bottom_limit)
|
|||
ImGui::SameLine(drag_left_width);
|
||||
ImGui::PushItemWidth(1.5 * slider_icon_width);
|
||||
bool b_clp_dist_input = ImGui::BBLDragFloat("##clp_dist_input", &clp_dist, 0.05f, 0.0f, 0.0f, "%.2f");
|
||||
if (slider_clp_dist || b_clp_dist_input) { m_c->object_clipper()->set_position(clp_dist, true); }
|
||||
if (slider_clp_dist || b_clp_dist_input) { m_c->object_clipper()->set_position_by_ratio(clp_dist, true); }
|
||||
|
||||
ImGui::Separator();
|
||||
m_imgui->bbl_checkbox(_L("Vertical"), m_vertical_only);
|
||||
|
|
|
@ -1,3 +1,7 @@
|
|||
///|/ Copyright (c) Prusa Research 2019 - 2023 Oleksandra Iushchenko @YuSanka, Enrico Turri @enricoturri1966, Lukáš Matěna @lukasmatena, Lukáš Hejl @hejllukas
|
||||
///|/
|
||||
///|/ PrusaSlicer is released under the terms of the AGPLv3 or higher
|
||||
///|/
|
||||
#ifndef slic3r_GLGizmoSeam_hpp_
|
||||
#define slic3r_GLGizmoSeam_hpp_
|
||||
|
||||
|
@ -32,9 +36,9 @@ protected:
|
|||
|
||||
wxString handle_snapshot_action_name(bool shift_down, Button button_down) const override;
|
||||
|
||||
std::string get_gizmo_entering_text() const override { return "Entering Seam painting"; }
|
||||
std::string get_gizmo_leaving_text() const override { return "Leaving Seam painting"; }
|
||||
std::string get_action_snapshot_name() override { return "Paint-on seam editing"; }
|
||||
std::string get_gizmo_entering_text() const override { return _u8L("Entering Seam painting"); }
|
||||
std::string get_gizmo_leaving_text() const override { return _u8L("Leaving Seam painting"); }
|
||||
std::string get_action_snapshot_name() const override { return _u8L("Paint-on seam editing"); }
|
||||
static const constexpr float CursorRadiusMin = 0.05f; // cannot be zero
|
||||
|
||||
private:
|
||||
|
|
|
@ -1,3 +1,7 @@
|
|||
///|/ Copyright (c) Prusa Research 2021 - 2023 Oleksandra Iushchenko @YuSanka, Lukáš Hejl @hejllukas, Enrico Turri @enricoturri1966, David Kocík @kocikdav, Filip Sykala @Jony01, Lukáš Matěna @lukasmatena, Vojtěch Bubník @bubnikv
|
||||
///|/
|
||||
///|/ PrusaSlicer is released under the terms of the AGPLv3 or higher
|
||||
///|/
|
||||
#include "GLGizmoSimplify.hpp"
|
||||
#include "slic3r/GUI/GLCanvas3D.hpp"
|
||||
#include "slic3r/GUI/GUI_App.hpp"
|
||||
|
|
|
@ -1,3 +1,7 @@
|
|||
///|/ Copyright (c) Prusa Research 2021 - 2023 Oleksandra Iushchenko @YuSanka, Enrico Turri @enricoturri1966, Vojtěch Bubník @bubnikv, Filip Sykala @Jony01, Lukáš Hejl @hejllukas, Lukáš Matěna @lukasmatena
|
||||
///|/
|
||||
///|/ PrusaSlicer is released under the terms of the AGPLv3 or higher
|
||||
///|/
|
||||
#ifndef slic3r_GLGizmoSimplify_hpp_
|
||||
#define slic3r_GLGizmoSimplify_hpp_
|
||||
|
||||
|
|
|
@ -445,8 +445,8 @@ void GLGizmoText::on_render()
|
|||
|
||||
m_grabbers[0].center = m_mouse_position_world;
|
||||
m_grabbers[0].enabled = true;
|
||||
ColorRGBA color = picking_color_component(0);
|
||||
m_grabbers[0].color = color;
|
||||
//ColorRGBA color = picking_color_component(0);
|
||||
//m_grabbers[0].color = color;
|
||||
|
||||
GLShaderProgram *shader = wxGetApp().get_shader("gouraud_light");
|
||||
if (shader != nullptr) {
|
||||
|
|
|
@ -1,3 +1,7 @@
|
|||
///|/ Copyright (c) Prusa Research 2019 - 2021 Lukáš Hejl @hejllukas, Lukáš Matěna @lukasmatena, Enrico Turri @enricoturri1966
|
||||
///|/
|
||||
///|/ PrusaSlicer is released under the terms of the AGPLv3 or higher
|
||||
///|/
|
||||
#ifndef slic3r_GLGizmos_hpp_
|
||||
#define slic3r_GLGizmos_hpp_
|
||||
|
||||
|
|
|
@ -1,3 +1,7 @@
|
|||
///|/ Copyright (c) Prusa Research 2020 - 2023 Lukáš Matěna @lukasmatena, Oleksandra Iushchenko @YuSanka, Enrico Turri @enricoturri1966, Tomáš Mészáros @tamasmeszaros, Vojtěch Bubník @bubnikv
|
||||
///|/
|
||||
///|/ PrusaSlicer is released under the terms of the AGPLv3 or higher
|
||||
///|/
|
||||
#include "GLGizmosCommon.hpp"
|
||||
|
||||
#include <cassert>
|
||||
|
@ -23,10 +27,10 @@ CommonGizmosDataPool::CommonGizmosDataPool(GLCanvas3D* canvas)
|
|||
using c = CommonGizmosDataID;
|
||||
m_data[c::SelectionInfo].reset( new SelectionInfo(this));
|
||||
m_data[c::InstancesHider].reset( new InstancesHider(this));
|
||||
m_data[c::HollowedMesh].reset( new HollowedMesh(this));
|
||||
// m_data[c::HollowedMesh].reset( new HollowedMesh(this));
|
||||
m_data[c::Raycaster].reset( new Raycaster(this));
|
||||
m_data[c::ObjectClipper].reset( new ObjectClipper(this));
|
||||
m_data[c::SupportsClipper].reset( new SupportsClipper(this));
|
||||
// m_data[c::SupportsClipper].reset( new SupportsClipper(this));
|
||||
|
||||
}
|
||||
|
||||
|
@ -59,13 +63,6 @@ InstancesHider* CommonGizmosDataPool::instances_hider() const
|
|||
return inst_hider->is_valid() ? inst_hider : nullptr;
|
||||
}
|
||||
|
||||
HollowedMesh* CommonGizmosDataPool::hollowed_mesh() const
|
||||
{
|
||||
HollowedMesh* hol_mesh = dynamic_cast<HollowedMesh*>(m_data.at(CommonGizmosDataID::HollowedMesh).get());
|
||||
assert(hol_mesh);
|
||||
return hol_mesh->is_valid() ? hol_mesh : nullptr;
|
||||
}
|
||||
|
||||
Raycaster* CommonGizmosDataPool::raycaster() const
|
||||
{
|
||||
Raycaster* rc = dynamic_cast<Raycaster*>(m_data.at(CommonGizmosDataID::Raycaster).get());
|
||||
|
@ -81,13 +78,6 @@ ObjectClipper* CommonGizmosDataPool::object_clipper() const
|
|||
return (oc && oc->is_valid()) ? oc : nullptr;
|
||||
}
|
||||
|
||||
SupportsClipper* CommonGizmosDataPool::supports_clipper() const
|
||||
{
|
||||
SupportsClipper* sc = dynamic_cast<SupportsClipper*>(m_data.at(CommonGizmosDataID::SupportsClipper).get());
|
||||
assert(sc);
|
||||
return sc->is_valid() ? sc : nullptr;
|
||||
}
|
||||
|
||||
#ifndef NDEBUG
|
||||
// Check the required resources one by one and return true if all
|
||||
// dependencies are met.
|
||||
|
@ -117,12 +107,13 @@ bool CommonGizmosDataPool::check_dependencies(CommonGizmosDataID required) const
|
|||
void SelectionInfo::on_update()
|
||||
{
|
||||
const Selection& selection = get_pool()->get_canvas()->get_selection();
|
||||
|
||||
m_model_object = nullptr;
|
||||
|
||||
if (selection.is_single_full_instance()) {
|
||||
m_model_object = selection.get_model()->objects[selection.get_object_idx()];
|
||||
m_z_shift = selection.get_first_volume()->get_sla_shift_z();
|
||||
}
|
||||
else
|
||||
m_model_object = nullptr;
|
||||
}
|
||||
|
||||
void SelectionInfo::on_release()
|
||||
|
@ -132,8 +123,7 @@ void SelectionInfo::on_release()
|
|||
|
||||
int SelectionInfo::get_active_instance() const
|
||||
{
|
||||
const Selection& selection = get_pool()->get_canvas()->get_selection();
|
||||
return selection.get_instance_idx();
|
||||
return get_pool()->get_canvas()->get_selection().get_instance_idx();
|
||||
}
|
||||
|
||||
|
||||
|
@ -154,7 +144,7 @@ void InstancesHider::on_update()
|
|||
if (mo && active_inst != -1) {
|
||||
canvas->toggle_model_objects_visibility(false);
|
||||
canvas->toggle_model_objects_visibility(true, mo, active_inst);
|
||||
canvas->toggle_sla_auxiliaries_visibility(m_show_supports, mo, active_inst);
|
||||
canvas->toggle_sla_auxiliaries_visibility(false, mo, active_inst);
|
||||
canvas->set_use_clipping_planes(true);
|
||||
// Some objects may be sinking, do not show whatever is below the bed.
|
||||
canvas->set_clipping_plane(0, ClippingPlane(Vec3d::UnitZ(), z_min));
|
||||
|
@ -170,7 +160,7 @@ void InstancesHider::on_update()
|
|||
for (const TriangleMesh* mesh : meshes) {
|
||||
m_clippers.emplace_back(new MeshClipper);
|
||||
m_clippers.back()->set_plane(ClippingPlane(-Vec3d::UnitZ(), z_min));
|
||||
m_clippers.back()->set_mesh(*mesh);
|
||||
m_clippers.back()->set_mesh(mesh->its);
|
||||
}
|
||||
m_old_meshes = meshes;
|
||||
}
|
||||
|
@ -187,13 +177,6 @@ void InstancesHider::on_release()
|
|||
m_clippers.clear();
|
||||
}
|
||||
|
||||
void InstancesHider::show_supports(bool show) {
|
||||
if (m_show_supports != show) {
|
||||
m_show_supports = show;
|
||||
on_update();
|
||||
}
|
||||
}
|
||||
|
||||
void InstancesHider::render_cut() const
|
||||
{
|
||||
const SelectionInfo* sel_info = get_pool()->selection_info();
|
||||
|
@ -228,104 +211,19 @@ void InstancesHider::render_cut() const
|
|||
}
|
||||
|
||||
|
||||
|
||||
void HollowedMesh::on_update()
|
||||
{
|
||||
const ModelObject* mo = get_pool()->selection_info()->model_object();
|
||||
bool is_sla = wxGetApp().preset_bundle->printers.get_selected_preset().printer_technology() == ptSLA;
|
||||
if (! mo || ! is_sla)
|
||||
return;
|
||||
|
||||
const GLCanvas3D* canvas = get_pool()->get_canvas();
|
||||
const PrintObjects& print_objects = canvas->sla_print()->objects();
|
||||
const SLAPrintObject* print_object = m_print_object_idx != -1
|
||||
? print_objects[m_print_object_idx]
|
||||
: nullptr;
|
||||
|
||||
// Find the respective SLAPrintObject.
|
||||
if (m_print_object_idx < 0 || m_print_objects_count != int(print_objects.size())) {
|
||||
m_print_objects_count = print_objects.size();
|
||||
m_print_object_idx = -1;
|
||||
for (const SLAPrintObject* po : print_objects) {
|
||||
++m_print_object_idx;
|
||||
if (po->model_object()->id() == mo->id()) {
|
||||
print_object = po;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// If there is a valid SLAPrintObject, check state of Hollowing step.
|
||||
if (print_object) {
|
||||
if (print_object->is_step_done(slaposDrillHoles) && print_object->has_mesh(slaposDrillHoles)) {
|
||||
size_t timestamp = print_object->step_state_with_timestamp(slaposDrillHoles).timestamp;
|
||||
if (timestamp > m_old_hollowing_timestamp) {
|
||||
const TriangleMesh& backend_mesh = print_object->get_mesh_to_slice();
|
||||
if (! backend_mesh.empty()) {
|
||||
m_hollowed_mesh_transformed.reset(new TriangleMesh(backend_mesh));
|
||||
Transform3d trafo_inv = canvas->sla_print()->sla_trafo(*mo).inverse();
|
||||
m_hollowed_mesh_transformed->transform(trafo_inv);
|
||||
m_drainholes = print_object->model_object()->sla_drain_holes;
|
||||
m_old_hollowing_timestamp = timestamp;
|
||||
|
||||
indexed_triangle_set interior = print_object->hollowed_interior_mesh();
|
||||
its_flip_triangles(interior);
|
||||
m_hollowed_interior_transformed = std::make_unique<TriangleMesh>(std::move(interior));
|
||||
m_hollowed_interior_transformed->transform(trafo_inv);
|
||||
}
|
||||
else {
|
||||
m_hollowed_mesh_transformed.reset(nullptr);
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
m_hollowed_mesh_transformed.reset(nullptr);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void HollowedMesh::on_release()
|
||||
{
|
||||
m_hollowed_mesh_transformed.reset();
|
||||
m_old_hollowing_timestamp = 0;
|
||||
m_print_object_idx = -1;
|
||||
}
|
||||
|
||||
|
||||
const TriangleMesh* HollowedMesh::get_hollowed_mesh() const
|
||||
{
|
||||
return m_hollowed_mesh_transformed.get();
|
||||
}
|
||||
|
||||
const TriangleMesh* HollowedMesh::get_hollowed_interior() const
|
||||
{
|
||||
return m_hollowed_interior_transformed.get();
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
void Raycaster::on_update()
|
||||
{
|
||||
wxBusyCursor wait;
|
||||
const ModelObject* mo = get_pool()->selection_info()->model_object();
|
||||
|
||||
if (! mo)
|
||||
if (mo == nullptr)
|
||||
return;
|
||||
|
||||
std::vector<const TriangleMesh*> meshes;
|
||||
const std::vector<ModelVolume*>& mvs = mo->volumes;
|
||||
if (mvs.size() == 1) {
|
||||
assert(mvs.front()->is_model_part());
|
||||
const HollowedMesh* hollowed_mesh_tracker = get_pool()->hollowed_mesh();
|
||||
if (hollowed_mesh_tracker && hollowed_mesh_tracker->get_hollowed_mesh())
|
||||
meshes.push_back(hollowed_mesh_tracker->get_hollowed_mesh());
|
||||
}
|
||||
if (meshes.empty()) {
|
||||
for (const ModelVolume* mv : mvs) {
|
||||
if (mv->is_model_part())
|
||||
meshes.push_back(&mv->mesh());
|
||||
}
|
||||
for (const ModelVolume* mv : mvs) {
|
||||
if (mv->is_model_part())
|
||||
meshes.push_back(&mv->mesh());
|
||||
}
|
||||
|
||||
if (meshes != m_old_meshes) {
|
||||
|
@ -351,9 +249,6 @@ std::vector<const MeshRaycaster*> Raycaster::raycasters() const
|
|||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
void ObjectClipper::on_update()
|
||||
{
|
||||
const ModelObject* mo = get_pool()->selection_info()->model_object();
|
||||
|
@ -362,24 +257,19 @@ void ObjectClipper::on_update()
|
|||
|
||||
// which mesh should be cut?
|
||||
std::vector<const TriangleMesh*> meshes;
|
||||
bool has_hollowed = get_pool()->hollowed_mesh() && get_pool()->hollowed_mesh()->get_hollowed_mesh();
|
||||
if (has_hollowed)
|
||||
meshes.push_back(get_pool()->hollowed_mesh()->get_hollowed_mesh());
|
||||
|
||||
if (meshes.empty())
|
||||
for (const ModelVolume* mv : mo->volumes)
|
||||
meshes.push_back(&mv->mesh());
|
||||
std::vector<Geometry::Transformation> trafos;
|
||||
for (const ModelVolume* mv : mo->volumes) {
|
||||
meshes.emplace_back(&mv->mesh());
|
||||
trafos.emplace_back(mv->get_transformation());
|
||||
}
|
||||
|
||||
if (meshes != m_old_meshes) {
|
||||
m_clippers.clear();
|
||||
for (const TriangleMesh* mesh : meshes) {
|
||||
m_clippers.emplace_back(new MeshClipper);
|
||||
m_clippers.back()->set_mesh(*mesh);
|
||||
for (size_t i = 0; i < meshes.size(); ++i) {
|
||||
m_clippers.emplace_back(new MeshClipper, trafos[i]);
|
||||
m_clippers.back().first->set_mesh(meshes[i]->its);
|
||||
}
|
||||
m_old_meshes = meshes;
|
||||
|
||||
if (has_hollowed)
|
||||
m_clippers.front()->set_negative_mesh(*get_pool()->hollowed_mesh()->get_hollowed_interior());
|
||||
m_old_meshes = std::move(meshes);
|
||||
|
||||
m_active_inst_bb_radius =
|
||||
mo->instance_bounding_box(get_pool()->selection_info()->get_active_instance()).radius();
|
||||
|
@ -396,45 +286,74 @@ void ObjectClipper::on_release()
|
|||
|
||||
}
|
||||
|
||||
void ObjectClipper::render_cut() const
|
||||
void ObjectClipper::render_cut(const std::vector<size_t>* ignore_idxs) const
|
||||
{
|
||||
if (m_clp_ratio == 0.)
|
||||
return;
|
||||
const SelectionInfo* sel_info = get_pool()->selection_info();
|
||||
const ModelObject* mo = sel_info->model_object();
|
||||
Geometry::Transformation inst_trafo;
|
||||
bool is_assem_cnv = get_pool()->get_canvas()->get_canvas_type() == GLCanvas3D::CanvasAssembleView;
|
||||
inst_trafo = is_assem_cnv ?
|
||||
mo->instances[sel_info->get_active_instance()]->get_assemble_transformation() :
|
||||
mo->instances[sel_info->get_active_instance()]->get_transformation();
|
||||
auto offset_to_assembly = mo->instances[0]->get_offset_to_assembly();
|
||||
const Geometry::Transformation inst_trafo = sel_info->model_object()->instances[sel_info->get_active_instance()]->get_transformation();
|
||||
|
||||
std::vector<size_t> ignore_idxs_local = ignore_idxs ? *ignore_idxs : std::vector<size_t>();
|
||||
|
||||
size_t clipper_id = 0;
|
||||
for (const ModelVolume* mv : mo->volumes) {
|
||||
const Geometry::Transformation vol_trafo = mv->get_transformation();
|
||||
Geometry::Transformation trafo = inst_trafo * vol_trafo;
|
||||
if (is_assem_cnv) {
|
||||
trafo.set_offset(trafo.get_offset() + offset_to_assembly * (GLVolume::explosion_ratio - 1.0) + vol_trafo.get_offset() * (GLVolume::explosion_ratio - 1.0));
|
||||
}
|
||||
else {
|
||||
trafo.set_offset(trafo.get_offset() + Vec3d(0., 0., sel_info->get_sla_shift()));
|
||||
}
|
||||
auto& clipper = m_clippers[clipper_id];
|
||||
clipper->set_plane(*m_clp);
|
||||
clipper->set_transformation(trafo);
|
||||
if (is_assem_cnv)
|
||||
clipper->set_limiting_plane(ClippingPlane(Vec3d::UnitZ(), std::numeric_limits<double>::max()));
|
||||
else
|
||||
clipper->set_limiting_plane(ClippingPlane(Vec3d::UnitZ(), -SINKING_Z_THRESHOLD));
|
||||
// BBS
|
||||
clipper->render_cut({ 0.25f, 0.25f, 0.25f, 1.0f });
|
||||
|
||||
++clipper_id;
|
||||
for (auto& clipper : m_clippers) {
|
||||
Geometry::Transformation trafo = inst_trafo * clipper.second;
|
||||
trafo.set_offset(trafo.get_offset() + Vec3d(0., 0., sel_info->get_sla_shift()));
|
||||
clipper.first->set_plane(*m_clp);
|
||||
clipper.first->set_transformation(trafo);
|
||||
clipper.first->set_limiting_plane(ClippingPlane(Vec3d::UnitZ(), -SINKING_Z_THRESHOLD));
|
||||
// BBS
|
||||
clipper.first->render_cut({ 0.25f, 0.25f, 0.25f, 1.0f }, &ignore_idxs_local);
|
||||
clipper.first->render_contour({ 1.f, 1.f, 1.f, 1.f }, &ignore_idxs_local);
|
||||
|
||||
// Now update the ignore idxs. Find the first element belonging to the next clipper,
|
||||
// and remove everything before it and decrement everything by current number of contours.
|
||||
const int num_of_contours = clipper.first->get_number_of_contours();
|
||||
ignore_idxs_local.erase(ignore_idxs_local.begin(), std::find_if(ignore_idxs_local.begin(), ignore_idxs_local.end(), [num_of_contours](size_t idx) { return idx >= size_t(num_of_contours); } ));
|
||||
for (size_t& idx : ignore_idxs_local)
|
||||
idx -= num_of_contours;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void ObjectClipper::set_position(double pos, bool keep_normal)
|
||||
int ObjectClipper::get_number_of_contours() const
|
||||
{
|
||||
int sum = 0;
|
||||
for (const auto& [clipper, trafo] : m_clippers)
|
||||
sum += clipper->get_number_of_contours();
|
||||
return sum;
|
||||
}
|
||||
|
||||
int ObjectClipper::is_projection_inside_cut(const Vec3d& point) const
|
||||
{
|
||||
if (m_clp_ratio == 0.)
|
||||
return -1;
|
||||
int idx_offset = 0;
|
||||
for (const auto& [clipper, trafo] : m_clippers) {
|
||||
if (int idx = clipper->is_projection_inside_cut(point); idx != -1)
|
||||
return idx_offset + idx;
|
||||
idx_offset += clipper->get_number_of_contours();
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
bool ObjectClipper::has_valid_contour() const
|
||||
{
|
||||
return m_clp_ratio != 0. && std::any_of(m_clippers.begin(), m_clippers.end(), [](const auto& cl) { return cl.first->has_valid_contour(); });
|
||||
}
|
||||
|
||||
std::vector<Vec3d> ObjectClipper::point_per_contour() const
|
||||
{
|
||||
std::vector<Vec3d> pts;
|
||||
|
||||
for (const auto& clipper : m_clippers) {
|
||||
const std::vector<Vec3d> pts_clipper = clipper.first->point_per_contour();
|
||||
pts.insert(pts.end(), pts_clipper.begin(), pts_clipper.end());;
|
||||
}
|
||||
return pts;
|
||||
}
|
||||
|
||||
|
||||
void ObjectClipper::set_position_by_ratio(double pos, bool keep_normal)
|
||||
{
|
||||
const ModelObject* mo = get_pool()->selection_info()->model_object();
|
||||
int active_inst = get_pool()->selection_info()->get_active_instance();
|
||||
|
@ -469,114 +388,26 @@ void ObjectClipper::set_position(double pos, bool keep_normal)
|
|||
get_pool()->get_canvas()->set_as_dirty();
|
||||
}
|
||||
|
||||
void ObjectClipper::set_range_and_pos(const Vec3d &cpl_normal, double cpl_offset, double pos)
|
||||
void ObjectClipper::set_range_and_pos(const Vec3d& cpl_normal, double cpl_offset, double pos)
|
||||
{
|
||||
m_clp.reset(new ClippingPlane(cpl_normal, cpl_offset));
|
||||
m_clp_ratio = pos;
|
||||
get_pool()->get_canvas()->set_as_dirty();
|
||||
}
|
||||
|
||||
bool ObjectClipper::is_projection_inside_cut(const Vec3d &point) const
|
||||
const ClippingPlane* ObjectClipper::get_clipping_plane(bool ignore_hide_clipped) const
|
||||
{
|
||||
return m_clp_ratio != 0. && std::any_of(m_clippers.begin(), m_clippers.end(), [point](const auto &cl) {
|
||||
return cl->is_projection_inside_cut(point);
|
||||
});
|
||||
static const ClippingPlane no_clip = ClippingPlane::ClipsNothing();
|
||||
return (ignore_hide_clipped || m_hide_clipped) ? m_clp.get() : &no_clip;
|
||||
}
|
||||
|
||||
bool ObjectClipper::has_valid_contour() const
|
||||
void ObjectClipper::set_behavior(bool hide_clipped, bool fill_cut, double contour_width)
|
||||
{
|
||||
return m_clp_ratio != 0. && std::any_of(m_clippers.begin(), m_clippers.end(), [](const auto &cl) {
|
||||
return cl->has_valid_contour();
|
||||
});
|
||||
m_hide_clipped = hide_clipped;
|
||||
for (auto& clipper : m_clippers)
|
||||
clipper.first->set_behaviour(fill_cut, contour_width);
|
||||
}
|
||||
|
||||
void SupportsClipper::on_update()
|
||||
{
|
||||
const ModelObject* mo = get_pool()->selection_info()->model_object();
|
||||
bool is_sla = wxGetApp().preset_bundle->printers.get_selected_preset().printer_technology() == ptSLA;
|
||||
if (! mo || ! is_sla)
|
||||
return;
|
||||
|
||||
const GLCanvas3D* canvas = get_pool()->get_canvas();
|
||||
const PrintObjects& print_objects = canvas->sla_print()->objects();
|
||||
const SLAPrintObject* print_object = m_print_object_idx != -1
|
||||
? print_objects[m_print_object_idx]
|
||||
: nullptr;
|
||||
|
||||
// Find the respective SLAPrintObject.
|
||||
if (m_print_object_idx < 0 || m_print_objects_count != int(print_objects.size())) {
|
||||
m_print_objects_count = print_objects.size();
|
||||
m_print_object_idx = -1;
|
||||
for (const SLAPrintObject* po : print_objects) {
|
||||
++m_print_object_idx;
|
||||
if (po->model_object()->id() == mo->id()) {
|
||||
print_object = po;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (print_object
|
||||
&& print_object->is_step_done(slaposSupportTree)
|
||||
&& ! print_object->support_mesh().empty())
|
||||
{
|
||||
// If the supports are already calculated, save the timestamp of the respective step
|
||||
// so we can later tell they were recalculated.
|
||||
size_t timestamp = print_object->step_state_with_timestamp(slaposSupportTree).timestamp;
|
||||
if (! m_clipper || timestamp != m_old_timestamp) {
|
||||
// The timestamp has changed.
|
||||
m_clipper.reset(new MeshClipper);
|
||||
// The mesh should already have the shared vertices calculated.
|
||||
m_clipper->set_mesh(print_object->support_mesh());
|
||||
m_old_timestamp = timestamp;
|
||||
}
|
||||
}
|
||||
else
|
||||
// The supports are not valid. We better dump the cached data.
|
||||
m_clipper.reset();
|
||||
}
|
||||
|
||||
|
||||
void SupportsClipper::on_release()
|
||||
{
|
||||
m_clipper.reset();
|
||||
m_old_timestamp = 0;
|
||||
m_print_object_idx = -1;
|
||||
}
|
||||
|
||||
void SupportsClipper::render_cut() const
|
||||
{
|
||||
const CommonGizmosDataObjects::ObjectClipper* ocl = get_pool()->object_clipper();
|
||||
if (ocl->get_position() == 0.
|
||||
|| ! get_pool()->instances_hider()->are_supports_shown()
|
||||
|| ! m_clipper)
|
||||
return;
|
||||
|
||||
const SelectionInfo* sel_info = get_pool()->selection_info();
|
||||
const ModelObject* mo = sel_info->model_object();
|
||||
const Geometry::Transformation inst_trafo = mo->instances[sel_info->get_active_instance()]->get_transformation();
|
||||
//Geometry::Transformation vol_trafo = mo->volumes.front()->get_transformation();
|
||||
Geometry::Transformation trafo = inst_trafo;// * vol_trafo;
|
||||
trafo.set_offset(trafo.get_offset() + Vec3d(0., 0., sel_info->get_sla_shift()));
|
||||
|
||||
|
||||
// Get transformation of supports
|
||||
Geometry::Transformation supports_trafo = trafo;
|
||||
supports_trafo.set_scaling_factor(Vec3d::Ones());
|
||||
supports_trafo.set_offset(Vec3d(trafo.get_offset()(0), trafo.get_offset()(1), sel_info->get_sla_shift()));
|
||||
supports_trafo.set_rotation(Vec3d(0., 0., trafo.get_rotation()(2)));
|
||||
// I don't know why, but following seems to be correct.
|
||||
supports_trafo.set_mirror(Vec3d(trafo.get_mirror()(0) * trafo.get_mirror()(1) * trafo.get_mirror()(2),
|
||||
1,
|
||||
1.));
|
||||
|
||||
m_clipper->set_plane(*ocl->get_clipping_plane());
|
||||
m_clipper->set_transformation(supports_trafo);
|
||||
|
||||
m_clipper->render_cut({ 1.0f, 0.f, 0.37f, 1.0f });
|
||||
}
|
||||
|
||||
|
||||
|
||||
using namespace AssembleViewDataObjects;
|
||||
AssembleViewDataPool::AssembleViewDataPool(GLCanvas3D* canvas)
|
||||
|
@ -683,7 +514,7 @@ void ModelObjectsClipper::on_update()
|
|||
m_clippers.clear();
|
||||
for (const TriangleMesh* mesh : meshes) {
|
||||
m_clippers.emplace_back(new MeshClipper);
|
||||
m_clippers.back()->set_mesh(*mesh);
|
||||
m_clippers.back()->set_mesh(mesh->its);
|
||||
}
|
||||
m_old_meshes = meshes;
|
||||
|
||||
|
|
|
@ -1,3 +1,7 @@
|
|||
///|/ Copyright (c) Prusa Research 2020 - 2023 Lukáš Matěna @lukasmatena, Oleksandra Iushchenko @YuSanka, Enrico Turri @enricoturri1966, Tomáš Mészáros @tamasmeszaros, Lukáš Hejl @hejllukas
|
||||
///|/
|
||||
///|/ PrusaSlicer is released under the terms of the AGPLv3 or higher
|
||||
///|/
|
||||
#ifndef slic3r_GUI_GLGizmosCommon_hpp_
|
||||
#define slic3r_GUI_GLGizmosCommon_hpp_
|
||||
|
||||
|
@ -6,12 +10,13 @@
|
|||
|
||||
#include "slic3r/GUI/3DScene.hpp"
|
||||
#include "slic3r/GUI/MeshUtils.hpp"
|
||||
#include "libslic3r/SLA/Hollowing.hpp"
|
||||
|
||||
namespace Slic3r {
|
||||
|
||||
class ModelObject;
|
||||
|
||||
class ModelInstance;
|
||||
class SLAPrintObject;
|
||||
class ModelVolume;
|
||||
|
||||
namespace GUI {
|
||||
|
||||
|
@ -67,10 +72,8 @@ enum class CommonGizmosDataID {
|
|||
None = 0,
|
||||
SelectionInfo = 1 << 0,
|
||||
InstancesHider = 1 << 1,
|
||||
HollowedMesh = 1 << 2,
|
||||
Raycaster = 1 << 3,
|
||||
ObjectClipper = 1 << 4,
|
||||
SupportsClipper = 1 << 5,
|
||||
|
||||
};
|
||||
|
||||
|
@ -89,10 +92,10 @@ public:
|
|||
// Getters for the data that need to be accessed from the gizmos directly.
|
||||
CommonGizmosDataObjects::SelectionInfo* selection_info() const;
|
||||
CommonGizmosDataObjects::InstancesHider* instances_hider() const;
|
||||
CommonGizmosDataObjects::HollowedMesh* hollowed_mesh() const;
|
||||
// CommonGizmosDataObjects::HollowedMesh* hollowed_mesh() const;
|
||||
CommonGizmosDataObjects::Raycaster* raycaster() const;
|
||||
CommonGizmosDataObjects::ObjectClipper* object_clipper() const;
|
||||
CommonGizmosDataObjects::SupportsClipper* supports_clipper() const;
|
||||
// CommonGizmosDataObjects::SupportsClipper* supports_clipper() const;
|
||||
|
||||
|
||||
GLCanvas3D* get_canvas() const { return m_canvas; }
|
||||
|
@ -141,7 +144,6 @@ protected:
|
|||
virtual void on_update() = 0;
|
||||
CommonGizmosDataPool* get_pool() const { return m_common; }
|
||||
|
||||
|
||||
private:
|
||||
bool m_is_valid = false;
|
||||
CommonGizmosDataPool* m_common = nullptr;
|
||||
|
@ -185,8 +187,6 @@ public:
|
|||
CommonGizmosDataID get_dependencies() const override { return CommonGizmosDataID::SelectionInfo; }
|
||||
#endif // NDEBUG
|
||||
|
||||
void show_supports(bool show);
|
||||
bool are_supports_shown() const { return m_show_supports; }
|
||||
void render_cut() const;
|
||||
|
||||
protected:
|
||||
|
@ -194,42 +194,12 @@ protected:
|
|||
void on_release() override;
|
||||
|
||||
private:
|
||||
bool m_show_supports = false;
|
||||
std::vector<const TriangleMesh*> m_old_meshes;
|
||||
std::vector<std::unique_ptr<MeshClipper>> m_clippers;
|
||||
};
|
||||
|
||||
|
||||
|
||||
class HollowedMesh : public CommonGizmosDataBase
|
||||
{
|
||||
public:
|
||||
explicit HollowedMesh(CommonGizmosDataPool* cgdp)
|
||||
: CommonGizmosDataBase(cgdp) {}
|
||||
#ifndef NDEBUG
|
||||
CommonGizmosDataID get_dependencies() const override { return CommonGizmosDataID::SelectionInfo; }
|
||||
#endif // NDEBUG
|
||||
|
||||
const sla::DrainHoles &get_drainholes() const { return m_drainholes; }
|
||||
|
||||
const TriangleMesh* get_hollowed_mesh() const;
|
||||
const TriangleMesh* get_hollowed_interior() const;
|
||||
|
||||
protected:
|
||||
void on_update() override;
|
||||
void on_release() override;
|
||||
|
||||
private:
|
||||
std::unique_ptr<TriangleMesh> m_hollowed_mesh_transformed;
|
||||
std::unique_ptr<TriangleMesh> m_hollowed_interior_transformed;
|
||||
size_t m_old_hollowing_timestamp = 0;
|
||||
int m_print_object_idx = -1;
|
||||
int m_print_objects_count = 0;
|
||||
sla::DrainHoles m_drainholes;
|
||||
};
|
||||
|
||||
|
||||
|
||||
class Raycaster : public CommonGizmosDataBase
|
||||
{
|
||||
public:
|
||||
|
@ -261,57 +231,31 @@ public:
|
|||
#ifndef NDEBUG
|
||||
CommonGizmosDataID get_dependencies() const override { return CommonGizmosDataID::SelectionInfo; }
|
||||
#endif // NDEBUG
|
||||
|
||||
void set_position(double pos, bool keep_normal);
|
||||
double get_position() const { return m_clp_ratio; }
|
||||
ClippingPlane* get_clipping_plane() const { return m_clp.get(); }
|
||||
void render_cut() const;
|
||||
const ClippingPlane* get_clipping_plane(bool ignore_hide_clipped = false) const;
|
||||
void render_cut(const std::vector<size_t>* ignore_idxs = nullptr) const;
|
||||
void set_position_by_ratio(double pos, bool keep_normal);
|
||||
void set_range_and_pos(const Vec3d& cpl_normal, double cpl_offset, double pos);
|
||||
void set_behavior(bool hide_clipped, bool fill_cut, double contour_width);
|
||||
|
||||
int get_number_of_contours() const;
|
||||
std::vector<Vec3d> point_per_contour() const;
|
||||
|
||||
void set_range_and_pos(const Vec3d &cpl_normal, double cpl_offset, double pos);
|
||||
|
||||
bool is_projection_inside_cut(const Vec3d &point_in) const;
|
||||
int is_projection_inside_cut(const Vec3d& point_in) const;
|
||||
bool has_valid_contour() const;
|
||||
|
||||
|
||||
protected:
|
||||
void on_update() override;
|
||||
void on_release() override;
|
||||
|
||||
private:
|
||||
std::vector<const TriangleMesh*> m_old_meshes;
|
||||
std::vector<std::unique_ptr<MeshClipper>> m_clippers;
|
||||
std::vector<std::pair<std::unique_ptr<MeshClipper>, Geometry::Transformation>> m_clippers;
|
||||
std::unique_ptr<ClippingPlane> m_clp;
|
||||
double m_clp_ratio = 0.;
|
||||
double m_active_inst_bb_radius = 0.;
|
||||
};
|
||||
|
||||
|
||||
|
||||
class SupportsClipper : public CommonGizmosDataBase
|
||||
{
|
||||
public:
|
||||
explicit SupportsClipper(CommonGizmosDataPool* cgdp)
|
||||
: CommonGizmosDataBase(cgdp) {}
|
||||
#ifndef NDEBUG
|
||||
CommonGizmosDataID get_dependencies() const override {
|
||||
return CommonGizmosDataID(
|
||||
int(CommonGizmosDataID::SelectionInfo)
|
||||
| int(CommonGizmosDataID::ObjectClipper)
|
||||
);
|
||||
}
|
||||
#endif // NDEBUG
|
||||
|
||||
void render_cut() const;
|
||||
|
||||
|
||||
protected:
|
||||
void on_update() override;
|
||||
void on_release() override;
|
||||
|
||||
private:
|
||||
size_t m_old_timestamp = 0;
|
||||
int m_print_object_idx = -1;
|
||||
int m_print_objects_count = 0;
|
||||
std::unique_ptr<MeshClipper> m_clipper;
|
||||
bool m_hide_clipped = true;
|
||||
};
|
||||
|
||||
} // namespace CommonGizmosDataObjects
|
||||
|
|
|
@ -1,3 +1,8 @@
|
|||
///|/ Copyright (c) Prusa Research 2019 - 2023 Oleksandra Iushchenko @YuSanka, Enrico Turri @enricoturri1966, Lukáš Matěna @lukasmatena, David Kocík @kocikdav, Filip Sykala @Jony01, Vojtěch Bubník @bubnikv, Lukáš Hejl @hejllukas
|
||||
///|/ Copyright (c) 2019 John Drake @foxox
|
||||
///|/
|
||||
///|/ PrusaSlicer is released under the terms of the AGPLv3 or higher
|
||||
///|/
|
||||
#include "libslic3r/libslic3r.h"
|
||||
#include "GLGizmosManager.hpp"
|
||||
#include "slic3r/GUI/GLCanvas3D.hpp"
|
||||
|
@ -269,20 +274,13 @@ float GLGizmosManager::get_layout_scale()
|
|||
return m_layout.scale;
|
||||
}
|
||||
|
||||
bool GLGizmosManager::init_arrow(const BackgroundTexture::Metadata& arrow_texture)
|
||||
bool GLGizmosManager::init_arrow(const std::string& filename)
|
||||
{
|
||||
if (m_arrow_texture.texture.get_id() != 0)
|
||||
if (m_arrow_texture.get_id() != 0)
|
||||
return true;
|
||||
|
||||
std::string path = resources_dir() + "/images/";
|
||||
bool res = false;
|
||||
|
||||
if (!arrow_texture.filename.empty())
|
||||
res = m_arrow_texture.texture.load_from_svg_file(path + arrow_texture.filename, false, false, false, 1000);
|
||||
if (res)
|
||||
m_arrow_texture.metadata = arrow_texture;
|
||||
|
||||
return res;
|
||||
const std::string path = resources_dir() + "/images/";
|
||||
return (!filename.empty()) ? m_arrow_texture.load_from_svg_file(path + filename, false, false, false, 1000) : false;
|
||||
}
|
||||
|
||||
void GLGizmosManager::set_overlay_icon_size(float size)
|
||||
|
@ -378,7 +376,7 @@ void GLGizmosManager::update_data()
|
|||
m_common_gizmos_data->update(get_current()
|
||||
? get_current()->get_requirements()
|
||||
: CommonGizmosDataID(0));
|
||||
if (m_current != Undefined) m_gizmos[m_current]->data_changed();
|
||||
if (m_current != Undefined) m_gizmos[m_current]->data_changed(m_serializing);
|
||||
|
||||
//BBS: GUI refactor: add object manipulation in gizmo
|
||||
m_object_manipulation.update_ui_from_settings();
|
||||
|
@ -600,10 +598,12 @@ bool GLGizmosManager::gizmos_toolbar_on_mouse(const wxMouseEvent &mouse_event) {
|
|||
mc.left = true;
|
||||
open_gizmo(gizmo);
|
||||
return true;
|
||||
} else if (mouse_event.RightDown()) {
|
||||
}
|
||||
else if (mouse_event.RightDown()) {
|
||||
mc.right = true;
|
||||
return true;
|
||||
} else if (mouse_event.MiddleDown()) {
|
||||
}
|
||||
else if (mouse_event.MiddleDown()) {
|
||||
mc.middle = true;
|
||||
return true;
|
||||
}
|
||||
|
@ -618,18 +618,21 @@ bool GLGizmosManager::gizmos_toolbar_on_mouse(const wxMouseEvent &mouse_event) {
|
|||
update_hover_state(Undefined);
|
||||
}
|
||||
// draging start on toolbar so no propagation into scene
|
||||
return true;
|
||||
} else if (mc.left && mouse_event.LeftUp()) {
|
||||
return true;
|
||||
}
|
||||
else if (mc.left && mouse_event.LeftUp()) {
|
||||
mc.left = false;
|
||||
return true;
|
||||
} else if (mc.right && mouse_event.RightUp()) {
|
||||
}
|
||||
else if (mc.right && mouse_event.RightUp()) {
|
||||
mc.right = false;
|
||||
return true;
|
||||
} else if (mc.middle && mouse_event.MiddleUp()) {
|
||||
}
|
||||
else if (mc.middle && mouse_event.MiddleUp()) {
|
||||
mc.middle = false;
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
// event out of window is not porocessed
|
||||
// left down on gizmo -> keep down -> move out of window -> release left
|
||||
if (mouse_event.Leaving()) mc.reset();
|
||||
|
@ -650,7 +653,7 @@ bool GLGizmosManager::on_mouse(const wxMouseEvent &mouse_event)
|
|||
// &m_gizmos[m_current]->on_mouse != &GLGizmoBase::on_mouse &&
|
||||
m_gizmos[m_current]->on_mouse(mouse_event))
|
||||
return true;
|
||||
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -662,8 +665,7 @@ bool GLGizmosManager::on_char(wxKeyEvent& evt)
|
|||
|
||||
bool processed = false;
|
||||
|
||||
if ((evt.GetModifiers() & ctrlMask) != 0)
|
||||
{
|
||||
if ((evt.GetModifiers() & ctrlMask) != 0) {
|
||||
switch (keyCode)
|
||||
{
|
||||
#ifdef __APPLE__
|
||||
|
@ -681,8 +683,7 @@ bool GLGizmosManager::on_char(wxKeyEvent& evt)
|
|||
}
|
||||
}
|
||||
}
|
||||
else if (!evt.HasModifiers())
|
||||
{
|
||||
else if (!evt.HasModifiers()) {
|
||||
switch (keyCode)
|
||||
{
|
||||
// key ESC
|
||||
|
@ -775,8 +776,7 @@ bool GLGizmosManager::on_char(wxKeyEvent& evt)
|
|||
}
|
||||
}
|
||||
|
||||
if (!processed && !evt.HasModifiers())
|
||||
{
|
||||
if (!processed && !evt.HasModifiers()) {
|
||||
if (handle_shortcut(keyCode))
|
||||
processed = true;
|
||||
}
|
||||
|
@ -792,15 +792,7 @@ bool GLGizmosManager::on_key(wxKeyEvent& evt)
|
|||
const int keyCode = evt.GetKeyCode();
|
||||
bool processed = false;
|
||||
|
||||
// todo: zhimin Each gizmo should handle key event in it own on_key() function
|
||||
if (m_current == Cut) {
|
||||
if (GLGizmoAdvancedCut *gizmo_cut = dynamic_cast<GLGizmoAdvancedCut *>(get_current())) {
|
||||
return gizmo_cut->on_key(evt);
|
||||
}
|
||||
}
|
||||
|
||||
if (evt.GetEventType() == wxEVT_KEY_UP)
|
||||
{
|
||||
if (evt.GetEventType() == wxEVT_KEY_UP) {
|
||||
/*if (m_current == SlaSupports || m_current == Hollow)
|
||||
{
|
||||
bool is_editing = true;
|
||||
|
@ -987,7 +979,7 @@ void GLGizmosManager::render_background(float left, float top, float right, floa
|
|||
|
||||
void GLGizmosManager::render_arrow(const GLCanvas3D& parent, EType highlighted_type) const
|
||||
{
|
||||
std::vector<size_t> selectable_idxs = get_selectable_idxs();
|
||||
const std::vector<size_t> selectable_idxs = get_selectable_idxs();
|
||||
if (selectable_idxs.empty())
|
||||
return;
|
||||
float cnv_w = (float)m_parent.get_canvas_size().get_width();
|
||||
|
@ -1006,18 +998,18 @@ void GLGizmosManager::render_arrow(const GLCanvas3D& parent, EType highlighted_t
|
|||
if (idx == highlighted_type) {
|
||||
int tex_width = m_icons_texture.get_width();
|
||||
int tex_height = m_icons_texture.get_height();
|
||||
unsigned int tex_id = m_arrow_texture.texture.get_id();
|
||||
unsigned int tex_id = m_arrow_texture.get_id();
|
||||
float inv_tex_width = (tex_width != 0.0f) ? 1.0f / tex_width : 0.0f;
|
||||
float inv_tex_height = (tex_height != 0.0f) ? 1.0f / tex_height : 0.0f;
|
||||
|
||||
float internal_left_uv = (float)m_arrow_texture.metadata.left * inv_tex_width;
|
||||
float internal_right_uv = 1.0f - (float)m_arrow_texture.metadata.right * inv_tex_width;
|
||||
float internal_top_uv = 1.0f - (float)m_arrow_texture.metadata.top * inv_tex_height;
|
||||
float internal_bottom_uv = (float)m_arrow_texture.metadata.bottom * inv_tex_height;
|
||||
const float left_uv = 0.0f;
|
||||
const float right_uv = 1.0f;
|
||||
const float top_uv = 1.0f;
|
||||
const float bottom_uv = 0.0f;
|
||||
|
||||
float arrow_sides_ratio = (float)m_arrow_texture.texture.get_height() / (float)m_arrow_texture.texture.get_width();
|
||||
float arrow_sides_ratio = (float)m_arrow_texture.get_height() / (float)m_arrow_texture.get_width();
|
||||
|
||||
GLTexture::render_sub_texture(tex_id, zoomed_top_x + zoomed_icons_size * 1.2f, zoomed_top_x + zoomed_icons_size * 1.2f + zoomed_icons_size * 2.2f * arrow_sides_ratio, zoomed_top_y - zoomed_icons_size * 1.6f , zoomed_top_y + zoomed_icons_size * 0.6f, { { internal_left_uv, internal_bottom_uv }, { internal_left_uv, internal_top_uv }, { internal_right_uv, internal_top_uv }, { internal_right_uv, internal_bottom_uv } });
|
||||
GLTexture::render_sub_texture(tex_id, zoomed_top_x + zoomed_icons_size * 1.2f, zoomed_top_x + zoomed_icons_size * 1.2f + zoomed_icons_size * 2.2f * arrow_sides_ratio, zoomed_top_y - zoomed_icons_size * 1.6f , zoomed_top_y + zoomed_icons_size * 0.6f, { { left_uv, bottom_uv }, { left_uv, top_uv }, { right_uv, top_uv }, { right_uv, bottom_uv } });
|
||||
break;
|
||||
}
|
||||
zoomed_top_y -= zoomed_stride_y;
|
||||
|
@ -1170,9 +1162,12 @@ bool GLGizmosManager::generate_icons_texture()
|
|||
{
|
||||
std::string path = resources_dir() + "/images/";
|
||||
std::vector<std::string> filenames;
|
||||
for (size_t idx = 0; idx<m_gizmos.size(); ++idx) {
|
||||
if (m_gizmos[idx] != nullptr) {
|
||||
const std::string& icon_filename = m_gizmos[idx]->get_icon_filename();
|
||||
for (size_t idx=0; idx<m_gizmos.size(); ++idx)
|
||||
{
|
||||
auto &gizmo = m_gizmos[idx];
|
||||
if (gizmo != nullptr)
|
||||
{
|
||||
const std::string& icon_filename = gizmo->get_icon_filename();
|
||||
if (!icon_filename.empty())
|
||||
filenames.push_back(path + icon_filename);
|
||||
}
|
||||
|
|
|
@ -1,3 +1,7 @@
|
|||
///|/ Copyright (c) Prusa Research 2019 - 2022 Enrico Turri @enricoturri1966, Lukáš Matěna @lukasmatena, Oleksandra Iushchenko @YuSanka, Filip Sykala @Jony01, David Kocík @kocikdav, Lukáš Hejl @hejllukas, Vojtěch Bubník @bubnikv
|
||||
///|/
|
||||
///|/ PrusaSlicer is released under the terms of the AGPLv3 or higher
|
||||
///|/
|
||||
#ifndef slic3r_GUI_GLGizmosManager_hpp_
|
||||
#define slic3r_GUI_GLGizmosManager_hpp_
|
||||
|
||||
|
@ -116,10 +120,10 @@ private:
|
|||
GLCanvas3D& m_parent;
|
||||
bool m_enabled;
|
||||
std::vector<std::unique_ptr<GLGizmoBase>> m_gizmos;
|
||||
mutable GLTexture m_icons_texture;
|
||||
mutable bool m_icons_texture_dirty;
|
||||
GLTexture m_icons_texture;
|
||||
bool m_icons_texture_dirty;
|
||||
BackgroundTexture m_background_texture;
|
||||
BackgroundTexture m_arrow_texture;
|
||||
GLTexture m_arrow_texture;
|
||||
Layout m_layout;
|
||||
EType m_current;
|
||||
EType m_hover;
|
||||
|
@ -175,7 +179,7 @@ public:
|
|||
|
||||
float get_layout_scale();
|
||||
|
||||
bool init_arrow(const BackgroundTexture::Metadata& arrow_texture);
|
||||
bool init_arrow(const std::string& filename);
|
||||
|
||||
template<class Archive>
|
||||
void load(Archive& ar)
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue