diff --git a/src/slic3r/GUI/GCodeViewer.cpp b/src/slic3r/GUI/GCodeViewer.cpp index 61f61988c..5251c01df 100644 --- a/src/slic3r/GUI/GCodeViewer.cpp +++ b/src/slic3r/GUI/GCodeViewer.cpp @@ -129,16 +129,19 @@ void GCodeViewer::TBuffer::reset() { // release gpu memory vertices.reset(); - indices.reset(); + for (IBuffer& buffer : indices) { + buffer.reset(); + } // release cpu memory + indices = std::vector(); paths = std::vector(); render_paths = std::vector(); } -void GCodeViewer::TBuffer::add_path(const GCodeProcessor::MoveVertex& move, unsigned int i_id, unsigned int s_id) +void GCodeViewer::TBuffer::add_path(const GCodeProcessor::MoveVertex& move, unsigned int b_id, size_t i_id, size_t s_id) { - Path::Endpoint endpoint = { i_id, s_id, move.position }; + Path::Endpoint endpoint = { b_id, i_id, s_id, move.position }; // use rounding to reduce the number of generated paths paths.push_back({ move.type, move.extrusion_role, endpoint, endpoint, move.delta_extruder, round_to_nearest(move.height, 2), round_to_nearest(move.width, 2), move.feedrate, move.fan_speed, @@ -561,7 +564,7 @@ void GCodeViewer::export_toolpaths_to_obj(const char* filename) const // the data needed is contained into the Extrude TBuffer const TBuffer& buffer = m_buffers[buffer_id(EMoveType::Extrude)]; - if (buffer.vertices.id == 0 || buffer.indices.id == 0) + if (!buffer.has_data()) return; // collect color information to generate materials @@ -611,10 +614,13 @@ void GCodeViewer::export_toolpaths_to_obj(const char* filename) const glsafe(::glBindBuffer(GL_ARRAY_BUFFER, 0)); // get indices data from index buffer on gpu - std::vector indices = std::vector(buffer.indices.count); - glsafe(::glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, buffer.indices.id)); - glsafe(::glGetBufferSubData(GL_ELEMENT_ARRAY_BUFFER, 0, static_cast(indices.size() * sizeof(unsigned int)), indices.data())); - glsafe(::glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0)); + MultiIndexBuffer indices; + for (size_t i = 0; i < buffer.indices.size(); ++i) { + indices.push_back(IndexBuffer(buffer.indices[i].count)); + glsafe(::glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, buffer.indices[i].id)); + glsafe(::glGetBufferSubData(GL_ELEMENT_ARRAY_BUFFER, 0, static_cast(indices.back().size() * sizeof(unsigned int)), indices.back().data())); + glsafe(::glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0)); + } auto get_vertex = [&vertices, floats_per_vertex](unsigned int id) { // extract vertex from vector of floats @@ -672,6 +678,7 @@ void GCodeViewer::export_toolpaths_to_obj(const char* filename) const for (size_t i = 0; i < buffer.render_paths.size(); ++i) { // get paths segments from buffer paths const RenderPath& render_path = buffer.render_paths[i]; + const IndexBuffer& ibuffer = indices[render_path.index_buffer_id]; const Path& path = buffer.paths[render_path.path_id]; float half_width = 0.5f * path.width; // clamp height to avoid artifacts due to z-fighting when importing the obj file into blender and similar @@ -687,7 +694,7 @@ void GCodeViewer::export_toolpaths_to_obj(const char* filename) const unsigned int end = start + render_path.sizes[j]; for (size_t k = start; k < end; k += static_cast(indices_per_segment)) { - Segment curr = generate_segment(indices[k + start_vertex_offset], indices[k + end_vertex_offset], half_width, half_height); + Segment curr = generate_segment(ibuffer[k + start_vertex_offset], ibuffer[k + end_vertex_offset], half_width, half_height); if (k == start) { // starting endpoint vertices/normals out_vertices.push_back(curr.v1 + curr.rl_displacement); out_normals.push_back(curr.right); // right @@ -710,7 +717,7 @@ void GCodeViewer::export_toolpaths_to_obj(const char* filename) const out_vertices_count += 2; size_t first_vertex_id = k - static_cast(indices_per_segment); - Segment prev = generate_segment(indices[first_vertex_id + start_vertex_offset], indices[first_vertex_id + end_vertex_offset], half_width, half_height); + Segment prev = generate_segment(ibuffer[first_vertex_id + start_vertex_offset], ibuffer[first_vertex_id + end_vertex_offset], half_width, half_height); float disp = 0.0f; float cos_dir = prev.dir.dot(curr.dir); if (cos_dir > -0.9998477f) { @@ -895,274 +902,277 @@ void GCodeViewer::load_toolpaths(const GCodeProcessor::Result& gcode_result) // format data into the buffers to be rendered as points auto add_as_point = [](const GCodeProcessor::MoveVertex& curr, TBuffer& buffer, - std::vector& buffer_vertices, std::vector& buffer_indices, size_t move_id) { - for (int j = 0; j < 3; ++j) { - buffer_vertices.push_back(curr.position[j]); - } - buffer.add_path(curr, static_cast(buffer_indices.size()), static_cast(move_id)); - buffer_indices.push_back(static_cast(buffer_indices.size())); + std::vector& buffer_vertices, unsigned int index_buffer_id, IndexBuffer& buffer_indices, size_t move_id) { + for (int j = 0; j < 3; ++j) { + buffer_vertices.push_back(curr.position[j]); + } + buffer.add_path(curr, index_buffer_id, static_cast(buffer_indices.size()), static_cast(move_id)); + buffer_indices.push_back(static_cast(buffer_indices.size())); }; // format data into the buffers to be rendered as lines auto add_as_line = [](const GCodeProcessor::MoveVertex& prev, const GCodeProcessor::MoveVertex& curr, TBuffer& buffer, - std::vector& buffer_vertices, std::vector& buffer_indices, size_t move_id) { - // x component of the normal to the current segment (the normal is parallel to the XY plane) - float normal_x = (curr.position - prev.position).normalized()[1]; + std::vector& buffer_vertices, unsigned int index_buffer_id, IndexBuffer& buffer_indices, size_t move_id) { + // x component of the normal to the current segment (the normal is parallel to the XY plane) + float normal_x = (curr.position - prev.position).normalized()[1]; - if (prev.type != curr.type || !buffer.paths.back().matches(curr)) { - // add starting vertex position - for (int j = 0; j < 3; ++j) { - buffer_vertices.push_back(prev.position[j]); + if (prev.type != curr.type || !buffer.paths.back().matches(curr)) { + // add starting vertex position + for (int j = 0; j < 3; ++j) { + buffer_vertices.push_back(prev.position[j]); + } + // add starting vertex normal x component + buffer_vertices.push_back(normal_x); + // add starting index + buffer_indices.push_back(static_cast(buffer_indices.size())); + buffer.add_path(curr, index_buffer_id, static_cast(buffer_indices.size() - 1), static_cast(move_id - 1)); + buffer.paths.back().first.position = prev.position; } - // add starting vertex normal x component - buffer_vertices.push_back(normal_x); - // add starting index - buffer_indices.push_back(static_cast(buffer_indices.size())); - buffer.add_path(curr, static_cast(buffer_indices.size() - 1), static_cast(move_id - 1)); - buffer.paths.back().first.position = prev.position; - } - Path& last_path = buffer.paths.back(); - if (last_path.first.i_id != last_path.last.i_id) { - // add previous vertex position - for (int j = 0; j < 3; ++j) { - buffer_vertices.push_back(prev.position[j]); + Path& last_path = buffer.paths.back(); + if (last_path.first.i_id != last_path.last.i_id) { + // add previous vertex position + for (int j = 0; j < 3; ++j) { + buffer_vertices.push_back(prev.position[j]); + } + // add previous vertex normal x component + buffer_vertices.push_back(normal_x); + // add previous index + buffer_indices.push_back(static_cast(buffer_indices.size())); } - // add previous vertex normal x component - buffer_vertices.push_back(normal_x); - // add previous index - buffer_indices.push_back(static_cast(buffer_indices.size())); - } - // add current vertex position - for (int j = 0; j < 3; ++j) { - buffer_vertices.push_back(curr.position[j]); - } - // add current vertex normal x component - buffer_vertices.push_back(normal_x); - // add current index - buffer_indices.push_back(static_cast(buffer_indices.size())); - last_path.last = { static_cast(buffer_indices.size() - 1), static_cast(move_id), curr.position }; + // add current vertex position + for (int j = 0; j < 3; ++j) { + buffer_vertices.push_back(curr.position[j]); + } + // add current vertex normal x component + buffer_vertices.push_back(normal_x); + // add current index + buffer_indices.push_back(static_cast(buffer_indices.size())); + last_path.last = { index_buffer_id, static_cast(buffer_indices.size() - 1), static_cast(move_id), curr.position }; }; // format data into the buffers to be rendered as solid auto add_as_solid = [](const GCodeProcessor::MoveVertex& prev, const GCodeProcessor::MoveVertex& curr, TBuffer& buffer, - std::vector& buffer_vertices, std::vector& buffer_indices, size_t move_id) { - static Vec3f prev_dir; - static Vec3f prev_up; - static float prev_length; - auto store_vertex = [](std::vector& buffer_vertices, const Vec3f& position, const Vec3f& normal) { - // append position - for (int j = 0; j < 3; ++j) { - buffer_vertices.push_back(position[j]); - } - // append normal - for (int j = 0; j < 3; ++j) { - buffer_vertices.push_back(normal[j]); - } - }; - auto store_triangle = [](std::vector& buffer_indices, unsigned int i1, unsigned int i2, unsigned int i3) { - buffer_indices.push_back(i1); - buffer_indices.push_back(i2); - buffer_indices.push_back(i3); - }; - auto extract_position_at = [](const std::vector& vertices, size_t id) { - return Vec3f(vertices[id + 0], vertices[id + 1], vertices[id + 2]); - }; - auto update_position_at = [](std::vector& vertices, size_t id, const Vec3f& position) { - vertices[id + 0] = position[0]; - vertices[id + 1] = position[1]; - vertices[id + 2] = position[2]; - }; - auto append_dummy_cap = [store_triangle](std::vector& buffer_indices, unsigned int id) { - store_triangle(buffer_indices, id, id, id); - store_triangle(buffer_indices, id, id, id); - }; - - if (prev.type != curr.type || !buffer.paths.back().matches(curr)) { - buffer.add_path(curr, static_cast(buffer_indices.size()), static_cast(move_id - 1)); - buffer.paths.back().first.position = prev.position; - } - - unsigned int starting_vertices_size = static_cast(buffer_vertices.size() / buffer.vertices.vertex_size_floats()); - - Vec3f dir = (curr.position - prev.position).normalized(); - Vec3f right = (std::abs(std::abs(dir.dot(Vec3f::UnitZ())) - 1.0f) < EPSILON) ? -Vec3f::UnitY() : Vec3f(dir[1], -dir[0], 0.0f).normalized(); - Vec3f left = -right; - Vec3f up = right.cross(dir); - Vec3f bottom = -up; - - Path& last_path = buffer.paths.back(); - - float half_width = 0.5f * last_path.width; - float half_height = 0.5f * last_path.height; - - Vec3f prev_pos = prev.position - half_height * up; - Vec3f curr_pos = curr.position - half_height * up; - - float length = (curr_pos - prev_pos).norm(); - if (last_path.vertices_count() == 1) { - // 1st segment - - // vertices 1st endpoint - store_vertex(buffer_vertices, prev_pos + half_height * up, up); - store_vertex(buffer_vertices, prev_pos + half_width * right, right); - store_vertex(buffer_vertices, prev_pos + half_height * bottom, bottom); - store_vertex(buffer_vertices, prev_pos + half_width * left, left); - - // vertices 2nd endpoint - store_vertex(buffer_vertices, curr_pos + half_height * up, up); - store_vertex(buffer_vertices, curr_pos + half_width * right, right); - store_vertex(buffer_vertices, curr_pos + half_height * bottom, bottom); - store_vertex(buffer_vertices, curr_pos + half_width * left, left); - - // triangles starting cap - store_triangle(buffer_indices, starting_vertices_size + 0, starting_vertices_size + 2, starting_vertices_size + 1); - store_triangle(buffer_indices, starting_vertices_size + 0, starting_vertices_size + 3, starting_vertices_size + 2); - - // dummy triangles outer corner cap - append_dummy_cap(buffer_indices, starting_vertices_size); - - // triangles sides - store_triangle(buffer_indices, starting_vertices_size + 0, starting_vertices_size + 1, starting_vertices_size + 4); - store_triangle(buffer_indices, starting_vertices_size + 1, starting_vertices_size + 5, starting_vertices_size + 4); - store_triangle(buffer_indices, starting_vertices_size + 1, starting_vertices_size + 2, starting_vertices_size + 5); - store_triangle(buffer_indices, starting_vertices_size + 2, starting_vertices_size + 6, starting_vertices_size + 5); - store_triangle(buffer_indices, starting_vertices_size + 2, starting_vertices_size + 3, starting_vertices_size + 6); - store_triangle(buffer_indices, starting_vertices_size + 3, starting_vertices_size + 7, starting_vertices_size + 6); - store_triangle(buffer_indices, starting_vertices_size + 3, starting_vertices_size + 0, starting_vertices_size + 7); - store_triangle(buffer_indices, starting_vertices_size + 0, starting_vertices_size + 4, starting_vertices_size + 7); - - // triangles ending cap - store_triangle(buffer_indices, starting_vertices_size + 4, starting_vertices_size + 6, starting_vertices_size + 7); - store_triangle(buffer_indices, starting_vertices_size + 4, starting_vertices_size + 5, starting_vertices_size + 6); - } - else { - // any other segment - float displacement = 0.0f; - float cos_dir = prev_dir.dot(dir); - if (cos_dir > -0.9998477f) { - // if the angle between adjacent segments is smaller than 179 degrees - Vec3f med_dir = (prev_dir + dir).normalized(); - displacement = half_width * ::tan(::acos(std::clamp(dir.dot(med_dir), -1.0f, 1.0f))); - } - - Vec3f displacement_vec = displacement * prev_dir; - bool can_displace = displacement > 0.0f && displacement < prev_length && displacement < length; - - size_t prev_right_id = (starting_vertices_size - 3) * buffer.vertices.vertex_size_floats(); - size_t prev_left_id = (starting_vertices_size - 1) * buffer.vertices.vertex_size_floats(); - Vec3f prev_right_pos = extract_position_at(buffer_vertices, prev_right_id); - Vec3f prev_left_pos = extract_position_at(buffer_vertices, prev_left_id); - - bool is_right_turn = prev_up.dot(prev_dir.cross(dir)) <= 0.0f; - // whether the angle between adjacent segments is greater than 45 degrees - bool is_sharp = cos_dir < 0.7071068f; - - bool right_displaced = false; - bool left_displaced = false; - - // displace the vertex (inner with respect to the corner) of the previous segment 2nd enpoint, if possible - if (can_displace) { - if (is_right_turn) { - prev_right_pos -= displacement_vec; - update_position_at(buffer_vertices, prev_right_id, prev_right_pos); - right_displaced = true; + std::vector& buffer_vertices, unsigned int index_buffer_id, IndexBuffer& buffer_indices, size_t move_id) { + static Vec3f prev_dir; + static Vec3f prev_up; + static float prev_length; + auto store_vertex = [](std::vector& buffer_vertices, const Vec3f& position, const Vec3f& normal) { + // append position + for (int j = 0; j < 3; ++j) { + buffer_vertices.push_back(position[j]); } - else { - prev_left_pos -= displacement_vec; - update_position_at(buffer_vertices, prev_left_id, prev_left_pos); - left_displaced = true; + // append normal + for (int j = 0; j < 3; ++j) { + buffer_vertices.push_back(normal[j]); } + }; + auto store_triangle = [](IndexBuffer& buffer_indices, unsigned int i1, unsigned int i2, unsigned int i3) { + buffer_indices.push_back(i1); + buffer_indices.push_back(i2); + buffer_indices.push_back(i3); + }; + auto extract_position_at = [](const std::vector& vertices, size_t id) { + return Vec3f(vertices[id + 0], vertices[id + 1], vertices[id + 2]); + }; + auto update_position_at = [](std::vector& vertices, size_t id, const Vec3f& position) { + vertices[id + 0] = position[0]; + vertices[id + 1] = position[1]; + vertices[id + 2] = position[2]; + }; + auto append_dummy_cap = [store_triangle](IndexBuffer& buffer_indices, unsigned int id) { + store_triangle(buffer_indices, id, id, id); + store_triangle(buffer_indices, id, id, id); + }; + + if (prev.type != curr.type || !buffer.paths.back().matches(curr)) { + buffer.add_path(curr, index_buffer_id, static_cast(buffer_indices.size()), static_cast(move_id - 1)); + buffer.paths.back().first.position = prev.position; } - if (!is_sharp) { - // displace the vertex (outer with respect to the corner) of the previous segment 2nd enpoint, if possible + unsigned int starting_vertices_size = static_cast(buffer_vertices.size() / buffer.vertices.vertex_size_floats()); + + Vec3f dir = (curr.position - prev.position).normalized(); + Vec3f right = (std::abs(std::abs(dir.dot(Vec3f::UnitZ())) - 1.0f) < EPSILON) ? -Vec3f::UnitY() : Vec3f(dir[1], -dir[0], 0.0f).normalized(); + Vec3f left = -right; + Vec3f up = right.cross(dir); + Vec3f bottom = -up; + + Path& last_path = buffer.paths.back(); + + float half_width = 0.5f * last_path.width; + float half_height = 0.5f * last_path.height; + + Vec3f prev_pos = prev.position - half_height * up; + Vec3f curr_pos = curr.position - half_height * up; + + float length = (curr_pos - prev_pos).norm(); + if (last_path.vertices_count() == 1) { + // 1st segment + + // vertices 1st endpoint + store_vertex(buffer_vertices, prev_pos + half_height * up, up); + store_vertex(buffer_vertices, prev_pos + half_width * right, right); + store_vertex(buffer_vertices, prev_pos + half_height * bottom, bottom); + store_vertex(buffer_vertices, prev_pos + half_width * left, left); + + // vertices 2nd endpoint + store_vertex(buffer_vertices, curr_pos + half_height * up, up); + store_vertex(buffer_vertices, curr_pos + half_width * right, right); + store_vertex(buffer_vertices, curr_pos + half_height * bottom, bottom); + store_vertex(buffer_vertices, curr_pos + half_width * left, left); + + // triangles starting cap + store_triangle(buffer_indices, starting_vertices_size + 0, starting_vertices_size + 2, starting_vertices_size + 1); + store_triangle(buffer_indices, starting_vertices_size + 0, starting_vertices_size + 3, starting_vertices_size + 2); + + // dummy triangles outer corner cap + append_dummy_cap(buffer_indices, starting_vertices_size); + + // triangles sides + store_triangle(buffer_indices, starting_vertices_size + 0, starting_vertices_size + 1, starting_vertices_size + 4); + store_triangle(buffer_indices, starting_vertices_size + 1, starting_vertices_size + 5, starting_vertices_size + 4); + store_triangle(buffer_indices, starting_vertices_size + 1, starting_vertices_size + 2, starting_vertices_size + 5); + store_triangle(buffer_indices, starting_vertices_size + 2, starting_vertices_size + 6, starting_vertices_size + 5); + store_triangle(buffer_indices, starting_vertices_size + 2, starting_vertices_size + 3, starting_vertices_size + 6); + store_triangle(buffer_indices, starting_vertices_size + 3, starting_vertices_size + 7, starting_vertices_size + 6); + store_triangle(buffer_indices, starting_vertices_size + 3, starting_vertices_size + 0, starting_vertices_size + 7); + store_triangle(buffer_indices, starting_vertices_size + 0, starting_vertices_size + 4, starting_vertices_size + 7); + + // triangles ending cap + store_triangle(buffer_indices, starting_vertices_size + 4, starting_vertices_size + 6, starting_vertices_size + 7); + store_triangle(buffer_indices, starting_vertices_size + 4, starting_vertices_size + 5, starting_vertices_size + 6); + } + else { + // any other segment + float displacement = 0.0f; + float cos_dir = prev_dir.dot(dir); + if (cos_dir > -0.9998477f) { + // if the angle between adjacent segments is smaller than 179 degrees + Vec3f med_dir = (prev_dir + dir).normalized(); + displacement = half_width * ::tan(::acos(std::clamp(dir.dot(med_dir), -1.0f, 1.0f))); + } + + Vec3f displacement_vec = displacement * prev_dir; + bool can_displace = displacement > 0.0f && displacement < prev_length&& displacement < length; + + size_t prev_right_id = (starting_vertices_size - 3) * buffer.vertices.vertex_size_floats(); + size_t prev_left_id = (starting_vertices_size - 1) * buffer.vertices.vertex_size_floats(); + Vec3f prev_right_pos = extract_position_at(buffer_vertices, prev_right_id); + Vec3f prev_left_pos = extract_position_at(buffer_vertices, prev_left_id); + + bool is_right_turn = prev_up.dot(prev_dir.cross(dir)) <= 0.0f; + // whether the angle between adjacent segments is greater than 45 degrees + bool is_sharp = cos_dir < 0.7071068f; + + bool right_displaced = false; + bool left_displaced = false; + + // displace the vertex (inner with respect to the corner) of the previous segment 2nd enpoint, if possible if (can_displace) { if (is_right_turn) { - prev_left_pos += displacement_vec; - update_position_at(buffer_vertices, prev_left_id, prev_left_pos); - left_displaced = true; - } - else { - prev_right_pos += displacement_vec; + prev_right_pos -= displacement_vec; update_position_at(buffer_vertices, prev_right_id, prev_right_pos); right_displaced = true; } + else { + prev_left_pos -= displacement_vec; + update_position_at(buffer_vertices, prev_left_id, prev_left_pos); + left_displaced = true; + } } - // vertices 1st endpoint (top and bottom are from previous segment 2nd endpoint) - // vertices position matches that of the previous segment 2nd endpoint, if displaced - store_vertex(buffer_vertices, right_displaced ? prev_right_pos : prev_pos + half_width * right, right); - store_vertex(buffer_vertices, left_displaced ? prev_left_pos : prev_pos + half_width * left, left); - } - else { - // vertices 1st endpoint (top and bottom are from previous segment 2nd endpoint) - // the inner corner vertex position matches that of the previous segment 2nd endpoint, if displaced - if (is_right_turn) { + if (!is_sharp) { + // displace the vertex (outer with respect to the corner) of the previous segment 2nd enpoint, if possible + if (can_displace) { + if (is_right_turn) { + prev_left_pos += displacement_vec; + update_position_at(buffer_vertices, prev_left_id, prev_left_pos); + left_displaced = true; + } + else { + prev_right_pos += displacement_vec; + update_position_at(buffer_vertices, prev_right_id, prev_right_pos); + right_displaced = true; + } + } + + // vertices 1st endpoint (top and bottom are from previous segment 2nd endpoint) + // vertices position matches that of the previous segment 2nd endpoint, if displaced store_vertex(buffer_vertices, right_displaced ? prev_right_pos : prev_pos + half_width * right, right); - store_vertex(buffer_vertices, prev_pos + half_width * left, left); - } - else { - store_vertex(buffer_vertices, prev_pos + half_width * right, right); store_vertex(buffer_vertices, left_displaced ? prev_left_pos : prev_pos + half_width * left, left); } - } - - // vertices 2nd endpoint - store_vertex(buffer_vertices, curr_pos + half_height * up, up); - store_vertex(buffer_vertices, curr_pos + half_width * right, right); - store_vertex(buffer_vertices, curr_pos + half_height * bottom, bottom); - store_vertex(buffer_vertices, curr_pos + half_width * left, left); - - // triangles starting cap - store_triangle(buffer_indices, starting_vertices_size - 4, starting_vertices_size - 2, starting_vertices_size + 0); - store_triangle(buffer_indices, starting_vertices_size - 4, starting_vertices_size + 1, starting_vertices_size - 2); - - // triangles outer corner cap - if (is_right_turn) { - if (left_displaced) - // dummy triangles - append_dummy_cap(buffer_indices, starting_vertices_size); else { - store_triangle(buffer_indices, starting_vertices_size - 4, starting_vertices_size + 1, starting_vertices_size - 1); - store_triangle(buffer_indices, starting_vertices_size + 1, starting_vertices_size - 2, starting_vertices_size - 1); + // vertices 1st endpoint (top and bottom are from previous segment 2nd endpoint) + // the inner corner vertex position matches that of the previous segment 2nd endpoint, if displaced + if (is_right_turn) { + store_vertex(buffer_vertices, right_displaced ? prev_right_pos : prev_pos + half_width * right, right); + store_vertex(buffer_vertices, prev_pos + half_width * left, left); + } + else { + store_vertex(buffer_vertices, prev_pos + half_width * right, right); + store_vertex(buffer_vertices, left_displaced ? prev_left_pos : prev_pos + half_width * left, left); + } + } + + // vertices 2nd endpoint + store_vertex(buffer_vertices, curr_pos + half_height * up, up); + store_vertex(buffer_vertices, curr_pos + half_width * right, right); + store_vertex(buffer_vertices, curr_pos + half_height * bottom, bottom); + store_vertex(buffer_vertices, curr_pos + half_width * left, left); + + // triangles starting cap + store_triangle(buffer_indices, starting_vertices_size - 4, starting_vertices_size - 2, starting_vertices_size + 0); + store_triangle(buffer_indices, starting_vertices_size - 4, starting_vertices_size + 1, starting_vertices_size - 2); + + // triangles outer corner cap + if (is_right_turn) { + if (left_displaced) + // dummy triangles + append_dummy_cap(buffer_indices, starting_vertices_size); + else { + store_triangle(buffer_indices, starting_vertices_size - 4, starting_vertices_size + 1, starting_vertices_size - 1); + store_triangle(buffer_indices, starting_vertices_size + 1, starting_vertices_size - 2, starting_vertices_size - 1); + } } - } - else { - if (right_displaced) - // dummy triangles - append_dummy_cap(buffer_indices, starting_vertices_size); else { - store_triangle(buffer_indices, starting_vertices_size - 4, starting_vertices_size - 3, starting_vertices_size + 0); - store_triangle(buffer_indices, starting_vertices_size - 3, starting_vertices_size - 2, starting_vertices_size + 0); + if (right_displaced) + // dummy triangles + append_dummy_cap(buffer_indices, starting_vertices_size); + else { + store_triangle(buffer_indices, starting_vertices_size - 4, starting_vertices_size - 3, starting_vertices_size + 0); + store_triangle(buffer_indices, starting_vertices_size - 3, starting_vertices_size - 2, starting_vertices_size + 0); + } } + + // triangles sides + store_triangle(buffer_indices, starting_vertices_size - 4, starting_vertices_size + 0, starting_vertices_size + 2); + store_triangle(buffer_indices, starting_vertices_size + 0, starting_vertices_size + 3, starting_vertices_size + 2); + store_triangle(buffer_indices, starting_vertices_size + 0, starting_vertices_size - 2, starting_vertices_size + 3); + store_triangle(buffer_indices, starting_vertices_size - 2, starting_vertices_size + 4, starting_vertices_size + 3); + store_triangle(buffer_indices, starting_vertices_size - 2, starting_vertices_size + 1, starting_vertices_size + 4); + store_triangle(buffer_indices, starting_vertices_size + 1, starting_vertices_size + 5, starting_vertices_size + 4); + store_triangle(buffer_indices, starting_vertices_size + 1, starting_vertices_size - 4, starting_vertices_size + 5); + store_triangle(buffer_indices, starting_vertices_size - 4, starting_vertices_size + 2, starting_vertices_size + 5); + + // triangles ending cap + store_triangle(buffer_indices, starting_vertices_size + 2, starting_vertices_size + 4, starting_vertices_size + 5); + store_triangle(buffer_indices, starting_vertices_size + 2, starting_vertices_size + 3, starting_vertices_size + 4); } - // triangles sides - store_triangle(buffer_indices, starting_vertices_size - 4, starting_vertices_size + 0, starting_vertices_size + 2); - store_triangle(buffer_indices, starting_vertices_size + 0, starting_vertices_size + 3, starting_vertices_size + 2); - store_triangle(buffer_indices, starting_vertices_size + 0, starting_vertices_size - 2, starting_vertices_size + 3); - store_triangle(buffer_indices, starting_vertices_size - 2, starting_vertices_size + 4, starting_vertices_size + 3); - store_triangle(buffer_indices, starting_vertices_size - 2, starting_vertices_size + 1, starting_vertices_size + 4); - store_triangle(buffer_indices, starting_vertices_size + 1, starting_vertices_size + 5, starting_vertices_size + 4); - store_triangle(buffer_indices, starting_vertices_size + 1, starting_vertices_size - 4, starting_vertices_size + 5); - store_triangle(buffer_indices, starting_vertices_size - 4, starting_vertices_size + 2, starting_vertices_size + 5); - - // triangles ending cap - store_triangle(buffer_indices, starting_vertices_size + 2, starting_vertices_size + 4, starting_vertices_size + 5); - store_triangle(buffer_indices, starting_vertices_size + 2, starting_vertices_size + 3, starting_vertices_size + 4); - } - - last_path.last = { static_cast(buffer_indices.size() - 1), static_cast(move_id), curr.position }; - prev_dir = dir; - prev_up = up; - prev_length = length; + last_path.last = { index_buffer_id, static_cast(buffer_indices.size() - 1), static_cast(move_id), curr.position }; + prev_dir = dir; + prev_up = up; + prev_length = length; }; // toolpaths data -> extract from result std::vector> vertices(m_buffers.size()); - std::vector> indices(m_buffers.size()); + std::vector indices(m_buffers.size()); + for (auto i : indices) { + i.push_back(IndexBuffer()); + } for (size_t i = 0; i < m_moves_count; ++i) { // skip first vertex if (i == 0) @@ -1174,7 +1184,34 @@ void GCodeViewer::load_toolpaths(const GCodeProcessor::Result& gcode_result) unsigned char id = buffer_id(curr.type); TBuffer& buffer = m_buffers[id]; std::vector& buffer_vertices = vertices[id]; - std::vector& buffer_indices = indices[id]; + MultiIndexBuffer& buffer_indices = indices[id]; + if (buffer_indices.empty()) + buffer_indices.push_back(IndexBuffer()); + + static const size_t THRESHOLD = 1024 * 1024 * 1024; + // if adding the indices for the current segment exceeds the threshold size of the current index buffer + // create another index buffer, and move the current path indices into it + if (buffer_indices.back().size() >= THRESHOLD - static_cast(buffer.indices_per_segment())) { + buffer_indices.push_back(IndexBuffer()); + if (curr.type == EMoveType::Extrude || curr.type == EMoveType::Travel) { + if (!(prev.type != curr.type || !buffer.paths.back().matches(curr))) { + Path& last_path = buffer.paths.back(); + size_t delta_id = last_path.last.i_id - last_path.first.i_id; + + // move indices of the last path from the previous into the new index buffer + IndexBuffer& src_buffer = buffer_indices[buffer_indices.size() - 2]; + IndexBuffer& dst_buffer = buffer_indices[buffer_indices.size() - 1]; + std::move(src_buffer.begin() + last_path.first.i_id, src_buffer.end(), std::back_inserter(dst_buffer)); + src_buffer.erase(src_buffer.begin() + last_path.first.i_id, src_buffer.end()); + + // updates path indices + last_path.first.b_id = buffer_indices.size() - 1; + last_path.first.i_id = 0; + last_path.last.b_id = buffer_indices.size() - 1; + last_path.last.i_id = delta_id; + } + } + } switch (curr.type) { @@ -1185,17 +1222,17 @@ void GCodeViewer::load_toolpaths(const GCodeProcessor::Result& gcode_result) case EMoveType::Retract: case EMoveType::Unretract: { - add_as_point(curr, buffer, buffer_vertices, buffer_indices, i); + add_as_point(curr, buffer, buffer_vertices, static_cast(buffer_indices.size()) - 1, buffer_indices.back(), i); break; } case EMoveType::Extrude: { - add_as_solid(prev, curr, buffer, buffer_vertices, buffer_indices, i); + add_as_solid(prev, curr, buffer, buffer_vertices, static_cast(buffer_indices.size()) - 1, buffer_indices.back(), i); break; } case EMoveType::Travel: { - add_as_line(prev, curr, buffer, buffer_vertices, buffer_indices, i); + add_as_line(prev, curr, buffer, buffer_vertices, static_cast(buffer_indices.size()) - 1, buffer_indices.back(), i); break; } default: { break; } @@ -1220,18 +1257,22 @@ void GCodeViewer::load_toolpaths(const GCodeProcessor::Result& gcode_result) glsafe(::glBindBuffer(GL_ARRAY_BUFFER, 0)); // indices - const std::vector& buffer_indices = indices[i]; - buffer.indices.count = buffer_indices.size(); + for (size_t j = 0; j < indices[i].size(); ++j) { + const IndexBuffer& buffer_indices = indices[i][j]; + buffer.indices.push_back(IBuffer()); + IBuffer& ibuffer = buffer.indices.back(); + ibuffer.count = buffer_indices.size(); #if ENABLE_GCODE_VIEWER_STATISTICS - m_statistics.indices_gpu_size += buffer.indices.count * sizeof(unsigned int); - m_statistics.max_indices_in_index_buffer = std::max(m_statistics.max_indices_in_index_buffer, static_cast(buffer.indices.count)); + m_statistics.indices_gpu_size += ibuffer.count * sizeof(unsigned int); + m_statistics.max_indices_in_index_buffer = std::max(m_statistics.max_indices_in_index_buffer, static_cast(ibuffer.count)); #endif // ENABLE_GCODE_VIEWER_STATISTICS - if (buffer.indices.count > 0) { - glsafe(::glGenBuffers(1, &buffer.indices.id)); - glsafe(::glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, buffer.indices.id)); - glsafe(::glBufferData(GL_ELEMENT_ARRAY_BUFFER, buffer.indices.count * sizeof(unsigned int), buffer_indices.data(), GL_STATIC_DRAW)); - glsafe(::glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0)); + if (ibuffer.count > 0) { + glsafe(::glGenBuffers(1, &ibuffer.id)); + glsafe(::glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ibuffer.id)); + glsafe(::glBufferData(GL_ELEMENT_ARRAY_BUFFER, buffer_indices.size() * sizeof(unsigned int), buffer_indices.data(), GL_STATIC_DRAW)); + glsafe(::glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0)); + } } } @@ -1240,9 +1281,15 @@ void GCodeViewer::load_toolpaths(const GCodeProcessor::Result& gcode_result) m_statistics.paths_size += SLIC3R_STDVEC_MEMSIZE(buffer.paths, Path); } unsigned int travel_buffer_id = buffer_id(EMoveType::Travel); - m_statistics.travel_segments_count = indices[travel_buffer_id].size() / m_buffers[travel_buffer_id].indices_per_segment(); + const MultiIndexBuffer& travel_buffer_indices = indices[travel_buffer_id]; + for (size_t i = 0; i < travel_buffer_indices.size(); ++i) { + m_statistics.travel_segments_count = travel_buffer_indices[i].size() / m_buffers[travel_buffer_id].indices_per_segment(); + } unsigned int extrude_buffer_id = buffer_id(EMoveType::Extrude); - m_statistics.extrude_segments_count = indices[extrude_buffer_id].size() / m_buffers[extrude_buffer_id].indices_per_segment(); + const MultiIndexBuffer& extrude_buffer_indices = indices[extrude_buffer_id]; + for (size_t i = 0; i < extrude_buffer_indices.size(); ++i) { + m_statistics.extrude_segments_count = extrude_buffer_indices[i].size() / m_buffers[extrude_buffer_id].indices_per_segment(); + } #endif // ENABLE_GCODE_VIEWER_STATISTICS // layers zs / roles / extruder ids / cp color ids -> extract from result @@ -1288,7 +1335,9 @@ void GCodeViewer::load_toolpaths(const GCodeProcessor::Result& gcode_result) } long long indices_size = 0; for (size_t i = 0; i < indices.size(); ++i) { - indices_size += SLIC3R_STDVEC_MEMSIZE(indices[i], unsigned int); + for (size_t j = 0; j < indices[i].size(); ++j) { + indices_size += SLIC3R_STDVEC_MEMSIZE(indices[i][j], unsigned int); + } } log_memory_used("Loaded G-code extrusion paths, ", vertices_size + indices_size); @@ -1380,7 +1429,7 @@ void GCodeViewer::refresh_render_paths(bool keep_sequential_current_first, bool auto travel_color = [this](const Path& path) { return (path.delta_extruder < 0.0f) ? Travel_Colors[2] /* Retract */ : - ((path.delta_extruder > 0.0f) ? Travel_Colors[1] /* Extrude */ : + ((path.delta_extruder > 0.0f) ? Travel_Colors[1] /* Extrude */ : Travel_Colors[0] /* Move */); }; @@ -1396,7 +1445,7 @@ void GCodeViewer::refresh_render_paths(bool keep_sequential_current_first, bool m_sequential_view.current.last = m_moves_count; // first pass: collect visible paths and update sequential view data - std::vector> paths; + std::vector> paths; for (TBuffer& buffer : m_buffers) { // reset render paths buffer.render_paths.clear(); @@ -1417,7 +1466,7 @@ void GCodeViewer::refresh_render_paths(bool keep_sequential_current_first, bool continue; // store valid path - paths.push_back({ &buffer, i }); + paths.push_back({ &buffer, path.first.b_id, static_cast(i) }); m_sequential_view.endpoints.first = std::min(m_sequential_view.endpoints.first, path.first.s_id); m_sequential_view.endpoints.last = std::max(m_sequential_view.endpoints.last, path.last.s_id); @@ -1434,7 +1483,7 @@ void GCodeViewer::refresh_render_paths(bool keep_sequential_current_first, bool // searches the path containing the current position for (const Path& path : buffer.paths) { if (path.contains(m_sequential_view.current.last)) { - unsigned int offset = m_sequential_view.current.last - path.first.s_id; + unsigned int offset = static_cast(m_sequential_view.current.last - path.first.s_id); if (offset > 0) { if (buffer.render_primitive_type == TBuffer::ERenderPrimitiveType::Line) offset = 2 * offset - 1; @@ -1443,11 +1492,11 @@ void GCodeViewer::refresh_render_paths(bool keep_sequential_current_first, bool offset = indices_count * (offset - 1) + (indices_count - 6); } } - offset += path.first.i_id; + offset += static_cast(path.first.i_id); // gets the index from the index buffer on gpu unsigned int index = 0; - glsafe(::glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, buffer.indices.id)); + glsafe(::glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, buffer.indices[path.first.b_id].id)); glsafe(::glGetBufferSubData(GL_ELEMENT_ARRAY_BUFFER, static_cast(offset * sizeof(unsigned int)), static_cast(sizeof(unsigned int)), static_cast(&index))); glsafe(::glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0)); @@ -1464,8 +1513,8 @@ void GCodeViewer::refresh_render_paths(bool keep_sequential_current_first, bool } // second pass: filter paths by sequential data and collect them by color - for (const auto& [buffer, id] : paths) { - const Path& path = buffer->paths[id]; + for (const auto& [buffer, index_buffer_id, path_id] : paths) { + const Path& path = buffer->paths[path_id]; if (m_sequential_view.current.last <= path.first.s_id || path.last.s_id <= m_sequential_view.current.first) continue; @@ -1477,18 +1526,21 @@ void GCodeViewer::refresh_render_paths(bool keep_sequential_current_first, bool default: { color = { 0.0f, 0.0f, 0.0f }; break; } } - auto it = std::find_if(buffer->render_paths.begin(), buffer->render_paths.end(), [color](const RenderPath& path) { return path.color == color; }); + unsigned int ibuffer_id = index_buffer_id; + auto it = std::find_if(buffer->render_paths.begin(), buffer->render_paths.end(), + [color, ibuffer_id](const RenderPath& path) { return path.index_buffer_id == ibuffer_id && path.color == color; }); if (it == buffer->render_paths.end()) { it = buffer->render_paths.insert(buffer->render_paths.end(), RenderPath()); it->color = color; - it->path_id = id; + it->path_id = path_id; + it->index_buffer_id = index_buffer_id; } unsigned int segments_count = std::min(m_sequential_view.current.last, path.last.s_id) - std::max(m_sequential_view.current.first, path.first.s_id) + 1; unsigned int size_in_indices = 0; switch (buffer->render_primitive_type) { - case TBuffer::ERenderPrimitiveType::Point: { size_in_indices = segments_count; break; } + case TBuffer::ERenderPrimitiveType::Point: { size_in_indices = segments_count; break; } case TBuffer::ERenderPrimitiveType::Line: case TBuffer::ERenderPrimitiveType::Triangle: { size_in_indices = buffer->indices_per_segment() * (segments_count - 1); break; } } @@ -1531,7 +1583,8 @@ void GCodeViewer::render_toolpaths() const shader.set_uniform("uniform_color", color4); }; - auto render_as_points = [this, zoom, point_size, near_plane_height, set_uniform_color](const TBuffer& buffer, EOptionsColors color_id, GLShaderProgram& shader) { + auto render_as_points = [this, zoom, point_size, near_plane_height, set_uniform_color] + (const TBuffer& buffer, unsigned int index_buffer_id, EOptionsColors color_id, GLShaderProgram& shader) { set_uniform_color(Options_Colors[static_cast(color_id)], shader); shader.set_uniform("zoom", zoom); shader.set_uniform("percent_outline_radius", 0.0f); @@ -1543,34 +1596,40 @@ void GCodeViewer::render_toolpaths() const glsafe(::glEnable(GL_POINT_SPRITE)); for (const RenderPath& path : buffer.render_paths) { - glsafe(::glMultiDrawElements(GL_POINTS, (const GLsizei*)path.sizes.data(), GL_UNSIGNED_INT, (const void* const*)path.offsets.data(), (GLsizei)path.sizes.size())); + if (path.index_buffer_id == index_buffer_id) { + glsafe(::glMultiDrawElements(GL_POINTS, (const GLsizei*)path.sizes.data(), GL_UNSIGNED_INT, (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)); }; - auto render_as_lines = [this, light_intensity, set_uniform_color](const TBuffer& buffer, GLShaderProgram& shader) { + auto render_as_lines = [this, light_intensity, set_uniform_color](const TBuffer& buffer, unsigned int index_buffer_id, GLShaderProgram& shader) { shader.set_uniform("light_intensity", light_intensity); for (const RenderPath& path : buffer.render_paths) { - set_uniform_color(path.color, shader); - glsafe(::glMultiDrawElements(GL_LINES, (const GLsizei*)path.sizes.data(), GL_UNSIGNED_INT, (const void* const*)path.offsets.data(), (GLsizei)path.sizes.size())); + if (path.index_buffer_id == index_buffer_id) { + set_uniform_color(path.color, shader); + glsafe(::glMultiDrawElements(GL_LINES, (const GLsizei*)path.sizes.data(), GL_UNSIGNED_INT, (const void* const*)path.offsets.data(), (GLsizei)path.sizes.size())); #if ENABLE_GCODE_VIEWER_STATISTICS - ++m_statistics.gl_multi_lines_calls_count; + ++m_statistics.gl_multi_lines_calls_count; #endif // ENABLE_GCODE_VIEWER_STATISTICS + } } }; - auto render_as_triangles = [this, set_uniform_color](const TBuffer& buffer, GLShaderProgram& shader) { + auto render_as_triangles = [this, set_uniform_color](const TBuffer& buffer, unsigned int index_buffer_id, GLShaderProgram& shader) { for (const RenderPath& path : buffer.render_paths) { - set_uniform_color(path.color, shader); - glsafe(::glMultiDrawElements(GL_TRIANGLES, (const GLsizei*)path.sizes.data(), GL_UNSIGNED_INT, (const void* const*)path.offsets.data(), (GLsizei)path.sizes.size())); + if (path.index_buffer_id == index_buffer_id) { + set_uniform_color(path.color, shader); + glsafe(::glMultiDrawElements(GL_TRIANGLES, (const GLsizei*)path.sizes.data(), GL_UNSIGNED_INT, (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 + } } }; @@ -1585,10 +1644,7 @@ void GCodeViewer::render_toolpaths() const for (unsigned char i = begin_id; i < end_id; ++i) { const TBuffer& buffer = m_buffers[i]; - if (!buffer.visible) - continue; - - if (buffer.vertices.id == 0 || buffer.indices.id == 0) + if (!buffer.visible || !buffer.has_data()) continue; GLShaderProgram* shader = wxGetApp().get_shader(buffer.shader.c_str()); @@ -1604,38 +1660,40 @@ void GCodeViewer::render_toolpaths() const glsafe(::glEnableClientState(GL_NORMAL_ARRAY)); } - glsafe(::glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, buffer.indices.id)); + for (size_t j = 0; j < buffer.indices.size(); ++j) { + glsafe(::glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, buffer.indices[j].id)); - switch (buffer.render_primitive_type) - { - case TBuffer::ERenderPrimitiveType::Point: - { - EOptionsColors color; - switch (buffer_type(i)) + switch (buffer.render_primitive_type) { - case EMoveType::Tool_change: { color = EOptionsColors::ToolChanges; break; } - case EMoveType::Color_change: { color = EOptionsColors::ColorChanges; break; } - case EMoveType::Pause_Print: { color = EOptionsColors::PausePrints; break; } - case EMoveType::Custom_GCode: { color = EOptionsColors::CustomGCodes; break; } - case EMoveType::Retract: { color = EOptionsColors::Retractions; break; } - case EMoveType::Unretract: { color = EOptionsColors::Unretractions; break; } + case TBuffer::ERenderPrimitiveType::Point: + { + EOptionsColors color; + switch (buffer_type(i)) + { + case EMoveType::Tool_change: { color = EOptionsColors::ToolChanges; break; } + case EMoveType::Color_change: { color = EOptionsColors::ColorChanges; break; } + case EMoveType::Pause_Print: { color = EOptionsColors::PausePrints; break; } + case EMoveType::Custom_GCode: { color = EOptionsColors::CustomGCodes; break; } + case EMoveType::Retract: { color = EOptionsColors::Retractions; break; } + case EMoveType::Unretract: { color = EOptionsColors::Unretractions; break; } + } + render_as_points(buffer, static_cast(j), color, *shader); + break; + } + case TBuffer::ERenderPrimitiveType::Line: + { + render_as_lines(buffer, static_cast(j), *shader); + break; + } + case TBuffer::ERenderPrimitiveType::Triangle: + { + render_as_triangles(buffer, static_cast(j), *shader); + break; + } } - render_as_points(buffer, color, *shader); - break; - } - case TBuffer::ERenderPrimitiveType::Line: - { - render_as_lines(buffer, *shader); - break; - } - case TBuffer::ERenderPrimitiveType::Triangle: - { - render_as_triangles(buffer, *shader); - break; - } - } - glsafe(::glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0)); + glsafe(::glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0)); + } if (has_normals) glsafe(::glDisableClientState(GL_NORMAL_ARRAY)); @@ -1698,90 +1756,90 @@ void GCodeViewer::render_legend() const std::function callback = nullptr) { if (!visible) ImGui::PushStyleVar(ImGuiStyleVar_Alpha, 0.3333f); - ImVec2 pos = ImGui::GetCursorScreenPos(); - switch (type) - { - default: - case EItemType::Rect: - { - draw_list->AddRectFilled({ pos.x + 1.0f, pos.y + 1.0f }, { pos.x + icon_size - 1.0f, pos.y + icon_size - 1.0f }, - ImGui::GetColorU32({ color[0], color[1], color[2], 1.0f })); - break; - } - case EItemType::Circle: - { - ImVec2 center(0.5f * (pos.x + pos.x + icon_size), 0.5f * (pos.y + pos.y + icon_size)); - if (m_buffers[buffer_id(EMoveType::Retract)].shader == "options_120") { - draw_list->AddCircleFilled(center, 0.5f * icon_size, - ImGui::GetColorU32({ 0.5f * color[0], 0.5f * color[1], 0.5f * color[2], 1.0f }), 16); - float radius = 0.5f * icon_size; - draw_list->AddCircleFilled(center, radius, ImGui::GetColorU32({ color[0], color[1], color[2], 1.0f }), 16); - radius = 0.5f * icon_size * 0.01f * 33.0f; - draw_list->AddCircleFilled(center, radius, ImGui::GetColorU32({ 0.5f * color[0], 0.5f * color[1], 0.5f * color[2], 1.0f }), 16); + ImVec2 pos = ImGui::GetCursorScreenPos(); + switch (type) + { + default: + case EItemType::Rect: + { + draw_list->AddRectFilled({ pos.x + 1.0f, pos.y + 1.0f }, { pos.x + icon_size - 1.0f, pos.y + icon_size - 1.0f }, + ImGui::GetColorU32({ color[0], color[1], color[2], 1.0f })); + break; } - else - draw_list->AddCircleFilled(center, 0.5f * icon_size, ImGui::GetColorU32({ color[0], color[1], color[2], 1.0f }), 16); + case EItemType::Circle: + { + ImVec2 center(0.5f * (pos.x + pos.x + icon_size), 0.5f * (pos.y + pos.y + icon_size)); + if (m_buffers[buffer_id(EMoveType::Retract)].shader == "options_120") { + draw_list->AddCircleFilled(center, 0.5f * icon_size, + ImGui::GetColorU32({ 0.5f * color[0], 0.5f * color[1], 0.5f * color[2], 1.0f }), 16); + float radius = 0.5f * icon_size; + draw_list->AddCircleFilled(center, radius, ImGui::GetColorU32({ color[0], color[1], color[2], 1.0f }), 16); + radius = 0.5f * icon_size * 0.01f * 33.0f; + draw_list->AddCircleFilled(center, radius, ImGui::GetColorU32({ 0.5f * color[0], 0.5f * color[1], 0.5f * color[2], 1.0f }), 16); + } + else + draw_list->AddCircleFilled(center, 0.5f * icon_size, ImGui::GetColorU32({ color[0], color[1], color[2], 1.0f }), 16); - break; - } - case EItemType::Hexagon: - { - ImVec2 center(0.5f * (pos.x + pos.x + icon_size), 0.5f * (pos.y + pos.y + icon_size)); - draw_list->AddNgonFilled(center, 0.5f * icon_size, ImGui::GetColorU32({ color[0], color[1], color[2], 1.0f }), 6); - break; - } - case EItemType::Line: - { - draw_list->AddLine({ pos.x + 1, pos.y + icon_size - 1}, { pos.x + icon_size - 1, pos.y + 1 }, ImGui::GetColorU32({ color[0], color[1], color[2], 1.0f }), 3.0f); - break; - } - } + break; + } + case EItemType::Hexagon: + { + ImVec2 center(0.5f * (pos.x + pos.x + icon_size), 0.5f * (pos.y + pos.y + icon_size)); + draw_list->AddNgonFilled(center, 0.5f * icon_size, ImGui::GetColorU32({ color[0], color[1], color[2], 1.0f }), 6); + break; + } + case EItemType::Line: + { + draw_list->AddLine({ pos.x + 1, pos.y + icon_size - 1 }, { pos.x + icon_size - 1, pos.y + 1 }, ImGui::GetColorU32({ color[0], color[1], color[2], 1.0f }), 3.0f); + break; + } + } - // draw text - ImGui::Dummy({ icon_size, icon_size }); - ImGui::SameLine(); - if (callback != nullptr) { - if (ImGui::MenuItem(label.c_str())) - callback(); - else { - // show tooltip - if (ImGui::IsItemHovered()) { - if (!visible) - ImGui::PopStyleVar(); - ImGui::PushStyleColor(ImGuiCol_PopupBg, ImGuiWrapper::COL_WINDOW_BACKGROUND); - ImGui::BeginTooltip(); - imgui.text(visible ? _u8L("Click to hide") : _u8L("Click to show")); - ImGui::EndTooltip(); - ImGui::PopStyleColor(); - if (!visible) - ImGui::PushStyleVar(ImGuiStyleVar_Alpha, 0.3333f); + // draw text + ImGui::Dummy({ icon_size, icon_size }); + ImGui::SameLine(); + if (callback != nullptr) { + if (ImGui::MenuItem(label.c_str())) + callback(); + else { + // show tooltip + if (ImGui::IsItemHovered()) { + if (!visible) + ImGui::PopStyleVar(); + ImGui::PushStyleColor(ImGuiCol_PopupBg, ImGuiWrapper::COL_WINDOW_BACKGROUND); + ImGui::BeginTooltip(); + imgui.text(visible ? _u8L("Click to hide") : _u8L("Click to show")); + ImGui::EndTooltip(); + ImGui::PopStyleColor(); + if (!visible) + ImGui::PushStyleVar(ImGuiStyleVar_Alpha, 0.3333f); - // to avoid the tooltip to change size when moving the mouse - wxGetApp().plater()->get_current_canvas3D()->set_as_dirty(); - wxGetApp().plater()->get_current_canvas3D()->request_extra_frame(); + // to avoid the tooltip to change size when moving the mouse + wxGetApp().plater()->get_current_canvas3D()->set_as_dirty(); + wxGetApp().plater()->get_current_canvas3D()->request_extra_frame(); + } + } + + if (!time.empty()) { + ImGui::SameLine(offsets[0]); + imgui.text(time); + ImGui::SameLine(offsets[1]); + pos = ImGui::GetCursorScreenPos(); + float width = std::max(1.0f, percent_bar_size * percent / max_percent); + draw_list->AddRectFilled({ pos.x, pos.y + 2.0f }, { pos.x + width, pos.y + icon_size - 2.0f }, + ImGui::GetColorU32(ImGuiWrapper::COL_ORANGE_LIGHT)); + ImGui::Dummy({ percent_bar_size, icon_size }); + ImGui::SameLine(); + char buf[64]; + ::sprintf(buf, "%.1f%%", 100.0f * percent); + ImGui::TextUnformatted((percent > 0.0f) ? buf : ""); } } + else + imgui.text(label); - if (!time.empty()) { - ImGui::SameLine(offsets[0]); - imgui.text(time); - ImGui::SameLine(offsets[1]); - pos = ImGui::GetCursorScreenPos(); - float width = std::max(1.0f, percent_bar_size * percent / max_percent); - draw_list->AddRectFilled({ pos.x, pos.y + 2.0f }, { pos.x + width, pos.y + icon_size - 2.0f }, - ImGui::GetColorU32(ImGuiWrapper::COL_ORANGE_LIGHT)); - ImGui::Dummy({ percent_bar_size, icon_size }); - ImGui::SameLine(); - char buf[64]; - ::sprintf(buf, "%.1f%%", 100.0f * percent); - ImGui::TextUnformatted((percent > 0.0f) ? buf : ""); - } - } - else - imgui.text(label); - - if (!visible) - ImGui::PopStyleVar(); + if (!visible) + ImGui::PopStyleVar(); }; auto append_range = [this, draw_list, &imgui, append_item](const Extrusions::Range& range, unsigned int decimals) { @@ -1969,13 +2027,13 @@ void GCodeViewer::render_legend() const append_headers({ _u8L("Feature type"), _u8L("Time"), _u8L("Percentage") }, offsets); break; } - case EViewType::Height: { imgui.title(_u8L("Height (mm)")); break; } - case EViewType::Width: { imgui.title(_u8L("Width (mm)")); break; } - case EViewType::Feedrate: { imgui.title(_u8L("Speed (mm/s)")); break; } - case EViewType::FanSpeed: { imgui.title(_u8L("Fan Speed (%)")); break; } + case EViewType::Height: { imgui.title(_u8L("Height (mm)")); break; } + case EViewType::Width: { imgui.title(_u8L("Width (mm)")); break; } + case EViewType::Feedrate: { imgui.title(_u8L("Speed (mm/s)")); break; } + case EViewType::FanSpeed: { imgui.title(_u8L("Fan Speed (%)")); break; } case EViewType::VolumetricRate: { imgui.title(_u8L("Volumetric flow rate (mm³/s)")); break; } - case EViewType::Tool: { imgui.title(_u8L("Tool")); break; } - case EViewType::ColorPrint: { imgui.title(_u8L("Color Print")); break; } + case EViewType::Tool: { imgui.title(_u8L("Tool")); break; } + case EViewType::ColorPrint: { imgui.title(_u8L("Color Print")); break; } default: { break; } } @@ -2001,10 +2059,10 @@ void GCodeViewer::render_legend() const } break; } - case EViewType::Height: { append_range(m_extrusions.ranges.height, 3); break; } - case EViewType::Width: { append_range(m_extrusions.ranges.width, 3); break; } - case EViewType::Feedrate: { append_range(m_extrusions.ranges.feedrate, 1); break; } - case EViewType::FanSpeed: { append_range(m_extrusions.ranges.fan_speed, 0); break; } + case EViewType::Height: { append_range(m_extrusions.ranges.height, 3); break; } + case EViewType::Width: { append_range(m_extrusions.ranges.width, 3); break; } + case EViewType::Feedrate: { append_range(m_extrusions.ranges.feedrate, 1); break; } + case EViewType::FanSpeed: { append_range(m_extrusions.ranges.fan_speed, 0); break; } case EViewType::VolumetricRate: { append_range(m_extrusions.ranges.volumetric_rate, 3); break; } case EViewType::Tool: { @@ -2237,7 +2295,7 @@ void GCodeViewer::render_legend() const auto any_option_available = [this]() { auto available = [this](EMoveType type) { const TBuffer& buffer = m_buffers[buffer_id(type)]; - return buffer.visible && buffer.indices.count > 0; + return buffer.visible && buffer.has_data(); }; return available(EMoveType::Color_change) || @@ -2250,7 +2308,7 @@ void GCodeViewer::render_legend() const auto add_option = [this, append_item](EMoveType move_type, EOptionsColors color, const std::string& text) { const TBuffer& buffer = m_buffers[buffer_id(move_type)]; - if (buffer.visible && buffer.indices.count > 0) + if (buffer.visible && buffer.has_data()) append_item((buffer.shader == "options_110") ? EItemType::Rect : EItemType::Circle, Options_Colors[static_cast(color)], text); }; @@ -2276,7 +2334,7 @@ void GCodeViewer::render_legend() const #if ENABLE_GCODE_VIEWER_STATISTICS void GCodeViewer::render_statistics() const { - static const float offset = 230.0f; + static const float offset = 250.0f; ImGuiWrapper& imgui = *wxGetApp().imgui(); diff --git a/src/slic3r/GUI/GCodeViewer.hpp b/src/slic3r/GUI/GCodeViewer.hpp index 7ced11be9..73c4ad7b2 100644 --- a/src/slic3r/GUI/GCodeViewer.hpp +++ b/src/slic3r/GUI/GCodeViewer.hpp @@ -18,6 +18,9 @@ namespace GUI { class GCodeViewer { using Color = std::array; + using IndexBuffer = std::vector; + using MultiIndexBuffer = std::vector; + static const std::vector Extrusion_Role_Colors; static const std::vector Options_Colors; static const std::vector Travel_Colors; @@ -112,10 +115,12 @@ class GCodeViewer { struct Endpoint { - // index into the indices buffer - unsigned int i_id{ 0u }; - // sequential id - unsigned int s_id{ 0u }; + // index of the index buffer + unsigned int b_id{ 0 }; + // index into the index buffer + size_t i_id{ 0 }; + // sequential id (index into the vertex buffer) + size_t s_id{ 0 }; Vec3f position{ Vec3f::Zero() }; }; @@ -134,14 +139,15 @@ class GCodeViewer bool matches(const GCodeProcessor::MoveVertex& move) const; size_t vertices_count() const { return last.s_id - first.s_id + 1; } - bool contains(unsigned int id) const { return first.s_id <= id && id <= last.s_id; } + bool contains(size_t id) const { return first.s_id <= id && id <= last.s_id; } }; // Used to batch the indices needed to render paths struct RenderPath { Color color; - size_t path_id; + unsigned int path_id; + unsigned int index_buffer_id; std::vector sizes; std::vector offsets; // use size_t because we need an unsigned int whose size matches pointer's size (used in the call glMultiDrawElements()) }; @@ -158,7 +164,7 @@ class GCodeViewer ERenderPrimitiveType render_primitive_type; VBuffer vertices; - IBuffer indices; + std::vector indices; std::string shader; std::vector paths; @@ -166,7 +172,10 @@ class GCodeViewer bool visible{ false }; void reset(); - void add_path(const GCodeProcessor::MoveVertex& move, unsigned int i_id, unsigned int s_id); + // b_id index of buffer contained in this->indices + // i_id index of first index contained in this->indices[b_id] + // s_id index of first vertex contained in this->vertices + void add_path(const GCodeProcessor::MoveVertex& move, unsigned int b_id, size_t i_id, size_t s_id); unsigned int indices_per_segment() const { switch (render_primitive_type) { @@ -194,6 +203,8 @@ class GCodeViewer default: { return 0; } } } + + bool has_data() const { return vertices.id != 0 && !indices.empty() && indices.front().id != 0; } }; // helper to render shells @@ -350,8 +361,8 @@ public: struct Endpoints { - unsigned int first{ 0 }; - unsigned int last{ 0 }; + size_t first{ 0 }; + size_t last{ 0 }; }; Endpoints endpoints;