diff --git a/resources/shaders/gouraud.fs b/resources/shaders/gouraud.fs index ed03bfe64..dbbebf7d6 100644 --- a/resources/shaders/gouraud.fs +++ b/resources/shaders/gouraud.fs @@ -1,5 +1,19 @@ #version 110 +#define INTENSITY_CORRECTION 0.6 + +// normalized values for (-0.6/1.31, 0.6/1.31, 1./1.31) +const vec3 LIGHT_TOP_DIR = vec3(-0.4574957, 0.4574957, 0.7624929); +#define LIGHT_TOP_DIFFUSE (0.8 * INTENSITY_CORRECTION) +#define LIGHT_TOP_SPECULAR (0.125 * INTENSITY_CORRECTION) +#define LIGHT_TOP_SHININESS 20.0 + +// normalized values for (1./1.43, 0.2/1.43, 1./1.43) +const vec3 LIGHT_FRONT_DIR = vec3(0.6985074, 0.1397015, 0.6985074); +#define LIGHT_FRONT_DIFFUSE (0.3 * INTENSITY_CORRECTION) + +#define INTENSITY_AMBIENT 0.3 + const vec3 ZERO = vec3(0.0, 0.0, 0.0); const vec3 GREEN = vec3(0.0, 0.7, 0.0); const vec3 YELLOW = vec3(0.5, 0.7, 0.0); @@ -42,14 +56,42 @@ vec3 sinking_color(vec3 color) return (mod(model_pos.x + model_pos.y + model_pos.z, BANDS_WIDTH) < (0.5 * BANDS_WIDTH)) ? mix(color, ZERO, 0.6666) : color; } +uniform bool compute_triangle_normals_in_fs; + void main() { if (any(lessThan(clipping_planes_dots, ZERO))) discard; - vec3 color = uniform_color.rgb; + vec3 color = uniform_color.rgb; float alpha = uniform_color.a; - if (slope.actived && world_normal_z < slope.normal_z - EPSILON) - { + + vec2 intensity_fs = intensity; + vec3 eye_normal_fs = eye_normal; + float world_normal_z_fs = world_normal_z; + if (compute_triangle_normals_in_fs) { + vec3 triangle_normal = normalize(cross(dFdx(model_pos.xyz), dFdy(model_pos.xyz))); + + // First transform the normal into camera space and normalize the result. + eye_normal_fs = normalize(gl_NormalMatrix * triangle_normal); + + // Compute the cos of the angle between the normal and lights direction. The light is directional so the direction is constant for every vertex. + // Since these two are normalized the cosine is the dot product. We also need to clamp the result to the [0,1] range. + float NdotL = max(dot(eye_normal_fs, LIGHT_TOP_DIR), 0.0); + + intensity_fs = vec2(0.0, 0.0); + intensity_fs.x = INTENSITY_AMBIENT + NdotL * LIGHT_TOP_DIFFUSE; + vec3 position = (gl_ModelViewMatrix * model_pos).xyz; + intensity_fs.y = LIGHT_TOP_SPECULAR * pow(max(dot(-normalize(position), reflect(-LIGHT_TOP_DIR, eye_normal_fs)), 0.0), LIGHT_TOP_SHININESS); + + // Perform the same lighting calculation for the 2nd light source (no specular applied). + NdotL = max(dot(eye_normal_fs, LIGHT_FRONT_DIR), 0.0); + intensity_fs.x += NdotL * LIGHT_FRONT_DIFFUSE; + + // z component of normal vector in world coordinate used for slope shading + world_normal_z_fs = slope.actived ? (normalize(slope.volume_world_normal_matrix * triangle_normal)).z : 0.0; + } + + if (slope.actived && world_normal_z_fs < slope.normal_z - EPSILON) { color = vec3(0.7, 0.7, 1.0); alpha = 1.0; } @@ -60,8 +102,8 @@ void main() color = (abs(world_pos_z) < 0.05) ? WHITE : sinking_color(color); #ifdef ENABLE_ENVIRONMENT_MAP if (use_environment_tex) - gl_FragColor = vec4(0.45 * texture2D(environment_tex, normalize(eye_normal).xy * 0.5 + 0.5).xyz + 0.8 * color * intensity.x, alpha); + gl_FragColor = vec4(0.45 * texture2D(environment_tex, normalize(eye_normal_fs).xy * 0.5 + 0.5).xyz + 0.8 * color * intensity_fs.x, alpha); else #endif - gl_FragColor = vec4(vec3(intensity.y) + color * intensity.x, alpha); + gl_FragColor = vec4(vec3(intensity_fs.y) + color * intensity_fs.x, alpha); } diff --git a/resources/shaders/gouraud.vs b/resources/shaders/gouraud.vs index f2706b386..20a142452 100644 --- a/resources/shaders/gouraud.vs +++ b/resources/shaders/gouraud.vs @@ -54,22 +54,26 @@ varying float world_pos_z; varying float world_normal_z; varying vec3 eye_normal; +uniform bool compute_triangle_normals_in_fs; + void main() { - // First transform the normal into camera space and normalize the result. - eye_normal = normalize(gl_NormalMatrix * gl_Normal); - - // Compute the cos of the angle between the normal and lights direction. The light is directional so the direction is constant for every vertex. - // Since these two are normalized the cosine is the dot product. We also need to clamp the result to the [0,1] range. - float NdotL = max(dot(eye_normal, LIGHT_TOP_DIR), 0.0); + if (!compute_triangle_normals_in_fs) { + // First transform the normal into camera space and normalize the result. + eye_normal = normalize(gl_NormalMatrix * gl_Normal); - intensity.x = INTENSITY_AMBIENT + NdotL * LIGHT_TOP_DIFFUSE; - vec3 position = (gl_ModelViewMatrix * gl_Vertex).xyz; - intensity.y = LIGHT_TOP_SPECULAR * pow(max(dot(-normalize(position), reflect(-LIGHT_TOP_DIR, eye_normal)), 0.0), LIGHT_TOP_SHININESS); + // Compute the cos of the angle between the normal and lights direction. The light is directional so the direction is constant for every vertex. + // Since these two are normalized the cosine is the dot product. We also need to clamp the result to the [0,1] range. + float NdotL = max(dot(eye_normal, LIGHT_TOP_DIR), 0.0); - // Perform the same lighting calculation for the 2nd light source (no specular applied). - NdotL = max(dot(eye_normal, LIGHT_FRONT_DIR), 0.0); - intensity.x += NdotL * LIGHT_FRONT_DIFFUSE; + intensity.x = INTENSITY_AMBIENT + NdotL * LIGHT_TOP_DIFFUSE; + vec3 position = (gl_ModelViewMatrix * gl_Vertex).xyz; + intensity.y = LIGHT_TOP_SPECULAR * pow(max(dot(-normalize(position), reflect(-LIGHT_TOP_DIR, eye_normal)), 0.0), LIGHT_TOP_SHININESS); + + // Perform the same lighting calculation for the 2nd light source (no specular applied). + NdotL = max(dot(eye_normal, LIGHT_FRONT_DIR), 0.0); + intensity.x += NdotL * LIGHT_FRONT_DIFFUSE; + } model_pos = gl_Vertex; // Point in homogenous coordinates. @@ -77,19 +81,17 @@ void main() world_pos_z = world_pos.z; // compute deltas for out of print volume detection (world coordinates) - if (print_box.actived) - { + if (print_box.actived) { delta_box_min = world_pos.xyz - print_box.min; delta_box_max = world_pos.xyz - print_box.max; - } - else - { + } else { delta_box_min = ZERO; delta_box_max = ZERO; } // z component of normal vector in world coordinate used for slope shading - world_normal_z = slope.actived ? (normalize(slope.volume_world_normal_matrix * gl_Normal)).z : 0.0; + if (!compute_triangle_normals_in_fs) + world_normal_z = slope.actived ? (normalize(slope.volume_world_normal_matrix * gl_Normal)).z : 0.0; gl_Position = ftransform(); // Fill in the scalars for fragment shader clipping. Fragments with any of these components lower than zero are discarded. diff --git a/src/slic3r/GUI/Gizmos/GLGizmoFdmSupports.cpp b/src/slic3r/GUI/Gizmos/GLGizmoFdmSupports.cpp index 5fa4ab51d..4048155fe 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoFdmSupports.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoFdmSupports.cpp @@ -170,6 +170,7 @@ void GLGizmoFdmSupports::on_render_input_window(float x, float y, float bottom_l if (mv->is_model_part()) { ++idx; m_triangle_selectors[idx]->reset(); + m_triangle_selectors[idx]->request_update_render_data(); } } @@ -285,13 +286,12 @@ void GLGizmoFdmSupports::select_facets_by_angle(float threshold_deg, bool block) // Now calculate dot product of vert_direction and facets' normals. int idx = -1; - for (const stl_facet& facet : mv->mesh().stl.facet_start) { + for (const stl_facet &facet : mv->mesh().stl.facet_start) { ++idx; - if (facet.normal.dot(down) > dot_limit) - m_triangle_selectors[mesh_id]->set_facet(idx, - block - ? EnforcerBlockerType::BLOCKER - : EnforcerBlockerType::ENFORCER); + if (facet.normal.dot(down) > dot_limit) { + m_triangle_selectors[mesh_id]->set_facet(idx, block ? EnforcerBlockerType::BLOCKER : EnforcerBlockerType::ENFORCER); + m_triangle_selectors.back()->request_update_render_data(); + } } } @@ -346,6 +346,7 @@ void GLGizmoFdmSupports::update_from_model_object() m_triangle_selectors.emplace_back(std::make_unique(*mesh)); m_triangle_selectors.back()->deserialize(mv->supported_facets.get_data()); + m_triangle_selectors.back()->request_update_render_data(); } } diff --git a/src/slic3r/GUI/Gizmos/GLGizmoMmuSegmentation.cpp b/src/slic3r/GUI/Gizmos/GLGizmoMmuSegmentation.cpp index 02fd81af8..345985222 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoMmuSegmentation.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoMmuSegmentation.cpp @@ -296,8 +296,10 @@ void GLGizmoMmuSegmentation::on_render_input_window(float x, float y, float bott if (m_imgui->checkbox(_L("Seed fill"), m_seed_fill_enabled)) if (!m_seed_fill_enabled) - for (auto &triangle_selector : m_triangle_selectors) + for (auto &triangle_selector : m_triangle_selectors) { triangle_selector->seed_fill_unselect_all_triangles(); + triangle_selector->request_update_render_data(); + } m_imgui->text(m_desc["seed_fill_angle"] + ":"); ImGui::AlignTextToFramePadding(); @@ -319,6 +321,7 @@ void GLGizmoMmuSegmentation::on_render_input_window(float x, float y, float bott if (mv->is_model_part()) { ++idx; m_triangle_selectors[idx]->reset(); + m_triangle_selectors[idx]->request_update_render_data(); } } @@ -437,8 +440,9 @@ void GLGizmoMmuSegmentation::init_model_triangle_selectors() const TriangleMesh *mesh = &mv->mesh(); int extruder_idx = (mv->extruder_id() > 0) ? mv->extruder_id() - 1 : 0; - m_triangle_selectors.emplace_back(std::make_unique(*mesh, m_modified_extruders_colors, m_original_extruders_colors[size_t(extruder_idx)])); + m_triangle_selectors.emplace_back(std::make_unique(*mesh, m_modified_extruders_colors, m_original_extruders_colors[size_t(extruder_idx)])); m_triangle_selectors.back()->deserialize(mv->mmu_segmentation_facets.get_data()); + m_triangle_selectors.back()->request_update_render_data(); } m_original_volumes_extruder_idxs = get_extruder_id_for_volumes(*mo); } @@ -466,54 +470,60 @@ std::array GLGizmoMmuSegmentation::get_cursor_sphere_right_button_colo return {color[0], color[1], color[2], 0.25f}; } -void TriangleSelectorMmuGui::render(ImGuiWrapper *imgui) +void TriangleSelectorMmGui::render(ImGuiWrapper *imgui) { static constexpr std::array seed_fill_color{0.f, 1.f, 0.44f, 1.f}; - for (auto &iva_color : m_iva_colors) - iva_color.release_geometry(); - m_iva_seed_fill.release_geometry(); + if (m_update_render_data) + update_render_data(); - for (const Triangle &tr : m_triangles) - if (tr.valid() && ! tr.is_split()) { - GLIndexedVertexArray *iva = nullptr; - if (tr.is_selected_by_seed_fill()) - iva = &m_iva_seed_fill; - else if (int color = int(tr.get_state()); color < int(m_iva_colors.size())) - iva = &m_iva_colors[color]; - if (iva) { - if (iva->vertices_and_normals_interleaved.size() + 18 > iva->vertices_and_normals_interleaved.capacity()) - iva->vertices_and_normals_interleaved.reserve(next_highest_power_of_2(iva->vertices_and_normals_interleaved.size() + 18)); - const Vec3f &n = m_mesh->stl.facet_start[tr.source_triangle].normal; - for (int i = 0; i < 3; ++ i) { - const Vec3f &v = m_vertices[tr.verts_idxs[i]].v; - iva->vertices_and_normals_interleaved.emplace_back(n.x()); - iva->vertices_and_normals_interleaved.emplace_back(n.y()); - iva->vertices_and_normals_interleaved.emplace_back(n.z()); - iva->vertices_and_normals_interleaved.emplace_back(v.x()); - iva->vertices_and_normals_interleaved.emplace_back(v.y()); - iva->vertices_and_normals_interleaved.emplace_back(v.z()); - } - } - } - - auto* shader = wxGetApp().get_current_shader(); + auto *shader = wxGetApp().get_current_shader(); if (!shader) return; assert(shader->get_name() == "gouraud"); + ScopeGuard guard([shader]() { if (shader) shader->set_uniform("compute_triangle_normals_in_fs", false);}); + shader->set_uniform("compute_triangle_normals_in_fs", true); - for (size_t i = 0; i <= m_iva_colors.size(); ++i) - if (GLIndexedVertexArray &iva = i == m_iva_colors.size() ? m_iva_seed_fill : m_iva_colors[i]; - ! iva.vertices_and_normals_interleaved.empty()) { - iva.vertices_and_normals_interleaved_size = iva.vertices_and_normals_interleaved.size(); - iva.triangle_indices.assign(iva.vertices_and_normals_interleaved_size / 6, 0); - std::iota(iva.triangle_indices.begin(), iva.triangle_indices.end(), 0); - iva.triangle_indices_size = iva.triangle_indices.size(); - iva.finalize_geometry(true); - shader->set_uniform("uniform_color", - (i == 0) ? m_default_volume_color : i == m_iva_colors.size() ? seed_fill_color : m_colors[i - 1]); - iva.render(); + 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]); + m_gizmo_scene.render(color_idx); } + + m_update_render_data = false; +} + +void TriangleSelectorMmGui::update_render_data() +{ + m_gizmo_scene.release_geometry(); + m_vertices.reserve(m_vertices.size() * 3); + for (const Vertex &vr : m_vertices) { + m_gizmo_scene.vertices.emplace_back(vr.v.x()); + m_gizmo_scene.vertices.emplace_back(vr.v.y()); + m_gizmo_scene.vertices.emplace_back(vr.v.z()); + } + m_gizmo_scene.finalize_vertices(); + + for (const Triangle &tr : m_triangles) + if (tr.valid() && !tr.is_split()) { + int color = int(tr.get_state()); + std::vector &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(); + if (iva.size() + 3 > iva.capacity()) + iva.reserve(next_highest_power_of_2(iva.size() + 3)); + + iva.emplace_back(tr.verts_idxs[0]); + iva.emplace_back(tr.verts_idxs[1]); + iva.emplace_back(tr.verts_idxs[2]); + } + + for (size_t color_idx = 0; color_idx < m_gizmo_scene.triangle_indices.size(); ++color_idx) + m_gizmo_scene.triangle_indices_sizes[color_idx] = m_gizmo_scene.triangle_indices[color_idx].size(); + + m_gizmo_scene.finalize_triangle_indices(); } wxString GLGizmoMmuSegmentation::handle_snapshot_action_name(bool shift_down, GLGizmoPainterBase::Button button_down) const @@ -528,4 +538,77 @@ wxString GLGizmoMmuSegmentation::handle_snapshot_action_name(bool shift_down, GL return action_name; } +void GLMmSegmentationGizmo3DScene::release_geometry() { + if (this->vertices_VBO_id) { + glsafe(::glDeleteBuffers(1, &this->vertices_VBO_id)); + this->vertices_VBO_id = 0; + } + for(auto &triangle_indices_VBO_id : triangle_indices_VBO_ids) { + glsafe(::glDeleteBuffers(1, &triangle_indices_VBO_id)); + triangle_indices_VBO_id = 0; + } + this->clear(); +} + +void GLMmSegmentationGizmo3DScene::render(size_t triangle_indices_idx) const +{ + assert(triangle_indices_idx < this->triangle_indices_VBO_ids.size()); + assert(this->triangle_indices_sizes.size() == this->triangle_indices_VBO_ids.size()); + assert(this->vertices_VBO_id != 0); + assert(this->triangle_indices_VBO_ids[triangle_indices_idx] != 0); + + glsafe(::glBindBuffer(GL_ARRAY_BUFFER, this->vertices_VBO_id)); + glsafe(::glVertexPointer(3, GL_FLOAT, 3 * sizeof(float), (const void*)(0 * sizeof(float)))); + + glsafe(::glEnableClientState(GL_VERTEX_ARRAY)); + + // Render using the Vertex Buffer Objects. + if (this->triangle_indices_sizes[triangle_indices_idx] > 0) { + glsafe(::glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, this->triangle_indices_VBO_ids[triangle_indices_idx])); + glsafe(::glDrawElements(GL_TRIANGLES, GLsizei(this->triangle_indices_sizes[triangle_indices_idx]), 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(::glBindBuffer(GL_ARRAY_BUFFER, 0)); + this->vertices.clear(); + } +} + +void GLMmSegmentationGizmo3DScene::finalize_triangle_indices() +{ + assert(triangle_indices_idx < this->triangle_indices.size()); + assert(std::all_of(triangle_indices_VBO_ids.cbegin(), triangle_indices_VBO_ids.cend(), [](const auto &ti_VBO_id) { return ti_VBO_id == 0; })); + + assert(this->triangle_indices.size() == this->triangle_indices_VBO_ids.size()); + for (size_t buffer_idx = 0; buffer_idx < this->triangle_indices.size(); ++buffer_idx) + 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(::glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0)); + this->triangle_indices[buffer_idx].clear(); + } +} + +void GLMmSegmentationGizmo3DScene::finalize_geometry() +{ + assert(this->vertices_VBO_id == 0); + assert(this->triangle_indices.size() == this->triangle_indices_VBO_ids.size()); + finalize_vertices(); + finalize_triangle_indices(); +} + } // namespace Slic3r diff --git a/src/slic3r/GUI/Gizmos/GLGizmoMmuSegmentation.hpp b/src/slic3r/GUI/Gizmos/GLGizmoMmuSegmentation.hpp index 5ece0ec2a..e890ca031 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoMmuSegmentation.hpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoMmuSegmentation.hpp @@ -5,24 +5,80 @@ namespace Slic3r::GUI { -class TriangleSelectorMmuGui : public TriangleSelectorGUI { +class GLMmSegmentationGizmo3DScene +{ public: - explicit TriangleSelectorMmuGui(const TriangleMesh& mesh, const std::vector> &colors, const std::array &default_volume_color) - : TriangleSelectorGUI(mesh), m_colors(colors), m_default_volume_color(default_volume_color) { - // Plus 1 is because the first position is allocated for non-painted triangles. - m_iva_colors = std::vector(colors.size() + 1); + GLMmSegmentationGizmo3DScene() = delete; + + explicit GLMmSegmentationGizmo3DScene(size_t triangle_indices_buffers_count) + { + this->triangle_indices = std::vector>(triangle_indices_buffers_count); + this->triangle_indices_sizes = std::vector(triangle_indices_buffers_count); + this->triangle_indices_VBO_ids = std::vector(triangle_indices_buffers_count); } - ~TriangleSelectorMmuGui() override = default; + + virtual ~GLMmSegmentationGizmo3DScene() { release_geometry(); } + + [[nodiscard]] inline bool has_VBOs(size_t triangle_indices_idx) const + { + assert(triangle_indices_idx < this->triangle_indices.size()); + 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(); + // Release the geometry data, release OpenGL VBOs. + void release_geometry(); + // Finalize the initialization of the geometry, upload the geometry to OpenGL VBO objects + // and possibly releasing it if it has been loaded into the VBOs. + void finalize_vertices(); + // 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(); + + void clear() + { + this->vertices.clear(); + for (std::vector &ti : this->triangle_indices) + ti.clear(); + + for (size_t &triangle_indices_size : this->triangle_indices_sizes) + triangle_indices_size = 0; + } + + void render(size_t triangle_indices_idx) const; + + std::vector vertices; + std::vector> triangle_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 triangle_indices_sizes; + + // 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 triangle_indices_VBO_ids; +}; + +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. + explicit TriangleSelectorMmGui(const TriangleMesh &mesh, const std::vector> &colors, const std::array &default_volume_color) + : TriangleSelectorGUI(mesh), m_colors(colors), m_default_volume_color(default_volume_color), m_gizmo_scene(colors.size() + 2) {} + ~TriangleSelectorMmGui() override = default; // Render current selection. Transformation matrices are supposed // to be already set. void render(ImGuiWrapper* imgui) override; private: + void update_render_data(); + const std::vector> &m_colors; - std::vector m_iva_colors; const std::array m_default_volume_color; - GLIndexedVertexArray m_iva_seed_fill; + GLMmSegmentationGizmo3DScene m_gizmo_scene; }; class GLGizmoMmuSegmentation : public GLGizmoPainterBase diff --git a/src/slic3r/GUI/Gizmos/GLGizmoPainterBase.cpp b/src/slic3r/GUI/Gizmos/GLGizmoPainterBase.cpp index f672471d6..c265942e5 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoPainterBase.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoPainterBase.cpp @@ -402,6 +402,8 @@ bool GLGizmoPainterBase::gizmo_event(SLAGizmoEventType action, const Vec2d& mous } else m_triangle_selectors[m_rr.mesh_id]->select_patch(m_rr.hit, int(m_rr.facet), camera_pos, m_cursor_radius, m_cursor_type, new_state, trafo_matrix, m_triangle_splitting_enabled); + + m_triangle_selectors[m_rr.mesh_id]->request_update_render_data(); m_last_mouse_click = mouse_position; } @@ -428,8 +430,10 @@ bool GLGizmoPainterBase::gizmo_event(SLAGizmoEventType action, const Vec2d& mous update_raycast_cache(mouse_position, camera, trafo_matrices); auto seed_fill_unselect_all = [this]() { - for (auto &triangle_selector : m_triangle_selectors) + for (auto &triangle_selector : m_triangle_selectors) { triangle_selector->seed_fill_unselect_all_triangles(); + triangle_selector->request_update_render_data(); + } }; if (m_rr.mesh_id == -1) { @@ -447,6 +451,7 @@ bool GLGizmoPainterBase::gizmo_event(SLAGizmoEventType action, const Vec2d& mous assert(m_rr.mesh_id < int(m_triangle_selectors.size())); m_triangle_selectors[m_rr.mesh_id]->seed_fill_select_triangles(m_rr.hit, int(m_rr.facet), m_seed_fill_angle); + m_triangle_selectors[m_rr.mesh_id]->request_update_render_data(); m_seed_fill_last_mesh_id = m_rr.mesh_id; return true; } @@ -589,28 +594,11 @@ void TriangleSelectorGUI::render(ImGuiWrapper* imgui) static constexpr std::array enforcers_color{0.47f, 0.47f, 1.f, 1.f}; static constexpr std::array blockers_color{1.f, 0.44f, 0.44f, 1.f}; - int enf_cnt = 0; - int blc_cnt = 0; - - for (auto *iva : {&m_iva_enforcers, &m_iva_blockers}) - iva->release_geometry(); - - for (const Triangle& tr : m_triangles) { - if (!tr.valid() || tr.is_split() || tr.get_state() == EnforcerBlockerType::NONE) - continue; - - GLIndexedVertexArray &iva = tr.get_state() == EnforcerBlockerType::ENFORCER ? m_iva_enforcers : m_iva_blockers; - int & cnt = tr.get_state() == EnforcerBlockerType::ENFORCER ? enf_cnt : blc_cnt; - - for (int i = 0; i < 3; ++i) - iva.push_geometry(m_vertices[tr.verts_idxs[i]].v, m_mesh->stl.facet_start[tr.source_triangle].normal); - iva.push_triangle(cnt, cnt + 1, cnt + 2); - cnt += 3; + if (m_update_render_data) { + update_render_data(); + m_update_render_data = false; } - for (auto *iva : {&m_iva_enforcers, &m_iva_blockers}) - iva->finalize_geometry(true); - auto* shader = wxGetApp().get_current_shader(); if (! shader) return; @@ -635,6 +623,33 @@ void TriangleSelectorGUI::render(ImGuiWrapper* imgui) +void TriangleSelectorGUI::update_render_data() +{ + int enf_cnt = 0; + int blc_cnt = 0; + + for (auto *iva : {&m_iva_enforcers, &m_iva_blockers}) + iva->release_geometry(); + + for (const Triangle &tr : m_triangles) { + if (!tr.valid() || tr.is_split() || tr.get_state() == EnforcerBlockerType::NONE) + continue; + + GLIndexedVertexArray &iva = tr.get_state() == EnforcerBlockerType::ENFORCER ? m_iva_enforcers : m_iva_blockers; + int & cnt = tr.get_state() == EnforcerBlockerType::ENFORCER ? enf_cnt : blc_cnt; + + for (int i = 0; i < 3; ++i) + iva.push_geometry(m_vertices[tr.verts_idxs[i]].v, m_mesh->stl.facet_start[tr.source_triangle].normal); + iva.push_triangle(cnt, cnt + 1, cnt + 2); + cnt += 3; + } + + for (auto *iva : {&m_iva_enforcers, &m_iva_blockers}) + iva->finalize_geometry(true); +} + + + #ifdef PRUSASLICER_TRIANGLE_SELECTOR_DEBUG void TriangleSelectorGUI::render_debug(ImGuiWrapper* imgui) { diff --git a/src/slic3r/GUI/Gizmos/GLGizmoPainterBase.hpp b/src/slic3r/GUI/Gizmos/GLGizmoPainterBase.hpp index b64585e9f..bfda33a20 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoPainterBase.hpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoPainterBase.hpp @@ -38,13 +38,20 @@ public: virtual void render(ImGuiWrapper *imgui); void render() { this->render(nullptr); } + void request_update_render_data() { m_update_render_data = true; }; + #ifdef PRUSASLICER_TRIANGLE_SELECTOR_DEBUG void render_debug(ImGuiWrapper* imgui); bool m_show_triangles{false}; bool m_show_invalid{false}; #endif +protected: + bool m_update_render_data = false; + private: + void update_render_data(); + GLIndexedVertexArray m_iva_enforcers; GLIndexedVertexArray m_iva_blockers; std::array m_varrays; diff --git a/src/slic3r/GUI/Gizmos/GLGizmoSeam.cpp b/src/slic3r/GUI/Gizmos/GLGizmoSeam.cpp index 6b28e8ca7..92b1b6603 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoSeam.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoSeam.cpp @@ -127,6 +127,7 @@ void GLGizmoSeam::on_render_input_window(float x, float y, float bottom_limit) if (mv->is_model_part()) { ++idx; m_triangle_selectors[idx]->reset(); + m_triangle_selectors[idx]->request_update_render_data(); } } @@ -257,6 +258,7 @@ void GLGizmoSeam::update_from_model_object() m_triangle_selectors.emplace_back(std::make_unique(*mesh)); m_triangle_selectors.back()->deserialize(mv->seam_facets.get_data()); + m_triangle_selectors.back()->request_update_render_data(); } }