mirror of
https://github.com/SoftFever/OrcaSlicer.git
synced 2025-10-26 18:21:18 -06:00
Fixed conflicts after merge with master
This commit is contained in:
commit
39ec1a6318
192 changed files with 7204 additions and 2296 deletions
|
|
@ -85,6 +85,7 @@ GLGizmoBase::GLGizmoBase(GLCanvas3D& parent, const std::string& icon_filename, u
|
|||
, m_dragging(false)
|
||||
, m_imgui(wxGetApp().imgui())
|
||||
, m_first_input_window_render(true)
|
||||
, m_dirty(false)
|
||||
{
|
||||
m_base_color = DEFAULT_BASE_COLOR;
|
||||
m_drag_color = DEFAULT_DRAG_COLOR;
|
||||
|
|
@ -154,6 +155,13 @@ void GLGizmoBase::update(const UpdateData& data)
|
|||
on_update(data);
|
||||
}
|
||||
|
||||
bool GLGizmoBase::update_items_state()
|
||||
{
|
||||
bool res = m_dirty;
|
||||
m_dirty = false;
|
||||
return res;
|
||||
};
|
||||
|
||||
std::array<float, 4> GLGizmoBase::picking_color_component(unsigned int id) const
|
||||
{
|
||||
static const float INV_255 = 1.0f / 255.0f;
|
||||
|
|
@ -209,6 +217,10 @@ std::string GLGizmoBase::format(float value, unsigned int decimals) const
|
|||
return Slic3r::string_printf("%.*f", decimals, value);
|
||||
}
|
||||
|
||||
void GLGizmoBase::set_dirty() {
|
||||
m_dirty = true;
|
||||
}
|
||||
|
||||
void GLGizmoBase::render_input_window(float x, float y, float bottom_limit)
|
||||
{
|
||||
on_render_input_window(x, y, bottom_limit);
|
||||
|
|
|
|||
|
|
@ -154,6 +154,9 @@ public:
|
|||
|
||||
void update(const UpdateData& data);
|
||||
|
||||
// returns True when Gizmo changed its state
|
||||
bool update_items_state();
|
||||
|
||||
void render() { m_tooltip.clear(); on_render(); }
|
||||
void render_for_picking() { on_render_for_picking(); }
|
||||
void render_input_window(float x, float y, float bottom_limit);
|
||||
|
|
@ -187,6 +190,13 @@ protected:
|
|||
void render_grabbers_for_picking(const BoundingBoxf3& box) const;
|
||||
|
||||
std::string format(float value, unsigned int decimals) const;
|
||||
|
||||
// Mark gizmo as dirty to Re-Render when idle()
|
||||
void set_dirty();
|
||||
private:
|
||||
// Flag for dirty visible state of Gizmo
|
||||
// When True then need new rendering
|
||||
bool m_dirty;
|
||||
};
|
||||
|
||||
// Produce an alpha channel checksum for the red green blue components. The alpha channel may then be used to verify, whether the rgb components
|
||||
|
|
|
|||
|
|
@ -282,21 +282,21 @@ void GLGizmoCut::update_contours()
|
|||
const GLVolume* first_glvolume = selection.get_volume(*selection.get_volume_idxs().begin());
|
||||
const BoundingBoxf3& box = first_glvolume->transformed_convex_hull_bounding_box();
|
||||
|
||||
const int object_idx = selection.get_object_idx();
|
||||
const ModelObject* model_object = wxGetApp().model().objects[selection.get_object_idx()];
|
||||
const int instance_idx = selection.get_instance_idx();
|
||||
|
||||
if (0.0 < m_cut_z && m_cut_z < m_max_z) {
|
||||
if (m_cut_contours.cut_z != m_cut_z || m_cut_contours.object_idx != object_idx || m_cut_contours.instance_idx != instance_idx) {
|
||||
if (m_cut_contours.cut_z != m_cut_z || m_cut_contours.object_id != model_object->id() || m_cut_contours.instance_idx != instance_idx) {
|
||||
m_cut_contours.cut_z = m_cut_z;
|
||||
|
||||
if (m_cut_contours.object_idx != object_idx) {
|
||||
m_cut_contours.mesh = wxGetApp().plater()->model().objects[object_idx]->raw_mesh();
|
||||
if (m_cut_contours.object_id != model_object->id()) {
|
||||
m_cut_contours.mesh = model_object->raw_mesh();
|
||||
m_cut_contours.mesh.repair();
|
||||
}
|
||||
|
||||
m_cut_contours.position = box.center();
|
||||
m_cut_contours.shift = Vec3d::Zero();
|
||||
m_cut_contours.object_idx = object_idx;
|
||||
m_cut_contours.object_id = model_object->id();
|
||||
m_cut_contours.instance_idx = instance_idx;
|
||||
m_cut_contours.contours.reset();
|
||||
|
||||
|
|
|
|||
|
|
@ -5,6 +5,7 @@
|
|||
#if ENABLE_SINKING_CONTOURS
|
||||
#include "slic3r/GUI/GLModel.hpp"
|
||||
#include "libslic3r/TriangleMesh.hpp"
|
||||
#include "libslic3r/ObjectID.hpp"
|
||||
#endif // ENABLE_SINKING_CONTOURS
|
||||
|
||||
namespace Slic3r {
|
||||
|
|
@ -33,7 +34,7 @@ class GLGizmoCut : public GLGizmoBase
|
|||
double cut_z{ 0.0 };
|
||||
Vec3d position{ Vec3d::Zero() };
|
||||
Vec3d shift{ Vec3d::Zero() };
|
||||
int object_idx{ -1 };
|
||||
ObjectID object_id;
|
||||
int instance_idx{ -1 };
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -67,8 +67,8 @@ void GLGizmoFdmSupports::render_painter_gizmo() const
|
|||
glsafe(::glEnable(GL_DEPTH_TEST));
|
||||
|
||||
render_triangles(selection);
|
||||
|
||||
m_c->object_clipper()->render_cut();
|
||||
m_c->instances_hider()->render_cut();
|
||||
render_cursor();
|
||||
|
||||
glsafe(::glDisable(GL_BLEND));
|
||||
|
|
|
|||
|
|
@ -42,6 +42,8 @@ std::string GLGizmoFlatten::on_get_name() const
|
|||
|
||||
bool GLGizmoFlatten::on_is_activable() const
|
||||
{
|
||||
// This is assumed in GLCanvas3D::do_rotate, do not change this
|
||||
// without updating that function too.
|
||||
return m_parent.get_selection().is_single_full_instance();
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -42,7 +42,7 @@ void GLGizmoMmuSegmentation::on_shutdown()
|
|||
std::string GLGizmoMmuSegmentation::on_get_name() const
|
||||
{
|
||||
// FIXME Lukas H.: Discuss and change shortcut
|
||||
return (_L("MMU painting") + " [N]").ToUTF8().data();
|
||||
return (_L("Multimaterial painting") + " [N]").ToUTF8().data();
|
||||
}
|
||||
|
||||
bool GLGizmoMmuSegmentation::on_is_selectable() const
|
||||
|
|
@ -51,6 +51,11 @@ bool GLGizmoMmuSegmentation::on_is_selectable() const
|
|||
&& wxGetApp().get_mode() != comSimple && wxGetApp().extruders_edited_cnt() > 1);
|
||||
}
|
||||
|
||||
bool GLGizmoMmuSegmentation::on_is_activable() const
|
||||
{
|
||||
return GLGizmoPainterBase::on_is_activable() && wxGetApp().extruders_edited_cnt() > 1;
|
||||
}
|
||||
|
||||
static std::vector<std::array<float, 4>> get_extruders_colors()
|
||||
{
|
||||
unsigned char rgb_color[3] = {};
|
||||
|
|
@ -142,6 +147,7 @@ void GLGizmoMmuSegmentation::render_painter_gizmo() const
|
|||
render_triangles(selection, false);
|
||||
|
||||
m_c->object_clipper()->render_cut();
|
||||
m_c->instances_hider()->render_cut();
|
||||
render_cursor();
|
||||
|
||||
glsafe(::glDisable(GL_BLEND));
|
||||
|
|
@ -322,8 +328,13 @@ void GLGizmoMmuSegmentation::on_render_input_window(float x, float y, float bott
|
|||
ImGui::AlignTextToFramePadding();
|
||||
ImGui::SameLine(tool_type_offset + m_imgui->scaled(0.f));
|
||||
ImGui::PushItemWidth(tool_type_radio_brush);
|
||||
if (m_imgui->radio_button(m_desc["tool_brush"], m_tool_type == GLGizmoMmuSegmentation::ToolType::BRUSH))
|
||||
if (m_imgui->radio_button(m_desc["tool_brush"], m_tool_type == GLGizmoMmuSegmentation::ToolType::BRUSH)) {
|
||||
m_tool_type = GLGizmoMmuSegmentation::ToolType::BRUSH;
|
||||
for (auto &triangle_selector : m_triangle_selectors) {
|
||||
triangle_selector->seed_fill_unselect_all_triangles();
|
||||
triangle_selector->request_update_render_data();
|
||||
}
|
||||
}
|
||||
|
||||
if (ImGui::IsItemHovered()) {
|
||||
ImGui::BeginTooltip();
|
||||
|
|
@ -334,24 +345,6 @@ void GLGizmoMmuSegmentation::on_render_input_window(float x, float y, float bott
|
|||
}
|
||||
|
||||
ImGui::SameLine(tool_type_offset + tool_type_radio_brush + m_imgui->scaled(0.f));
|
||||
ImGui::PushItemWidth(tool_type_radio_bucket_fill);
|
||||
if (m_imgui->radio_button(m_desc["tool_bucket_fill"], m_tool_type == GLGizmoMmuSegmentation::ToolType::BUCKET_FILL)) {
|
||||
m_tool_type = GLGizmoMmuSegmentation::ToolType::BUCKET_FILL;
|
||||
for (auto &triangle_selector : m_triangle_selectors) {
|
||||
triangle_selector->seed_fill_unselect_all_triangles();
|
||||
triangle_selector->request_update_render_data();
|
||||
}
|
||||
}
|
||||
|
||||
if (ImGui::IsItemHovered()) {
|
||||
ImGui::BeginTooltip();
|
||||
ImGui::PushTextWrapPos(max_tooltip_width);
|
||||
ImGui::TextUnformatted(_L("Paints neighboring facets that have the same color.").ToUTF8().data());
|
||||
ImGui::PopTextWrapPos();
|
||||
ImGui::EndTooltip();
|
||||
}
|
||||
|
||||
ImGui::SameLine(tool_type_offset + tool_type_radio_brush + tool_type_radio_bucket_fill + m_imgui->scaled(0.f));
|
||||
ImGui::PushItemWidth(tool_type_radio_seed_fill);
|
||||
if (m_imgui->radio_button(m_desc["tool_seed_fill"], m_tool_type == GLGizmoMmuSegmentation::ToolType::SEED_FILL)) {
|
||||
m_tool_type = GLGizmoMmuSegmentation::ToolType::SEED_FILL;
|
||||
|
|
@ -369,6 +362,24 @@ void GLGizmoMmuSegmentation::on_render_input_window(float x, float y, float bott
|
|||
ImGui::EndTooltip();
|
||||
}
|
||||
|
||||
ImGui::SameLine(tool_type_offset + tool_type_radio_brush + tool_type_radio_seed_fill + m_imgui->scaled(0.f));
|
||||
ImGui::PushItemWidth(tool_type_radio_bucket_fill);
|
||||
if (m_imgui->radio_button(m_desc["tool_bucket_fill"], m_tool_type == GLGizmoMmuSegmentation::ToolType::BUCKET_FILL)) {
|
||||
m_tool_type = GLGizmoMmuSegmentation::ToolType::BUCKET_FILL;
|
||||
for (auto &triangle_selector : m_triangle_selectors) {
|
||||
triangle_selector->seed_fill_unselect_all_triangles();
|
||||
triangle_selector->request_update_render_data();
|
||||
}
|
||||
}
|
||||
|
||||
if (ImGui::IsItemHovered()) {
|
||||
ImGui::BeginTooltip();
|
||||
ImGui::PushTextWrapPos(max_tooltip_width);
|
||||
ImGui::TextUnformatted(_L("Paints neighboring facets that have the same color.").ToUTF8().data());
|
||||
ImGui::PopTextWrapPos();
|
||||
ImGui::EndTooltip();
|
||||
}
|
||||
|
||||
ImGui::Separator();
|
||||
|
||||
if(m_tool_type == ToolType::BRUSH) {
|
||||
|
|
@ -454,7 +465,12 @@ void GLGizmoMmuSegmentation::on_render_input_window(float x, float y, float bott
|
|||
"placed after the number with no whitespace in between.");
|
||||
ImGui::SameLine(sliders_width);
|
||||
ImGui::PushItemWidth(window_width - sliders_width);
|
||||
m_imgui->slider_float("##seed_fill_angle", &m_seed_fill_angle, SeedFillAngleMin, SeedFillAngleMax, format_str.data());
|
||||
if(m_imgui->slider_float("##seed_fill_angle", &m_seed_fill_angle, SeedFillAngleMin, SeedFillAngleMax, format_str.data()))
|
||||
for (auto &triangle_selector : m_triangle_selectors) {
|
||||
triangle_selector->seed_fill_unselect_all_triangles();
|
||||
triangle_selector->request_update_render_data();
|
||||
}
|
||||
|
||||
if (ImGui::IsItemHovered()) {
|
||||
ImGui::BeginTooltip();
|
||||
ImGui::PushTextWrapPos(max_tooltip_width);
|
||||
|
|
@ -581,10 +597,13 @@ std::array<float, 4> GLGizmoMmuSegmentation::get_cursor_sphere_right_button_colo
|
|||
return {color[0], color[1], color[2], 0.25f};
|
||||
}
|
||||
|
||||
static std::array<float, 4> get_seed_fill_color(const std::array<float, 4> &base_color)
|
||||
{
|
||||
return {base_color[0] * 0.75f, base_color[1] * 0.75f, base_color[2] * 0.75f, 1.f};
|
||||
}
|
||||
|
||||
void TriangleSelectorMmGui::render(ImGuiWrapper *imgui)
|
||||
{
|
||||
static constexpr std::array<float, 4> seed_fill_color{0.f, 1.f, 0.44f, 1.f};
|
||||
|
||||
if (m_update_render_data)
|
||||
update_render_data();
|
||||
|
||||
|
|
@ -597,12 +616,28 @@ void TriangleSelectorMmGui::render(ImGuiWrapper *imgui)
|
|||
|
||||
for (size_t color_idx = 0; color_idx < m_gizmo_scene.triangle_indices.size(); ++color_idx)
|
||||
if (m_gizmo_scene.has_VBOs(color_idx)) {
|
||||
shader->set_uniform("uniform_color", color_idx == 0 ? m_default_volume_color :
|
||||
color_idx == (m_gizmo_scene.triangle_indices.size() - 1) ? seed_fill_color :
|
||||
m_colors[color_idx - 1]);
|
||||
if (color_idx > m_colors.size()) // Seed fill VBO
|
||||
shader->set_uniform("uniform_color", get_seed_fill_color(color_idx == (m_colors.size() + 1) ? m_default_volume_color : m_colors[color_idx - (m_colors.size() + 1) - 1]));
|
||||
else // Normal VBO
|
||||
shader->set_uniform("uniform_color", color_idx == 0 ? m_default_volume_color : m_colors[color_idx - 1]);
|
||||
|
||||
m_gizmo_scene.render(color_idx);
|
||||
}
|
||||
|
||||
if (m_gizmo_scene.has_contour_VBO()) {
|
||||
ScopeGuard guard_gouraud([shader]() { shader->start_using(); });
|
||||
shader->stop_using();
|
||||
|
||||
auto *contour_shader = wxGetApp().get_shader("mm_contour");
|
||||
contour_shader->start_using();
|
||||
|
||||
glsafe(::glDepthFunc(GL_LEQUAL));
|
||||
m_gizmo_scene.render_contour();
|
||||
glsafe(::glDepthFunc(GL_LESS));
|
||||
|
||||
contour_shader->stop_using();
|
||||
}
|
||||
|
||||
m_update_render_data = false;
|
||||
}
|
||||
|
||||
|
|
@ -619,10 +654,10 @@ void TriangleSelectorMmGui::update_render_data()
|
|||
|
||||
for (const Triangle &tr : m_triangles)
|
||||
if (tr.valid() && !tr.is_split()) {
|
||||
int color = int(tr.get_state());
|
||||
std::vector<int> &iva = tr.is_selected_by_seed_fill() ? m_gizmo_scene.triangle_indices.back() :
|
||||
color < int(m_gizmo_scene.triangle_indices.size() - 1) ? m_gizmo_scene.triangle_indices[color] :
|
||||
m_gizmo_scene.triangle_indices.front();
|
||||
int color = int(tr.get_state()) <= int(m_colors.size()) ? int(tr.get_state()) : 0;
|
||||
assert(m_colors.size() + 1 + color < m_gizmo_scene.triangle_indices.size());
|
||||
std::vector<int> &iva = m_gizmo_scene.triangle_indices[color + tr.is_selected_by_seed_fill() * (m_colors.size() + 1)];
|
||||
|
||||
if (iva.size() + 3 > iva.capacity())
|
||||
iva.reserve(next_highest_power_of_2(iva.size() + 3));
|
||||
|
||||
|
|
@ -635,6 +670,24 @@ void TriangleSelectorMmGui::update_render_data()
|
|||
m_gizmo_scene.triangle_indices_sizes[color_idx] = m_gizmo_scene.triangle_indices[color_idx].size();
|
||||
|
||||
m_gizmo_scene.finalize_triangle_indices();
|
||||
|
||||
std::vector<Vec2i> contour_edges = this->get_seed_fill_contour();
|
||||
m_gizmo_scene.contour_vertices.reserve(contour_edges.size() * 6);
|
||||
for (const Vec2i &edge : contour_edges) {
|
||||
m_gizmo_scene.contour_vertices.emplace_back(m_vertices[edge(0)].v.x());
|
||||
m_gizmo_scene.contour_vertices.emplace_back(m_vertices[edge(0)].v.y());
|
||||
m_gizmo_scene.contour_vertices.emplace_back(m_vertices[edge(0)].v.z());
|
||||
|
||||
m_gizmo_scene.contour_vertices.emplace_back(m_vertices[edge(1)].v.x());
|
||||
m_gizmo_scene.contour_vertices.emplace_back(m_vertices[edge(1)].v.y());
|
||||
m_gizmo_scene.contour_vertices.emplace_back(m_vertices[edge(1)].v.z());
|
||||
}
|
||||
|
||||
m_gizmo_scene.contour_indices.assign(m_gizmo_scene.contour_vertices.size() / 3, 0);
|
||||
std::iota(m_gizmo_scene.contour_indices.begin(), m_gizmo_scene.contour_indices.end(), 0);
|
||||
m_gizmo_scene.contour_indices_size = m_gizmo_scene.contour_indices.size();
|
||||
|
||||
m_gizmo_scene.finalize_contour();
|
||||
}
|
||||
|
||||
wxString GLGizmoMmuSegmentation::handle_snapshot_action_name(bool shift_down, GLGizmoPainterBase::Button button_down) const
|
||||
|
|
@ -658,6 +711,14 @@ void GLMmSegmentationGizmo3DScene::release_geometry() {
|
|||
glsafe(::glDeleteBuffers(1, &triangle_indices_VBO_id));
|
||||
triangle_indices_VBO_id = 0;
|
||||
}
|
||||
if (this->contour_vertices_VBO_id) {
|
||||
glsafe(::glDeleteBuffers(1, &this->contour_vertices_VBO_id));
|
||||
this->contour_vertices_VBO_id = 0;
|
||||
}
|
||||
if (this->contour_indices_VBO_id) {
|
||||
glsafe(::glDeleteBuffers(1, &this->contour_indices_VBO_id));
|
||||
this->contour_indices_VBO_id = 0;
|
||||
}
|
||||
this->clear();
|
||||
}
|
||||
|
||||
|
|
@ -685,13 +746,36 @@ void GLMmSegmentationGizmo3DScene::render(size_t triangle_indices_idx) const
|
|||
glsafe(::glBindBuffer(GL_ARRAY_BUFFER, 0));
|
||||
}
|
||||
|
||||
void GLMmSegmentationGizmo3DScene::render_contour() const
|
||||
{
|
||||
assert(this->contour_vertices_VBO_id != 0);
|
||||
assert(this->contour_indices_VBO_id != 0);
|
||||
|
||||
glsafe(::glLineWidth(4.0f));
|
||||
|
||||
glsafe(::glBindBuffer(GL_ARRAY_BUFFER, this->contour_vertices_VBO_id));
|
||||
glsafe(::glVertexPointer(3, GL_FLOAT, 3 * sizeof(float), nullptr));
|
||||
|
||||
glsafe(::glEnableClientState(GL_VERTEX_ARRAY));
|
||||
|
||||
if (this->contour_indices_size > 0) {
|
||||
glsafe(::glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, this->contour_indices_VBO_id));
|
||||
glsafe(::glDrawElements(GL_LINES, GLsizei(this->contour_indices_size), GL_UNSIGNED_INT, nullptr));
|
||||
glsafe(::glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0));
|
||||
}
|
||||
|
||||
glsafe(::glDisableClientState(GL_VERTEX_ARRAY));
|
||||
|
||||
glsafe(::glBindBuffer(GL_ARRAY_BUFFER, 0));
|
||||
}
|
||||
|
||||
void GLMmSegmentationGizmo3DScene::finalize_vertices()
|
||||
{
|
||||
assert(this->vertices_VBO_id == 0);
|
||||
if (!this->vertices.empty()) {
|
||||
glsafe(::glGenBuffers(1, &this->vertices_VBO_id));
|
||||
glsafe(::glBindBuffer(GL_ARRAY_BUFFER, this->vertices_VBO_id));
|
||||
glsafe(::glBufferData(GL_ARRAY_BUFFER, this->vertices.size() * 4, this->vertices.data(), GL_STATIC_DRAW));
|
||||
glsafe(::glBufferData(GL_ARRAY_BUFFER, this->vertices.size() * sizeof(float), this->vertices.data(), GL_STATIC_DRAW));
|
||||
glsafe(::glBindBuffer(GL_ARRAY_BUFFER, 0));
|
||||
this->vertices.clear();
|
||||
}
|
||||
|
|
@ -706,19 +790,32 @@ void GLMmSegmentationGizmo3DScene::finalize_triangle_indices()
|
|||
if (!this->triangle_indices[buffer_idx].empty()) {
|
||||
glsafe(::glGenBuffers(1, &this->triangle_indices_VBO_ids[buffer_idx]));
|
||||
glsafe(::glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, this->triangle_indices_VBO_ids[buffer_idx]));
|
||||
glsafe(::glBufferData(GL_ELEMENT_ARRAY_BUFFER, this->triangle_indices[buffer_idx].size() * 4, this->triangle_indices[buffer_idx].data(),
|
||||
GL_STATIC_DRAW));
|
||||
glsafe(::glBufferData(GL_ELEMENT_ARRAY_BUFFER, this->triangle_indices[buffer_idx].size() * sizeof(int), this->triangle_indices[buffer_idx].data(), GL_STATIC_DRAW));
|
||||
glsafe(::glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0));
|
||||
this->triangle_indices[buffer_idx].clear();
|
||||
}
|
||||
}
|
||||
|
||||
void GLMmSegmentationGizmo3DScene::finalize_geometry()
|
||||
void GLMmSegmentationGizmo3DScene::finalize_contour()
|
||||
{
|
||||
assert(this->vertices_VBO_id == 0);
|
||||
assert(this->triangle_indices.size() == this->triangle_indices_VBO_ids.size());
|
||||
finalize_vertices();
|
||||
finalize_triangle_indices();
|
||||
assert(this->contour_vertices_VBO_id == 0);
|
||||
assert(this->contour_indices_VBO_id == 0);
|
||||
|
||||
if (!this->contour_vertices.empty()) {
|
||||
glsafe(::glGenBuffers(1, &this->contour_vertices_VBO_id));
|
||||
glsafe(::glBindBuffer(GL_ARRAY_BUFFER, this->contour_vertices_VBO_id));
|
||||
glsafe(::glBufferData(GL_ARRAY_BUFFER, this->contour_vertices.size() * sizeof(float), this->contour_vertices.data(), GL_STATIC_DRAW));
|
||||
glsafe(::glBindBuffer(GL_ARRAY_BUFFER, 0));
|
||||
this->contour_vertices.clear();
|
||||
}
|
||||
|
||||
if (!this->contour_indices.empty()) {
|
||||
glsafe(::glGenBuffers(1, &this->contour_indices_VBO_id));
|
||||
glsafe(::glBindBuffer(GL_ARRAY_BUFFER, this->contour_indices_VBO_id));
|
||||
glsafe(::glBufferData(GL_ARRAY_BUFFER, this->contour_indices.size() * sizeof(unsigned int), this->contour_indices.data(), GL_STATIC_DRAW));
|
||||
glsafe(::glBindBuffer(GL_ARRAY_BUFFER, 0));
|
||||
this->contour_indices.clear();
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace Slic3r
|
||||
|
|
|
|||
|
|
@ -25,9 +25,8 @@ public:
|
|||
return this->triangle_indices_VBO_ids[triangle_indices_idx] != 0;
|
||||
}
|
||||
|
||||
// Finalize the initialization of the geometry and indices, upload the geometry and indices to OpenGL VBO objects
|
||||
// and possibly releasing it if it has been loaded into the VBOs.
|
||||
void finalize_geometry();
|
||||
[[nodiscard]] inline bool has_contour_VBO() const { return this->contour_indices_VBO_id != 0; }
|
||||
|
||||
// Release the geometry data, release OpenGL VBOs.
|
||||
void release_geometry();
|
||||
// Finalize the initialization of the geometry, upload the geometry to OpenGL VBO objects
|
||||
|
|
@ -36,6 +35,9 @@ public:
|
|||
// Finalize the initialization of the indices, upload the indices to OpenGL VBO objects
|
||||
// and possibly releasing it if it has been loaded into the VBOs.
|
||||
void finalize_triangle_indices();
|
||||
// Finalize the initialization of the contour geometry and the indices, upload both to OpenGL VBO objects
|
||||
// and possibly releasing it if it has been loaded into the VBOs.
|
||||
void finalize_contour();
|
||||
|
||||
void clear()
|
||||
{
|
||||
|
|
@ -45,28 +47,41 @@ public:
|
|||
|
||||
for (size_t &triangle_indices_size : this->triangle_indices_sizes)
|
||||
triangle_indices_size = 0;
|
||||
|
||||
this->contour_vertices.clear();
|
||||
this->contour_indices.clear();
|
||||
this->contour_indices_size = 0;
|
||||
}
|
||||
|
||||
void render(size_t triangle_indices_idx) const;
|
||||
|
||||
void render_contour() const;
|
||||
|
||||
std::vector<float> vertices;
|
||||
std::vector<std::vector<int>> triangle_indices;
|
||||
|
||||
std::vector<float> contour_vertices;
|
||||
std::vector<int> contour_indices;
|
||||
|
||||
// When the triangle indices are loaded into the graphics card as Vertex Buffer Objects,
|
||||
// the above mentioned std::vectors are cleared and the following variables keep their original length.
|
||||
std::vector<size_t> triangle_indices_sizes;
|
||||
size_t contour_indices_size{0};
|
||||
|
||||
// IDs of the Vertex Array Objects, into which the geometry has been loaded.
|
||||
// Zero if the VBOs are not sent to GPU yet.
|
||||
unsigned int vertices_VBO_id{0};
|
||||
std::vector<unsigned int> triangle_indices_VBO_ids;
|
||||
|
||||
unsigned int contour_vertices_VBO_id{0};
|
||||
unsigned int contour_indices_VBO_id{0};
|
||||
};
|
||||
|
||||
class TriangleSelectorMmGui : public TriangleSelectorGUI {
|
||||
public:
|
||||
// Plus 2 in the initialization of m_gizmo_scene is because the first position is allocated for non-painted triangles, and the last position is allocated for seed fill.
|
||||
// Plus 1 in the initialization of m_gizmo_scene is because the first position is allocated for non-painted triangles, and the indices above colors.size() are allocated for seed fill.
|
||||
explicit TriangleSelectorMmGui(const TriangleMesh &mesh, const std::vector<std::array<float, 4>> &colors, const std::array<float, 4> &default_volume_color)
|
||||
: TriangleSelectorGUI(mesh), m_colors(colors), m_default_volume_color(default_volume_color), m_gizmo_scene(colors.size() + 2) {}
|
||||
: TriangleSelectorGUI(mesh), m_colors(colors), m_default_volume_color(default_volume_color), m_gizmo_scene(2 * (colors.size() + 1)) {}
|
||||
~TriangleSelectorMmGui() override = default;
|
||||
|
||||
// Render current selection. Transformation matrices are supposed
|
||||
|
|
@ -109,6 +124,7 @@ protected:
|
|||
std::string on_get_name() const override;
|
||||
|
||||
bool on_is_selectable() const override;
|
||||
bool on_is_activable() const override;
|
||||
|
||||
wxString handle_snapshot_action_name(bool shift_down, Button button_down) const override;
|
||||
|
||||
|
|
|
|||
|
|
@ -283,7 +283,7 @@ bool GLGizmoPainterBase::gizmo_event(SLAGizmoEventType action, const Vec2d& mous
|
|||
return true;
|
||||
}
|
||||
else if (alt_down) {
|
||||
if (m_tool_type == ToolType::BRUSH) {
|
||||
if (m_tool_type == ToolType::BRUSH && (m_cursor_type == TriangleSelector::CursorType::SPHERE || m_cursor_type == TriangleSelector::CursorType::CIRCLE)) {
|
||||
m_cursor_radius = action == SLAGizmoEventType::MouseWheelDown ? std::max(m_cursor_radius - CursorRadiusStep, CursorRadiusMin)
|
||||
: std::min(m_cursor_radius + CursorRadiusStep, CursorRadiusMax);
|
||||
m_parent.set_as_dirty();
|
||||
|
|
@ -292,6 +292,11 @@ bool GLGizmoPainterBase::gizmo_event(SLAGizmoEventType action, const Vec2d& mous
|
|||
m_seed_fill_angle = action == SLAGizmoEventType::MouseWheelDown ? std::max(m_seed_fill_angle - SeedFillAngleStep, SeedFillAngleMin)
|
||||
: std::min(m_seed_fill_angle + SeedFillAngleStep, SeedFillAngleMax);
|
||||
m_parent.set_as_dirty();
|
||||
if (m_rr.mesh_id != -1) {
|
||||
m_triangle_selectors[m_rr.mesh_id]->seed_fill_select_triangles(m_rr.hit, int(m_rr.facet), m_seed_fill_angle, true);
|
||||
m_triangle_selectors[m_rr.mesh_id]->request_update_render_data();
|
||||
m_seed_fill_last_mesh_id = m_rr.mesh_id;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
@ -319,11 +324,11 @@ bool GLGizmoPainterBase::gizmo_event(SLAGizmoEventType action, const Vec2d& mous
|
|||
new_state = action == SLAGizmoEventType::LeftDown ? this->get_left_button_state_type() : this->get_right_button_state_type();
|
||||
}
|
||||
|
||||
const Camera& camera = wxGetApp().plater()->get_camera();
|
||||
const Selection& selection = m_parent.get_selection();
|
||||
const ModelObject* mo = m_c->selection_info()->model_object();
|
||||
const ModelInstance* mi = mo->instances[selection.get_instance_idx()];
|
||||
const Transform3d& instance_trafo = mi->get_transformation().get_matrix();
|
||||
const Camera &camera = wxGetApp().plater()->get_camera();
|
||||
const Selection &selection = m_parent.get_selection();
|
||||
const ModelObject *mo = m_c->selection_info()->model_object();
|
||||
const ModelInstance *mi = mo->instances[selection.get_instance_idx()];
|
||||
const Transform3d &instance_trafo = mi->get_transformation().get_matrix();
|
||||
|
||||
// List of mouse positions that will be used as seeds for painting.
|
||||
std::vector<Vec2d> mouse_positions{mouse_position};
|
||||
|
|
@ -382,6 +387,13 @@ bool GLGizmoPainterBase::gizmo_event(SLAGizmoEventType action, const Vec2d& mous
|
|||
assert(m_rr.mesh_id < int(m_triangle_selectors.size()));
|
||||
if (m_tool_type == ToolType::SEED_FILL || m_tool_type == ToolType::BUCKET_FILL || (m_tool_type == ToolType::BRUSH && m_cursor_type == TriangleSelector::CursorType::POINTER)) {
|
||||
m_triangle_selectors[m_rr.mesh_id]->seed_fill_apply_on_triangles(new_state);
|
||||
if (m_tool_type == ToolType::SEED_FILL)
|
||||
m_triangle_selectors[m_rr.mesh_id]->seed_fill_select_triangles(m_rr.hit, int(m_rr.facet), m_seed_fill_angle, true);
|
||||
else if (m_tool_type == ToolType::BRUSH && m_cursor_type == TriangleSelector::CursorType::POINTER)
|
||||
m_triangle_selectors[m_rr.mesh_id]->bucket_fill_select_triangles(m_rr.hit, int(m_rr.facet), false, true);
|
||||
else if (m_tool_type == ToolType::BUCKET_FILL)
|
||||
m_triangle_selectors[m_rr.mesh_id]->bucket_fill_select_triangles(m_rr.hit, int(m_rr.facet), true, true);
|
||||
|
||||
m_seed_fill_last_mesh_id = -1;
|
||||
} else if (m_tool_type == ToolType::BRUSH)
|
||||
m_triangle_selectors[m_rr.mesh_id]->select_patch(m_rr.hit, int(m_rr.facet), camera_pos, m_cursor_radius, m_cursor_type,
|
||||
|
|
@ -515,7 +527,7 @@ bool GLGizmoPainterBase::on_is_activable() const
|
|||
const Selection& selection = m_parent.get_selection();
|
||||
|
||||
if (wxGetApp().preset_bundle->printers.get_edited_preset().printer_technology() != ptFFF
|
||||
|| !selection.is_single_full_instance())
|
||||
|| !selection.is_single_full_instance() || wxGetApp().get_mode() == comSimple)
|
||||
return false;
|
||||
|
||||
// Check that none of the selected volumes is outside. Only SLA auxiliaries (supports) are allowed outside.
|
||||
|
|
|
|||
|
|
@ -114,7 +114,7 @@ protected:
|
|||
|
||||
bool m_triangle_splitting_enabled = true;
|
||||
ToolType m_tool_type = ToolType::BRUSH;
|
||||
float m_seed_fill_angle = 0.f;
|
||||
float m_seed_fill_angle = 30.f;
|
||||
|
||||
static constexpr float SeedFillAngleMin = 0.0f;
|
||||
static constexpr float SeedFillAngleMax = 90.f;
|
||||
|
|
|
|||
|
|
@ -497,9 +497,6 @@ void GLGizmoRotate3D::on_render()
|
|||
m_gizmos[Z].render();
|
||||
}
|
||||
|
||||
const char * GLGizmoRotate3D::RotoptimzeWindow::options[RotoptimizeJob::get_methods_count()];
|
||||
bool GLGizmoRotate3D::RotoptimzeWindow::options_valid = false;
|
||||
|
||||
GLGizmoRotate3D::RotoptimzeWindow::RotoptimzeWindow(ImGuiWrapper * imgui,
|
||||
State & state,
|
||||
const Alignment &alignment)
|
||||
|
|
@ -515,21 +512,26 @@ GLGizmoRotate3D::RotoptimzeWindow::RotoptimzeWindow(ImGuiWrapper * imgui,
|
|||
y = std::min(y, alignment.bottom_limit - win_h);
|
||||
ImGui::SetWindowPos(ImVec2(x, y), ImGuiCond_Always);
|
||||
|
||||
ImGui::PushItemWidth(200.f);
|
||||
ImGui::PushItemWidth(300.f);
|
||||
|
||||
size_t methods_cnt = RotoptimizeJob::get_methods_count();
|
||||
if (!options_valid) {
|
||||
for (size_t i = 0; i < methods_cnt; ++i)
|
||||
options[i] = RotoptimizeJob::get_method_names()[i].c_str();
|
||||
if (ImGui::BeginCombo(_L("Choose goal").c_str(), RotoptimizeJob::get_method_name(state.method_id).c_str())) {
|
||||
for (size_t i = 0; i < RotoptimizeJob::get_methods_count(); ++i) {
|
||||
if (ImGui::Selectable(RotoptimizeJob::get_method_name(i).c_str())) {
|
||||
state.method_id = i;
|
||||
wxGetApp().app_config->set("sla_auto_rotate",
|
||||
"method_id",
|
||||
std::to_string(state.method_id));
|
||||
}
|
||||
|
||||
options_valid = true;
|
||||
if (ImGui::IsItemHovered())
|
||||
ImGui::SetTooltip("%s", RotoptimizeJob::get_method_description(i).c_str());
|
||||
}
|
||||
|
||||
ImGui::EndCombo();
|
||||
}
|
||||
|
||||
int citem = state.method_id;
|
||||
if (ImGui::Combo(_L("Choose goal").c_str(), &citem, options, methods_cnt) ) {
|
||||
state.method_id = citem;
|
||||
wxGetApp().app_config->set("sla_auto_rotate", "method_id", std::to_string(state.method_id));
|
||||
}
|
||||
if (ImGui::IsItemHovered())
|
||||
ImGui::SetTooltip("%s", RotoptimizeJob::get_method_description(state.method_id).c_str());
|
||||
|
||||
ImGui::Separator();
|
||||
|
||||
|
|
|
|||
|
|
@ -138,10 +138,6 @@ private:
|
|||
|
||||
class RotoptimzeWindow {
|
||||
ImGuiWrapper *m_imgui = nullptr;
|
||||
|
||||
static const char * options [];
|
||||
static bool options_valid;
|
||||
|
||||
public:
|
||||
|
||||
struct State {
|
||||
|
|
|
|||
|
|
@ -63,6 +63,7 @@ void GLGizmoSeam::render_painter_gizmo() const
|
|||
render_triangles(selection);
|
||||
|
||||
m_c->object_clipper()->render_cut();
|
||||
m_c->instances_hider()->render_cut();
|
||||
render_cursor();
|
||||
|
||||
glsafe(::glDisable(GL_BLEND));
|
||||
|
|
|
|||
385
src/slic3r/GUI/Gizmos/GLGizmoSimplify.cpp
Normal file
385
src/slic3r/GUI/Gizmos/GLGizmoSimplify.cpp
Normal file
|
|
@ -0,0 +1,385 @@
|
|||
#include "GLGizmoSimplify.hpp"
|
||||
#include "slic3r/GUI/GLCanvas3D.hpp"
|
||||
#include "slic3r/GUI/GUI_App.hpp"
|
||||
#include "slic3r/GUI/GUI_ObjectManipulation.hpp"
|
||||
#include "slic3r/GUI/GUI_ObjectList.hpp"
|
||||
#include "slic3r/GUI/NotificationManager.hpp"
|
||||
#include "slic3r/GUI/Plater.hpp"
|
||||
#include "libslic3r/AppConfig.hpp"
|
||||
#include "libslic3r/Model.hpp"
|
||||
#include "libslic3r/QuadricEdgeCollapse.hpp"
|
||||
|
||||
namespace Slic3r::GUI {
|
||||
|
||||
GLGizmoSimplify::GLGizmoSimplify(GLCanvas3D & parent,
|
||||
const std::string &icon_filename,
|
||||
unsigned int sprite_id)
|
||||
: GLGizmoBase(parent, icon_filename, -1)
|
||||
, m_state(State::settings)
|
||||
, m_is_valid_result(false)
|
||||
, m_exist_preview(false)
|
||||
, m_progress(0)
|
||||
, m_volume(nullptr)
|
||||
, m_obj_index(0)
|
||||
, m_need_reload(false)
|
||||
|
||||
, tr_mesh_name(_u8L("Mesh name"))
|
||||
, tr_triangles(_u8L("Triangles"))
|
||||
, tr_preview(_u8L("Preview"))
|
||||
, tr_detail_level(_u8L("Detail level"))
|
||||
, tr_decimate_ratio(_u8L("Decimate ratio"))
|
||||
{}
|
||||
|
||||
GLGizmoSimplify::~GLGizmoSimplify() {
|
||||
m_state = State::canceling;
|
||||
if (m_worker.joinable()) m_worker.join();
|
||||
}
|
||||
|
||||
bool GLGizmoSimplify::on_init()
|
||||
{
|
||||
//m_grabbers.emplace_back();
|
||||
//m_shortcut_key = WXK_CONTROL_C;
|
||||
return true;
|
||||
}
|
||||
|
||||
std::string GLGizmoSimplify::on_get_name() const
|
||||
{
|
||||
return (_L("Simplify")).ToUTF8().data();
|
||||
}
|
||||
|
||||
void GLGizmoSimplify::on_render() {}
|
||||
void GLGizmoSimplify::on_render_for_picking() {}
|
||||
|
||||
void GLGizmoSimplify::on_render_input_window(float x, float y, float bottom_limit)
|
||||
{
|
||||
create_gui_cfg();
|
||||
const Selection &selection = m_parent.get_selection();
|
||||
int object_idx = selection.get_object_idx();
|
||||
ModelObject *obj = wxGetApp().plater()->model().objects[object_idx];
|
||||
ModelVolume *act_volume = obj->volumes.front();
|
||||
|
||||
// Check selection of new volume
|
||||
// Do not reselect object when processing
|
||||
if (act_volume != m_volume && m_state == State::settings) {
|
||||
bool change_window_position = (m_volume == nullptr);
|
||||
// select different model
|
||||
if (m_volume != nullptr && m_original_its.has_value()) {
|
||||
set_its(*m_original_its);
|
||||
}
|
||||
|
||||
m_obj_index = object_idx; // to remember correct object
|
||||
m_volume = act_volume;
|
||||
m_original_its = {};
|
||||
m_configuration.decimate_ratio = 50.; // default value
|
||||
m_configuration.fix_count_by_ratio(m_volume->mesh().its.indices.size());
|
||||
m_is_valid_result = false;
|
||||
m_exist_preview = false;
|
||||
|
||||
if (change_window_position) {
|
||||
ImVec2 pos = ImGui::GetMousePos();
|
||||
pos.x -= m_gui_cfg->window_offset_x;
|
||||
pos.y -= m_gui_cfg->window_offset_y;
|
||||
// minimal top left value
|
||||
ImVec2 tl(m_gui_cfg->window_padding, m_gui_cfg->window_padding);
|
||||
if (pos.x < tl.x) pos.x = tl.x;
|
||||
if (pos.y < tl.y) pos.y = tl.y;
|
||||
// maximal bottom right value
|
||||
auto parent_size = m_parent.get_canvas_size();
|
||||
ImVec2 br(
|
||||
parent_size.get_width() - (2 * m_gui_cfg->window_offset_x + m_gui_cfg->window_padding),
|
||||
parent_size.get_height() - (2 * m_gui_cfg->window_offset_y + m_gui_cfg->window_padding));
|
||||
if (pos.x > br.x) pos.x = br.x;
|
||||
if (pos.y > br.y) pos.y = br.y;
|
||||
ImGui::SetNextWindowPos(pos, ImGuiCond_Always);
|
||||
}
|
||||
}
|
||||
|
||||
int flag = ImGuiWindowFlags_AlwaysAutoResize | ImGuiWindowFlags_NoResize |
|
||||
ImGuiWindowFlags_NoCollapse;
|
||||
m_imgui->begin(on_get_name(), flag);
|
||||
|
||||
size_t triangle_count = m_volume->mesh().its.indices.size();
|
||||
// already reduced mesh
|
||||
if (m_original_its.has_value())
|
||||
triangle_count = m_original_its->indices.size();
|
||||
|
||||
m_imgui->text_colored(ImGuiWrapper::COL_ORANGE_LIGHT, tr_mesh_name + ":");
|
||||
ImGui::SameLine(m_gui_cfg->top_left_width);
|
||||
std::string name = m_volume->name;
|
||||
if (name.length() > m_gui_cfg->max_char_in_name)
|
||||
name = name.substr(0, m_gui_cfg->max_char_in_name - 3) + "...";
|
||||
m_imgui->text(name);
|
||||
m_imgui->text_colored(ImGuiWrapper::COL_ORANGE_LIGHT, tr_triangles + ":");
|
||||
ImGui::SameLine(m_gui_cfg->top_left_width);
|
||||
m_imgui->text(std::to_string(triangle_count));
|
||||
/*
|
||||
m_imgui->text_colored(ImGuiWrapper::COL_ORANGE_LIGHT, tr_preview + ":");
|
||||
ImGui::SameLine(m_gui_cfg->top_left_width);
|
||||
if (m_exist_preview) {
|
||||
m_imgui->text(std::to_string(m_volume->mesh().its.indices.size()));
|
||||
} else {
|
||||
m_imgui->text("---");
|
||||
}*/
|
||||
|
||||
ImGui::Separator();
|
||||
|
||||
if(ImGui::RadioButton("##use_error", !m_configuration.use_count)) {
|
||||
m_is_valid_result = false;
|
||||
m_configuration.use_count = !m_configuration.use_count;
|
||||
}
|
||||
ImGui::SameLine();
|
||||
m_imgui->disabled_begin(m_configuration.use_count);
|
||||
ImGui::Text("%s", tr_detail_level.c_str());
|
||||
std::vector<std::string> reduce_captions = {
|
||||
static_cast<std::string>(_u8L("Extra high")),
|
||||
static_cast<std::string>(_u8L("High")),
|
||||
static_cast<std::string>(_u8L("Medium")),
|
||||
static_cast<std::string>(_u8L("Low")),
|
||||
static_cast<std::string>(_u8L("Extra low"))
|
||||
};
|
||||
ImGui::SameLine(m_gui_cfg->bottom_left_width);
|
||||
ImGui::SetNextItemWidth(m_gui_cfg->input_width);
|
||||
static int reduction = 2;
|
||||
if(ImGui::SliderInt("##ReductionLevel", &reduction, 0, 4, reduce_captions[reduction].c_str())) {
|
||||
m_is_valid_result = false;
|
||||
if (reduction < 0) reduction = 0;
|
||||
if (reduction > 4) reduction = 4;
|
||||
switch (reduction) {
|
||||
case 0: m_configuration.max_error = 1e-3f; break;
|
||||
case 1: m_configuration.max_error = 1e-2f; break;
|
||||
case 2: m_configuration.max_error = 0.1f; break;
|
||||
case 3: m_configuration.max_error = 0.5f; break;
|
||||
case 4: m_configuration.max_error = 1.f; break;
|
||||
}
|
||||
}
|
||||
m_imgui->disabled_end(); // !use_count
|
||||
|
||||
if (ImGui::RadioButton("##use_count", m_configuration.use_count)) {
|
||||
m_is_valid_result = false;
|
||||
m_configuration.use_count = !m_configuration.use_count;
|
||||
}
|
||||
ImGui::SameLine();
|
||||
|
||||
// show preview result triangle count (percent)
|
||||
if (m_need_reload && !m_configuration.use_count) {
|
||||
m_configuration.wanted_count = static_cast<uint32_t>(m_volume->mesh().its.indices.size());
|
||||
m_configuration.decimate_ratio =
|
||||
(1.0f - (m_configuration.wanted_count / (float) triangle_count)) * 100.f;
|
||||
}
|
||||
|
||||
m_imgui->disabled_begin(!m_configuration.use_count);
|
||||
ImGui::Text("%s", tr_decimate_ratio.c_str());
|
||||
ImGui::SameLine(m_gui_cfg->bottom_left_width);
|
||||
ImGui::SetNextItemWidth(m_gui_cfg->input_width);
|
||||
const char * format = (m_configuration.decimate_ratio > 10)? "%.0f %%":
|
||||
((m_configuration.decimate_ratio > 1)? "%.1f %%":"%.2f %%");
|
||||
if (ImGui::SliderFloat("##decimate_ratio", &m_configuration.decimate_ratio, 0.f, 100.f, format)) {
|
||||
m_is_valid_result = false;
|
||||
if (m_configuration.decimate_ratio < 0.f)
|
||||
m_configuration.decimate_ratio = 0.01f;
|
||||
if (m_configuration.decimate_ratio > 100.f)
|
||||
m_configuration.decimate_ratio = 100.f;
|
||||
m_configuration.fix_count_by_ratio(triangle_count);
|
||||
}
|
||||
|
||||
ImGui::NewLine();
|
||||
ImGui::SameLine(m_gui_cfg->bottom_left_width);
|
||||
ImGui::Text(_L("%d triangles").c_str(), m_configuration.wanted_count);
|
||||
m_imgui->disabled_end(); // use_count
|
||||
|
||||
if (m_state == State::settings) {
|
||||
if (m_imgui->button(_L("Cancel"))) {
|
||||
if (m_original_its.has_value()) {
|
||||
set_its(*m_original_its);
|
||||
m_state = State::close_on_end;
|
||||
} else {
|
||||
close();
|
||||
}
|
||||
}
|
||||
ImGui::SameLine(m_gui_cfg->bottom_left_width);
|
||||
if (m_imgui->button(_L("Preview"))) {
|
||||
m_state = State::preview;
|
||||
// simplify but not aply on mesh
|
||||
process();
|
||||
}
|
||||
ImGui::SameLine();
|
||||
if (m_imgui->button(_L("Apply"))) {
|
||||
if (!m_is_valid_result) {
|
||||
m_state = State::close_on_end;
|
||||
process();
|
||||
} else {
|
||||
// use preview and close
|
||||
if (m_exist_preview) {
|
||||
// fix hollowing, sla support points, modifiers, ...
|
||||
auto plater = wxGetApp().plater();
|
||||
plater->changed_mesh(m_obj_index);
|
||||
}
|
||||
close();
|
||||
}
|
||||
}
|
||||
} else {
|
||||
m_imgui->disabled_begin(m_state == State::canceling);
|
||||
if (m_imgui->button(_L("Cancel"))) m_state = State::canceling;
|
||||
m_imgui->disabled_end();
|
||||
|
||||
ImGui::SameLine(m_gui_cfg->bottom_left_width);
|
||||
// draw progress bar
|
||||
char buf[32];
|
||||
sprintf(buf, L("Process %d / 100"), m_progress);
|
||||
ImGui::ProgressBar(m_progress / 100., ImVec2(m_gui_cfg->input_width, 0.f), buf);
|
||||
}
|
||||
m_imgui->end();
|
||||
|
||||
if (m_need_reload) {
|
||||
m_need_reload = false;
|
||||
bool close_on_end = (m_state == State::close_on_end);
|
||||
// Reload visualization of mesh - change VBO, FBO on GPU
|
||||
m_parent.reload_scene(true);
|
||||
// set m_state must be before close() !!!
|
||||
m_state = State::settings;
|
||||
if (close_on_end) {
|
||||
// fix hollowing, sla support points, modifiers, ...
|
||||
auto plater = wxGetApp().plater();
|
||||
plater->changed_mesh(m_obj_index);
|
||||
close();
|
||||
}
|
||||
|
||||
// Fix warning icon in object list
|
||||
wxGetApp().obj_list()->update_item_error_icon(m_obj_index, -1);
|
||||
}
|
||||
}
|
||||
|
||||
void GLGizmoSimplify::close() {
|
||||
// close gizmo == open it again
|
||||
GLGizmosManager &gizmos_mgr = m_parent.get_gizmos_manager();
|
||||
gizmos_mgr.open_gizmo(GLGizmosManager::EType::Simplify);
|
||||
}
|
||||
|
||||
|
||||
void GLGizmoSimplify::process()
|
||||
{
|
||||
class SimplifyCanceledException : public std::exception {
|
||||
public:
|
||||
const char* what() const throw() { return L("Model simplification has been canceled"); }
|
||||
};
|
||||
|
||||
if (!m_original_its.has_value())
|
||||
m_original_its = m_volume->mesh().its; // copy
|
||||
|
||||
auto plater = wxGetApp().plater();
|
||||
plater->take_snapshot(_L("Simplify ") + m_volume->name);
|
||||
plater->clear_before_change_mesh(m_obj_index);
|
||||
m_progress = 0;
|
||||
if (m_worker.joinable()) m_worker.join();
|
||||
m_worker = std::thread([this]() {
|
||||
// store original triangles
|
||||
uint32_t triangle_count = (m_configuration.use_count) ? m_configuration.wanted_count : 0;
|
||||
float max_error = (!m_configuration.use_count) ? m_configuration.max_error : std::numeric_limits<float>::max();
|
||||
|
||||
std::function<void(void)> throw_on_cancel = [&]() {
|
||||
if (m_state == State::canceling) {
|
||||
throw SimplifyCanceledException();
|
||||
}
|
||||
};
|
||||
|
||||
std::function<void(int)> statusfn = [this](int percent) {
|
||||
m_progress = percent;
|
||||
|
||||
// check max 4fps
|
||||
static int64_t last = 0;
|
||||
int64_t now = m_parent.timestamp_now();
|
||||
if ((now - last) < 250) return;
|
||||
last = now;
|
||||
|
||||
request_rerender();
|
||||
};
|
||||
|
||||
indexed_triangle_set collapsed = *m_original_its; // copy
|
||||
|
||||
try {
|
||||
its_quadric_edge_collapse(collapsed, triangle_count, &max_error, throw_on_cancel, statusfn);
|
||||
set_its(collapsed);
|
||||
m_is_valid_result = true;
|
||||
m_exist_preview = true;
|
||||
} catch (SimplifyCanceledException &) {
|
||||
// set state out of main thread
|
||||
m_state = State::settings;
|
||||
}
|
||||
// need to render last status fn to change bar graph to buttons
|
||||
request_rerender();
|
||||
});
|
||||
}
|
||||
|
||||
void GLGizmoSimplify::set_its(indexed_triangle_set &its) {
|
||||
auto tm = std::make_unique<TriangleMesh>(its);
|
||||
tm->repair();
|
||||
m_volume->set_mesh(std::move(tm));
|
||||
m_volume->set_new_unique_id();
|
||||
m_volume->get_object()->invalidate_bounding_box();
|
||||
m_need_reload = true;
|
||||
}
|
||||
|
||||
bool GLGizmoSimplify::on_is_activable() const
|
||||
{
|
||||
return !m_parent.get_selection().is_empty();
|
||||
}
|
||||
|
||||
void GLGizmoSimplify::on_set_state()
|
||||
{
|
||||
// Closing gizmo. e.g. selecting another one
|
||||
if (GLGizmoBase::m_state == GLGizmoBase::Off) {
|
||||
|
||||
// refuse outgoing during simlification
|
||||
if (m_state != State::settings) {
|
||||
GLGizmoBase::m_state = GLGizmoBase::On;
|
||||
auto notification_manager = wxGetApp().plater()->get_notification_manager();
|
||||
notification_manager->push_notification(
|
||||
NotificationType::CustomNotification,
|
||||
NotificationManager::NotificationLevel::RegularNotification,
|
||||
_u8L("ERROR: Wait until Simplification ends or Cancel process."));
|
||||
return;
|
||||
}
|
||||
|
||||
// revert preview
|
||||
if (m_exist_preview) {
|
||||
set_its(*m_original_its);
|
||||
m_parent.reload_scene(true);
|
||||
m_need_reload = false;
|
||||
}
|
||||
|
||||
// invalidate selected model
|
||||
m_volume = nullptr;
|
||||
} else if (GLGizmoBase::m_state == GLGizmoBase::On) {
|
||||
// when open by hyperlink it needs to show up
|
||||
request_rerender();
|
||||
}
|
||||
}
|
||||
|
||||
void GLGizmoSimplify::create_gui_cfg() {
|
||||
if (m_gui_cfg.has_value()) return;
|
||||
int space_size = m_imgui->calc_text_size(":MM").x;
|
||||
GuiCfg cfg;
|
||||
cfg.top_left_width = std::max(m_imgui->calc_text_size(tr_mesh_name).x,
|
||||
m_imgui->calc_text_size(tr_triangles).x)
|
||||
+ space_size;
|
||||
|
||||
const float radio_size = ImGui::GetFrameHeight();
|
||||
cfg.bottom_left_width =
|
||||
std::max(m_imgui->calc_text_size(tr_detail_level).x,
|
||||
m_imgui->calc_text_size(tr_decimate_ratio).x) +
|
||||
space_size + radio_size;
|
||||
|
||||
cfg.input_width = cfg.bottom_left_width * 1.5;
|
||||
cfg.window_offset_x = (cfg.bottom_left_width + cfg.input_width)/2;
|
||||
cfg.window_offset_y = ImGui::GetTextLineHeightWithSpacing() * 5;
|
||||
m_gui_cfg = cfg;
|
||||
}
|
||||
|
||||
void GLGizmoSimplify::request_rerender() {
|
||||
wxGetApp().plater()->CallAfter([this]() {
|
||||
set_dirty();
|
||||
m_parent.schedule_extra_frame(0);
|
||||
});
|
||||
}
|
||||
|
||||
} // namespace Slic3r::GUI
|
||||
106
src/slic3r/GUI/Gizmos/GLGizmoSimplify.hpp
Normal file
106
src/slic3r/GUI/Gizmos/GLGizmoSimplify.hpp
Normal file
|
|
@ -0,0 +1,106 @@
|
|||
#ifndef slic3r_GLGizmoSimplify_hpp_
|
||||
#define slic3r_GLGizmoSimplify_hpp_
|
||||
|
||||
// Include GLGizmoBase.hpp before I18N.hpp as it includes some libigl code,
|
||||
// which overrides our localization "L" macro.
|
||||
#include "GLGizmoBase.hpp"
|
||||
#include "admesh/stl.h" // indexed_triangle_set
|
||||
#include <thread>
|
||||
#include <optional>
|
||||
#include <atomic>
|
||||
|
||||
namespace Slic3r {
|
||||
|
||||
class ModelVolume;
|
||||
|
||||
namespace GUI {
|
||||
|
||||
|
||||
class GLGizmoSimplify : public GLGizmoBase
|
||||
{
|
||||
public:
|
||||
GLGizmoSimplify(GLCanvas3D& parent, const std::string& icon_filename, unsigned int sprite_id);
|
||||
virtual ~GLGizmoSimplify();
|
||||
protected:
|
||||
virtual bool on_init() override;
|
||||
virtual std::string on_get_name() const override;
|
||||
virtual void on_render() override;
|
||||
virtual void on_render_for_picking() override;
|
||||
virtual void on_render_input_window(float x, float y, float bottom_limit) override;
|
||||
virtual bool on_is_activable() const override;
|
||||
virtual bool on_is_selectable() const override { return false; }
|
||||
virtual void on_set_state() override;
|
||||
|
||||
private:
|
||||
void close();
|
||||
void process();
|
||||
void set_its(indexed_triangle_set &its);
|
||||
void create_gui_cfg();
|
||||
void request_rerender();
|
||||
|
||||
std::atomic_bool m_is_valid_result; // differ what to do in apply
|
||||
std::atomic_bool m_exist_preview; // set when process end
|
||||
|
||||
volatile int m_progress; // percent of done work
|
||||
ModelVolume *m_volume; //
|
||||
size_t m_obj_index;
|
||||
|
||||
std::optional<indexed_triangle_set> m_original_its;
|
||||
|
||||
volatile bool m_need_reload; // after simplify, glReload must be on main thread
|
||||
std::thread m_worker;
|
||||
|
||||
enum class State {
|
||||
settings,
|
||||
preview, // simplify to show preview
|
||||
close_on_end, // simplify with close on end
|
||||
canceling // after button click, before canceled
|
||||
};
|
||||
volatile State m_state;
|
||||
|
||||
struct Configuration
|
||||
{
|
||||
bool use_count = false;
|
||||
// minimal triangle count
|
||||
float decimate_ratio = 50.f; // in percent
|
||||
uint32_t wanted_count = 0; // initialize by percents
|
||||
|
||||
// maximal quadric error
|
||||
float max_error = 1.;
|
||||
|
||||
void fix_count_by_ratio(size_t triangle_count)
|
||||
{
|
||||
wanted_count = static_cast<uint32_t>(
|
||||
std::round(triangle_count * (100.f-decimate_ratio) / 100.f));
|
||||
}
|
||||
} m_configuration;
|
||||
|
||||
// This configs holds GUI layout size given by translated texts.
|
||||
// etc. When language changes, GUI is recreated and this class constructed again,
|
||||
// so the change takes effect. (info by GLGizmoFdmSupports.hpp)
|
||||
struct GuiCfg
|
||||
{
|
||||
int top_left_width = 100;
|
||||
int bottom_left_width = 100;
|
||||
int input_width = 100;
|
||||
int window_offset_x = 100;
|
||||
int window_offset_y = 100;
|
||||
int window_padding = 0;
|
||||
|
||||
// trunc model name when longer
|
||||
size_t max_char_in_name = 30;
|
||||
};
|
||||
std::optional<GuiCfg> m_gui_cfg;
|
||||
|
||||
// translations used for calc window size
|
||||
const std::string tr_mesh_name;
|
||||
const std::string tr_triangles;
|
||||
const std::string tr_preview;
|
||||
const std::string tr_detail_level;
|
||||
const std::string tr_decimate_ratio;
|
||||
};
|
||||
|
||||
} // namespace GUI
|
||||
} // namespace Slic3r
|
||||
|
||||
#endif // slic3r_GLGizmoSimplify_hpp_
|
||||
|
|
@ -447,7 +447,8 @@ bool GLGizmoSlaSupports::gizmo_event(SLAGizmoEventType action, const Vec2d& mous
|
|||
}
|
||||
|
||||
if (action == SLAGizmoEventType::DiscardChanges) {
|
||||
editing_mode_discard_changes();
|
||||
ask_about_changes_call_after([this](){ editing_mode_apply_changes(); },
|
||||
[this](){ editing_mode_discard_changes(); });
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
@ -879,6 +880,22 @@ CommonGizmosDataID GLGizmoSlaSupports::on_get_requirements() const
|
|||
|
||||
|
||||
|
||||
void GLGizmoSlaSupports::ask_about_changes_call_after(std::function<void()> on_yes, std::function<void()> on_no)
|
||||
{
|
||||
wxGetApp().CallAfter([this, on_yes, on_no]() {
|
||||
// Following is called through CallAfter, because otherwise there was a problem
|
||||
// on OSX with the wxMessageDialog being shown several times when clicked into.
|
||||
MessageDialog dlg(GUI::wxGetApp().mainframe, _L("Do you want to save your manually "
|
||||
"edited support points?") + "\n",_L("Save support points?"), wxICON_QUESTION | wxYES | wxNO | wxCANCEL );
|
||||
int ret = dlg.ShowModal();
|
||||
if (ret == wxID_YES)
|
||||
on_yes();
|
||||
else if (ret == wxID_NO)
|
||||
on_no();
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
void GLGizmoSlaSupports::on_set_state()
|
||||
{
|
||||
if (m_state == m_old_state)
|
||||
|
|
@ -901,17 +918,8 @@ void GLGizmoSlaSupports::on_set_state()
|
|||
if (m_state == Off && m_old_state != Off) { // the gizmo was just turned Off
|
||||
bool will_ask = m_editing_mode && unsaved_changes() && on_is_activable();
|
||||
if (will_ask) {
|
||||
wxGetApp().CallAfter([this]() {
|
||||
// Following is called through CallAfter, because otherwise there was a problem
|
||||
// on OSX with the wxMessageDialog being shown several times when clicked into.
|
||||
//wxMessageDialog dlg(GUI::wxGetApp().mainframe, _L("Do you want to save your manually "
|
||||
MessageDialog dlg(GUI::wxGetApp().mainframe, _L("Do you want to save your manually "
|
||||
"edited support points?") + "\n",_L("Save changes?"), wxICON_QUESTION | wxYES | wxNO);
|
||||
if (dlg.ShowModal() == wxID_YES)
|
||||
editing_mode_apply_changes();
|
||||
else
|
||||
editing_mode_discard_changes();
|
||||
});
|
||||
ask_about_changes_call_after([this](){ editing_mode_apply_changes(); },
|
||||
[this](){ editing_mode_discard_changes(); });
|
||||
// refuse to be turned off so the gizmo is active when the CallAfter is executed
|
||||
m_state = m_old_state;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -117,6 +117,7 @@ private:
|
|||
void auto_generate();
|
||||
void switch_to_editing_mode();
|
||||
void disable_editing_mode();
|
||||
void ask_about_changes_call_after(std::function<void()> on_yes, std::function<void()> on_no);
|
||||
|
||||
protected:
|
||||
void on_set_state() override;
|
||||
|
|
|
|||
|
|
@ -150,6 +150,30 @@ void InstancesHider::on_update()
|
|||
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->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(), 0.));
|
||||
canvas->set_clipping_plane(1, ClippingPlane(-Vec3d::UnitZ(), std::numeric_limits<double>::max()));
|
||||
|
||||
|
||||
std::vector<const TriangleMesh*> meshes;
|
||||
for (const ModelVolume* mv : mo->volumes)
|
||||
meshes.push_back(&mv->mesh());
|
||||
|
||||
if (meshes != m_old_meshes) {
|
||||
m_clippers.clear();
|
||||
for (const TriangleMesh* mesh : meshes) {
|
||||
m_clippers.emplace_back(new MeshClipper);
|
||||
if (mo->get_instance_min_z(active_inst) < SINKING_Z_THRESHOLD)
|
||||
m_clippers.back()->set_plane(ClippingPlane(-Vec3d::UnitZ(), 0.));
|
||||
else {
|
||||
m_clippers.back()->set_plane(ClippingPlane::ClipsNothing());
|
||||
m_clippers.back()->set_limiting_plane(ClippingPlane::ClipsNothing());
|
||||
}
|
||||
m_clippers.back()->set_mesh(*mesh);
|
||||
}
|
||||
m_old_meshes = meshes;
|
||||
}
|
||||
}
|
||||
else
|
||||
canvas->toggle_model_objects_visibility(true);
|
||||
|
|
@ -158,6 +182,9 @@ void InstancesHider::on_update()
|
|||
void InstancesHider::on_release()
|
||||
{
|
||||
get_pool()->get_canvas()->toggle_model_objects_visibility(true);
|
||||
get_pool()->get_canvas()->set_use_clipping_planes(false);
|
||||
m_old_meshes.clear();
|
||||
m_clippers.clear();
|
||||
}
|
||||
|
||||
void InstancesHider::show_supports(bool show) {
|
||||
|
|
@ -167,6 +194,38 @@ void InstancesHider::show_supports(bool show) {
|
|||
}
|
||||
}
|
||||
|
||||
void InstancesHider::render_cut() const
|
||||
{
|
||||
const SelectionInfo* sel_info = get_pool()->selection_info();
|
||||
const ModelObject* mo = sel_info->model_object();
|
||||
Geometry::Transformation inst_trafo = mo->instances[sel_info->get_active_instance()]->get_transformation();
|
||||
|
||||
size_t clipper_id = 0;
|
||||
for (const ModelVolume* mv : mo->volumes) {
|
||||
Geometry::Transformation vol_trafo = mv->get_transformation();
|
||||
Geometry::Transformation trafo = inst_trafo * vol_trafo;
|
||||
trafo.set_offset(trafo.get_offset() + Vec3d(0., 0., sel_info->get_sla_shift()));
|
||||
|
||||
auto& clipper = m_clippers[clipper_id];
|
||||
clipper->set_transformation(trafo);
|
||||
const ObjectClipper* obj_clipper = get_pool()->object_clipper();
|
||||
if (obj_clipper->is_valid() && obj_clipper->get_clipping_plane()
|
||||
&& obj_clipper->get_position() != 0.) {
|
||||
ClippingPlane clp = *get_pool()->object_clipper()->get_clipping_plane();
|
||||
clp.set_normal(-clp.get_normal());
|
||||
clipper->set_limiting_plane(clp);
|
||||
} else
|
||||
clipper->set_limiting_plane(ClippingPlane::ClipsNothing());
|
||||
|
||||
glsafe(::glPushMatrix());
|
||||
glsafe(::glColor3f(0.8f, 0.3f, 0.0f));
|
||||
clipper->render_cut();
|
||||
glsafe(::glPopMatrix());
|
||||
|
||||
++clipper_id;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
void HollowedMesh::on_update()
|
||||
|
|
@ -348,6 +407,7 @@ void ObjectClipper::render_cut() const
|
|||
const SelectionInfo* sel_info = get_pool()->selection_info();
|
||||
const ModelObject* mo = sel_info->model_object();
|
||||
Geometry::Transformation inst_trafo = mo->instances[sel_info->get_active_instance()]->get_transformation();
|
||||
const bool sinking = mo->bounding_box().min.z() < SINKING_Z_THRESHOLD;
|
||||
|
||||
size_t clipper_id = 0;
|
||||
for (const ModelVolume* mv : mo->volumes) {
|
||||
|
|
@ -358,7 +418,9 @@ void ObjectClipper::render_cut() const
|
|||
auto& clipper = m_clippers[clipper_id];
|
||||
clipper->set_plane(*m_clp);
|
||||
clipper->set_transformation(trafo);
|
||||
|
||||
clipper->set_limiting_plane(sinking ?
|
||||
ClippingPlane(Vec3d::UnitZ(), 0.)
|
||||
: ClippingPlane::ClipsNothing());
|
||||
glsafe(::glPushMatrix());
|
||||
glsafe(::glColor3f(1.0f, 0.37f, 0.0f));
|
||||
clipper->render_cut();
|
||||
|
|
|
|||
|
|
@ -180,6 +180,7 @@ public:
|
|||
|
||||
void show_supports(bool show);
|
||||
bool are_supports_shown() const { return m_show_supports; }
|
||||
void render_cut() const;
|
||||
|
||||
protected:
|
||||
void on_update() override;
|
||||
|
|
@ -187,6 +188,8 @@ protected:
|
|||
|
||||
private:
|
||||
bool m_show_supports = false;
|
||||
std::vector<const TriangleMesh*> m_old_meshes;
|
||||
std::vector<std::unique_ptr<MeshClipper>> m_clippers;
|
||||
};
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -20,6 +20,7 @@
|
|||
#include "slic3r/GUI/Gizmos/GLGizmoHollow.hpp"
|
||||
#include "slic3r/GUI/Gizmos/GLGizmoSeam.hpp"
|
||||
#include "slic3r/GUI/Gizmos/GLGizmoMmuSegmentation.hpp"
|
||||
#include "slic3r/GUI/Gizmos/GLGizmoSimplify.hpp"
|
||||
|
||||
#include "libslic3r/Model.hpp"
|
||||
#include "libslic3r/PresetBundle.hpp"
|
||||
|
|
@ -50,14 +51,7 @@ std::vector<size_t> GLGizmosManager::get_selectable_idxs() const
|
|||
return out;
|
||||
}
|
||||
|
||||
std::vector<size_t> GLGizmosManager::get_activable_idxs() const
|
||||
{
|
||||
std::vector<size_t> out;
|
||||
for (size_t i=0; i<m_gizmos.size(); ++i)
|
||||
if (m_gizmos[i]->is_activable())
|
||||
out.push_back(i);
|
||||
return out;
|
||||
}
|
||||
|
||||
|
||||
size_t GLGizmosManager::get_gizmo_idx_from_mouse(const Vec2d& mouse_pos) const
|
||||
{
|
||||
|
|
@ -109,7 +103,8 @@ bool GLGizmosManager::init()
|
|||
m_gizmos.emplace_back(new GLGizmoSlaSupports(m_parent, "sla_supports.svg", 6));
|
||||
m_gizmos.emplace_back(new GLGizmoFdmSupports(m_parent, "fdm_supports.svg", 7));
|
||||
m_gizmos.emplace_back(new GLGizmoSeam(m_parent, "seam.svg", 8));
|
||||
m_gizmos.emplace_back(new GLGizmoMmuSegmentation(m_parent, "fdm_supports.svg", 9));
|
||||
m_gizmos.emplace_back(new GLGizmoMmuSegmentation(m_parent, "mmu_segmentation.svg", 9));
|
||||
m_gizmos.emplace_back(new GLGizmoSimplify(m_parent, "cut.svg", 10));
|
||||
|
||||
m_common_gizmos_data.reset(new CommonGizmosDataPool(&m_parent));
|
||||
|
||||
|
|
@ -137,8 +132,7 @@ bool GLGizmosManager::init_arrow(const BackgroundTexture::Metadata& arrow_textur
|
|||
bool res = false;
|
||||
|
||||
if (!arrow_texture.filename.empty())
|
||||
res = m_arrow_texture.texture.load_from_file(path + arrow_texture.filename, false, GLTexture::SingleThreaded, false);
|
||||
// res = m_arrow_texture.texture.load_from_svg_file(path + arrow_texture.filename, false, true, false, 100);
|
||||
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;
|
||||
|
||||
|
|
@ -169,7 +163,7 @@ void GLGizmosManager::refresh_on_off_state()
|
|||
return;
|
||||
|
||||
if (m_current != Undefined
|
||||
&& (! m_gizmos[m_current]->is_activable() || ! m_gizmos[m_current]->is_selectable())) {
|
||||
&& ! m_gizmos[m_current]->is_activable()) {
|
||||
activate_gizmo(Undefined);
|
||||
update_data();
|
||||
}
|
||||
|
|
@ -187,7 +181,7 @@ void GLGizmosManager::reset_all_states()
|
|||
bool GLGizmosManager::open_gizmo(EType type)
|
||||
{
|
||||
int idx = int(type);
|
||||
if (m_gizmos[idx]->is_selectable() && m_gizmos[idx]->is_activable()) {
|
||||
if (m_gizmos[idx]->is_activable()) {
|
||||
activate_gizmo(m_current == idx ? Undefined : (EType)idx);
|
||||
update_data();
|
||||
return true;
|
||||
|
|
@ -304,7 +298,7 @@ bool GLGizmosManager::handle_shortcut(int key)
|
|||
auto it = std::find_if(m_gizmos.begin(), m_gizmos.end(),
|
||||
[key](const std::unique_ptr<GLGizmoBase>& gizmo) {
|
||||
int gizmo_key = gizmo->get_shortcut_key();
|
||||
return gizmo->is_selectable()
|
||||
return gizmo->is_activable()
|
||||
&& ((gizmo_key == key - 64) || (gizmo_key == key - 96));
|
||||
});
|
||||
|
||||
|
|
@ -1024,7 +1018,7 @@ void GLGizmosManager::render_arrow(const GLCanvas3D& parent, EType highlighted_t
|
|||
|
||||
float arrow_sides_ratio = (float)m_arrow_texture.texture.get_height() / (float)m_arrow_texture.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 * arrow_sides_ratio, zoomed_top_y - zoomed_icons_size, zoomed_top_y, { { internal_left_uv, internal_top_uv }, { internal_left_uv, internal_bottom_uv }, { internal_right_uv, internal_bottom_uv }, { internal_right_uv, internal_top_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, { { internal_left_uv, internal_bottom_uv }, { internal_left_uv, internal_top_uv }, { internal_right_uv, internal_top_uv }, { internal_right_uv, internal_bottom_uv } });
|
||||
break;
|
||||
}
|
||||
zoomed_top_y -= zoomed_stride_y;
|
||||
|
|
@ -1077,6 +1071,7 @@ void GLGizmosManager::do_render_overlay() const
|
|||
float u_offset = 1.0f / (float)tex_width;
|
||||
float v_offset = 1.0f / (float)tex_height;
|
||||
|
||||
float current_y = FLT_MAX;
|
||||
for (size_t idx : selectable_idxs)
|
||||
{
|
||||
GLGizmoBase* gizmo = m_gizmos[idx].get();
|
||||
|
|
@ -1090,12 +1085,18 @@ void GLGizmosManager::do_render_overlay() const
|
|||
float u_right = u_left + du - u_offset;
|
||||
|
||||
GLTexture::render_sub_texture(icons_texture_id, zoomed_top_x, zoomed_top_x + zoomed_icons_size, zoomed_top_y - zoomed_icons_size, zoomed_top_y, { { u_left, v_bottom }, { u_right, v_bottom }, { u_right, v_top }, { u_left, v_top } });
|
||||
if (idx == m_current) {
|
||||
float toolbar_top = cnv_h - wxGetApp().plater()->get_view_toolbar().get_height();
|
||||
gizmo->render_input_window(width, 0.5f * cnv_h - zoomed_top_y * zoom, toolbar_top);
|
||||
if (idx == m_current || current_y == FLT_MAX) {
|
||||
// The FLT_MAX trick is here so that even non-selectable but activable
|
||||
// gizmos are passed some meaningful value.
|
||||
current_y = 0.5f * cnv_h - zoomed_top_y * zoom;
|
||||
}
|
||||
zoomed_top_y -= zoomed_stride_y;
|
||||
}
|
||||
|
||||
if (m_current != Undefined) {
|
||||
float toolbar_top = cnv_h - wxGetApp().plater()->get_view_toolbar().get_height();
|
||||
m_gizmos[m_current]->render_input_window(width, current_y, toolbar_top);
|
||||
}
|
||||
}
|
||||
|
||||
float GLGizmosManager::get_scaled_total_height() const
|
||||
|
|
@ -1246,6 +1247,14 @@ bool GLGizmosManager::is_in_editing_mode(bool error_notification) const
|
|||
}
|
||||
|
||||
|
||||
bool GLGizmosManager::is_hiding_instances() const
|
||||
{
|
||||
return (m_common_gizmos_data
|
||||
&& m_common_gizmos_data->instances_hider()
|
||||
&& m_common_gizmos_data->instances_hider()->is_valid());
|
||||
}
|
||||
|
||||
|
||||
int GLGizmosManager::get_shortcut_key(GLGizmosManager::EType type) const
|
||||
{
|
||||
return m_gizmos[type]->get_shortcut_key();
|
||||
|
|
|
|||
|
|
@ -69,6 +69,7 @@ public:
|
|||
FdmSupports,
|
||||
Seam,
|
||||
MmuSegmentation,
|
||||
Simplify,
|
||||
Undefined
|
||||
};
|
||||
|
||||
|
|
@ -101,7 +102,6 @@ private:
|
|||
std::pair<EType, bool> m_highlight; // bool true = higlightedShown, false = highlightedHidden
|
||||
|
||||
std::vector<size_t> get_selectable_idxs() const;
|
||||
std::vector<size_t> get_activable_idxs() const;
|
||||
size_t get_gizmo_idx_from_mouse(const Vec2d& mouse_pos) const;
|
||||
|
||||
void activate_gizmo(EType type);
|
||||
|
|
@ -122,7 +122,6 @@ private:
|
|||
MouseCapture m_mouse_capture;
|
||||
std::string m_tooltip;
|
||||
bool m_serializing;
|
||||
//std::unique_ptr<CommonGizmosData> m_common_gizmos_data;
|
||||
std::unique_ptr<CommonGizmosDataPool> m_common_gizmos_data;
|
||||
|
||||
public:
|
||||
|
|
@ -218,6 +217,7 @@ public:
|
|||
bool wants_reslice_supports_on_undo() const;
|
||||
|
||||
bool is_in_editing_mode(bool error_notification = false) const;
|
||||
bool is_hiding_instances() const;
|
||||
|
||||
void render_current_gizmo() const;
|
||||
void render_current_gizmo_for_picking_pass() const;
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue