diff --git a/src/OrcaSlicer.cpp b/src/OrcaSlicer.cpp index 127efa712d..c8ba1cdd31 100644 --- a/src/OrcaSlicer.cpp +++ b/src/OrcaSlicer.cpp @@ -2353,7 +2353,7 @@ int CLI::run(int argc, char **argv) // continue; for (int instance_idx = 0; instance_idx < (int)model_object.instances.size(); ++ instance_idx) { const ModelInstance &model_instance = *model_object.instances[instance_idx]; - glvolume_collection.load_object_volume(&model_object, obj_idx, volume_idx, instance_idx, true, false, true); + glvolume_collection.load_object_volume(&model_object, obj_idx, volume_idx, instance_idx, false, true); //glvolume_collection.volumes.back()->geometry_id = key.geometry_id; std::string color = filament_color?filament_color->get_at(extruder_id - 1):"#00FF00"; diff --git a/src/libslic3r/BuildVolume.hpp b/src/libslic3r/BuildVolume.hpp index 4ab007f8b8..0df41f1be5 100644 --- a/src/libslic3r/BuildVolume.hpp +++ b/src/libslic3r/BuildVolume.hpp @@ -93,6 +93,9 @@ public: // Called on initial G-code preview on OpenGL vertex buffer interleaved normals and vertices. bool all_paths_inside_vertices_and_normals_interleaved(const std::vector& paths, const Eigen::AlignedBox& bbox, bool ignore_bottom = true) const; + const std::pair, std::vector>& top_bottom_convex_hull_decomposition_scene() const { return m_top_bottom_convex_hull_decomposition_scene; } + const std::pair, std::vector>& top_bottom_convex_hull_decomposition_bed() const { return m_top_bottom_convex_hull_decomposition_bed; } + private: // Source definition of the print bed geometry (PrintConfig::printable_area) std::vector m_bed_shape; diff --git a/src/slic3r/CMakeLists.txt b/src/slic3r/CMakeLists.txt index 61dc8c9491..d9ad26a6ee 100644 --- a/src/slic3r/CMakeLists.txt +++ b/src/slic3r/CMakeLists.txt @@ -131,8 +131,8 @@ set(SLIC3R_GUI_SOURCES GUI/Gizmos/GLGizmoSimplify.hpp GUI/Gizmos/GLGizmoMmuSegmentation.cpp GUI/Gizmos/GLGizmoMmuSegmentation.hpp - GUI/Gizmos/GLGizmoFaceDetector.cpp - GUI/Gizmos/GLGizmoFaceDetector.hpp + #GUI/Gizmos/GLGizmoFaceDetector.cpp + #GUI/Gizmos/GLGizmoFaceDetector.hpp GUI/Gizmos/GLGizmoSeam.cpp GUI/Gizmos/GLGizmoSeam.hpp GUI/Gizmos/GLGizmoText.cpp diff --git a/src/slic3r/GUI/3DScene.cpp b/src/slic3r/GUI/3DScene.cpp index 4d3d79923d..ac533c3365 100644 --- a/src/slic3r/GUI/3DScene.cpp +++ b/src/slic3r/GUI/3DScene.cpp @@ -1,12 +1,5 @@ -#include "slic3r/GUI/3DScene.hpp" #include -#if ENABLE_SMOOTH_NORMALS -#include -#include -#include -#endif // ENABLE_SMOOTH_NORMALS - #include "3DScene.hpp" #include "GLShader.hpp" #include "GUI_App.hpp" @@ -96,227 +89,6 @@ Slic3r::ColorRGBA adjust_color_for_rendering(const Slic3r::ColorRGBA &colors) namespace Slic3r { -#if ENABLE_SMOOTH_NORMALS -static void smooth_normals_corner(TriangleMesh& mesh, std::vector& normals) -{ - using MapMatrixXfUnaligned = Eigen::Map>; - using MapMatrixXiUnaligned = Eigen::Map>; - - std::vector face_normals = its_face_normals(mesh.its); - - Eigen::MatrixXd vertices = MapMatrixXfUnaligned(mesh.its.vertices.front().data(), - Eigen::Index(mesh.its.vertices.size()), 3).cast(); - Eigen::MatrixXi indices = MapMatrixXiUnaligned(mesh.its.indices.front().data(), - Eigen::Index(mesh.its.indices.size()), 3); - Eigen::MatrixXd in_normals = MapMatrixXfUnaligned(face_normals.front().data(), - Eigen::Index(face_normals.size()), 3).cast(); - Eigen::MatrixXd out_normals; - - igl::per_corner_normals(vertices, indices, in_normals, 1.0, out_normals); - - normals = std::vector(mesh.its.vertices.size()); - for (size_t i = 0; i < mesh.its.indices.size(); ++i) { - for (size_t j = 0; j < 3; ++j) { - normals[mesh.its.indices[i][j]] = out_normals.row(i * 3 + j).cast(); - } - } -} - -static void smooth_normals_vertex(TriangleMesh& mesh, std::vector& normals) -{ - using MapMatrixXfUnaligned = Eigen::Map>; - using MapMatrixXiUnaligned = Eigen::Map>; - - Eigen::MatrixXd vertices = MapMatrixXfUnaligned(mesh.its.vertices.front().data(), - Eigen::Index(mesh.its.vertices.size()), 3).cast(); - Eigen::MatrixXi indices = MapMatrixXiUnaligned(mesh.its.indices.front().data(), - Eigen::Index(mesh.its.indices.size()), 3); - Eigen::MatrixXd out_normals; - -// igl::per_vertex_normals(vertices, indices, igl::PER_VERTEX_NORMALS_WEIGHTING_TYPE_UNIFORM, out_normals); -// igl::per_vertex_normals(vertices, indices, igl::PER_VERTEX_NORMALS_WEIGHTING_TYPE_AREA, out_normals); - igl::per_vertex_normals(vertices, indices, igl::PER_VERTEX_NORMALS_WEIGHTING_TYPE_ANGLE, out_normals); -// igl::per_vertex_normals(vertices, indices, igl::PER_VERTEX_NORMALS_WEIGHTING_TYPE_DEFAULT, out_normals); - - normals = std::vector(mesh.its.vertices.size()); - for (size_t i = 0; i < static_cast(out_normals.rows()); ++i) { - normals[i] = out_normals.row(i).cast(); - } -} -#endif // ENABLE_SMOOTH_NORMALS - -#if ENABLE_SMOOTH_NORMALS -void GLIndexedVertexArray::load_mesh_full_shading(const TriangleMesh& mesh, bool smooth_normals) -#else -void GLIndexedVertexArray::load_mesh_full_shading(const TriangleMesh& mesh) -#endif // ENABLE_SMOOTH_NORMALS -{ - assert(triangle_indices.empty() && vertices_and_normals_interleaved_size == 0); - assert(quad_indices.empty() && triangle_indices_size == 0); - assert(vertices_and_normals_interleaved.size() % 6 == 0 && quad_indices_size == vertices_and_normals_interleaved.size()); - -#if ENABLE_SMOOTH_NORMALS - if (smooth_normals) { - TriangleMesh new_mesh(mesh); - std::vector normals; - smooth_normals_corner(new_mesh, normals); -// smooth_normals_vertex(new_mesh, normals); - - this->vertices_and_normals_interleaved.reserve(this->vertices_and_normals_interleaved.size() + 3 * 2 * new_mesh.its.vertices.size()); - for (size_t i = 0; i < new_mesh.its.vertices.size(); ++i) { - const stl_vertex& v = new_mesh.its.vertices[i]; - const stl_normal& n = normals[i]; - this->push_geometry(v(0), v(1), v(2), n(0), n(1), n(2)); - } - - for (size_t i = 0; i < new_mesh.its.indices.size(); ++i) { - const stl_triangle_vertex_indices& idx = new_mesh.its.indices[i]; - this->push_triangle(idx(0), idx(1), idx(2)); - } - } - else { -#endif // ENABLE_SMOOTH_NORMALS - this->load_its_flat_shading(mesh.its); -#if ENABLE_SMOOTH_NORMALS - } -#endif // ENABLE_SMOOTH_NORMALS -} - -void GLIndexedVertexArray::load_its_flat_shading(const indexed_triangle_set &its) -{ - this->vertices_and_normals_interleaved.reserve(this->vertices_and_normals_interleaved.size() + 3 * 3 * 2 * its.indices.size()); - unsigned int vertices_count = 0; - for (int i = 0; i < int(its.indices.size()); ++ i) { - stl_triangle_vertex_indices face = its.indices[i]; - stl_vertex vertex[3] = { its.vertices[face[0]], its.vertices[face[1]], its.vertices[face[2]] }; - stl_vertex n = face_normal_normalized(vertex); - for (int j = 0; j < 3; ++j) - this->push_geometry(vertex[j](0), vertex[j](1), vertex[j](2), n(0), n(1), n(2)); - this->push_triangle(vertices_count, vertices_count + 1, vertices_count + 2); - vertices_count += 3; - } - BOOST_LOG_TRIVIAL(debug) << __FUNCTION__<< boost::format(", this %1%, indices size %2%, vertices %3%, triangles %4% ") - %this %its.indices.size() %this->vertices_and_normals_interleaved.size() %this->triangle_indices.size() ; -} - -void GLIndexedVertexArray::finalize_geometry(bool opengl_initialized) -{ - assert(this->vertices_and_normals_interleaved_VBO_id == 0); - assert(this->triangle_indices_VBO_id == 0); - assert(this->quad_indices_VBO_id == 0); - - if (! opengl_initialized) { - // Shrink the data vectors to conserve memory in case the data cannot be transfered to the OpenGL driver yet. - this->shrink_to_fit(); - return; - } - - BOOST_LOG_TRIVIAL(debug) << __FUNCTION__<< boost::format(", this %1% ") %this; - if (! this->vertices_and_normals_interleaved.empty()) { - glsafe(::glGenBuffers(1, &this->vertices_and_normals_interleaved_VBO_id)); - glsafe(::glBindBuffer(GL_ARRAY_BUFFER, this->vertices_and_normals_interleaved_VBO_id)); - glsafe(::glBufferData(GL_ARRAY_BUFFER, this->vertices_and_normals_interleaved.size() * 4, this->vertices_and_normals_interleaved.data(), GL_STATIC_DRAW)); - glsafe(::glBindBuffer(GL_ARRAY_BUFFER, 0)); - this->vertices_and_normals_interleaved.clear(); - } - if (! this->triangle_indices.empty()) { - glsafe(::glGenBuffers(1, &this->triangle_indices_VBO_id)); - glsafe(::glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, this->triangle_indices_VBO_id)); - glsafe(::glBufferData(GL_ELEMENT_ARRAY_BUFFER, this->triangle_indices.size() * 4, this->triangle_indices.data(), GL_STATIC_DRAW)); - glsafe(::glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0)); - this->triangle_indices.clear(); - } - if (! this->quad_indices.empty()) { - glsafe(::glGenBuffers(1, &this->quad_indices_VBO_id)); - glsafe(::glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, this->quad_indices_VBO_id)); - glsafe(::glBufferData(GL_ELEMENT_ARRAY_BUFFER, this->quad_indices.size() * 4, this->quad_indices.data(), GL_STATIC_DRAW)); - glsafe(::glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0)); - this->quad_indices.clear(); - } -} - -void GLIndexedVertexArray::release_geometry() -{ - if (this->vertices_and_normals_interleaved_VBO_id) { - glsafe(::glDeleteBuffers(1, &this->vertices_and_normals_interleaved_VBO_id)); - this->vertices_and_normals_interleaved_VBO_id = 0; - } - if (this->triangle_indices_VBO_id) { - glsafe(::glDeleteBuffers(1, &this->triangle_indices_VBO_id)); - this->triangle_indices_VBO_id = 0; - } - if (this->quad_indices_VBO_id) { - glsafe(::glDeleteBuffers(1, &this->quad_indices_VBO_id)); - this->quad_indices_VBO_id = 0; - } - this->clear(); -} - -void GLIndexedVertexArray::render() const -{ - assert(this->vertices_and_normals_interleaved_VBO_id != 0); - assert(this->triangle_indices_VBO_id != 0 || this->quad_indices_VBO_id != 0); - - glsafe(::glBindBuffer(GL_ARRAY_BUFFER, this->vertices_and_normals_interleaved_VBO_id)); - glsafe(::glVertexPointer(3, GL_FLOAT, 6 * sizeof(float), (const void*)(3 * sizeof(float)))); - glsafe(::glNormalPointer(GL_FLOAT, 6 * sizeof(float), nullptr)); - - glsafe(::glEnableClientState(GL_VERTEX_ARRAY)); - glsafe(::glEnableClientState(GL_NORMAL_ARRAY)); - - // Render using the Vertex Buffer Objects. - if (this->triangle_indices_size > 0) { - glsafe(::glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, this->triangle_indices_VBO_id)); - glsafe(::glDrawElements(GL_TRIANGLES, GLsizei(this->triangle_indices_size), GL_UNSIGNED_INT, nullptr)); - glsafe(glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0)); - } - if (this->quad_indices_size > 0) { - glsafe(::glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, this->quad_indices_VBO_id)); - glsafe(::glDrawElements(GL_QUADS, GLsizei(this->quad_indices_size), GL_UNSIGNED_INT, nullptr)); - glsafe(glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0)); - } - - glsafe(::glDisableClientState(GL_VERTEX_ARRAY)); - glsafe(::glDisableClientState(GL_NORMAL_ARRAY)); - - glsafe(::glBindBuffer(GL_ARRAY_BUFFER, 0)); -} - -void GLIndexedVertexArray::render( - const std::pair& tverts_range, - const std::pair& qverts_range) const -{ - // this method has been called before calling finalize() ? - if (this->vertices_and_normals_interleaved_VBO_id == 0 && !this->vertices_and_normals_interleaved.empty()) - return; - - assert(this->vertices_and_normals_interleaved_VBO_id != 0); - assert(this->triangle_indices_VBO_id != 0 || this->quad_indices_VBO_id != 0); - - // Render using the Vertex Buffer Objects. - glsafe(::glBindBuffer(GL_ARRAY_BUFFER, this->vertices_and_normals_interleaved_VBO_id)); - glsafe(::glVertexPointer(3, GL_FLOAT, 6 * sizeof(float), (const void*)(3 * sizeof(float)))); - glsafe(::glNormalPointer(GL_FLOAT, 6 * sizeof(float), nullptr)); - - glsafe(::glEnableClientState(GL_VERTEX_ARRAY)); - glsafe(::glEnableClientState(GL_NORMAL_ARRAY)); - - if (this->triangle_indices_size > 0) { - glsafe(::glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, this->triangle_indices_VBO_id)); - glsafe(::glDrawElements(GL_TRIANGLES, GLsizei(std::min(this->triangle_indices_size, tverts_range.second - tverts_range.first)), GL_UNSIGNED_INT, (const void*)(tverts_range.first * 4))); - glsafe(::glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0)); - } - if (this->quad_indices_size > 0) { - glsafe(::glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, this->quad_indices_VBO_id)); - glsafe(::glDrawElements(GL_QUADS, GLsizei(std::min(this->quad_indices_size, qverts_range.second - qverts_range.first)), GL_UNSIGNED_INT, (const void*)(qverts_range.first * 4))); - glsafe(::glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0)); - } - - glsafe(::glDisableClientState(GL_VERTEX_ARRAY)); - glsafe(::glDisableClientState(GL_NORMAL_ARRAY)); - - glsafe(::glBindBuffer(GL_ARRAY_BUFFER, 0)); -} const float GLVolume::SinkingContours::HalfWidth = 0.25f; @@ -440,7 +212,6 @@ GLVolume::GLVolume(float r, float g, float b, float a) , force_neutral_color(false) , force_sinking_contours(false) , tverts_range(0, size_t(-1)) - , qverts_range(0, size_t(-1)) { color = { r, g, b, a }; set_render_color(color); @@ -593,34 +364,28 @@ const BoundingBoxf3& GLVolume::transformed_non_sinking_bounding_box() const void GLVolume::set_range(double min_z, double max_z) { - this->qverts_range.first = 0; - this->qverts_range.second = this->indexed_vertex_array.quad_indices_size; this->tverts_range.first = 0; - this->tverts_range.second = this->indexed_vertex_array.triangle_indices_size; - if (! this->print_zs.empty()) { + this->tverts_range.second = this->model.indices_count(); + + if (!this->print_zs.empty()) { // The Z layer range is specified. // First test whether the Z span of this object is not out of (min_z, max_z) completely. - if (this->print_zs.front() > max_z || this->print_zs.back() < min_z) { - this->qverts_range.second = 0; + if (this->print_zs.front() > max_z || this->print_zs.back() < min_z) this->tverts_range.second = 0; - } else { + else { // Then find the lowest layer to be displayed. size_t i = 0; - for (; i < this->print_zs.size() && this->print_zs[i] < min_z; ++ i); - if (i == this->print_zs.size()) { + for (; i < this->print_zs.size() && this->print_zs[i] < min_z; ++i); + if (i == this->print_zs.size()) // This shall not happen. - this->qverts_range.second = 0; this->tverts_range.second = 0; - } else { + else { // Remember start of the layer. - this->qverts_range.first = this->offsets[i * 2]; - this->tverts_range.first = this->offsets[i * 2 + 1]; + this->tverts_range.first = this->offsets[i]; // Some layers are above $min_z. Which? - for (; i < this->print_zs.size() && this->print_zs[i] <= max_z; ++ i); - if (i < this->print_zs.size()) { - this->qverts_range.second = this->offsets[i * 2]; - this->tverts_range.second = this->offsets[i * 2 + 1]; - } + for (; i < this->print_zs.size() && this->print_zs[i] <= max_z; ++i); + if (i < this->print_zs.size()) + this->tverts_range.second = this->offsets[i]; } } } @@ -628,7 +393,7 @@ void GLVolume::set_range(double min_z, double max_z) //BBS: add outline related logic //static unsigned char stencil_data[1284][2944]; -void GLVolume::render(bool with_outline) const +void GLVolume::render(bool with_outline) { if (!is_active) return; @@ -657,19 +422,18 @@ void GLVolume::render(bool with_outline) const color_volume = true; if (mv->mmu_segmentation_facets.timestamp() != mmuseg_ts) { BOOST_LOG_TRIVIAL(debug) << __FUNCTION__<< boost::format(", this %1%, name %2%, current mmuseg_ts %3%, current color size %4%") - %this %this->name %mmuseg_ts %mmuseg_ivas.size() ; - mmuseg_ivas.clear(); + %this %this->name %mmuseg_ts %mmuseg_models.size() ; + mmuseg_models.clear(); std::vector its_per_color; mv->mmu_segmentation_facets.get_facets(*mv, its_per_color); - mmuseg_ivas.resize(its_per_color.size()); + mmuseg_models.resize(its_per_color.size()); for (int idx = 0; idx < its_per_color.size(); idx++) { - mmuseg_ivas[idx].load_its_flat_shading(its_per_color[idx]); - mmuseg_ivas[idx].finalize_geometry(true); + mmuseg_models[idx].init_from(its_per_color[idx]); } mmuseg_ts = mv->mmu_segmentation_facets.timestamp(); BOOST_LOG_TRIVIAL(debug) << __FUNCTION__<< boost::format(", this %1%, name %2%, new mmuseg_ts %3%, new color size %4%") - %this %this->name %mmuseg_ts %mmuseg_ivas.size(); + %this %this->name %mmuseg_ts %mmuseg_models.size(); } } while (0); @@ -683,9 +447,9 @@ void GLVolume::render(bool with_outline) const colors[index].a(render_color.a()); } glsafe(::glMultMatrixd(world_matrix().data())); - for (int idx = 0; idx < mmuseg_ivas.size(); idx++) { - GLIndexedVertexArray& iva = mmuseg_ivas[idx]; - if (iva.triangle_indices_size == 0 && iva.quad_indices_size == 0) + for (int idx = 0; idx < mmuseg_models.size(); idx++) { + GUI::GLModel &m = mmuseg_models[idx]; + if (m.is_empty()) continue; if (shader) { @@ -696,24 +460,27 @@ void GLVolume::render(bool with_outline) const //shader->set_uniform("uniform_color", colors[extruder_id - 1]); //to make black not too hard too see ColorRGBA new_color = adjust_color_for_rendering(colors[extruder_id - 1]); - shader->set_uniform("uniform_color", new_color); + m.set_color(new_color); } else { if (idx <= colors.size()) { //shader->set_uniform("uniform_color", colors[idx - 1]); //to make black not too hard too see ColorRGBA new_color = adjust_color_for_rendering(colors[idx - 1]); - shader->set_uniform("uniform_color", new_color); + m.set_color(new_color); } else { //shader->set_uniform("uniform_color", colors[0]); //to make black not too hard too see ColorRGBA new_color = adjust_color_for_rendering(colors[0]); - shader->set_uniform("uniform_color", new_color); + m.set_color(new_color); } } } - iva.render(this->tverts_range, this->qverts_range); + if (tverts_range == std::make_pair(0, -1)) + m.render(); + else + m.render(this->tverts_range); /*if (force_native_color && (render_color[3] < 1.0)) { BOOST_LOG_TRIVIAL(debug) << __FUNCTION__<< boost::format(", this %1%, name %2%, tverts_range {%3,%4}, qverts_range{%5%, %6%}") %this %this->name %this->tverts_range.first %this->tverts_range.second @@ -723,7 +490,10 @@ void GLVolume::render(bool with_outline) const } else { glsafe(::glMultMatrixd(world_matrix().data())); - this->indexed_vertex_array.render(this->tverts_range, this->qverts_range); + if (tverts_range == std::make_pair(0, -1)) + model.render(); + else + model.render(this->tverts_range); } }; @@ -832,7 +602,7 @@ void GLVolume::render(bool with_outline) const float scale = 1.02f; ColorRGBA body_color = { 1.0f, 1.0f, 1.0f, 1.0f }; //red - shader->set_uniform("uniform_color", body_color); + model.set_color(body_color); shader->set_uniform("is_outline", true); glsafe(::glPopMatrix()); glsafe(::glPushMatrix()); @@ -840,7 +610,10 @@ void GLVolume::render(bool with_outline) const Transform3d matrix = world_matrix(); matrix.scale(scale); glsafe(::glMultMatrixd(matrix.data())); - this->indexed_vertex_array.render(this->tverts_range, this->qverts_range); + if (tverts_range == std::make_pair(0, -1)) + model.render(); + else + model.render(this->tverts_range); //BOOST_LOG_TRIVIAL(info) << boost::format(": %1%, outline render for body, shader name %2%")%__LINE__ %shader->get_name(); shader->set_uniform("is_outline", false); @@ -862,7 +635,7 @@ void GLVolume::render(bool with_outline) const } //BBS add render for simple case -void GLVolume::simple_render(GLShaderProgram* shader, ModelObjectPtrs& model_objects, std::vector& extruder_colors) const +void GLVolume::simple_render(GLShaderProgram* shader, ModelObjectPtrs& model_objects, std::vector& extruder_colors) { if (this->is_left_handed()) glFrontFace(GL_CW); @@ -885,13 +658,12 @@ void GLVolume::simple_render(GLShaderProgram* shader, ModelObjectPtrs& model_obj color_volume = true; if (model_volume->mmu_segmentation_facets.timestamp() != mmuseg_ts) { - mmuseg_ivas.clear(); + mmuseg_models.clear(); std::vector its_per_color; model_volume->mmu_segmentation_facets.get_facets(*model_volume, its_per_color); - mmuseg_ivas.resize(its_per_color.size()); + mmuseg_models.resize(its_per_color.size()); for (int idx = 0; idx < its_per_color.size(); idx++) { - mmuseg_ivas[idx].load_its_flat_shading(its_per_color[idx]); - mmuseg_ivas[idx].finalize_geometry(true); + mmuseg_models[idx].init_from(its_per_color[idx]); } mmuseg_ts = model_volume->mmu_segmentation_facets.timestamp(); @@ -900,9 +672,9 @@ void GLVolume::simple_render(GLShaderProgram* shader, ModelObjectPtrs& model_obj if (color_volume) { glsafe(::glMultMatrixd(world_matrix().data())); - for (int idx = 0; idx < mmuseg_ivas.size(); idx++) { - GLIndexedVertexArray& iva = mmuseg_ivas[idx]; - if (iva.triangle_indices_size == 0 && iva.quad_indices_size == 0) + for (int idx = 0; idx < mmuseg_models.size(); idx++) { + GUI::GLModel &m = mmuseg_models[idx]; + if (m.is_empty()) continue; if (shader) { @@ -910,29 +682,35 @@ void GLVolume::simple_render(GLShaderProgram* shader, ModelObjectPtrs& model_obj int extruder_id = model_volume->extruder_id(); //to make black not too hard too see ColorRGBA new_color = adjust_color_for_rendering(extruder_colors[extruder_id - 1]); - shader->set_uniform("uniform_color", new_color); + m.set_color(new_color); } else { if (idx <= extruder_colors.size()) { //shader->set_uniform("uniform_color", extruder_colors[idx - 1]); //to make black not too hard too see ColorRGBA new_color = adjust_color_for_rendering(extruder_colors[idx - 1]); - shader->set_uniform("uniform_color", new_color); + m.set_color(new_color); } else { //shader->set_uniform("uniform_color", extruder_colors[0]); //to make black not too hard too see ColorRGBA new_color = adjust_color_for_rendering(extruder_colors[0]); - shader->set_uniform("uniform_color", new_color); + m.set_color(new_color); } } } - iva.render(this->tverts_range, this->qverts_range); + if (tverts_range == std::make_pair(0, -1)) + m.render(); + else + m.render(this->tverts_range); } } else { glsafe(::glMultMatrixd(world_matrix().data())); - this->indexed_vertex_array.render(this->tverts_range, this->qverts_range); + if (tverts_range == std::make_pair(0, -1)) + model.render(); + else + model.render(this->tverts_range); } glsafe(::glPopMatrix()); @@ -967,12 +745,12 @@ GLWipeTowerVolume::GLWipeTowerVolume(const std::vector& colors) m_colors = colors; } -void GLWipeTowerVolume::render(bool with_outline) const +void GLWipeTowerVolume::render(bool with_outline) { if (!is_active) return; - if (m_colors.size() == 0 || m_colors.size() != iva_per_colors.size()) + if (m_colors.size() == 0 || m_colors.size() != model_per_colors.size()) return; if (this->is_left_handed()) @@ -983,11 +761,9 @@ void GLWipeTowerVolume::render(bool with_outline) const GLShaderProgram* shader = GUI::wxGetApp().get_current_shader(); for (int i = 0; i < m_colors.size(); i++) { - if (shader) { - ColorRGBA new_color = adjust_color_for_rendering(m_colors[i]); - shader->set_uniform("uniform_color", new_color); - } - this->iva_per_colors[i].render(); + ColorRGBA new_color = adjust_color_for_rendering(m_colors[i]); + this->model_per_colors[i].set_color(new_color); + this->model_per_colors[i].render(); } glsafe(::glPopMatrix()); @@ -1005,24 +781,22 @@ bool GLWipeTowerVolume::IsTransparent() { } std::vector GLVolumeCollection::load_object( - const ModelObject *model_object, - int obj_idx, - const std::vector &instance_idxs, - bool opengl_initialized) + const ModelObject* model_object, + int obj_idx, + const std::vector& instance_idxs) { std::vector volumes_idx; for (int volume_idx = 0; volume_idx < int(model_object->volumes.size()); ++volume_idx) for (int instance_idx : instance_idxs) - volumes_idx.emplace_back(this->GLVolumeCollection::load_object_volume(model_object, obj_idx, volume_idx, instance_idx, opengl_initialized)); + volumes_idx.emplace_back(this->GLVolumeCollection::load_object_volume(model_object, obj_idx, volume_idx, instance_idx)); return volumes_idx; } int GLVolumeCollection::load_object_volume( - const ModelObject *model_object, + const ModelObject* model_object, int obj_idx, int volume_idx, int instance_idx, - bool opengl_initialized, bool in_assemble_view, bool use_loaded_id) { @@ -1034,15 +808,14 @@ int GLVolumeCollection::load_object_volume( GLVolume& v = *this->volumes.back(); v.set_color(color_from_model_volume(*model_volume)); v.name = model_volume->name; + #if ENABLE_SMOOTH_NORMALS - v.indexed_vertex_array.load_mesh(mesh, true); + v.model.init_from(mesh, true); #else - v.indexed_vertex_array.load_mesh(mesh); + v.model.init_from(mesh); #endif // ENABLE_SMOOTH_NORMALS - v.indexed_vertex_array.finalize_geometry(opengl_initialized); v.composite_id = GLVolume::CompositeID(obj_idx, volume_idx, instance_idx); - if (model_volume->is_model_part()) - { + if (model_volume->is_model_part()) { // GLVolume will reference a convex hull from model_volume! v.set_convex_hull(model_volume->get_convex_hull_shared_ptr()); if (extruder_id != -1) @@ -1070,14 +843,13 @@ int GLVolumeCollection::load_object_volume( // This function produces volumes for multiple instances in a single shot, // as some object specific mesh conversions may be expensive. void GLVolumeCollection::load_object_auxiliary( - const SLAPrintObject *print_object, + const SLAPrintObject* print_object, int obj_idx, // pairs of const std::vector>& instances, SLAPrintObjectStep milestone, // Timestamp of the last change of the milestone - size_t timestamp, - bool opengl_initialized) + size_t timestamp) { assert(print_object->is_step_done(milestone)); Transform3d mesh_trafo_inv = print_object->trafo().inverse(); @@ -1091,11 +863,11 @@ void GLVolumeCollection::load_object_auxiliary( this->volumes.emplace_back(new GLVolume((milestone == slaposPad) ? GLVolume::SLA_PAD_COLOR : GLVolume::SLA_SUPPORT_COLOR)); GLVolume& v = *this->volumes.back(); #if ENABLE_SMOOTH_NORMALS - v.indexed_vertex_array.load_mesh(mesh, true); + v.model.init_from(mesh, true); #else - v.indexed_vertex_array.load_mesh(mesh); + v.model.init_from(mesh); #endif // ENABLE_SMOOTH_NORMALS - v.indexed_vertex_array.finalize_geometry(opengl_initialized); + v.model.set_color((milestone == slaposPad) ? GLVolume::SLA_PAD_COLOR : GLVolume::SLA_SUPPORT_COLOR); v.composite_id = GLVolume::CompositeID(obj_idx, -int(milestone), (int)instance_idx.first); v.geometry_id = std::pair(timestamp, model_instance.id().id); // Create a copy of the convex hull mesh for each instance. Use a move operator on the last instance. @@ -1113,7 +885,7 @@ void GLVolumeCollection::load_object_auxiliary( int GLVolumeCollection::load_wipe_tower_preview( int obj_idx, float pos_x, float pos_y, float width, float depth, float height, - float rotation_angle, bool size_unknown, float brim_width, bool opengl_initialized) + float rotation_angle, bool size_unknown, float brim_width) { int plate_idx = obj_idx - 1000; @@ -1146,15 +918,13 @@ int GLVolumeCollection::load_wipe_tower_preview( color.a(0.66f); volumes.emplace_back(new GLWipeTowerVolume(colors)); GLWipeTowerVolume& v = *dynamic_cast(volumes.back()); - v.iva_per_colors.resize(colors.size()); + v.model_per_colors.resize(colors.size()); for (int i = 0; i < colors.size(); i++) { TriangleMesh color_part = make_cube(width, depth / colors.size(), height); color_part.translate({ 0.f, depth * i / colors.size(), 0. }); - v.iva_per_colors[i].load_mesh(color_part); - v.iva_per_colors[i].finalize_geometry(opengl_initialized); + v.model_per_colors[i].init_from(color_part); } - v.indexed_vertex_array.load_mesh(wipe_tower_shell); - v.indexed_vertex_array.finalize_geometry(opengl_initialized); + v.model.init_from(wipe_tower_shell); v.set_convex_hull(wipe_tower_shell); v.set_volume_offset(Vec3d(pos_x, pos_y, 0.0)); v.set_volume_rotation(Vec3d(0., 0., (M_PI / 180.) * rotation_angle)); @@ -1166,21 +936,19 @@ int GLVolumeCollection::load_wipe_tower_preview( return int(volumes.size() - 1); } -GLVolume* GLVolumeCollection::new_toolpath_volume(const ColorRGBA& rgba, size_t reserve_vbo_floats) +GLVolume* GLVolumeCollection::new_toolpath_volume(const ColorRGBA& rgba) { - GLVolume *out = new_nontoolpath_volume(rgba, reserve_vbo_floats); - out->is_extrusion_path = true; - return out; + GLVolume* out = new_nontoolpath_volume(rgba); + out->is_extrusion_path = true; + return out; } -GLVolume* GLVolumeCollection::new_nontoolpath_volume(const ColorRGBA& rgba, size_t reserve_vbo_floats) +GLVolume* GLVolumeCollection::new_nontoolpath_volume(const ColorRGBA& rgba) { - GLVolume *out = new GLVolume(rgba); - out->is_extrusion_path = false; - // Reserving number of vertices (3x position + 3x color) - out->indexed_vertex_array.reserve(reserve_vbo_floats / 6); - this->volumes.emplace_back(out); - return out; + GLVolume* out = new GLVolume(rgba); + out->is_extrusion_path = false; + this->volumes.emplace_back(out); + return out; } GLVolumeWithIdAndZList volumes_to_render(const GLVolumePtrs& volumes, GLVolumeCollection::ERenderType type, const Transform3d& view_matrix, std::function filter_func) @@ -1284,7 +1052,8 @@ void GLVolumeCollection::render( glsafe(::glEnableClientState(GL_VERTEX_ARRAY)); glsafe(::glEnableClientState(GL_NORMAL_ARRAY)); - shader->set_uniform("uniform_color", volume.first->render_color); + if (!volume.first->model.is_initialized()) + shader->set_uniform("uniform_color", volume.first->render_color); shader->set_uniform("z_range", m_z_range, 2); shader->set_uniform("clipping_plane", m_clipping_plane, 4); //BOOST_LOG_TRIVIAL(info) << boost::format("set uniform_color to {%1%, %2%, %3%, %4%}, with_outline=%5%, selected %6%") @@ -1326,6 +1095,7 @@ void GLVolumeCollection::render( #endif // ENABLE_ENVIRONMENT_MAP glcheck(); + volume.first->model.set_color(volume.first->render_color); //BBS: add outline related logic volume.first->render(with_outline && volume.first->selected); @@ -1617,60 +1387,63 @@ std::string GLVolumeCollection::log_memory_info() const return " (GLVolumeCollection RAM: " + format_memsize_MB(this->cpu_memory_used()) + " GPU: " + format_memsize_MB(this->gpu_memory_used()) + " Both: " + format_memsize_MB(this->gpu_memory_used()) + ")"; } -// caller is responsible for supplying NO lines with zero length -static void thick_lines_to_indexed_vertex_array( - const Lines &lines, - const std::vector &widths, - const std::vector &heights, - bool closed, - double top_z, - GLIndexedVertexArray &volume) +static void thick_lines_to_geometry( + const Lines& lines, + const std::vector& widths, + const std::vector& heights, + bool closed, + double top_z, + GUI::GLModel::Geometry& geometry) { - assert(! lines.empty()); + assert(!lines.empty()); if (lines.empty()) return; -#define LEFT 0 -#define RIGHT 1 -#define TOP 2 -#define BOTTOM 3 + enum Direction : unsigned char + { + Left, + Right, + Top, + Bottom + }; // right, left, top, bottom - int idx_prev[4] = { -1, -1, -1, -1 }; - double bottom_z_prev = 0.; - Vec2d b1_prev(Vec2d::Zero()); - Vec2d v_prev(Vec2d::Zero()); - int idx_initial[4] = { -1, -1, -1, -1 }; - double width_initial = 0.; - double bottom_z_initial = 0.0; - double len_prev = 0.0; + std::array idx_prev = { -1, -1, -1, -1 }; + std::array idx_initial = { -1, -1, -1, -1 }; + + double bottom_z_prev = 0.0; + Vec2d b1_prev(Vec2d::Zero()); + Vec2d v_prev(Vec2d::Zero()); + double len_prev = 0.0; + double width_initial = 0.0; + double bottom_z_initial = 0.0; // loop once more in case of closed loops - size_t lines_end = closed ? (lines.size() + 1) : lines.size(); - for (size_t ii = 0; ii < lines_end; ++ ii) { - size_t i = (ii == lines.size()) ? 0 : ii; - const Line &line = lines[i]; - double bottom_z = top_z - heights[i]; - double middle_z = 0.5 * (top_z + bottom_z); - double width = widths[i]; + const size_t lines_end = closed ? (lines.size() + 1) : lines.size(); + for (size_t ii = 0; ii < lines_end; ++ii) { + const size_t i = (ii == lines.size()) ? 0 : ii; + const Line& line = lines[i]; + const double bottom_z = top_z - heights[i]; + const double middle_z = 0.5 * (top_z + bottom_z); + const double width = widths[i]; - bool is_first = (ii == 0); - bool is_last = (ii == lines_end - 1); - bool is_closing = closed && is_last; + const bool is_first = (ii == 0); + const bool is_last = (ii == lines_end - 1); + const bool is_closing = closed && is_last; - Vec2d v = unscale(line.vector()).normalized(); - double len = unscale(line.length()); + const Vec2d v = unscale(line.vector()).normalized(); + const double len = unscale(line.length()); - Vec2d a = unscale(line.a); - Vec2d b = unscale(line.b); + const Vec2d a = unscale(line.a); + const Vec2d b = unscale(line.b); Vec2d a1 = a; Vec2d a2 = a; Vec2d b1 = b; Vec2d b2 = b; { - double dist = 0.5 * width; // scaled - double dx = dist * v(0); - double dy = dist * v(1); + const double dist = 0.5 * width; // scaled + const double dx = dist * v.x(); + const double dy = dist * v.y(); a1 += Vec2d(+dy, -dx); a2 += Vec2d(-dy, +dx); b1 += Vec2d(+dy, -dx); @@ -1678,102 +1451,101 @@ static void thick_lines_to_indexed_vertex_array( } // calculate new XY normals - Vec2d xy_right_normal = unscale(line.normal()).normalized(); + const Vec2d xy_right_normal = unscale(line.normal()).normalized(); - int idx_a[4] = { 0, 0, 0, 0 }; // initialized to avoid warnings - int idx_b[4] = { 0, 0, 0, 0 }; // initialized to avoid warnings - int idx_last = int(volume.vertices_and_normals_interleaved.size() / 6); + std::array idx_a = { 0, 0, 0, 0 }; + std::array idx_b = { 0, 0, 0, 0 }; + int idx_last = int(geometry.vertices_count()); - bool bottom_z_different = bottom_z_prev != bottom_z; + const bool bottom_z_different = bottom_z_prev != bottom_z; bottom_z_prev = bottom_z; - if (!is_first && bottom_z_different) - { + if (!is_first && bottom_z_different) { // Found a change of the layer thickness -> Add a cap at the end of the previous segment. - volume.push_quad(idx_b[BOTTOM], idx_b[LEFT], idx_b[TOP], idx_b[RIGHT]); + geometry.add_uint_triangle(idx_b[Bottom], idx_b[Left], idx_b[Top]); + geometry.add_uint_triangle(idx_b[Bottom], idx_b[Top], idx_b[Right]); } // Share top / bottom vertices if possible. if (is_first) { - idx_a[TOP] = idx_last++; - volume.push_geometry(a(0), a(1), top_z , 0., 0., 1.); - } else { - idx_a[TOP] = idx_prev[TOP]; + idx_a[Top] = idx_last++; + geometry.add_vertex(Vec3f(a.x(), a.y(), top_z), Vec3f(0.0f, 0.0f, 1.0f)); } + else + idx_a[Top] = idx_prev[Top]; if (is_first || bottom_z_different) { // Start of the 1st line segment or a change of the layer thickness while maintaining the print_z. - idx_a[BOTTOM] = idx_last ++; - volume.push_geometry(a(0), a(1), bottom_z, 0., 0., -1.); - idx_a[LEFT ] = idx_last ++; - volume.push_geometry(a2(0), a2(1), middle_z, -xy_right_normal(0), -xy_right_normal(1), 0.0); - idx_a[RIGHT] = idx_last ++; - volume.push_geometry(a1(0), a1(1), middle_z, xy_right_normal(0), xy_right_normal(1), 0.0); - } - else { - idx_a[BOTTOM] = idx_prev[BOTTOM]; + idx_a[Bottom] = idx_last++; + geometry.add_vertex(Vec3f(a.x(), a.y(), bottom_z), Vec3f(0.0f, 0.0f, -1.0f)); + idx_a[Left] = idx_last++; + geometry.add_vertex(Vec3f(a2.x(), a2.y(), middle_z), Vec3f(-xy_right_normal.x(), -xy_right_normal.y(), 0.0f)); + idx_a[Right] = idx_last++; + geometry.add_vertex(Vec3f(a1.x(), a1.y(), middle_z), Vec3f(xy_right_normal.x(), xy_right_normal.y(), 0.0f)); } + else + idx_a[Bottom] = idx_prev[Bottom]; if (is_first) { // Start of the 1st line segment. - width_initial = width; + width_initial = width; bottom_z_initial = bottom_z; - memcpy(idx_initial, idx_a, sizeof(int) * 4); - } else { + idx_initial = idx_a; + } + else { // Continuing a previous segment. // Share left / right vertices if possible. - double v_dot = v_prev.dot(v); + const double v_dot = v_prev.dot(v); // To reduce gpu memory usage, we try to reuse vertices - // To reduce the visual artifacts, due to averaged normals, we allow to reuse vertices only when any of two adjacent edges + // To reduce the visual artifacts, due to averaged normals, we allow to reuse vertices only when any of two adjacent edges // is longer than a fixed threshold. // The following value is arbitrary, it comes from tests made on a bunch of models showing the visual artifacts - double len_threshold = 2.5; + const double len_threshold = 2.5; // Generate new vertices if the angle between adjacent edges is greater than 45 degrees or thresholds conditions are met - bool sharp = (v_dot < 0.707) || (len_prev > len_threshold) || (len > len_threshold); + const bool sharp = (v_dot < 0.707) || (len_prev > len_threshold) || (len > len_threshold); if (sharp) { - if (!bottom_z_different) - { + if (!bottom_z_different) { // Allocate new left / right points for the start of this segment as these points will receive their own normals to indicate a sharp turn. - idx_a[RIGHT] = idx_last++; - volume.push_geometry(a1(0), a1(1), middle_z, xy_right_normal(0), xy_right_normal(1), 0.0); - idx_a[LEFT] = idx_last++; - volume.push_geometry(a2(0), a2(1), middle_z, -xy_right_normal(0), -xy_right_normal(1), 0.0); - if (cross2(v_prev, v) > 0.) { + idx_a[Right] = idx_last++; + geometry.add_vertex(Vec3f(a1.x(), a1.y(), middle_z), Vec3f(xy_right_normal.x(), xy_right_normal.y(), 0.0f)); + idx_a[Left] = idx_last++; + geometry.add_vertex(Vec3f(a2.x(), a2.y(), middle_z), Vec3f(-xy_right_normal.x(), -xy_right_normal.y(), 0.0f)); + if (cross2(v_prev, v) > 0.0) { // Right turn. Fill in the right turn wedge. - volume.push_triangle(idx_prev[RIGHT], idx_a[RIGHT], idx_prev[TOP]); - volume.push_triangle(idx_prev[RIGHT], idx_prev[BOTTOM], idx_a[RIGHT]); + geometry.add_uint_triangle(idx_prev[Right], idx_a[Right], idx_prev[Top]); + geometry.add_uint_triangle(idx_prev[Right], idx_prev[Bottom], idx_a[Right]); } else { // Left turn. Fill in the left turn wedge. - volume.push_triangle(idx_prev[LEFT], idx_prev[TOP], idx_a[LEFT]); - volume.push_triangle(idx_prev[LEFT], idx_a[LEFT], idx_prev[BOTTOM]); + geometry.add_uint_triangle(idx_prev[Left], idx_prev[Top], idx_a[Left]); + geometry.add_uint_triangle(idx_prev[Left], idx_a[Left], idx_prev[Bottom]); } } } - else - { - if (!bottom_z_different) - { + else { + if (!bottom_z_different) { // The two successive segments are nearly collinear. - idx_a[LEFT ] = idx_prev[LEFT]; - idx_a[RIGHT] = idx_prev[RIGHT]; + idx_a[Left] = idx_prev[Left]; + idx_a[Right] = idx_prev[Right]; } } if (is_closing) { if (!sharp) { - if (!bottom_z_different) - { + if (!bottom_z_different) { // Closing a loop with smooth transition. Unify the closing left / right vertices. - memcpy(volume.vertices_and_normals_interleaved.data() + idx_initial[LEFT ] * 6, volume.vertices_and_normals_interleaved.data() + idx_prev[LEFT ] * 6, sizeof(float) * 6); - memcpy(volume.vertices_and_normals_interleaved.data() + idx_initial[RIGHT] * 6, volume.vertices_and_normals_interleaved.data() + idx_prev[RIGHT] * 6, sizeof(float) * 6); - volume.vertices_and_normals_interleaved.erase(volume.vertices_and_normals_interleaved.end() - 12, volume.vertices_and_normals_interleaved.end()); + geometry.set_vertex(idx_initial[Left], geometry.extract_position_3(idx_prev[Left]), geometry.extract_normal_3(idx_prev[Left])); + geometry.set_vertex(idx_initial[Right], geometry.extract_position_3(idx_prev[Right]), geometry.extract_normal_3(idx_prev[Right])); + geometry.remove_vertex(geometry.vertices_count() - 1); + geometry.remove_vertex(geometry.vertices_count() - 1); // Replace the left / right vertex indices to point to the start of the loop. - for (size_t u = volume.quad_indices.size() - 16; u < volume.quad_indices.size(); ++ u) { - if (volume.quad_indices[u] == idx_prev[LEFT]) - volume.quad_indices[u] = idx_initial[LEFT]; - else if (volume.quad_indices[u] == idx_prev[RIGHT]) - volume.quad_indices[u] = idx_initial[RIGHT]; + const size_t indices_count = geometry.indices_count(); + for (size_t u = indices_count - 24; u < indices_count; ++u) { + const unsigned int id = geometry.extract_uint_index(u); + if (id == (unsigned int)idx_prev[Left]) + geometry.set_uint_index(u, (unsigned int)idx_initial[Left]); + else if (id == (unsigned int)idx_prev[Right]) + geometry.set_uint_index(u, (unsigned int)idx_initial[Right]); } } } @@ -1783,235 +1555,232 @@ static void thick_lines_to_indexed_vertex_array( } // Only new allocate top / bottom vertices, if not closing a loop. - if (is_closing) { - idx_b[TOP] = idx_initial[TOP]; - } else { - idx_b[TOP] = idx_last ++; - volume.push_geometry(b(0), b(1), top_z , 0., 0., 1.); + if (is_closing) + idx_b[Top] = idx_initial[Top]; + else { + idx_b[Top] = idx_last++; + geometry.add_vertex(Vec3f(b.x(), b.y(), top_z), Vec3f(0.0f, 0.0f, 1.0f)); } - if (is_closing && (width == width_initial) && (bottom_z == bottom_z_initial)) { - idx_b[BOTTOM] = idx_initial[BOTTOM]; - } else { - idx_b[BOTTOM] = idx_last ++; - volume.push_geometry(b(0), b(1), bottom_z, 0., 0., -1.); + if (is_closing && width == width_initial && bottom_z == bottom_z_initial) + idx_b[Bottom] = idx_initial[Bottom]; + else { + idx_b[Bottom] = idx_last++; + geometry.add_vertex(Vec3f(b.x(), b.y(), bottom_z), Vec3f(0.0f, 0.0f, -1.0f)); } // Generate new vertices for the end of this line segment. - idx_b[LEFT ] = idx_last ++; - volume.push_geometry(b2(0), b2(1), middle_z, -xy_right_normal(0), -xy_right_normal(1), 0.0); - idx_b[RIGHT ] = idx_last ++; - volume.push_geometry(b1(0), b1(1), middle_z, xy_right_normal(0), xy_right_normal(1), 0.0); + idx_b[Left] = idx_last++; + geometry.add_vertex(Vec3f(b2.x(), b2.y(), middle_z), Vec3f(-xy_right_normal.x(), -xy_right_normal.y(), 0.0f)); + idx_b[Right] = idx_last++; + geometry.add_vertex(Vec3f(b1.x(), b1.y(), middle_z), Vec3f(xy_right_normal.x(), xy_right_normal.y(), 0.0f)); - memcpy(idx_prev, idx_b, 4 * sizeof(int)); + idx_prev = idx_b; bottom_z_prev = bottom_z; b1_prev = b1; v_prev = v; len_prev = len; - if (bottom_z_different && (closed || (!is_first && !is_last))) - { + if (bottom_z_different && (closed || (!is_first && !is_last))) { // Found a change of the layer thickness -> Add a cap at the beginning of this segment. - volume.push_quad(idx_a[BOTTOM], idx_a[RIGHT], idx_a[TOP], idx_a[LEFT]); + geometry.add_uint_triangle(idx_a[Bottom], idx_a[Right], idx_a[Top]); + geometry.add_uint_triangle(idx_a[Bottom], idx_a[Top], idx_a[Left]); } - if (! closed) { + if (!closed) { // Terminate open paths with caps. - if (is_first) - volume.push_quad(idx_a[BOTTOM], idx_a[RIGHT], idx_a[TOP], idx_a[LEFT]); + if (is_first) { + geometry.add_uint_triangle(idx_a[Bottom], idx_a[Right], idx_a[Top]); + geometry.add_uint_triangle(idx_a[Bottom], idx_a[Top], idx_a[Left]); + } // We don't use 'else' because both cases are true if we have only one line. - if (is_last) - volume.push_quad(idx_b[BOTTOM], idx_b[LEFT], idx_b[TOP], idx_b[RIGHT]); + if (is_last) { + geometry.add_uint_triangle(idx_b[Bottom], idx_b[Left], idx_b[Top]); + geometry.add_uint_triangle(idx_b[Bottom], idx_b[Top], idx_b[Right]); + } } // Add quads for a straight hollow tube-like segment. // bottom-right face - volume.push_quad(idx_a[BOTTOM], idx_b[BOTTOM], idx_b[RIGHT], idx_a[RIGHT]); + geometry.add_uint_triangle(idx_a[Bottom], idx_b[Bottom], idx_b[Right]); + geometry.add_uint_triangle(idx_a[Bottom], idx_b[Right], idx_a[Right]); // top-right face - volume.push_quad(idx_a[RIGHT], idx_b[RIGHT], idx_b[TOP], idx_a[TOP]); + geometry.add_uint_triangle(idx_a[Right], idx_b[Right], idx_b[Top]); + geometry.add_uint_triangle(idx_a[Right], idx_b[Top], idx_a[Top]); // top-left face - volume.push_quad(idx_a[TOP], idx_b[TOP], idx_b[LEFT], idx_a[LEFT]); + geometry.add_uint_triangle(idx_a[Top], idx_b[Top], idx_b[Left]); + geometry.add_uint_triangle(idx_a[Top], idx_b[Left], idx_a[Left]); // bottom-left face - volume.push_quad(idx_a[LEFT], idx_b[LEFT], idx_b[BOTTOM], idx_a[BOTTOM]); + geometry.add_uint_triangle(idx_a[Left], idx_b[Left], idx_b[Bottom]); + geometry.add_uint_triangle(idx_a[Left], idx_b[Bottom], idx_a[Bottom]); } - -#undef LEFT -#undef RIGHT -#undef TOP -#undef BOTTOM } // caller is responsible for supplying NO lines with zero length -static void thick_lines_to_indexed_vertex_array(const Lines3& lines, +static void thick_lines_to_geometry( + const Lines3& lines, const std::vector& widths, const std::vector& heights, - bool closed, - GLIndexedVertexArray& volume) + bool closed, + GUI::GLModel::Geometry& geometry) { assert(!lines.empty()); if (lines.empty()) return; -#define LEFT 0 -#define RIGHT 1 -#define TOP 2 -#define BOTTOM 3 + enum Direction : unsigned char + { + Left, + Right, + Top, + Bottom + }; // left, right, top, bottom - int idx_initial[4] = { -1, -1, -1, -1 }; - int idx_prev[4] = { -1, -1, -1, -1 }; - double z_prev = 0.0; - double len_prev = 0.0; - Vec3d n_right_prev = Vec3d::Zero(); - Vec3d n_top_prev = Vec3d::Zero(); - Vec3d unit_v_prev = Vec3d::Zero(); - double width_initial = 0.0; + std::array idx_prev = { -1, -1, -1, -1 }; + std::array idx_initial = { -1, -1, -1, -1 }; + + double z_prev = 0.0; + double len_prev = 0.0; + Vec3d n_right_prev = Vec3d::Zero(); + Vec3d n_top_prev = Vec3d::Zero(); + Vec3d unit_v_prev = Vec3d::Zero(); + double width_initial = 0.0; // new vertices around the line endpoints // left, right, top, bottom - Vec3d a[4] = { Vec3d::Zero(), Vec3d::Zero(), Vec3d::Zero(), Vec3d::Zero() }; - Vec3d b[4] = { Vec3d::Zero(), Vec3d::Zero(), Vec3d::Zero(), Vec3d::Zero() }; + std::array a = { Vec3d::Zero(), Vec3d::Zero(), Vec3d::Zero(), Vec3d::Zero() }; + std::array b = { Vec3d::Zero(), Vec3d::Zero(), Vec3d::Zero(), Vec3d::Zero() }; // loop once more in case of closed loops - size_t lines_end = closed ? (lines.size() + 1) : lines.size(); - for (size_t ii = 0; ii < lines_end; ++ii) - { - size_t i = (ii == lines.size()) ? 0 : ii; + const size_t lines_end = closed ? (lines.size() + 1) : lines.size(); + for (size_t ii = 0; ii < lines_end; ++ii) { + const size_t i = (ii == lines.size()) ? 0 : ii; const Line3& line = lines[i]; - double height = heights[i]; - double width = widths[i]; + const double height = heights[i]; + const double width = widths[i]; - Vec3d unit_v = unscale(line.vector()).normalized(); - double len = unscale(line.length()); + const Vec3d unit_v = unscale(line.vector()).normalized(); + const double len = unscale(line.length()); Vec3d n_top = Vec3d::Zero(); Vec3d n_right = Vec3d::Zero(); - if ((line.a(0) == line.b(0)) && (line.a(1) == line.b(1))) - { + if (line.a.x() == line.b.x() && line.a.y() == line.b.y()) { // vertical segment n_top = Vec3d::UnitY(); n_right = Vec3d::UnitX(); - if (line.a(2) < line.b(2)) + if (line.a.z() < line.b.z()) n_right = -n_right; } - else - { + else { // horizontal segment n_right = unit_v.cross(Vec3d::UnitZ()).normalized(); n_top = n_right.cross(unit_v).normalized(); } - Vec3d rl_displacement = 0.5 * width * n_right; - Vec3d tb_displacement = 0.5 * height * n_top; - Vec3d l_a = unscale(line.a); - Vec3d l_b = unscale(line.b); + const Vec3d rl_displacement = 0.5 * width * n_right; + const Vec3d tb_displacement = 0.5 * height * n_top; + const Vec3d l_a = unscale(line.a); + const Vec3d l_b = unscale(line.b); - a[RIGHT] = l_a + rl_displacement; - a[LEFT] = l_a - rl_displacement; - a[TOP] = l_a + tb_displacement; - a[BOTTOM] = l_a - tb_displacement; - b[RIGHT] = l_b + rl_displacement; - b[LEFT] = l_b - rl_displacement; - b[TOP] = l_b + tb_displacement; - b[BOTTOM] = l_b - tb_displacement; + a[Right] = l_a + rl_displacement; + a[Left] = l_a - rl_displacement; + a[Top] = l_a + tb_displacement; + a[Bottom] = l_a - tb_displacement; + b[Right] = l_b + rl_displacement; + b[Left] = l_b - rl_displacement; + b[Top] = l_b + tb_displacement; + b[Bottom] = l_b - tb_displacement; - Vec3d n_bottom = -n_top; - Vec3d n_left = -n_right; + const Vec3d n_bottom = -n_top; + const Vec3d n_left = -n_right; - int idx_a[4]; - int idx_b[4]; - int idx_last = int(volume.vertices_and_normals_interleaved.size() / 6); + std::array idx_a = { 0, 0, 0, 0}; + std::array idx_b = { 0, 0, 0, 0 }; + int idx_last = int(geometry.vertices_count()); - bool z_different = (z_prev != l_a(2)); - z_prev = l_b(2); + const bool z_different = (z_prev != l_a.z()); + z_prev = l_b.z(); // Share top / bottom vertices if possible. - if (ii == 0) - { - idx_a[TOP] = idx_last++; - volume.push_geometry(a[TOP], n_top); + if (ii == 0) { + idx_a[Top] = idx_last++; + geometry.add_vertex((Vec3f)a[Top].cast(), (Vec3f)n_top.cast()); } else - idx_a[TOP] = idx_prev[TOP]; + idx_a[Top] = idx_prev[Top]; - if ((ii == 0) || z_different) - { + if (ii == 0 || z_different) { // Start of the 1st line segment or a change of the layer thickness while maintaining the print_z. - idx_a[BOTTOM] = idx_last++; - volume.push_geometry(a[BOTTOM], n_bottom); - idx_a[LEFT] = idx_last++; - volume.push_geometry(a[LEFT], n_left); - idx_a[RIGHT] = idx_last++; - volume.push_geometry(a[RIGHT], n_right); + idx_a[Bottom] = idx_last++; + geometry.add_vertex((Vec3f)a[Bottom].cast(), (Vec3f)n_bottom.cast()); + idx_a[Left] = idx_last++; + geometry.add_vertex((Vec3f)a[Left].cast(), (Vec3f)n_left.cast()); + idx_a[Right] = idx_last++; + geometry.add_vertex((Vec3f)a[Right].cast(), (Vec3f)n_right.cast()); } else - idx_a[BOTTOM] = idx_prev[BOTTOM]; + idx_a[Bottom] = idx_prev[Bottom]; - if (ii == 0) - { + if (ii == 0) { // Start of the 1st line segment. width_initial = width; - ::memcpy(idx_initial, idx_a, sizeof(int) * 4); + idx_initial = idx_a; } - else - { + else { // Continuing a previous segment. // Share left / right vertices if possible. - double v_dot = unit_v_prev.dot(unit_v); - bool is_right_turn = n_top_prev.dot(unit_v_prev.cross(unit_v)) > 0.0; + const double v_dot = unit_v_prev.dot(unit_v); + const bool is_right_turn = n_top_prev.dot(unit_v_prev.cross(unit_v)) > 0.0; // To reduce gpu memory usage, we try to reuse vertices - // To reduce the visual artifacts, due to averaged normals, we allow to reuse vertices only when any of two adjacent edges + // To reduce the visual artifacts, due to averaged normals, we allow to reuse vertices only when any of two adjacent edges // is longer than a fixed threshold. // The following value is arbitrary, it comes from tests made on a bunch of models showing the visual artifacts - double len_threshold = 2.5; + const double len_threshold = 2.5; // Generate new vertices if the angle between adjacent edges is greater than 45 degrees or thresholds conditions are met - bool is_sharp = (v_dot < 0.707) || (len_prev > len_threshold) || (len > len_threshold); - if (is_sharp) - { + const bool is_sharp = v_dot < 0.707 || len_prev > len_threshold || len > len_threshold; + if (is_sharp) { // Allocate new left / right points for the start of this segment as these points will receive their own normals to indicate a sharp turn. - idx_a[RIGHT] = idx_last++; - volume.push_geometry(a[RIGHT], n_right); - idx_a[LEFT] = idx_last++; - volume.push_geometry(a[LEFT], n_left); + idx_a[Right] = idx_last++; + geometry.add_vertex((Vec3f)a[Right].cast(), (Vec3f)n_right.cast()); + idx_a[Left] = idx_last++; + geometry.add_vertex((Vec3f)a[Left].cast(), (Vec3f)n_left.cast()); - if (is_right_turn) - { + if (is_right_turn) { // Right turn. Fill in the right turn wedge. - volume.push_triangle(idx_prev[RIGHT], idx_a[RIGHT], idx_prev[TOP]); - volume.push_triangle(idx_prev[RIGHT], idx_prev[BOTTOM], idx_a[RIGHT]); + geometry.add_uint_triangle(idx_prev[Right], idx_a[Right], idx_prev[Top]); + geometry.add_uint_triangle(idx_prev[Right], idx_prev[Bottom], idx_a[Right]); } - else - { + else { // Left turn. Fill in the left turn wedge. - volume.push_triangle(idx_prev[LEFT], idx_prev[TOP], idx_a[LEFT]); - volume.push_triangle(idx_prev[LEFT], idx_a[LEFT], idx_prev[BOTTOM]); + geometry.add_uint_triangle(idx_prev[Left], idx_prev[Top], idx_a[Left]); + geometry.add_uint_triangle(idx_prev[Left], idx_a[Left], idx_prev[Bottom]); } } - else - { + else { // The two successive segments are nearly collinear. - idx_a[LEFT] = idx_prev[LEFT]; - idx_a[RIGHT] = idx_prev[RIGHT]; + idx_a[Left] = idx_prev[Left]; + idx_a[Right] = idx_prev[Right]; } - if (ii == lines.size()) - { - if (!is_sharp) - { + if (ii == lines.size()) { + if (!is_sharp) { // Closing a loop with smooth transition. Unify the closing left / right vertices. - ::memcpy(volume.vertices_and_normals_interleaved.data() + idx_initial[LEFT] * 6, volume.vertices_and_normals_interleaved.data() + idx_prev[LEFT] * 6, sizeof(float) * 6); - ::memcpy(volume.vertices_and_normals_interleaved.data() + idx_initial[RIGHT] * 6, volume.vertices_and_normals_interleaved.data() + idx_prev[RIGHT] * 6, sizeof(float) * 6); - volume.vertices_and_normals_interleaved.erase(volume.vertices_and_normals_interleaved.end() - 12, volume.vertices_and_normals_interleaved.end()); + geometry.set_vertex(idx_initial[Left], geometry.extract_position_3(idx_prev[Left]), geometry.extract_normal_3(idx_prev[Left])); + geometry.set_vertex(idx_initial[Right], geometry.extract_position_3(idx_prev[Right]), geometry.extract_normal_3(idx_prev[Right])); + geometry.remove_vertex(geometry.vertices_count() - 1); + geometry.remove_vertex(geometry.vertices_count() - 1); // Replace the left / right vertex indices to point to the start of the loop. - for (size_t u = volume.quad_indices.size() - 16; u < volume.quad_indices.size(); ++u) - { - if (volume.quad_indices[u] == idx_prev[LEFT]) - volume.quad_indices[u] = idx_initial[LEFT]; - else if (volume.quad_indices[u] == idx_prev[RIGHT]) - volume.quad_indices[u] = idx_initial[RIGHT]; + const size_t indices_count = geometry.indices_count(); + for (size_t u = indices_count - 24; u < indices_count; ++u) { + const unsigned int id = geometry.extract_uint_index(u); + if (id == (unsigned int)idx_prev[Left]) + geometry.set_uint_index(u, (unsigned int)idx_initial[Left]); + else if (id == (unsigned int)idx_prev[Right]) + geometry.set_uint_index(u, (unsigned int)idx_initial[Right]); } } @@ -2021,246 +1790,161 @@ static void thick_lines_to_indexed_vertex_array(const Lines3& lines, } // Only new allocate top / bottom vertices, if not closing a loop. - if (closed && (ii + 1 == lines.size())) - idx_b[TOP] = idx_initial[TOP]; - else - { - idx_b[TOP] = idx_last++; - volume.push_geometry(b[TOP], n_top); + if (closed && ii + 1 == lines.size()) + idx_b[Top] = idx_initial[Top]; + else { + idx_b[Top] = idx_last++; + geometry.add_vertex((Vec3f)b[Top].cast(), (Vec3f)n_top.cast()); } - if (closed && (ii + 1 == lines.size()) && (width == width_initial)) - idx_b[BOTTOM] = idx_initial[BOTTOM]; - else - { - idx_b[BOTTOM] = idx_last++; - volume.push_geometry(b[BOTTOM], n_bottom); + if (closed && ii + 1 == lines.size() && width == width_initial) + idx_b[Bottom] = idx_initial[Bottom]; + else { + idx_b[Bottom] = idx_last++; + geometry.add_vertex((Vec3f)b[Bottom].cast(), (Vec3f)n_bottom.cast()); } // Generate new vertices for the end of this line segment. - idx_b[LEFT] = idx_last++; - volume.push_geometry(b[LEFT], n_left); - idx_b[RIGHT] = idx_last++; - volume.push_geometry(b[RIGHT], n_right); + idx_b[Left] = idx_last++; + geometry.add_vertex((Vec3f)b[Left].cast(), (Vec3f)n_left.cast()); + idx_b[Right] = idx_last++; + geometry.add_vertex((Vec3f)b[Right].cast(), (Vec3f)n_right.cast()); - ::memcpy(idx_prev, idx_b, 4 * sizeof(int)); + idx_prev = idx_b; n_right_prev = n_right; n_top_prev = n_top; unit_v_prev = unit_v; len_prev = len; - if (!closed) - { + if (!closed) { // Terminate open paths with caps. - if (i == 0) - volume.push_quad(idx_a[BOTTOM], idx_a[RIGHT], idx_a[TOP], idx_a[LEFT]); + if (i == 0) { + geometry.add_uint_triangle(idx_a[Bottom], idx_a[Right], idx_a[Top]); + geometry.add_uint_triangle(idx_a[Bottom], idx_a[Top], idx_a[Left]); + } // We don't use 'else' because both cases are true if we have only one line. - if (i + 1 == lines.size()) - volume.push_quad(idx_b[BOTTOM], idx_b[LEFT], idx_b[TOP], idx_b[RIGHT]); + if (i + 1 == lines.size()) { + geometry.add_uint_triangle(idx_b[Bottom], idx_b[Left], idx_b[Top]); + geometry.add_uint_triangle(idx_b[Bottom], idx_b[Top], idx_b[Right]); + } } // Add quads for a straight hollow tube-like segment. // bottom-right face - volume.push_quad(idx_a[BOTTOM], idx_b[BOTTOM], idx_b[RIGHT], idx_a[RIGHT]); + geometry.add_uint_triangle(idx_a[Bottom], idx_b[Bottom], idx_b[Right]); + geometry.add_uint_triangle(idx_a[Bottom], idx_b[Right], idx_a[Right]); // top-right face - volume.push_quad(idx_a[RIGHT], idx_b[RIGHT], idx_b[TOP], idx_a[TOP]); + geometry.add_uint_triangle(idx_a[Right], idx_b[Right], idx_b[Top]); + geometry.add_uint_triangle(idx_a[Right], idx_b[Top], idx_a[Top]); // top-left face - volume.push_quad(idx_a[TOP], idx_b[TOP], idx_b[LEFT], idx_a[LEFT]); + geometry.add_uint_triangle(idx_a[Top], idx_b[Top], idx_b[Left]); + geometry.add_uint_triangle(idx_a[Top], idx_b[Left], idx_a[Left]); // bottom-left face - volume.push_quad(idx_a[LEFT], idx_b[LEFT], idx_b[BOTTOM], idx_a[BOTTOM]); + geometry.add_uint_triangle(idx_a[Left], idx_b[Left], idx_b[Bottom]); + geometry.add_uint_triangle(idx_a[Left], idx_b[Bottom], idx_a[Bottom]); } - -#undef LEFT -#undef RIGHT -#undef TOP -#undef BOTTOM -} - -static void point_to_indexed_vertex_array(const Vec3crd& point, - double width, - double height, - GLIndexedVertexArray& volume) -{ - // builds a double piramid, with vertices on the local axes, around the point - - Vec3d center = unscale(point); - - double scale_factor = 1.0; - double w = scale_factor * width; - double h = scale_factor * height; - - // new vertices ids - int idx_last = int(volume.vertices_and_normals_interleaved.size() / 6); - int idxs[6]; - for (int i = 0; i < 6; ++i) - { - idxs[i] = idx_last + i; - } - - Vec3d displacement_x(w, 0.0, 0.0); - Vec3d displacement_y(0.0, w, 0.0); - Vec3d displacement_z(0.0, 0.0, h); - - Vec3d unit_x(1.0, 0.0, 0.0); - Vec3d unit_y(0.0, 1.0, 0.0); - Vec3d unit_z(0.0, 0.0, 1.0); - - // vertices - volume.push_geometry(center - displacement_x, -unit_x); // idxs[0] - volume.push_geometry(center + displacement_x, unit_x); // idxs[1] - volume.push_geometry(center - displacement_y, -unit_y); // idxs[2] - volume.push_geometry(center + displacement_y, unit_y); // idxs[3] - volume.push_geometry(center - displacement_z, -unit_z); // idxs[4] - volume.push_geometry(center + displacement_z, unit_z); // idxs[5] - - // top piramid faces - volume.push_triangle(idxs[0], idxs[2], idxs[5]); - volume.push_triangle(idxs[2], idxs[1], idxs[5]); - volume.push_triangle(idxs[1], idxs[3], idxs[5]); - volume.push_triangle(idxs[3], idxs[0], idxs[5]); - - // bottom piramid faces - volume.push_triangle(idxs[2], idxs[0], idxs[4]); - volume.push_triangle(idxs[1], idxs[2], idxs[4]); - volume.push_triangle(idxs[3], idxs[1], idxs[4]); - volume.push_triangle(idxs[0], idxs[3], idxs[4]); } void _3DScene::thick_lines_to_verts( - const Lines &lines, - const std::vector &widths, - const std::vector &heights, - bool closed, - double top_z, - GLVolume &volume) -{ - thick_lines_to_indexed_vertex_array(lines, widths, heights, closed, top_z, volume.indexed_vertex_array); -} - -void _3DScene::thick_lines_to_verts(const Lines3& lines, + const Lines& lines, const std::vector& widths, const std::vector& heights, - bool closed, - GLVolume& volume) + bool closed, + double top_z, + GUI::GLModel::Geometry& geometry) { - thick_lines_to_indexed_vertex_array(lines, widths, heights, closed, volume.indexed_vertex_array); + thick_lines_to_geometry(lines, widths, heights, closed, top_z, geometry); } -static void thick_point_to_verts(const Vec3crd& point, - double width, - double height, - GLVolume& volume) +void _3DScene::thick_lines_to_verts( + const Lines3& lines, + const std::vector& widths, + const std::vector& heights, + bool closed, + GUI::GLModel::Geometry& geometry) { - point_to_indexed_vertex_array(point, width, height, volume.indexed_vertex_array); -} - -void _3DScene::extrusionentity_to_verts(const Polyline &polyline, float width, float height, float print_z, GLVolume& volume) -{ - if (polyline.size() >= 2) { - size_t num_segments = polyline.size() - 1; - thick_lines_to_verts(polyline.lines(), std::vector(num_segments, width), std::vector(num_segments, height), false, print_z, volume); - } + thick_lines_to_geometry(lines, widths, heights, closed, geometry); } // Fill in the qverts and tverts with quads and triangles for the extrusion_path. -void _3DScene::extrusionentity_to_verts(const ExtrusionPath &extrusion_path, float print_z, GLVolume &volume) -{ - extrusionentity_to_verts(extrusion_path.polyline, extrusion_path.width, extrusion_path.height, print_z, volume); -} - -// Fill in the qverts and tverts with quads and triangles for the extrusion_path. -void _3DScene::extrusionentity_to_verts(const ExtrusionPath &extrusion_path, float print_z, const Point ©, GLVolume &volume) +void _3DScene::extrusionentity_to_verts(const ExtrusionPath& extrusion_path, float print_z, const Point& copy, GUI::GLModel::Geometry& geometry) { Polyline polyline = extrusion_path.polyline; polyline.remove_duplicate_points(); polyline.translate(copy); - Lines lines = polyline.lines(); + const Lines lines = polyline.lines(); std::vector widths(lines.size(), extrusion_path.width); std::vector heights(lines.size(), extrusion_path.height); - thick_lines_to_verts(lines, widths, heights, false, print_z, volume); + thick_lines_to_verts(lines, widths, heights, false, print_z, geometry); } // Fill in the qverts and tverts with quads and triangles for the extrusion_loop. -void _3DScene::extrusionentity_to_verts(const ExtrusionLoop &extrusion_loop, float print_z, const Point ©, GLVolume &volume) +void _3DScene::extrusionentity_to_verts(const ExtrusionLoop& extrusion_loop, float print_z, const Point& copy, GUI::GLModel::Geometry& geometry) { Lines lines; std::vector widths; std::vector heights; - for (const ExtrusionPath &extrusion_path : extrusion_loop.paths) { + for (const ExtrusionPath& extrusion_path : extrusion_loop.paths) { Polyline polyline = extrusion_path.polyline; polyline.remove_duplicate_points(); polyline.translate(copy); - Lines lines_this = polyline.lines(); + const Lines lines_this = polyline.lines(); append(lines, lines_this); widths.insert(widths.end(), lines_this.size(), extrusion_path.width); heights.insert(heights.end(), lines_this.size(), extrusion_path.height); } - thick_lines_to_verts(lines, widths, heights, true, print_z, volume); + thick_lines_to_verts(lines, widths, heights, true, print_z, geometry); } // Fill in the qverts and tverts with quads and triangles for the extrusion_multi_path. -void _3DScene::extrusionentity_to_verts(const ExtrusionMultiPath &extrusion_multi_path, float print_z, const Point ©, GLVolume &volume) +void _3DScene::extrusionentity_to_verts(const ExtrusionMultiPath& extrusion_multi_path, float print_z, const Point& copy, GUI::GLModel::Geometry& geometry) { Lines lines; std::vector widths; std::vector heights; - for (const ExtrusionPath &extrusion_path : extrusion_multi_path.paths) { + for (const ExtrusionPath& extrusion_path : extrusion_multi_path.paths) { Polyline polyline = extrusion_path.polyline; polyline.remove_duplicate_points(); polyline.translate(copy); - Lines lines_this = polyline.lines(); + const Lines lines_this = polyline.lines(); append(lines, lines_this); widths.insert(widths.end(), lines_this.size(), extrusion_path.width); heights.insert(heights.end(), lines_this.size(), extrusion_path.height); } - thick_lines_to_verts(lines, widths, heights, false, print_z, volume); + thick_lines_to_verts(lines, widths, heights, false, print_z, geometry); } -void _3DScene::extrusionentity_to_verts(const ExtrusionEntityCollection &extrusion_entity_collection, float print_z, const Point ©, GLVolume &volume) +void _3DScene::extrusionentity_to_verts(const ExtrusionEntityCollection& extrusion_entity_collection, float print_z, const Point& copy, GUI::GLModel::Geometry& geometry) { - for (const ExtrusionEntity *extrusion_entity : extrusion_entity_collection.entities) - extrusionentity_to_verts(extrusion_entity, print_z, copy, volume); + for (const ExtrusionEntity* extrusion_entity : extrusion_entity_collection.entities) + extrusionentity_to_verts(extrusion_entity, print_z, copy, geometry); } -void _3DScene::extrusionentity_to_verts(const ExtrusionEntity *extrusion_entity, float print_z, const Point ©, GLVolume &volume) +void _3DScene::extrusionentity_to_verts(const ExtrusionEntity* extrusion_entity, float print_z, const Point& copy, GUI::GLModel::Geometry& geometry) { if (extrusion_entity != nullptr) { - auto *extrusion_path = dynamic_cast(extrusion_entity); + auto* extrusion_path = dynamic_cast(extrusion_entity); if (extrusion_path != nullptr) - extrusionentity_to_verts(*extrusion_path, print_z, copy, volume); + extrusionentity_to_verts(*extrusion_path, print_z, copy, geometry); else { - auto *extrusion_loop = dynamic_cast(extrusion_entity); + auto* extrusion_loop = dynamic_cast(extrusion_entity); if (extrusion_loop != nullptr) - extrusionentity_to_verts(*extrusion_loop, print_z, copy, volume); + extrusionentity_to_verts(*extrusion_loop, print_z, copy, geometry); else { - auto *extrusion_multi_path = dynamic_cast(extrusion_entity); + auto* extrusion_multi_path = dynamic_cast(extrusion_entity); if (extrusion_multi_path != nullptr) - extrusionentity_to_verts(*extrusion_multi_path, print_z, copy, volume); + extrusionentity_to_verts(*extrusion_multi_path, print_z, copy, geometry); else { - auto *extrusion_entity_collection = dynamic_cast(extrusion_entity); + auto* extrusion_entity_collection = dynamic_cast(extrusion_entity); if (extrusion_entity_collection != nullptr) - extrusionentity_to_verts(*extrusion_entity_collection, print_z, copy, volume); - else { + extrusionentity_to_verts(*extrusion_entity_collection, print_z, copy, geometry); + else throw Slic3r::RuntimeError("Unexpected extrusion_entity type in to_verts()"); - } } } } } } -void _3DScene::polyline3_to_verts(const Polyline3& polyline, double width, double height, GLVolume& volume) -{ - Lines3 lines = polyline.lines(); - std::vector widths(lines.size(), width); - std::vector heights(lines.size(), height); - thick_lines_to_verts(lines, widths, heights, false, volume); -} - -void _3DScene::point3_to_verts(const Vec3crd& point, double width, double height, GLVolume& volume) -{ - thick_point_to_verts(point, width, height, volume); -} - } // namespace Slic3r diff --git a/src/slic3r/GUI/3DScene.hpp b/src/slic3r/GUI/3DScene.hpp index 83101754b5..5c01e22f9c 100644 --- a/src/slic3r/GUI/3DScene.hpp +++ b/src/slic3r/GUI/3DScene.hpp @@ -57,207 +57,6 @@ using ModelObjectPtrs = std::vector; // Return appropriate color based on the ModelVolume. extern ColorRGBA color_from_model_volume(const ModelVolume& model_volume); -// A container for interleaved arrays of 3D vertices and normals, -// possibly indexed by triangles and / or quads. -class GLIndexedVertexArray { -public: - // Only Eigen types of Nx16 size are vectorized. This bounding box will not be vectorized. - static_assert(sizeof(Eigen::AlignedBox) == 24, "Eigen::AlignedBox is not being vectorized, thus it does not need to be aligned"); - using BoundingBox = Eigen::AlignedBox; - - GLIndexedVertexArray() { m_bounding_box.setEmpty(); } - GLIndexedVertexArray(const GLIndexedVertexArray &rhs) : - vertices_and_normals_interleaved(rhs.vertices_and_normals_interleaved), - triangle_indices(rhs.triangle_indices), - quad_indices(rhs.quad_indices), - m_bounding_box(rhs.m_bounding_box) - { assert(!rhs.has_VBOs()); m_bounding_box.setEmpty(); } - GLIndexedVertexArray(GLIndexedVertexArray &&rhs) : - vertices_and_normals_interleaved(std::move(rhs.vertices_and_normals_interleaved)), - triangle_indices(std::move(rhs.triangle_indices)), - quad_indices(std::move(rhs.quad_indices)), - m_bounding_box(rhs.m_bounding_box) - { assert(! rhs.has_VBOs()); } - - ~GLIndexedVertexArray() { release_geometry(); } - - GLIndexedVertexArray& operator=(const GLIndexedVertexArray &rhs) - { - assert(vertices_and_normals_interleaved_VBO_id == 0); - assert(triangle_indices_VBO_id == 0); - assert(quad_indices_VBO_id == 0); - assert(rhs.vertices_and_normals_interleaved_VBO_id == 0); - assert(rhs.triangle_indices_VBO_id == 0); - assert(rhs.quad_indices_VBO_id == 0); - this->vertices_and_normals_interleaved = rhs.vertices_and_normals_interleaved; - this->triangle_indices = rhs.triangle_indices; - this->quad_indices = rhs.quad_indices; - this->m_bounding_box = rhs.m_bounding_box; - this->vertices_and_normals_interleaved_size = rhs.vertices_and_normals_interleaved_size; - this->triangle_indices_size = rhs.triangle_indices_size; - this->quad_indices_size = rhs.quad_indices_size; - return *this; - } - - GLIndexedVertexArray& operator=(GLIndexedVertexArray &&rhs) - { - assert(vertices_and_normals_interleaved_VBO_id == 0); - assert(triangle_indices_VBO_id == 0); - assert(quad_indices_VBO_id == 0); - assert(rhs.vertices_and_normals_interleaved_VBO_id == 0); - assert(rhs.triangle_indices_VBO_id == 0); - assert(rhs.quad_indices_VBO_id == 0); - this->vertices_and_normals_interleaved = std::move(rhs.vertices_and_normals_interleaved); - this->triangle_indices = std::move(rhs.triangle_indices); - this->quad_indices = std::move(rhs.quad_indices); - this->m_bounding_box = rhs.m_bounding_box; - this->vertices_and_normals_interleaved_size = rhs.vertices_and_normals_interleaved_size; - this->triangle_indices_size = rhs.triangle_indices_size; - this->quad_indices_size = rhs.quad_indices_size; - return *this; - } - - // Vertices and their normals, interleaved to be used by void glInterleavedArrays(GL_N3F_V3F, 0, x) - std::vector vertices_and_normals_interleaved; - std::vector triangle_indices; - std::vector quad_indices; - - // When the geometry data is loaded into the graphics card as Vertex Buffer Objects, - // the above mentioned std::vectors are cleared and the following variables keep their original length. - size_t vertices_and_normals_interleaved_size{ 0 }; - size_t triangle_indices_size{ 0 }; - size_t quad_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_and_normals_interleaved_VBO_id{ 0 }; - unsigned int triangle_indices_VBO_id{ 0 }; - unsigned int quad_indices_VBO_id{ 0 }; - -#if ENABLE_SMOOTH_NORMALS - void load_mesh_full_shading(const TriangleMesh& mesh, bool smooth_normals = false); - void load_mesh(const TriangleMesh& mesh, bool smooth_normals = false) { this->load_mesh_full_shading(mesh, smooth_normals); } -#else - void load_mesh_full_shading(const TriangleMesh& mesh); - void load_mesh(const TriangleMesh& mesh) { this->load_mesh_full_shading(mesh); } -#endif // ENABLE_SMOOTH_NORMALS - - void load_its_flat_shading(const indexed_triangle_set &its); - - inline bool has_VBOs() const { return vertices_and_normals_interleaved_VBO_id != 0; } - - inline void reserve(size_t sz) { - this->vertices_and_normals_interleaved.reserve(sz * 6); - this->triangle_indices.reserve(sz * 3); - this->quad_indices.reserve(sz * 4); - } - - inline void push_geometry(float x, float y, float z, float nx, float ny, float nz) { - assert(this->vertices_and_normals_interleaved_VBO_id == 0); - if (this->vertices_and_normals_interleaved_VBO_id != 0) - return; - - if (this->vertices_and_normals_interleaved.size() + 6 > this->vertices_and_normals_interleaved.capacity()) - this->vertices_and_normals_interleaved.reserve(next_highest_power_of_2(this->vertices_and_normals_interleaved.size() + 6)); - this->vertices_and_normals_interleaved.emplace_back(nx); - this->vertices_and_normals_interleaved.emplace_back(ny); - this->vertices_and_normals_interleaved.emplace_back(nz); - this->vertices_and_normals_interleaved.emplace_back(x); - this->vertices_and_normals_interleaved.emplace_back(y); - this->vertices_and_normals_interleaved.emplace_back(z); - - this->vertices_and_normals_interleaved_size = this->vertices_and_normals_interleaved.size(); - m_bounding_box.extend(Vec3f(x, y, z)); - }; - - inline void push_geometry(double x, double y, double z, double nx, double ny, double nz) { - push_geometry(float(x), float(y), float(z), float(nx), float(ny), float(nz)); - } - - template - inline void push_geometry(const Eigen::MatrixBase& p, const Eigen::MatrixBase& n) { - push_geometry(float(p(0)), float(p(1)), float(p(2)), float(n(0)), float(n(1)), float(n(2))); - } - - inline void push_triangle(int idx1, int idx2, int idx3) { - assert(this->vertices_and_normals_interleaved_VBO_id == 0); - if (this->vertices_and_normals_interleaved_VBO_id != 0) - return; - - if (this->triangle_indices.size() + 3 > this->vertices_and_normals_interleaved.capacity()) - this->triangle_indices.reserve(next_highest_power_of_2(this->triangle_indices.size() + 3)); - this->triangle_indices.emplace_back(idx1); - this->triangle_indices.emplace_back(idx2); - this->triangle_indices.emplace_back(idx3); - this->triangle_indices_size = this->triangle_indices.size(); - }; - - inline void push_quad(int idx1, int idx2, int idx3, int idx4) { - assert(this->vertices_and_normals_interleaved_VBO_id == 0); - if (this->vertices_and_normals_interleaved_VBO_id != 0) - return; - - if (this->quad_indices.size() + 4 > this->vertices_and_normals_interleaved.capacity()) - this->quad_indices.reserve(next_highest_power_of_2(this->quad_indices.size() + 4)); - this->quad_indices.emplace_back(idx1); - this->quad_indices.emplace_back(idx2); - this->quad_indices.emplace_back(idx3); - this->quad_indices.emplace_back(idx4); - this->quad_indices_size = this->quad_indices.size(); - }; - - // Finalize the initialization of the geometry & indices, - // upload the geometry and indices to OpenGL VBO objects - // and shrink the allocated data, possibly relasing it if it has been loaded into the VBOs. - void finalize_geometry(bool opengl_initialized); - // Release the geometry data, release OpenGL VBOs. - void release_geometry(); - - void render() const; - void render(const std::pair& tverts_range, const std::pair& qverts_range) const; - - // Is there any geometry data stored? - bool empty() const { return vertices_and_normals_interleaved_size == 0; } - - void clear() { - this->vertices_and_normals_interleaved.clear(); - this->triangle_indices.clear(); - this->quad_indices.clear(); - vertices_and_normals_interleaved_size = 0; - triangle_indices_size = 0; - quad_indices_size = 0; - m_bounding_box.setEmpty(); - } - - // Shrink the internal storage to tighly fit the data stored. - void shrink_to_fit() { - this->vertices_and_normals_interleaved.shrink_to_fit(); - this->triangle_indices.shrink_to_fit(); - this->quad_indices.shrink_to_fit(); - } - - const BoundingBox& bounding_box() const { return m_bounding_box; } - - // Return an estimate of the memory consumed by this class. - size_t cpu_memory_used() const { return sizeof(*this) + vertices_and_normals_interleaved.capacity() * sizeof(float) + triangle_indices.capacity() * sizeof(int) + quad_indices.capacity() * sizeof(int); } - // Return an estimate of the memory held by GPU vertex buffers. - size_t gpu_memory_used() const - { - size_t memsize = 0; - if (this->vertices_and_normals_interleaved_VBO_id != 0) - memsize += this->vertices_and_normals_interleaved_size * 4; - if (this->triangle_indices_VBO_id != 0) - memsize += this->triangle_indices_size * 4; - if (this->quad_indices_VBO_id != 0) - memsize += this->quad_indices_size * 4; - return memsize; - } - size_t total_memory_used() const { return this->cpu_memory_used() + this->gpu_memory_used(); } - -private: - BoundingBox m_bounding_box; -}; - class GLVolume { public: std::string name; @@ -400,15 +199,13 @@ public: // Is mouse or rectangle selection over this object to select/deselect it ? EHoverState hover; - // Interleaved triangles & normals with indexed triangles & quads. - GLIndexedVertexArray indexed_vertex_array; + GUI::GLModel model; // BBS - mutable std::vector mmuseg_ivas; + mutable std::vector mmuseg_models; mutable ObjectBase::Timestamp mmuseg_ts; // Ranges of triangle and quad indices to be rendered. std::pair tverts_range; - std::pair qverts_range; // If the qverts or tverts contain thick extrusions, then offsets keeps pointers of the starts // of the extrusions per layer. @@ -418,13 +215,7 @@ public: // Bounding box of this volume, in unscaled coordinates. BoundingBoxf3 bounding_box() const { - BoundingBoxf3 out; - if (! this->indexed_vertex_array.bounding_box().isEmpty()) { - out.min = this->indexed_vertex_array.bounding_box().min().cast(); - out.max = this->indexed_vertex_array.bounding_box().max().cast(); - out.defined = true; - }; - return out; + return this->model.get_bounding_box(); } void set_color(const ColorRGBA& rgba) { color = rgba; } @@ -517,18 +308,15 @@ public: // convex hull const TriangleMesh* convex_hull() const { return m_convex_hull.get(); } - bool empty() const { return this->indexed_vertex_array.empty(); } + bool empty() const { return this->model.is_empty(); } void set_range(double low, double high); //BBS: add outline related logic and add virtual specifier - virtual void render(bool with_outline = false) const; + virtual void render(bool with_outline = false); //BBS: add simple render function for thumbnail - void simple_render(GLShaderProgram* shader, ModelObjectPtrs& model_objects, std::vector& extruder_colors) const; - - void finalize_geometry(bool opengl_initialized) { this->indexed_vertex_array.finalize_geometry(opengl_initialized); } - void release_geometry() { this->indexed_vertex_array.release_geometry(); } + void simple_render(GLShaderProgram* shader, ModelObjectPtrs& model_objects, std::vector& extruder_colors); void set_bounding_boxes_as_dirty() { m_transformed_bounding_box.reset(); @@ -545,11 +333,11 @@ public: // Return an estimate of the memory consumed by this class. size_t cpu_memory_used() const { - //FIXME what to do wih m_convex_hull? - return sizeof(*this) - sizeof(this->indexed_vertex_array) + this->indexed_vertex_array.cpu_memory_used() + this->print_zs.capacity() * sizeof(coordf_t) + this->offsets.capacity() * sizeof(size_t); + return sizeof(*this) + this->model.cpu_memory_used() + this->print_zs.capacity() * sizeof(coordf_t) + + this->offsets.capacity() * sizeof(size_t); } // Return an estimate of the memory held by GPU vertex buffers. - size_t gpu_memory_used() const { return this->indexed_vertex_array.gpu_memory_used(); } + size_t gpu_memory_used() const { return this->model.gpu_memory_used(); } size_t total_memory_used() const { return this->cpu_memory_used() + this->gpu_memory_used(); } }; @@ -557,9 +345,9 @@ public: class GLWipeTowerVolume : public GLVolume { public: GLWipeTowerVolume(const std::vector& colors); - virtual void render(bool with_outline = false) const; + virtual void render(bool with_outline = false); - std::vector iva_per_colors; + std::vector model_per_colors; bool IsTransparent(); private: @@ -627,17 +415,15 @@ public: ~GLVolumeCollection() { clear(); } std::vector load_object( - const ModelObject *model_object, + const ModelObject* model_object, int obj_idx, - const std::vector &instance_idxs, - bool opengl_initialized); + const std::vector& instance_idxs); int load_object_volume( - const ModelObject *model_object, + const ModelObject* model_object, int obj_idx, int volume_idx, int instance_idx, - bool opengl_initialized, bool in_assemble_view = false, bool use_loaded_id = false); @@ -649,14 +435,13 @@ public: const std::vector>& instances, SLAPrintObjectStep milestone, // Timestamp of the last change of the milestone - size_t timestamp, - bool opengl_initialized); + size_t timestamp); int load_wipe_tower_preview( - int obj_idx, float pos_x, float pos_y, float width, float depth, float height, float rotation_angle, bool size_unknown, float brim_width, bool opengl_initialized); + int obj_idx, float pos_x, float pos_y, float width, float depth, float height, float rotation_angle, bool size_unknown, float brim_width); - GLVolume* new_toolpath_volume(const ColorRGBA& rgba, size_t reserve_vbo_floats = 0); - GLVolume* new_nontoolpath_volume(const ColorRGBA& rgba, size_t reserve_vbo_floats = 0); + GLVolume* new_toolpath_volume(const ColorRGBA& rgba); + GLVolume* new_nontoolpath_volume(const ColorRGBA& rgba); int get_selection_support_threshold_angle(bool&) const; // Render the volumes by OpenGL. @@ -667,13 +452,6 @@ public: std::function filter_func = std::function(), bool with_outline = true) const; - // Finalize the initialization of the geometry & indices, - // upload the geometry and indices to OpenGL VBO objects - // and shrink the allocated data, possibly relasing it if it has been loaded into the VBOs. - void finalize_geometry(bool opengl_initialized) { for (auto* v : volumes) v->finalize_geometry(opengl_initialized); } - // Release the geometry data assigned to the volumes. - // If OpenGL VBOs were allocated, an OpenGL context has to be active to release them. - void release_geometry() { for (auto *v : volumes) v->release_geometry(); } // Clear the geometry void clear() { for (auto *v : volumes) delete v; volumes.clear(); } @@ -724,17 +502,13 @@ GLVolumeWithIdAndZList volumes_to_render(const GLVolumePtrs& volumes, GLVolumeCo struct _3DScene { - static void thick_lines_to_verts(const Lines& lines, const std::vector& widths, const std::vector& heights, bool closed, double top_z, GLVolume& volume); - static void thick_lines_to_verts(const Lines3& lines, const std::vector& widths, const std::vector& heights, bool closed, GLVolume& volume); - static void extrusionentity_to_verts(const Polyline &polyline, float width, float height, float print_z, GLVolume& volume); - static void extrusionentity_to_verts(const ExtrusionPath& extrusion_path, float print_z, GLVolume& volume); - static void extrusionentity_to_verts(const ExtrusionPath& extrusion_path, float print_z, const Point& copy, GLVolume& volume); - static void extrusionentity_to_verts(const ExtrusionLoop& extrusion_loop, float print_z, const Point& copy, GLVolume& volume); - static void extrusionentity_to_verts(const ExtrusionMultiPath& extrusion_multi_path, float print_z, const Point& copy, GLVolume& volume); - static void extrusionentity_to_verts(const ExtrusionEntityCollection& extrusion_entity_collection, float print_z, const Point& copy, GLVolume& volume); - static void extrusionentity_to_verts(const ExtrusionEntity* extrusion_entity, float print_z, const Point& copy, GLVolume& volume); - static void polyline3_to_verts(const Polyline3& polyline, double width, double height, GLVolume& volume); - static void point3_to_verts(const Vec3crd& point, double width, double height, GLVolume& volume); + static void thick_lines_to_verts(const Lines& lines, const std::vector& widths, const std::vector& heights, bool closed, double top_z, GUI::GLModel::Geometry& geometry); + static void thick_lines_to_verts(const Lines3& lines, const std::vector& widths, const std::vector& heights, bool closed, GUI::GLModel::Geometry& geometry); + static void extrusionentity_to_verts(const ExtrusionPath& extrusion_path, float print_z, const Point& copy, GUI::GLModel::Geometry& geometry); + static void extrusionentity_to_verts(const ExtrusionLoop& extrusion_loop, float print_z, const Point& copy, GUI::GLModel::Geometry& geometry); + static void extrusionentity_to_verts(const ExtrusionMultiPath& extrusion_multi_path, float print_z, const Point& copy, GUI::GLModel::Geometry& geometry); + static void extrusionentity_to_verts(const ExtrusionEntityCollection& extrusion_entity_collection, float print_z, const Point& copy, GUI::GLModel::Geometry& geometry); + static void extrusionentity_to_verts(const ExtrusionEntity* extrusion_entity, float print_z, const Point& copy, GUI::GLModel::Geometry& geometry); }; } diff --git a/src/slic3r/GUI/GCodeViewer.cpp b/src/slic3r/GUI/GCodeViewer.cpp index 7f3fa3d3b1..675af85d22 100644 --- a/src/slic3r/GUI/GCodeViewer.cpp +++ b/src/slic3r/GUI/GCodeViewer.cpp @@ -920,7 +920,7 @@ std::vector GCodeViewer::get_plater_extruder() //BBS: always load shell at preview void GCodeViewer::load(const GCodeProcessorResult& gcode_result, const Print& print, const BuildVolume& build_volume, - const std::vector& exclude_bounding_box, bool initialized, ConfigOptionMode mode, bool only_gcode) + const std::vector& exclude_bounding_box, ConfigOptionMode mode, bool only_gcode) { // avoid processing if called with the same gcode_result if (m_last_result_id == gcode_result.id) { @@ -975,7 +975,7 @@ m_sequential_view.m_show_gcode_window = false; //BBS: always load shell at preview /*if (wxGetApp().is_editor()) { - //load_shells(print, initialized); + load_shells(print); } else {*/ //BBS: add only gcode mode @@ -3088,9 +3088,9 @@ void GCodeViewer::load_toolpaths(const GCodeProcessorResult& gcode_result, const } //BBS: always load shell when preview -void GCodeViewer::load_shells(const Print& print, bool initialized, bool force_previewing) +void GCodeViewer::load_shells(const Print& print, bool force_previewing) { - BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << boost::format(": initialized=%1%, force_previewing=%2%")%initialized %force_previewing; + BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << boost::format(": force_previewing=%1%") %force_previewing; if ((print.id().id == m_shells.print_id)&&(print.get_modified_count() == m_shells.print_modify_count)) { //BBS: update force previewing logic if (force_previewing) @@ -3138,7 +3138,7 @@ void GCodeViewer::load_shells(const Print& print, bool initialized, bool force_p instance_ids.resize(instance_index); size_t current_volumes_count = m_shells.volumes.volumes.size(); - m_shells.volumes.load_object(model_obj, object_idx, instance_ids, initialized); + m_shells.volumes.load_object(model_obj, object_idx, instance_ids); // adjust shells' z if raft is present const SlicingParameters& slicing_parameters = obj->slicing_parameters(); @@ -4080,14 +4080,6 @@ void GCodeViewer::render_shells() if (shader == nullptr) return; - // when the background processing is enabled, it may happen that the shells data have been loaded - // before opengl has been initialized for the preview canvas. - // when this happens, the volumes' data have not been sent to gpu yet. - for (GLVolume* v : m_shells.volumes.volumes) { - if (!v->indexed_vertex_array.has_VBOs()) - v->finalize_geometry(true); - } - glsafe(::glEnable(GL_DEPTH_TEST)); // glsafe(::glDepthMask(GL_FALSE)); diff --git a/src/slic3r/GUI/GCodeViewer.hpp b/src/slic3r/GUI/GCodeViewer.hpp index 2bb2542f24..fa638f0a08 100644 --- a/src/slic3r/GUI/GCodeViewer.hpp +++ b/src/slic3r/GUI/GCodeViewer.hpp @@ -810,7 +810,7 @@ public: // extract rendering data from the given parameters //BBS: add only gcode mode void load(const GCodeProcessorResult& gcode_result, const Print& print, const BuildVolume& build_volume, - const std::vector& exclude_bounding_box, bool initialized, ConfigOptionMode mode, bool only_gcode = false); + const std::vector& exclude_bounding_box, ConfigOptionMode mode, bool only_gcode = false); // recalculate ranges in dependence of what is visible and sets tool/print colors void refresh(const GCodeProcessorResult& gcode_result, const std::vector& str_tool_colors); void refresh_render_paths(); @@ -820,7 +820,7 @@ public: void reset(); //BBS: always load shell at preview void reset_shell(); - void load_shells(const Print& print, bool initialized, bool force_previewing = false); + void load_shells(const Print& print, bool force_previewing = false); void set_shells_on_preview(bool is_previewing) { m_shells.previewing = is_previewing; } //BBS: add all plates filament statistics void render_all_plates_stats(const std::vector& gcode_result_list, bool show = true) const; @@ -900,7 +900,7 @@ public: private: void load_toolpaths(const GCodeProcessorResult& gcode_result, const BuildVolume& build_volume, const std::vector& exclude_bounding_box); //BBS: always load shell at preview - //void load_shells(const Print& print, bool initialized); + //void load_shells(const Print& print); void refresh_render_paths(bool keep_sequential_current_first, bool keep_sequential_current_last) const; void render_toolpaths(); void render_shells(); diff --git a/src/slic3r/GUI/GLCanvas3D.cpp b/src/slic3r/GUI/GLCanvas3D.cpp index 6aa3a5fcf5..f66a59fb12 100644 --- a/src/slic3r/GUI/GLCanvas3D.cpp +++ b/src/slic3r/GUI/GLCanvas3D.cpp @@ -97,10 +97,6 @@ void GLCanvas3D::load_render_colors() // Number of floats static constexpr const size_t MAX_VERTEX_BUFFER_SIZE = 131072 * 6; // 3.15MB -// Reserve size in number of floats. -static constexpr const size_t VERTEX_BUFFER_RESERVE_SIZE = 131072 * 2; // 1.05MB -// Reserve size in number of floats, maximum sum of all preallocated buffers. -//static constexpr const size_t VERTEX_BUFFER_RESERVE_SIZE_SUM_MAX = 1024 * 1024 * 128 / 4; // 128MB namespace Slic3r { namespace GUI { @@ -1175,10 +1171,6 @@ bool GLCanvas3D::init() if (m_main_toolbar.is_enabled()) m_layers_editing.init(); - // on linux the gl context is not valid until the canvas is not shown on screen - // we defer the geometry finalization of volumes until the first call to render() - m_volumes.finalize_geometry(true); - BOOST_LOG_TRIVIAL(info) <<__FUNCTION__<< ": before gizmo init"; if (m_gizmos.is_enabled() && !m_gizmos.init()) std::cout << "Unable to initialize gizmos: please, check that all the required textures are available" << std::endl; @@ -2136,7 +2128,7 @@ std::vector GLCanvas3D::load_object(const ModelObject& model_object, int ob instance_idxs.emplace_back(i); } } - return m_volumes.load_object(&model_object, obj_idx, instance_idxs, m_initialized); + return m_volumes.load_object(&model_object, obj_idx, instance_idxs); } std::vector GLCanvas3D::load_object(const Model& model, int obj_idx) @@ -2447,7 +2439,7 @@ void GLCanvas3D::reload_scene(bool refresh_immediately, bool force_full_scene_re // Note the index of the loaded volume, so that we can reload the main model GLVolume with the hollowed mesh // later in this function. it->volume_idx = m_volumes.volumes.size(); - m_volumes.load_object_volume(&model_object, obj_idx, volume_idx, instance_idx, m_initialized, m_canvas_type == ECanvasType::CanvasAssembleView); + m_volumes.load_object_volume(&model_object, obj_idx, volume_idx, instance_idx, m_canvas_type == ECanvasType::CanvasAssembleView); m_volumes.volumes.back()->geometry_id = key.geometry_id; update_object_list = true; } else { @@ -2504,31 +2496,32 @@ void GLCanvas3D::reload_scene(bool refresh_immediately, bool force_full_scene_re GLVolume &volume = *m_volumes.volumes[it->volume_idx]; if (! volume.offsets.empty() && state.step[istep].timestamp != volume.offsets.front()) { // The backend either produced a new hollowed mesh, or it invalidated the one that the front end has seen. - volume.indexed_vertex_array.release_geometry(); - if (state.step[istep].state == PrintStateBase::DONE) { + volume.model.reset(); + if (state.step[istep].state == PrintStateBase::DONE) { TriangleMesh mesh = print_object->get_mesh(slaposDrillHoles); assert(! mesh.empty()); mesh.transform(sla_print->sla_trafo(*m_model->objects[volume.object_idx()]).inverse()); #if ENABLE_SMOOTH_NORMALS - volume.indexed_vertex_array.load_mesh(mesh, true); + volume.model.init_from(mesh, true); #else - volume.indexed_vertex_array.load_mesh(mesh); -#endif // ENABLE_SMOOTH_NORMALS - } else { - // Reload the original volume. -#if ENABLE_SMOOTH_NORMALS - volume.indexed_vertex_array.load_mesh(m_model->objects[volume.object_idx()]->volumes[volume.volume_idx()]->mesh(), true); -#else - volume.indexed_vertex_array.load_mesh(m_model->objects[volume.object_idx()]->volumes[volume.volume_idx()]->mesh()); + volume.model.init_from(mesh); +#endif // ENABLE_SMOOTH_NORMALS + } + else { + // Reload the original volume. +#if ENABLE_SMOOTH_NORMALS + volume.model.init_from(m_model->objects[volume.object_idx()]->volumes[volume.volume_idx()]->mesh(), true); +#else + volume.model.init_from(m_model->objects[volume.object_idx()]->volumes[volume.volume_idx()]->mesh()); #endif // ENABLE_SMOOTH_NORMALS } - volume.finalize_geometry(true); } //FIXME it is an ugly hack to write the timestamp into the "offsets" field to not have to add another member variable // to the GLVolume. We should refactor GLVolume significantly, so that the GLVolume will not contain member variables // of various concenrs (model vs. 3D print path). volume.offsets = { state.step[istep].timestamp }; - } else if (state.step[istep].state == PrintStateBase::DONE) { + } + else if (state.step[istep].state == PrintStateBase::DONE) { // Check whether there is an existing auxiliary volume to be updated, or a new auxiliary volume to be created. ModelVolumeState key(state.step[istep].timestamp, instance.instance_id.id); auto it = std::lower_bound(aux_volume_state.begin(), aux_volume_state.end(), key, model_volume_state_lower); @@ -2540,7 +2533,8 @@ void GLCanvas3D::reload_scene(bool refresh_immediately, bool force_full_scene_re instances[istep].emplace_back(std::pair(instance_idx, print_instance_idx)); else shift_zs[object_idx] = 0.; - } else { + } + else { // Recycling an old GLVolume. Update the Object/Instance indices into the current Model. m_volumes.volumes[it->volume_idx]->composite_id = GLVolume::CompositeID(object_idx, m_volumes.volumes[it->volume_idx]->volume_idx(), instance_idx); m_volumes.volumes[it->volume_idx]->set_instance_transformation(model_object->instances[instance_idx]->get_transformation()); @@ -2550,7 +2544,7 @@ void GLCanvas3D::reload_scene(bool refresh_immediately, bool force_full_scene_re for (size_t istep = 0; istep < sla_steps.size(); ++istep) if (!instances[istep].empty()) - m_volumes.load_object_auxiliary(print_object, object_idx, instances[istep], sla_steps[istep], state.step[istep].timestamp, m_initialized); + m_volumes.load_object_auxiliary(print_object, object_idx, instances[istep], sla_steps[istep], state.step[istep].timestamp); } // Shift-up all volumes of the object so that it has the right elevation with respect to the print bed @@ -2614,7 +2608,7 @@ void GLCanvas3D::reload_scene(bool refresh_immediately, bool force_full_scene_re int volume_idx_wipe_tower_new = m_volumes.load_wipe_tower_preview( 1000 + plate_id, x + plate_origin(0), y + plate_origin(1), (float)wipe_tower_size(0), (float)wipe_tower_size(1), (float)wipe_tower_size(2), a, - /*!print->is_step_done(psWipeTower)*/ true, brim_width, m_initialized); + /*!print->is_step_done(psWipeTower)*/ true, brim_width); int volume_idx_wipe_tower_old = volume_idxs_wipe_tower_old[plate_id]; if (volume_idx_wipe_tower_old != -1) map_glvolume_old_to_new[volume_idx_wipe_tower_old] = volume_idx_wipe_tower_new; @@ -2687,26 +2681,11 @@ void GLCanvas3D::reload_scene(bool refresh_immediately, bool force_full_scene_re m_dirty = true; } -static void reserve_new_volume_finalize_old_volume(GLVolume& vol_new, GLVolume& vol_old, bool gl_initialized, size_t prealloc_size = VERTEX_BUFFER_RESERVE_SIZE) -{ - // Assign the large pre-allocated buffers to the new GLVolume. - vol_new.indexed_vertex_array = std::move(vol_old.indexed_vertex_array); - // Copy the content back to the old GLVolume. - vol_old.indexed_vertex_array = vol_new.indexed_vertex_array; - // Clear the buffers, but keep them pre-allocated. - vol_new.indexed_vertex_array.clear(); - // Just make sure that clear did not clear the reserved memory. - // Reserving number of vertices (3x position + 3x color) - vol_new.indexed_vertex_array.reserve(prealloc_size / 6); - // Finalize the old geometry, possibly move data to the graphics card. - vol_old.finalize_geometry(gl_initialized); -} - void GLCanvas3D::load_shells(const Print& print, bool force_previewing) { if (m_initialized) { - m_gcode_viewer.load_shells(print, m_initialized, force_previewing); + m_gcode_viewer.load_shells(print, force_previewing); m_gcode_viewer.update_shells_color_by_extruder(m_config); } } @@ -2726,7 +2705,7 @@ void GLCanvas3D::load_gcode_preview(const GCodeProcessorResult& gcode_result, co //when load gcode directly, it is too late m_gcode_viewer.init(wxGetApp().get_mode(), wxGetApp().preset_bundle); m_gcode_viewer.load(gcode_result, *this->fff_print(), wxGetApp().plater()->build_volume(), exclude_bounding_box, - m_initialized, wxGetApp().get_mode(), only_gcode); + wxGetApp().get_mode(), only_gcode); if (wxGetApp().is_editor()) { //BBS: always load shell at preview, do this in load_shells @@ -5637,7 +5616,7 @@ void GLCanvas3D::render_thumbnail_internal(ThumbnailData& thumbnail_data, const curr_color = vol->color; ColorRGBA new_color = adjust_color_for_rendering(curr_color); - shader->set_uniform("uniform_color", new_color); + vol->model.set_color(new_color); shader->set_uniform("volume_world_matrix", vol->world_matrix()); //BBS set all volume to orange //shader->set_uniform("uniform_color", orange); @@ -7192,6 +7171,10 @@ void GLCanvas3D::_render_style_editor() void GLCanvas3D::_render_volumes_for_picking() const { + GLShaderProgram* shader = wxGetApp().get_shader("flat"); + if (shader == nullptr) + return; + // do not cull backfaces to show broken geometry, if any glsafe(::glDisable(GL_CULL_FACE)); @@ -7209,8 +7192,10 @@ void GLCanvas3D::_render_volumes_for_picking() const //BBS: remove the bed picking logic const unsigned int id = volume.second.first; //const unsigned int id = 1 + volume.second.first; - glsafe(::glColor4fv(picking_decode(id).data())); - volume.first->render(); + volume.first->model.set_color(picking_decode(id)); + shader->start_using(); + volume.first->render(); + shader->stop_using(); } } @@ -8384,22 +8369,23 @@ void GLCanvas3D::_load_print_toolpaths(const BuildVolume &build_volume) skirt_height = std::min(skirt_height, print_zs.size()); print_zs.erase(print_zs.begin() + skirt_height, print_zs.end()); - GLVolume *volume = m_volumes.new_toolpath_volume(color, VERTEX_BUFFER_RESERVE_SIZE); + GLVolume* volume = m_volumes.new_toolpath_volume(color); + GLModel::Geometry init_data; + init_data.format = { GLModel::Geometry::EPrimitiveType::Triangles, GLModel::Geometry::EVertexLayout::P3N3, GLModel::Geometry::EIndexType::UINT }; for (size_t i = 0; i < skirt_height; ++ i) { volume->print_zs.emplace_back(print_zs[i]); - volume->offsets.emplace_back(volume->indexed_vertex_array.quad_indices.size()); - volume->offsets.emplace_back(volume->indexed_vertex_array.triangle_indices.size()); + volume->offsets.emplace_back(init_data.indices_count()); //BBS: usage of m_brim are deleted - _3DScene::extrusionentity_to_verts(print->skirt(), print_zs[i], Point(0, 0), *volume); + _3DScene::extrusionentity_to_verts(print->skirt(), print_zs[i], Point(0, 0), init_data); // Ensure that no volume grows over the limits. If the volume is too large, allocate a new one. - if (volume->indexed_vertex_array.vertices_and_normals_interleaved.size() > MAX_VERTEX_BUFFER_SIZE) { - GLVolume &vol = *volume; + if (init_data.vertices_size_bytes() > MAX_VERTEX_BUFFER_SIZE) { + volume->model.init_from(std::move(init_data)); + GLVolume &vol = *volume; volume = m_volumes.new_toolpath_volume(vol.color); - reserve_new_volume_finalize_old_volume(*volume, vol, m_initialized); } } - volume->is_outside = ! build_volume.all_paths_inside_vertices_and_normals_interleaved(volume->indexed_vertex_array.vertices_and_normals_interleaved, volume->indexed_vertex_array.bounding_box()); - volume->indexed_vertex_array.finalize_geometry(m_initialized); + volume->model.init_from(std::move(init_data)); + volume->is_outside = !contains(build_volume, volume->model); } void GLCanvas3D::_load_print_object_toolpaths(const PrintObject& print_object, const BuildVolume& build_volume, const std::vector& str_tool_colors, const std::vector& color_print_values) @@ -8571,7 +8557,10 @@ void GLCanvas3D::_load_print_object_toolpaths(const PrintObject& print_object, c // Allocate the volume before locking. GLVolume *volume = new GLVolume(color); volume->is_extrusion_path = true; - tbb::spin_mutex::scoped_lock lock; + // to prevent sending data to gpu (in the main thread) while + // editing the model geometry + volume->model.disable_render(); + tbb::spin_mutex::scoped_lock lock; // Lock by ROII, so if the emplace_back() fails, the lock will be released. lock.acquire(new_volume_mutex); m_volumes.volumes.emplace_back(volume); @@ -8583,31 +8572,36 @@ void GLCanvas3D::_load_print_object_toolpaths(const PrintObject& print_object, c tbb::blocked_range(0, ctxt.layers.size(), grain_size), [&ctxt, &new_volume, is_selected_separate_extruder, this](const tbb::blocked_range& range) { GLVolumePtrs vols; - auto volume = [&ctxt, &vols](size_t layer_idx, int extruder, int feature) -> GLVolume& { - return *vols[ctxt.color_by_color_print()? + std::vector geometries; + auto select_geometry = [&ctxt, &geometries](size_t layer_idx, int extruder, int feature) -> GLModel::Geometry& { + return geometries[ctxt.color_by_color_print() ? ctxt.color_print_color_idx_by_layer_idx_and_extruder(layer_idx, extruder) : - ctxt.color_by_tool() ? - std::min(ctxt.number_tools() - 1, std::max(extruder - 1, 0)) : - feature - ]; + ctxt.color_by_tool() ? + std::min(ctxt.number_tools() - 1, std::max(extruder - 1, 0)) : + feature + ]; }; if (ctxt.color_by_color_print() || ctxt.color_by_tool()) { - for (size_t i = 0; i < ctxt.number_tools(); ++i) + for (size_t i = 0; i < ctxt.number_tools(); ++i) { vols.emplace_back(new_volume(ctxt.color_tool(i))); + geometries.emplace_back(GLModel::Geometry()); + } } - else + else { vols = { new_volume(ctxt.color_perimeters()), new_volume(ctxt.color_infill()), new_volume(ctxt.color_support()) }; - for (GLVolume *vol : vols) - // Reserving number of vertices (3x position + 3x color) - vol->indexed_vertex_array.reserve(VERTEX_BUFFER_RESERVE_SIZE / 6); + geometries = { GLModel::Geometry(), GLModel::Geometry(), GLModel::Geometry() }; + } + + assert(vols.size() == geometries.size()); + for (GLModel::Geometry& g : geometries) { + g.format = { GLModel::Geometry::EPrimitiveType::Triangles, GLModel::Geometry::EVertexLayout::P3N3, GLModel::Geometry::EIndexType::UINT }; + } for (size_t idx_layer = range.begin(); idx_layer < range.end(); ++ idx_layer) { const Layer *layer = ctxt.layers[idx_layer]; - if (is_selected_separate_extruder) - { + if (is_selected_separate_extruder) { bool at_least_one_has_correct_extruder = false; - for (const LayerRegion* layerm : layer->regions()) - { + for (const LayerRegion* layerm : layer->regions()) { if (layerm->slices.surfaces.empty()) continue; const PrintRegionConfig& cfg = layerm->region().config(); @@ -8622,12 +8616,14 @@ void GLCanvas3D::_load_print_object_toolpaths(const PrintObject& print_object, c continue; } - for (GLVolume *vol : vols) + for (size_t i = 0; i < vols.size(); ++i) { + GLVolume* vol = vols[i]; if (vol->print_zs.empty() || vol->print_zs.back() != layer->print_z) { vol->print_zs.emplace_back(layer->print_z); - vol->offsets.emplace_back(vol->indexed_vertex_array.quad_indices.size()); - vol->offsets.emplace_back(vol->indexed_vertex_array.triangle_indices.size()); + vol->offsets.emplace_back(geometries[i].indices_count()); } + } + for (const PrintInstance &instance : *ctxt.shifted_copies) { const Point © = instance.shift; for (const LayerRegion *layerm : layer->regions()) { @@ -8641,18 +8637,16 @@ void GLCanvas3D::_load_print_object_toolpaths(const PrintObject& print_object, c } if (ctxt.has_perimeters) _3DScene::extrusionentity_to_verts(layerm->perimeters, float(layer->print_z), copy, - volume(idx_layer, layerm->region().config().wall_filament.value, 0)); + select_geometry(idx_layer, layerm->region().config().wall_filament.value, 0)); if (ctxt.has_infill) { for (const ExtrusionEntity *ee : layerm->fills.entities) { // fill represents infill extrusions of a single island. const auto *fill = dynamic_cast(ee); if (! fill->entities.empty()) _3DScene::extrusionentity_to_verts(*fill, float(layer->print_z), copy, - volume(idx_layer, - is_solid_infill(fill->entities.front()->role()) ? - layerm->region().config().solid_infill_filament : - layerm->region().config().sparse_infill_filament, - 1)); + select_geometry(idx_layer, is_solid_infill(fill->entities.front()->role()) ? + layerm->region().config().solid_infill_filament : + layerm->region().config().sparse_infill_filament, 1)); } } } @@ -8661,28 +8655,25 @@ void GLCanvas3D::_load_print_object_toolpaths(const PrintObject& print_object, c if (support_layer) { for (const ExtrusionEntity *extrusion_entity : support_layer->support_fills.entities) _3DScene::extrusionentity_to_verts(extrusion_entity, float(layer->print_z), copy, - volume(idx_layer, - (extrusion_entity->role() == erSupportMaterial || - extrusion_entity->role() == erSupportTransition) ? - support_layer->object()->config().support_filament : - support_layer->object()->config().support_interface_filament, - 2)); + select_geometry(idx_layer, (extrusion_entity->role() == erSupportMaterial || extrusion_entity->role() == erSupportTransition) ? + support_layer->object()->config().support_filament : + support_layer->object()->config().support_interface_filament, 2)); } } } // Ensure that no volume grows over the limits. If the volume is too large, allocate a new one. for (size_t i = 0; i < vols.size(); ++i) { GLVolume &vol = *vols[i]; - if (vol.indexed_vertex_array.vertices_and_normals_interleaved.size() > MAX_VERTEX_BUFFER_SIZE) { - vols[i] = new_volume(vol.color); - reserve_new_volume_finalize_old_volume(*vols[i], vol, false); - } + if (geometries[i].vertices_size_bytes() > MAX_VERTEX_BUFFER_SIZE) { + vol.model.init_from(std::move(geometries[i])); + vols[i] = new_volume(vol.color); + } } } - for (GLVolume *vol : vols) - // Ideally one would call vol->indexed_vertex_array.finalize() here to move the buffers to the OpenGL driver, - // but this code runs in parallel and the OpenGL driver is not thread safe. - vol->indexed_vertex_array.shrink_to_fit(); + for (size_t i = 0; i < vols.size(); ++i) { + if (!geometries[i].is_empty()) + vols[i]->model.init_from(std::move(geometries[i])); + } }); BOOST_LOG_TRIVIAL(debug) << "Loading print object toolpaths in parallel - finalizing results" << m_volumes.log_memory_info() << log_memory_info(); @@ -8697,8 +8688,9 @@ void GLCanvas3D::_load_print_object_toolpaths(const PrintObject& print_object, c } for (size_t i = volumes_cnt_initial; i < m_volumes.volumes.size(); ++i) { GLVolume* v = m_volumes.volumes[i]; - v->is_outside = ! build_volume.all_paths_inside_vertices_and_normals_interleaved(v->indexed_vertex_array.vertices_and_normals_interleaved, v->indexed_vertex_array.bounding_box()); - v->indexed_vertex_array.finalize_geometry(m_initialized); + v->is_outside = !contains(build_volume, v->model); + // We are done editinig the model, now it can be sent to gpu + v->model.enable_render(); } BOOST_LOG_TRIVIAL(debug) << "Loading print object toolpaths in parallel - end" << m_volumes.log_memory_info() << log_memory_info(); @@ -8718,10 +8710,10 @@ void GLCanvas3D::_load_wipe_tower_toolpaths(const BuildVolume& build_volume, con struct Ctxt { - const Print *print; - const std::vector* tool_colors; - Vec2f wipe_tower_pos; - float wipe_tower_angle; + const Print *print; + const std::vector *tool_colors; + Vec2f wipe_tower_pos; + float wipe_tower_angle; static ColorRGBA color_support() { return ColorRGBA::GREENISH(); } @@ -8771,6 +8763,9 @@ void GLCanvas3D::_load_wipe_tower_toolpaths(const BuildVolume& build_volume, con auto new_volume = [this, &new_volume_mutex](const ColorRGBA& color) { auto *volume = new GLVolume(color); volume->is_extrusion_path = true; + // to prevent sending data to gpu (in the main thread) while + // editing the model geometry + volume->model.disable_render(); tbb::spin_mutex::scoped_lock lock; lock.acquire(new_volume_mutex); m_volumes.volumes.emplace_back(volume); @@ -8784,23 +8779,29 @@ void GLCanvas3D::_load_wipe_tower_toolpaths(const BuildVolume& build_volume, con [&ctxt, &new_volume](const tbb::blocked_range& range) { // Bounding box of this slab of a wipe tower. GLVolumePtrs vols; + std::vector geometries; if (ctxt.color_by_tool()) { - for (size_t i = 0; i < ctxt.number_tools(); ++i) + for (size_t i = 0; i < ctxt.number_tools(); ++i) { vols.emplace_back(new_volume(ctxt.color_tool(i))); + geometries.emplace_back(GLModel::Geometry()); + } } - else + else { vols = { new_volume(ctxt.color_support()) }; - for (GLVolume *volume : vols) - // Reserving number of vertices (3x position + 3x color) - volume->indexed_vertex_array.reserve(VERTEX_BUFFER_RESERVE_SIZE / 6); + geometries = { GLModel::Geometry() }; + } + + assert(vols.size() == geometries.size()); + for (GLModel::Geometry& g : geometries) { + g.format = { GLModel::Geometry::EPrimitiveType::Triangles, GLModel::Geometry::EVertexLayout::P3N3, GLModel::Geometry::EIndexType::UINT }; + } for (size_t idx_layer = range.begin(); idx_layer < range.end(); ++idx_layer) { const std::vector &layer = ctxt.tool_change(idx_layer); for (size_t i = 0; i < vols.size(); ++i) { GLVolume &vol = *vols[i]; if (vol.print_zs.empty() || vol.print_zs.back() != layer.front().print_z) { vol.print_zs.emplace_back(layer.front().print_z); - vol.offsets.emplace_back(vol.indexed_vertex_array.quad_indices.size()); - vol.offsets.emplace_back(vol.indexed_vertex_array.triangle_indices.size()); + vol.offsets.emplace_back(geometries[i].indices_count()); } } for (const WipeTower::ToolChangeResult &extrusions : layer) { @@ -8843,20 +8844,22 @@ void GLCanvas3D::_load_wipe_tower_toolpaths(const BuildVolume& build_volume, con e_prev = e; } _3DScene::thick_lines_to_verts(lines, widths, heights, lines.front().a == lines.back().b, extrusions.print_z, - *vols[ctxt.volume_idx(e.tool, 0)]); + geometries[ctxt.volume_idx(e.tool, 0)]); } } } for (size_t i = 0; i < vols.size(); ++i) { GLVolume &vol = *vols[i]; - if (vol.indexed_vertex_array.vertices_and_normals_interleaved.size() > MAX_VERTEX_BUFFER_SIZE) { + if (geometries[i].vertices_size_bytes() > MAX_VERTEX_BUFFER_SIZE) { + vol.model.init_from(std::move(geometries[i])); vols[i] = new_volume(vol.color); - reserve_new_volume_finalize_old_volume(*vols[i], vol, false); } } - for (GLVolume *vol : vols) - vol->indexed_vertex_array.shrink_to_fit(); - }); + for (size_t i = 0; i < vols.size(); ++i) { + if (!geometries[i].is_empty()) + vols[i]->model.init_from(std::move(geometries[i])); + } + }); BOOST_LOG_TRIVIAL(debug) << "Loading wipe tower toolpaths in parallel - finalizing results" << m_volumes.log_memory_info() << log_memory_info(); // Remove empty volumes from the newly added volumes. @@ -8870,8 +8873,9 @@ void GLCanvas3D::_load_wipe_tower_toolpaths(const BuildVolume& build_volume, con } for (size_t i = volumes_cnt_initial; i < m_volumes.volumes.size(); ++i) { GLVolume* v = m_volumes.volumes[i]; - v->is_outside = ! build_volume.all_paths_inside_vertices_and_normals_interleaved(v->indexed_vertex_array.vertices_and_normals_interleaved, v->indexed_vertex_array.bounding_box()); - v->indexed_vertex_array.finalize_geometry(m_initialized); + v->is_outside = !contains(build_volume, v->model); + // We are done editinig the model, now it can be sent to gpu + v->model.enable_render(); } BOOST_LOG_TRIVIAL(debug) << "Loading wipe tower toolpaths in parallel - end" << m_volumes.log_memory_info() << log_memory_info(); @@ -8895,11 +8899,10 @@ void GLCanvas3D::_load_sla_shells() m_volumes.volumes.emplace_back(new GLVolume(color)); GLVolume& v = *m_volumes.volumes.back(); #if ENABLE_SMOOTH_NORMALS - v.indexed_vertex_array.load_mesh(mesh, true); + v.model.init_from(mesh, true); #else - v.indexed_vertex_array.load_mesh(mesh); + v.model.init_from(mesh); #endif // ENABLE_SMOOTH_NORMALS - v.indexed_vertex_array.finalize_geometry(m_initialized); v.shader_outside_printer_detection_enabled = outside_printer_detection_enabled; v.composite_id.volume_id = volume_id; v.set_instance_offset(unscale(instance.shift.x(), instance.shift.y(), 0.0)); diff --git a/src/slic3r/GUI/GLModel.cpp b/src/slic3r/GUI/GLModel.cpp index 0cb7bfc96b..5a17467706 100644 --- a/src/slic3r/GUI/GLModel.cpp +++ b/src/slic3r/GUI/GLModel.cpp @@ -8,15 +8,50 @@ #include "libslic3r/TriangleMesh.hpp" #include "libslic3r/Model.hpp" #include "libslic3r/Polygon.hpp" +#include "libslic3r/BuildVolume.hpp" +#include "libslic3r/Geometry/ConvexHull.hpp" #include #include +#if ENABLE_SMOOTH_NORMALS +#include +#include +#include +#endif // ENABLE_SMOOTH_NORMALS + #include namespace Slic3r { namespace GUI { +#if ENABLE_SMOOTH_NORMALS +static void smooth_normals_corner(const TriangleMesh& mesh, std::vector& normals) +{ + using MapMatrixXfUnaligned = Eigen::Map>; + using MapMatrixXiUnaligned = Eigen::Map>; + + std::vector face_normals = its_face_normals(mesh.its); + + Eigen::MatrixXd vertices = MapMatrixXfUnaligned(mesh.its.vertices.front().data(), + Eigen::Index(mesh.its.vertices.size()), 3).cast(); + Eigen::MatrixXi indices = MapMatrixXiUnaligned(mesh.its.indices.front().data(), + Eigen::Index(mesh.its.indices.size()), 3); + Eigen::MatrixXd in_normals = MapMatrixXfUnaligned(face_normals.front().data(), + Eigen::Index(face_normals.size()), 3).cast(); + Eigen::MatrixXd out_normals; + + igl::per_corner_normals(vertices, indices, in_normals, 1.0, out_normals); + + normals = std::vector(mesh.its.vertices.size()); + for (size_t i = 0; i < mesh.its.indices.size(); ++i) { + for (size_t j = 0; j < 3; ++j) { + normals[mesh.its.indices[i][j]] = out_normals.row(i * 3 + j).cast(); + } + } +} +#endif // ENABLE_SMOOTH_NORMALS + void GLModel::Geometry::reserve_vertices(size_t vertices_count) { vertices.reserve(vertices_count * vertex_stride_floats(format)); @@ -206,6 +241,35 @@ Vec2f GLModel::Geometry::extract_tex_coord_2(size_t id) const return { *(start + 0), *(start + 1) }; } +void GLModel::Geometry::set_vertex(size_t id, const Vec3f& position, const Vec3f& normal) +{ + assert(format.vertex_layout == EVertexLayout::P3N3); + assert(id < vertices_count()); + if (id < vertices_count()) { + float* start = &vertices[id * vertex_stride_floats(format)]; + *(start + 0) = position.x(); + *(start + 1) = position.y(); + *(start + 2) = position.z(); + *(start + 3) = normal.x(); + *(start + 4) = normal.y(); + *(start + 5) = normal.z(); + } +} + +void GLModel::Geometry::set_ushort_index(size_t id, unsigned short index) +{ + assert(id < indices_count()); + if (id < indices_count()) + ::memcpy(indices.data() + id * sizeof(unsigned short), &index, sizeof(unsigned short)); +} + +void GLModel::Geometry::set_uint_index(size_t id, unsigned int index) +{ + assert(id < indices_count()); + if (id < indices_count()) + ::memcpy(indices.data() + id * sizeof(unsigned int), &index, sizeof(unsigned int)); +} + unsigned int GLModel::Geometry::extract_uint_index(size_t id) const { if (format.index_type != EIndexType::UINT) { @@ -218,7 +282,7 @@ unsigned int GLModel::Geometry::extract_uint_index(size_t id) const return -1; } - unsigned int ret = -1; + unsigned int ret = (unsigned int)-1; ::memcpy(&ret, indices.data() + id * index_stride_bytes(format), sizeof(unsigned int)); return ret; } @@ -235,11 +299,21 @@ unsigned short GLModel::Geometry::extract_ushort_index(size_t id) const return -1; } - unsigned short ret = -1; + unsigned short ret = (unsigned short)-1; ::memcpy(&ret, indices.data() + id * index_stride_bytes(format), sizeof(unsigned short)); return ret; } +void GLModel::Geometry::remove_vertex(size_t id) +{ + assert(id < vertices_count()); + if (id < vertices_count()) { + size_t stride = vertex_stride_floats(format); + std::vector::iterator it = vertices.begin() + id * stride; + vertices.erase(it, it + stride); + } +} + size_t GLModel::Geometry::vertex_stride_floats(const Format& format) { switch (format.vertex_layout) @@ -417,21 +491,24 @@ void GLModel::init_from(const indexed_triangle_set& its) } Geometry& data = m_render_data.geometry; - data.format = { Geometry::EPrimitiveType::Triangles, Geometry::EVertexLayout::P3N3, Geometry::EIndexType::UINT }; + data.format = { Geometry::EPrimitiveType::Triangles, Geometry::EVertexLayout::P3N3, GLModel::Geometry::index_type(3 * its.indices.size()) }; data.reserve_vertices(3 * its.indices.size()); data.reserve_indices(3 * its.indices.size()); // vertices + indices unsigned int vertices_counter = 0; for (uint32_t i = 0; i < its.indices.size(); ++i) { - stl_triangle_vertex_indices face = its.indices[i]; - stl_vertex vertex[3] = { its.vertices[face[0]], its.vertices[face[1]], its.vertices[face[2]] }; - stl_vertex n = face_normal_normalized(vertex); + const stl_triangle_vertex_indices face = its.indices[i]; + const stl_vertex vertex[3] = { its.vertices[face[0]], its.vertices[face[1]], its.vertices[face[2]] }; + const stl_vertex n = face_normal_normalized(vertex); for (size_t j = 0; j < 3; ++j) { data.add_vertex(vertex[j], n); } vertices_counter += 3; - data.add_uint_triangle(vertices_counter - 3, vertices_counter - 2, vertices_counter - 1); + if (data.format.index_type == GLModel::Geometry::EIndexType::USHORT) + data.add_ushort_triangle((unsigned short)vertices_counter - 3, (unsigned short)vertices_counter - 2, (unsigned short)vertices_counter - 1); + else + data.add_uint_triangle(vertices_counter - 3, vertices_counter - 2, vertices_counter - 1); } // update bounding box @@ -553,6 +630,17 @@ static GLenum get_index_type(const GLModel::Geometry::Format& format) void GLModel::render() { + render(std::make_pair(0, indices_count())); +} + +void GLModel::render(const std::pair& range) +{ + if (m_render_disabled) + return; + + if (range.second == range.first) + return; + GLShaderProgram* shader = wxGetApp().get_current_shader(); if (shader == nullptr) @@ -570,8 +658,8 @@ void GLModel::render() const GLenum index_type = get_index_type(data.format); const size_t vertex_stride_bytes = Geometry::vertex_stride_bytes(data.format); - const bool position = Geometry::has_position(data.format); - const bool normal = Geometry::has_normal(data.format); + const bool position = Geometry::has_position(data.format); + const bool normal = Geometry::has_normal(data.format); const bool tex_coord = Geometry::has_tex_coord(data.format); glsafe(::glBindBuffer(GL_ARRAY_BUFFER, m_render_data.vbo_id)); @@ -592,7 +680,7 @@ void GLModel::render() shader->set_uniform("uniform_color", data.color); glsafe(::glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, m_render_data.ibo_id)); - glsafe(::glDrawElements(mode, indices_count(), index_type, nullptr)); + glsafe(::glDrawElements(mode, range.second - range.first + 1, index_type, (const void*)(range.first * Geometry::index_stride_bytes(data.format)))); glsafe(::glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0)); if (tex_coord) @@ -721,6 +809,61 @@ static void append_triangle(GLModel::Geometry& data, unsigned short v1, unsigned data.add_ushort_index(v2); data.add_ushort_index(v3); } + +template +inline bool all_vertices_inside(const GLModel::Geometry& geometry, Fn fn) +{ + const size_t position_stride_floats = geometry.position_stride_floats(geometry.format); + const size_t position_offset_floats = geometry.position_offset_floats(geometry.format); + assert(position_stride_floats == 3); + if (geometry.vertices.empty() || position_stride_floats != 3) + return false; + + for (auto it = geometry.vertices.begin(); it != geometry.vertices.end(); ) { + it += position_offset_floats; + if (!fn({ *it, *(it + 1), *(it + 2) })) + return false; + it += (geometry.vertex_stride_floats(geometry.format) - position_offset_floats - position_stride_floats); + } + return true; +} + +bool contains(const BuildVolume& volume, const GLModel& model, bool ignore_bottom) +{ + static constexpr const double epsilon = BuildVolume::BedEpsilon; + switch (volume.type()) { + case BuildVolume_Type::Rectangle: + { + BoundingBox3Base build_volume = volume.bounding_volume().inflated(epsilon); + if (volume.printable_height() == 0.0) + build_volume.max.z() = std::numeric_limits::max(); + if (ignore_bottom) + build_volume.min.z() = -std::numeric_limits::max(); + const BoundingBoxf3& model_box = model.get_bounding_box(); + return build_volume.contains(model_box.min) && build_volume.contains(model_box.max); + } + case BuildVolume_Type::Circle: + { + const Geometry::Circled& circle = volume.circle(); + const Vec2f c = unscaled(circle.center); + const float r = unscaled(circle.radius) + float(epsilon); + const float r2 = sqr(r); + return volume.printable_height() == 0.0 ? + all_vertices_inside(model.get_geometry(), [c, r2](const Vec3f& p) { return (to_2d(p) - c).squaredNorm() <= r2; }) : + + all_vertices_inside(model.get_geometry(), [c, r2, z = volume.printable_height() + epsilon](const Vec3f& p) { return (to_2d(p) - c).squaredNorm() <= r2 && p.z() <= z; }); + } + case BuildVolume_Type::Convex: + //FIXME doing test on convex hull until we learn to do test on non-convex polygons efficiently. + case BuildVolume_Type::Custom: + return volume.printable_height() == 0.0 ? + all_vertices_inside(model.get_geometry(), [&volume](const Vec3f& p) { return Geometry::inside_convex_polygon(volume.top_bottom_convex_hull_decomposition_bed(), to_2d(p).cast()); }) : + all_vertices_inside(model.get_geometry(), [&volume, z = volume.printable_height() + epsilon](const Vec3f& p) { return Geometry::inside_convex_polygon(volume.top_bottom_convex_hull_decomposition_bed(), to_2d(p).cast()) && p.z() <= z; }); + default: + return true; + } +} + GLModel::Geometry stilized_arrow(unsigned short resolution, float tip_radius, float tip_height, float stem_radius, float stem_height) { resolution = std::max(4, resolution); diff --git a/src/slic3r/GUI/GLModel.hpp b/src/slic3r/GUI/GLModel.hpp index 98feaaad0a..79c615f31c 100644 --- a/src/slic3r/GUI/GLModel.hpp +++ b/src/slic3r/GUI/GLModel.hpp @@ -14,6 +14,7 @@ namespace Slic3r { class TriangleMesh; class Polygon; using Polygons = std::vector; +class BuildVolume; namespace GUI { @@ -69,6 +70,11 @@ namespace GUI { void add_vertex(const Vec3f& position, const Vec2f& tex_coord); // EVertexLayout::P3T2 void add_vertex(const Vec3f& position, const Vec3f& normal); // EVertexLayout::P3N3 + void set_vertex(size_t id, const Vec3f& position, const Vec3f& normal); // EVertexLayout::P3N3 + + void set_ushort_index(size_t id, unsigned short index); + void set_uint_index(size_t id, unsigned int index); + void add_ushort_index(unsigned short id); void add_uint_index(unsigned int id); @@ -86,7 +92,9 @@ namespace GUI { unsigned int extract_uint_index(size_t id) const; unsigned short extract_ushort_index(size_t id) const; - bool is_empty() const { return vertices.empty() || indices.empty(); } + void remove_vertex(size_t id); + + bool is_empty() const { return vertices_count() == 0 || indices_count() == 0; } size_t vertices_count() const { return vertices.size() / vertex_stride_floats(format); } size_t indices_count() const { return indices.size() / index_stride_bytes(format); } @@ -133,6 +141,14 @@ namespace GUI { private: RenderData m_render_data; + // By default the vertex and index buffers data are sent to gpu at the first call to render() method. + // If you need to initialize a model from outside the main thread, so that a call to render() may happen + // before the initialization is complete, use the methods: + // disable_render() + // ... do your initialization ... + // enable_render() + // to keep the data on cpu side until needed. + bool m_render_disabled{ false }; BoundingBoxf3 m_bounding_box; std::string m_filename; @@ -150,6 +166,7 @@ namespace GUI { size_t indices_size_bytes() const { return indices_count() * Geometry::index_stride_bytes(m_render_data.geometry.format); } + const Geometry& get_geometry() const { return m_render_data.geometry; } void init_from(Geometry&& data); void init_from(const TriangleMesh& mesh); void init_from(const indexed_triangle_set& its); @@ -161,16 +178,40 @@ namespace GUI { void reset(); void render(); + void render(const std::pair& range); void render_instanced(unsigned int instances_vbo, unsigned int instances_count); bool is_initialized() const { return vertices_count() > 0 && indices_count() > 0; } + bool is_empty() const { return m_render_data.geometry.is_empty(); } const BoundingBoxf3& get_bounding_box() const { return m_bounding_box; } const std::string& get_filename() const { return m_filename; } + bool is_render_disabled() const { return m_render_disabled; } + void enable_render() { m_render_disabled = false; } + void disable_render() { m_render_disabled = true; } + + size_t cpu_memory_used() const { + size_t ret = 0; + if (!m_render_data.geometry.vertices.empty()) + ret += vertices_size_bytes(); + if (!m_render_data.geometry.indices.empty()) + ret += indices_size_bytes(); + return ret; + } + size_t gpu_memory_used() const { + size_t ret = 0; + if (m_render_data.geometry.vertices.empty()) + ret += vertices_size_bytes(); + if (m_render_data.geometry.indices.empty()) + ret += indices_size_bytes(); + return ret; + } + private: bool send_to_gpu(); }; + bool contains(const BuildVolume& volume, const GLModel& model, bool ignore_bottom = true); // create an arrow with cylindrical stem and conical tip, with the given dimensions and resolution // the origin of the arrow is in the center of the stem cap diff --git a/src/slic3r/GUI/Gizmos/GLGizmoFaceDetector.cpp b/src/slic3r/GUI/Gizmos/GLGizmoFaceDetector.cpp index b96be246a3..90b274decd 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoFaceDetector.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoFaceDetector.cpp @@ -32,9 +32,9 @@ std::string GLGizmoFaceDetector::on_get_name() const void GLGizmoFaceDetector::on_render() { - if (m_iva.has_VBOs()) { - ::glColor4f(0.f, 0.f, 1.f, 0.4f); - m_iva.render(); + if (model.is_initialized()) { + model.set_color({0.f, 0.f, 1.f, 0.4f}); + model.render(); } } @@ -72,7 +72,7 @@ void GLGizmoFaceDetector::on_render_input_window(float x, float y, float bottom_ void GLGizmoFaceDetector::on_set_state() { if (get_state() == On) { - m_iva.release_geometry(); + model.reset(); display_exterior_face(); } } @@ -94,7 +94,10 @@ void GLGizmoFaceDetector::perform_recognition(const Selection& selection) void GLGizmoFaceDetector::display_exterior_face() { int cnt = 0; - m_iva.release_geometry(); + model.reset(); + + GLModel::Geometry init_data; + init_data.format = { GLModel::Geometry::EPrimitiveType::Triangles, GLModel::Geometry::EVertexLayout::P3N3, GLModel::Geometry::EIndexType::UINT }; const ModelObjectPtrs& objects = wxGetApp().model().objects; for (ModelObject* mo : objects) { @@ -110,19 +113,15 @@ void GLGizmoFaceDetector::display_exterior_face() continue; for (int i = 0; i < 3; ++i) { - m_iva.push_geometry(double(mv_its.vertices[facet_vert_idxs[i]](0)), - double(mv_its.vertices[facet_vert_idxs[i]](1)), - double(mv_its.vertices[facet_vert_idxs[i]](2)), - 0., 0., 1.); + init_data.add_vertex((Vec3f) mv_its.vertices[facet_vert_idxs[i]].cast(), Vec3f{0.0f, 0.0f, 1.0f}); } - m_iva.push_triangle(cnt, cnt + 1, cnt + 2); + init_data.add_uint_triangle(cnt, cnt + 1, cnt + 2); cnt += 3; } } } - - m_iva.finalize_geometry(true); + model.init_from(std::move(init_data)); } CommonGizmosDataID GLGizmoFaceDetector::on_get_requirements() const diff --git a/src/slic3r/GUI/Gizmos/GLGizmoFaceDetector.hpp b/src/slic3r/GUI/Gizmos/GLGizmoFaceDetector.hpp index c20cf4c209..c028a3f2b2 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoFaceDetector.hpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoFaceDetector.hpp @@ -28,7 +28,7 @@ private: void perform_recognition(const Selection& selection); void display_exterior_face(); - GLIndexedVertexArray m_iva; + GUI::GLModel model; double m_sample_interval = {0.5}; }; diff --git a/src/slic3r/GUI/Gizmos/GLGizmoFdmSupports.cpp b/src/slic3r/GUI/Gizmos/GLGizmoFdmSupports.cpp index b9dc5770d4..86aa18f894 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoFdmSupports.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoFdmSupports.cpp @@ -894,13 +894,16 @@ void GLGizmoFdmSupports::run_thread() print->set_status(100, L("Support Generated")); goto _finished; } + GLModel::Geometry init_data; + init_data.format = { GLModel::Geometry::EPrimitiveType::Triangles, GLModel::Geometry::EVertexLayout::P3N3, GLModel::Geometry::EIndexType::UINT }; for (const SupportLayer *support_layer : m_print_instance.print_object->support_layers()) { for (const ExtrusionEntity *extrusion_entity : support_layer->support_fills.entities) { - _3DScene::extrusionentity_to_verts(extrusion_entity, float(support_layer->print_z), m_print_instance.shift, *m_support_volume); + _3DScene::extrusionentity_to_verts(extrusion_entity, float(support_layer->print_z), m_print_instance.shift, init_data); } } + m_support_volume->model.init_from(std::move(init_data)); BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << ", finished extrusionentity_to_verts, update status to 100%"; print->set_status(100, L("Support Generated")); @@ -926,7 +929,6 @@ _finished: void GLGizmoFdmSupports::generate_support_volume() { BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << ",before finalize_geometry"; - m_support_volume->indexed_vertex_array.finalize_geometry(m_parent.is_initialized()); std::unique_lock lck(m_mutex); m_volume_ready = true; diff --git a/src/slic3r/GUI/Gizmos/GLGizmosManager.cpp b/src/slic3r/GUI/Gizmos/GLGizmosManager.cpp index 0acfd3eb1e..1e500ff406 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmosManager.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmosManager.cpp @@ -17,7 +17,7 @@ #include "slic3r/GUI/Gizmos/GLGizmoFdmSupports.hpp" // BBS #include "slic3r/GUI/Gizmos/GLGizmoAdvancedCut.hpp" -#include "slic3r/GUI/Gizmos/GLGizmoFaceDetector.hpp" +//#include "slic3r/GUI/Gizmos/GLGizmoFaceDetector.hpp" #include "slic3r/GUI/Gizmos/GLGizmoHollow.hpp" #include "slic3r/GUI/Gizmos/GLGizmoSeam.hpp" #include "slic3r/GUI/Gizmos/GLGizmoMmuSegmentation.hpp" diff --git a/src/slic3r/GUI/ImGuiWrapper.cpp b/src/slic3r/GUI/ImGuiWrapper.cpp index f061cd7970..bc2e84e946 100644 --- a/src/slic3r/GUI/ImGuiWrapper.cpp +++ b/src/slic3r/GUI/ImGuiWrapper.cpp @@ -2388,8 +2388,8 @@ void ImGuiWrapper::render_draw_data(ImDrawData *draw_data) { // Avoid rendering when minimized, scale coordinates for retina displays (screen coordinates != framebuffer coordinates) ImGuiIO& io = ImGui::GetIO(); - int fb_width = (int)(draw_data->DisplaySize.x * io.DisplayFramebufferScale.x); - int fb_height = (int)(draw_data->DisplaySize.y * io.DisplayFramebufferScale.y); + const int fb_width = (int)(draw_data->DisplaySize.x * io.DisplayFramebufferScale.x); + const int fb_height = (int)(draw_data->DisplaySize.y * io.DisplayFramebufferScale.y); if (fb_width == 0 || fb_height == 0) return; draw_data->ScaleClipRects(io.DisplayFramebufferScale); @@ -2432,8 +2432,7 @@ void ImGuiWrapper::render_draw_data(ImDrawData *draw_data) // Render command lists ImVec2 pos = draw_data->DisplayPos; - for (int n = 0; n < draw_data->CmdListsCount; n++) - { + for (int n = 0; n < draw_data->CmdListsCount; ++n) { const ImDrawList* cmd_list = draw_data->CmdLists[n]; const ImDrawVert* vtx_buffer = cmd_list->VtxBuffer.Data; const ImDrawIdx* idx_buffer = cmd_list->IdxBuffer.Data; @@ -2441,19 +2440,14 @@ void ImGuiWrapper::render_draw_data(ImDrawData *draw_data) glsafe(::glTexCoordPointer(2, GL_FLOAT, sizeof(ImDrawVert), (const GLvoid*)((const char*)vtx_buffer + IM_OFFSETOF(ImDrawVert, uv)))); glsafe(::glColorPointer(4, GL_UNSIGNED_BYTE, sizeof(ImDrawVert), (const GLvoid*)((const char*)vtx_buffer + IM_OFFSETOF(ImDrawVert, col)))); - for (int cmd_i = 0; cmd_i < cmd_list->CmdBuffer.Size; cmd_i++) - { + for (int cmd_i = 0; cmd_i < cmd_list->CmdBuffer.Size; ++cmd_i) { const ImDrawCmd* pcmd = &cmd_list->CmdBuffer[cmd_i]; if (pcmd->UserCallback) - { // User callback (registered via ImDrawList::AddCallback) pcmd->UserCallback(cmd_list, pcmd); - } - else - { + else { ImVec4 clip_rect = ImVec4(pcmd->ClipRect.x - pos.x, pcmd->ClipRect.y - pos.y, pcmd->ClipRect.z - pos.x, pcmd->ClipRect.w - pos.y); - if (clip_rect.x < fb_width && clip_rect.y < fb_height && clip_rect.z >= 0.0f && clip_rect.w >= 0.0f) - { + if (clip_rect.x < fb_width && clip_rect.y < fb_height && clip_rect.z >= 0.0f && clip_rect.w >= 0.0f) { // Apply scissor/clipping rectangle glsafe(::glScissor((int)clip_rect.x, (int)(fb_height - clip_rect.w), (int)(clip_rect.z - clip_rect.x), (int)(clip_rect.w - clip_rect.y))); diff --git a/src/slic3r/Utils/CalibUtils.cpp b/src/slic3r/Utils/CalibUtils.cpp index 82382293f8..a496d1ff34 100644 --- a/src/slic3r/Utils/CalibUtils.cpp +++ b/src/slic3r/Utils/CalibUtils.cpp @@ -926,7 +926,7 @@ void CalibUtils::process_and_store_3mf(Model *model, const DynamicPrintConfig &f const ModelVolume &model_volume = *model_object.volumes[volume_idx]; for (int instance_idx = 0; instance_idx < (int)model_object.instances.size(); ++ instance_idx) { const ModelInstance &model_instance = *model_object.instances[instance_idx]; - glvolume_collection.load_object_volume(&model_object, obj_idx, volume_idx, instance_idx, true, false, true); + glvolume_collection.load_object_volume(&model_object, obj_idx, volume_idx, instance_idx, false, true); glvolume_collection.volumes.back()->set_render_color(new_color); glvolume_collection.volumes.back()->set_color(new_color); //glvolume_collection.volumes.back()->printable = model_instance.printable;