diff --git a/src/slic3r/GUI/GCodeViewer.cpp b/src/slic3r/GUI/GCodeViewer.cpp index 9fcef6a65..347f781e7 100644 --- a/src/slic3r/GUI/GCodeViewer.cpp +++ b/src/slic3r/GUI/GCodeViewer.cpp @@ -2636,12 +2636,7 @@ void GCodeViewer::render_toolpaths() float near_plane_height = camera.get_type() == Camera::EType::Perspective ? static_cast(viewport[3]) / (2.0f * static_cast(2.0 * std::tan(0.5 * Geometry::deg2rad(camera.get_fov())))) : static_cast(viewport[3]) * 0.0005; -#if ENABLE_GCODE_VIEWER_STATISTICS - auto render_as_points = [this, zoom, point_size, near_plane_height] -#else - auto render_as_points = [zoom, point_size, near_plane_height] -#endif // ENABLE_GCODE_VIEWER_STATISTICS - (const TBuffer& buffer, unsigned int ibuffer_id, GLShaderProgram& shader) { + auto shader_init_as_points = [zoom, point_size, near_plane_height](GLShaderProgram& shader) { #if ENABLE_FIXED_SCREEN_SIZE_POINT_MARKERS shader.set_uniform("use_fixed_screen_size", 1); #else @@ -2652,65 +2647,67 @@ void GCodeViewer::render_toolpaths() shader.set_uniform("percent_center_radius", 0.33f); shader.set_uniform("point_size", point_size); shader.set_uniform("near_plane_height", near_plane_height); + }; + auto render_as_points = [ +#if ENABLE_GCODE_VIEWER_STATISTICS + this +#endif // ENABLE_GCODE_VIEWER_STATISTICS + ](std::vector::iterator it_path, std::vector::iterator it_end, GLShaderProgram& shader, int uniform_color) { glsafe(::glEnable(GL_VERTEX_PROGRAM_POINT_SIZE)); glsafe(::glEnable(GL_POINT_SPRITE)); - for (const RenderPath& path : buffer.render_paths) { - if (path.ibuffer_id == ibuffer_id) { - shader.set_uniform("uniform_color", path.color); - glsafe(::glMultiDrawElements(GL_POINTS, (const GLsizei*)path.sizes.data(), GL_UNSIGNED_SHORT, (const void* const*)path.offsets.data(), (GLsizei)path.sizes.size())); + for (auto it = it_path; it != it_end && (*it_path)->ibuffer_id == (*it)->ibuffer_id; ++ it) { + const RenderPath& path = **it; + glsafe(::glUniform4fv(uniform_color, 1, static_cast(path.color.data()))); + glsafe(::glMultiDrawElements(GL_POINTS, (const GLsizei*)path.sizes.data(), GL_UNSIGNED_SHORT, (const void* const*)path.offsets.data(), (GLsizei)path.sizes.size())); #if ENABLE_GCODE_VIEWER_STATISTICS - ++m_statistics.gl_multi_points_calls_count; + ++m_statistics.gl_multi_points_calls_count; #endif // ENABLE_GCODE_VIEWER_STATISTICS - } } glsafe(::glDisable(GL_POINT_SPRITE)); glsafe(::glDisable(GL_VERTEX_PROGRAM_POINT_SIZE)); }; -#if ENABLE_GCODE_VIEWER_STATISTICS - auto render_as_lines = [this, light_intensity] -#else - auto render_as_lines = [light_intensity] -#endif // ENABLE_GCODE_VIEWER_STATISTICS - (const TBuffer& buffer, unsigned int ibuffer_id, GLShaderProgram& shader) { + auto shader_init_as_lines = [light_intensity](GLShaderProgram &shader) { shader.set_uniform("light_intensity", light_intensity); - for (const RenderPath& path : buffer.render_paths) { - if (path.ibuffer_id == ibuffer_id) { - shader.set_uniform("uniform_color", path.color); - glsafe(::glMultiDrawElements(GL_LINES, (const GLsizei*)path.sizes.data(), GL_UNSIGNED_SHORT, (const void* const*)path.offsets.data(), (GLsizei)path.sizes.size())); + }; + auto render_as_lines = [ #if ENABLE_GCODE_VIEWER_STATISTICS - ++m_statistics.gl_multi_lines_calls_count; + this +#endif // ENABLE_GCODE_VIEWER_STATISTICS + ](std::vector::iterator it_path, std::vector::iterator it_end, GLShaderProgram &shader, int uniform_color) { + for (auto it = it_path; it != it_end && (*it_path)->ibuffer_id == (*it)->ibuffer_id; ++it) { + const RenderPath& path = **it; + glsafe(::glUniform4fv(uniform_color, 1, static_cast(path.color.data()))); + glsafe(::glMultiDrawElements(GL_LINES, (const GLsizei*)path.sizes.data(), GL_UNSIGNED_SHORT, (const void* const*)path.offsets.data(), (GLsizei)path.sizes.size())); +#if ENABLE_GCODE_VIEWER_STATISTICS + ++m_statistics.gl_multi_lines_calls_count; #endif // ENABLE_GCODE_VIEWER_STATISTICS - } } }; + auto render_as_triangles = [ #if ENABLE_GCODE_VIEWER_STATISTICS - auto render_as_triangles = [this] -#else - auto render_as_triangles = [] + this #endif // ENABLE_GCODE_VIEWER_STATISTICS - (const TBuffer& buffer, unsigned int ibuffer_id, GLShaderProgram& shader) { - for (const RenderPath& path : buffer.render_paths) { - if (path.ibuffer_id == ibuffer_id) { - shader.set_uniform("uniform_color", path.color); - glsafe(::glMultiDrawElements(GL_TRIANGLES, (const GLsizei*)path.sizes.data(), GL_UNSIGNED_SHORT, (const void* const*)path.offsets.data(), (GLsizei)path.sizes.size())); + ](std::vector::iterator it_path, std::vector::iterator it_end, GLShaderProgram &shader, int uniform_color) { + for (auto it = it_path; it != it_end && (*it_path)->ibuffer_id == (*it)->ibuffer_id; ++it) { + const RenderPath& path = **it; + glsafe(::glUniform4fv(uniform_color, 1, static_cast(path.color.data()))); + glsafe(::glMultiDrawElements(GL_TRIANGLES, (const GLsizei*)path.sizes.data(), GL_UNSIGNED_SHORT, (const void* const*)path.offsets.data(), (GLsizei)path.sizes.size())); #if ENABLE_GCODE_VIEWER_STATISTICS - ++m_statistics.gl_multi_triangles_calls_count; + ++m_statistics.gl_multi_triangles_calls_count; #endif // ENABLE_GCODE_VIEWER_STATISTICS - } } }; + auto render_as_instanced_model = [ #if ENABLE_GCODE_VIEWER_STATISTICS - auto render_as_instanced_model = [this] -#else - auto render_as_instanced_model = [] + this #endif // ENABLE_GCODE_VIEWER_STATISTICS - (TBuffer& buffer, GLShaderProgram & shader) { + ](TBuffer& buffer, GLShaderProgram & shader) { for (auto& range : buffer.model.instances.render_ranges.ranges) { if (range.vbo == 0 && range.count > 0) { glsafe(::glGenBuffers(1, &range.vbo)); @@ -2815,8 +2812,27 @@ void GCodeViewer::render_toolpaths() shader->set_uniform("emission_factor", 0.0f); } else { - for (size_t j = 0; j < buffer.indices.size(); ++j) { - const IBuffer& i_buffer = buffer.indices[j]; + switch (buffer.render_primitive_type) { + case TBuffer::ERenderPrimitiveType::Point: shader_init_as_points(*shader); break; + case TBuffer::ERenderPrimitiveType::Line: shader_init_as_lines(*shader); break; + default: break; + } + int uniform_color = shader->get_uniform_location("uniform_color"); + // Render paths are sorted by ibuffer_id. + std::vector paths; + paths.reserve(buffer.render_paths.size()); + for (const RenderPath& path : buffer.render_paths) + paths.emplace_back(&path); + std::stable_sort(paths.begin(), paths.end(), [](const auto* l, const auto* r){ return l->ibuffer_id < r->ibuffer_id; }); + //FIXME maybe std::sort would suffice? + auto it_path = paths.begin(); + for (unsigned int ibuffer_id = 0; ibuffer_id < static_cast(buffer.indices.size()); ++ibuffer_id) { + const IBuffer& i_buffer = buffer.indices[ibuffer_id]; + // Skip all paths with ibuffer_id < ibuffer_id. + for (; it_path != paths.end() && (*it_path)->ibuffer_id < ibuffer_id; ++ it_path) ; + if (it_path == paths.end() || (*it_path)->ibuffer_id > ibuffer_id) + // Not found. This shall not happen. + continue; glsafe(::glBindBuffer(GL_ARRAY_BUFFER, i_buffer.vbo)); glsafe(::glVertexPointer(buffer.vertices.position_size_floats(), GL_FLOAT, buffer.vertices.vertex_size_bytes(), (const void*)buffer.vertices.position_offset_bytes())); @@ -2829,19 +2845,20 @@ void GCodeViewer::render_toolpaths() glsafe(::glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, i_buffer.ibo)); + // Render all elements with it_path->ibuffer_id == ibuffer_id, possible with varying colors. switch (buffer.render_primitive_type) { case TBuffer::ERenderPrimitiveType::Point: { - render_as_points(buffer, static_cast(j), *shader); + render_as_points(it_path, paths.end(), *shader, uniform_color); break; } case TBuffer::ERenderPrimitiveType::Line: { glsafe(::glLineWidth(static_cast(line_width(zoom)))); - render_as_lines(buffer, static_cast(j), *shader); + render_as_lines(it_path, paths.end(), *shader, uniform_color); break; } case TBuffer::ERenderPrimitiveType::Triangle: { - render_as_triangles(buffer, static_cast(j), *shader); + render_as_triangles(it_path, paths.end(), *shader, uniform_color); break; } default: { break; }