Use multiple index buffers to render toolpaths in preview

This commit is contained in:
enricoturri1966 2020-09-16 15:45:53 +02:00
parent 743d6643ae
commit 7a10e23470
2 changed files with 480 additions and 411 deletions

View File

@ -129,16 +129,19 @@ void GCodeViewer::TBuffer::reset()
{ {
// release gpu memory // release gpu memory
vertices.reset(); vertices.reset();
indices.reset(); for (IBuffer& buffer : indices) {
buffer.reset();
}
// release cpu memory // release cpu memory
indices = std::vector<IBuffer>();
paths = std::vector<Path>(); paths = std::vector<Path>();
render_paths = std::vector<RenderPath>(); render_paths = std::vector<RenderPath>();
} }
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 // use rounding to reduce the number of generated paths
paths.push_back({ move.type, move.extrusion_role, endpoint, endpoint, move.delta_extruder, 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, 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 // the data needed is contained into the Extrude TBuffer
const TBuffer& buffer = m_buffers[buffer_id(EMoveType::Extrude)]; const TBuffer& buffer = m_buffers[buffer_id(EMoveType::Extrude)];
if (buffer.vertices.id == 0 || buffer.indices.id == 0) if (!buffer.has_data())
return; return;
// collect color information to generate materials // 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)); glsafe(::glBindBuffer(GL_ARRAY_BUFFER, 0));
// get indices data from index buffer on gpu // get indices data from index buffer on gpu
std::vector<unsigned int> indices = std::vector<unsigned int>(buffer.indices.count); MultiIndexBuffer indices;
glsafe(::glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, buffer.indices.id)); for (size_t i = 0; i < buffer.indices.size(); ++i) {
glsafe(::glGetBufferSubData(GL_ELEMENT_ARRAY_BUFFER, 0, static_cast<GLsizeiptr>(indices.size() * sizeof(unsigned int)), indices.data())); 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<GLsizeiptr>(indices.back().size() * sizeof(unsigned int)), indices.back().data()));
glsafe(::glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0)); glsafe(::glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0));
}
auto get_vertex = [&vertices, floats_per_vertex](unsigned int id) { auto get_vertex = [&vertices, floats_per_vertex](unsigned int id) {
// extract vertex from vector of floats // 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) { for (size_t i = 0; i < buffer.render_paths.size(); ++i) {
// get paths segments from buffer paths // get paths segments from buffer paths
const RenderPath& render_path = buffer.render_paths[i]; 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]; const Path& path = buffer.paths[render_path.path_id];
float half_width = 0.5f * path.width; 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 // 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]; unsigned int end = start + render_path.sizes[j];
for (size_t k = start; k < end; k += static_cast<size_t>(indices_per_segment)) { for (size_t k = start; k < end; k += static_cast<size_t>(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) { if (k == start) {
// starting endpoint vertices/normals // starting endpoint vertices/normals
out_vertices.push_back(curr.v1 + curr.rl_displacement); out_normals.push_back(curr.right); // right 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; out_vertices_count += 2;
size_t first_vertex_id = k - static_cast<size_t>(indices_per_segment); size_t first_vertex_id = k - static_cast<size_t>(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 disp = 0.0f;
float cos_dir = prev.dir.dot(curr.dir); float cos_dir = prev.dir.dot(curr.dir);
if (cos_dir > -0.9998477f) { if (cos_dir > -0.9998477f) {
@ -895,17 +902,17 @@ void GCodeViewer::load_toolpaths(const GCodeProcessor::Result& gcode_result)
// format data into the buffers to be rendered as points // format data into the buffers to be rendered as points
auto add_as_point = [](const GCodeProcessor::MoveVertex& curr, TBuffer& buffer, auto add_as_point = [](const GCodeProcessor::MoveVertex& curr, TBuffer& buffer,
std::vector<float>& buffer_vertices, std::vector<unsigned int>& buffer_indices, size_t move_id) { std::vector<float>& buffer_vertices, unsigned int index_buffer_id, IndexBuffer& buffer_indices, size_t move_id) {
for (int j = 0; j < 3; ++j) { for (int j = 0; j < 3; ++j) {
buffer_vertices.push_back(curr.position[j]); buffer_vertices.push_back(curr.position[j]);
} }
buffer.add_path(curr, static_cast<unsigned int>(buffer_indices.size()), static_cast<unsigned int>(move_id)); buffer.add_path(curr, index_buffer_id, static_cast<size_t>(buffer_indices.size()), static_cast<size_t>(move_id));
buffer_indices.push_back(static_cast<unsigned int>(buffer_indices.size())); buffer_indices.push_back(static_cast<unsigned int>(buffer_indices.size()));
}; };
// format data into the buffers to be rendered as lines // format data into the buffers to be rendered as lines
auto add_as_line = [](const GCodeProcessor::MoveVertex& prev, const GCodeProcessor::MoveVertex& curr, TBuffer& buffer, auto add_as_line = [](const GCodeProcessor::MoveVertex& prev, const GCodeProcessor::MoveVertex& curr, TBuffer& buffer,
std::vector<float>& buffer_vertices, std::vector<unsigned int>& buffer_indices, size_t move_id) { std::vector<float>& 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) // 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]; float normal_x = (curr.position - prev.position).normalized()[1];
@ -918,7 +925,7 @@ void GCodeViewer::load_toolpaths(const GCodeProcessor::Result& gcode_result)
buffer_vertices.push_back(normal_x); buffer_vertices.push_back(normal_x);
// add starting index // add starting index
buffer_indices.push_back(static_cast<unsigned int>(buffer_indices.size())); buffer_indices.push_back(static_cast<unsigned int>(buffer_indices.size()));
buffer.add_path(curr, static_cast<unsigned int>(buffer_indices.size() - 1), static_cast<unsigned int>(move_id - 1)); buffer.add_path(curr, index_buffer_id, static_cast<size_t>(buffer_indices.size() - 1), static_cast<size_t>(move_id - 1));
buffer.paths.back().first.position = prev.position; buffer.paths.back().first.position = prev.position;
} }
@ -942,12 +949,12 @@ void GCodeViewer::load_toolpaths(const GCodeProcessor::Result& gcode_result)
buffer_vertices.push_back(normal_x); buffer_vertices.push_back(normal_x);
// add current index // add current index
buffer_indices.push_back(static_cast<unsigned int>(buffer_indices.size())); buffer_indices.push_back(static_cast<unsigned int>(buffer_indices.size()));
last_path.last = { static_cast<unsigned int>(buffer_indices.size() - 1), static_cast<unsigned int>(move_id), curr.position }; last_path.last = { index_buffer_id, static_cast<size_t>(buffer_indices.size() - 1), static_cast<size_t>(move_id), curr.position };
}; };
// format data into the buffers to be rendered as solid // format data into the buffers to be rendered as solid
auto add_as_solid = [](const GCodeProcessor::MoveVertex& prev, const GCodeProcessor::MoveVertex& curr, TBuffer& buffer, auto add_as_solid = [](const GCodeProcessor::MoveVertex& prev, const GCodeProcessor::MoveVertex& curr, TBuffer& buffer,
std::vector<float>& buffer_vertices, std::vector<unsigned int>& buffer_indices, size_t move_id) { std::vector<float>& buffer_vertices, unsigned int index_buffer_id, IndexBuffer& buffer_indices, size_t move_id) {
static Vec3f prev_dir; static Vec3f prev_dir;
static Vec3f prev_up; static Vec3f prev_up;
static float prev_length; static float prev_length;
@ -961,7 +968,7 @@ void GCodeViewer::load_toolpaths(const GCodeProcessor::Result& gcode_result)
buffer_vertices.push_back(normal[j]); buffer_vertices.push_back(normal[j]);
} }
}; };
auto store_triangle = [](std::vector<unsigned int>& buffer_indices, unsigned int i1, unsigned int i2, unsigned int i3) { auto store_triangle = [](IndexBuffer& buffer_indices, unsigned int i1, unsigned int i2, unsigned int i3) {
buffer_indices.push_back(i1); buffer_indices.push_back(i1);
buffer_indices.push_back(i2); buffer_indices.push_back(i2);
buffer_indices.push_back(i3); buffer_indices.push_back(i3);
@ -974,13 +981,13 @@ void GCodeViewer::load_toolpaths(const GCodeProcessor::Result& gcode_result)
vertices[id + 1] = position[1]; vertices[id + 1] = position[1];
vertices[id + 2] = position[2]; vertices[id + 2] = position[2];
}; };
auto append_dummy_cap = [store_triangle](std::vector<unsigned int>& buffer_indices, unsigned int id) { 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);
store_triangle(buffer_indices, id, id, id); store_triangle(buffer_indices, id, id, id);
}; };
if (prev.type != curr.type || !buffer.paths.back().matches(curr)) { if (prev.type != curr.type || !buffer.paths.back().matches(curr)) {
buffer.add_path(curr, static_cast<unsigned int>(buffer_indices.size()), static_cast<unsigned int>(move_id - 1)); buffer.add_path(curr, index_buffer_id, static_cast<size_t>(buffer_indices.size()), static_cast<size_t>(move_id - 1));
buffer.paths.back().first.position = prev.position; buffer.paths.back().first.position = prev.position;
} }
@ -1154,7 +1161,7 @@ void GCodeViewer::load_toolpaths(const GCodeProcessor::Result& gcode_result)
store_triangle(buffer_indices, starting_vertices_size + 2, starting_vertices_size + 3, starting_vertices_size + 4); store_triangle(buffer_indices, starting_vertices_size + 2, starting_vertices_size + 3, starting_vertices_size + 4);
} }
last_path.last = { static_cast<unsigned int>(buffer_indices.size() - 1), static_cast<unsigned int>(move_id), curr.position }; last_path.last = { index_buffer_id, static_cast<size_t>(buffer_indices.size() - 1), static_cast<size_t>(move_id), curr.position };
prev_dir = dir; prev_dir = dir;
prev_up = up; prev_up = up;
prev_length = length; prev_length = length;
@ -1162,7 +1169,10 @@ void GCodeViewer::load_toolpaths(const GCodeProcessor::Result& gcode_result)
// toolpaths data -> extract from result // toolpaths data -> extract from result
std::vector<std::vector<float>> vertices(m_buffers.size()); std::vector<std::vector<float>> vertices(m_buffers.size());
std::vector<std::vector<unsigned int>> indices(m_buffers.size()); std::vector<MultiIndexBuffer> indices(m_buffers.size());
for (auto i : indices) {
i.push_back(IndexBuffer());
}
for (size_t i = 0; i < m_moves_count; ++i) { for (size_t i = 0; i < m_moves_count; ++i) {
// skip first vertex // skip first vertex
if (i == 0) if (i == 0)
@ -1174,7 +1184,34 @@ void GCodeViewer::load_toolpaths(const GCodeProcessor::Result& gcode_result)
unsigned char id = buffer_id(curr.type); unsigned char id = buffer_id(curr.type);
TBuffer& buffer = m_buffers[id]; TBuffer& buffer = m_buffers[id];
std::vector<float>& buffer_vertices = vertices[id]; std::vector<float>& buffer_vertices = vertices[id];
std::vector<unsigned int>& 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<size_t>(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) switch (curr.type)
{ {
@ -1185,17 +1222,17 @@ void GCodeViewer::load_toolpaths(const GCodeProcessor::Result& gcode_result)
case EMoveType::Retract: case EMoveType::Retract:
case EMoveType::Unretract: case EMoveType::Unretract:
{ {
add_as_point(curr, buffer, buffer_vertices, buffer_indices, i); add_as_point(curr, buffer, buffer_vertices, static_cast<unsigned int>(buffer_indices.size()) - 1, buffer_indices.back(), i);
break; break;
} }
case EMoveType::Extrude: case EMoveType::Extrude:
{ {
add_as_solid(prev, curr, buffer, buffer_vertices, buffer_indices, i); add_as_solid(prev, curr, buffer, buffer_vertices, static_cast<unsigned int>(buffer_indices.size()) - 1, buffer_indices.back(), i);
break; break;
} }
case EMoveType::Travel: case EMoveType::Travel:
{ {
add_as_line(prev, curr, buffer, buffer_vertices, buffer_indices, i); add_as_line(prev, curr, buffer, buffer_vertices, static_cast<unsigned int>(buffer_indices.size()) - 1, buffer_indices.back(), i);
break; break;
} }
default: { break; } default: { break; }
@ -1220,29 +1257,39 @@ void GCodeViewer::load_toolpaths(const GCodeProcessor::Result& gcode_result)
glsafe(::glBindBuffer(GL_ARRAY_BUFFER, 0)); glsafe(::glBindBuffer(GL_ARRAY_BUFFER, 0));
// indices // indices
const std::vector<unsigned int>& buffer_indices = indices[i]; for (size_t j = 0; j < indices[i].size(); ++j) {
buffer.indices.count = buffer_indices.size(); 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 #if ENABLE_GCODE_VIEWER_STATISTICS
m_statistics.indices_gpu_size += buffer.indices.count * sizeof(unsigned int); 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<long long>(buffer.indices.count)); m_statistics.max_indices_in_index_buffer = std::max(m_statistics.max_indices_in_index_buffer, static_cast<long long>(ibuffer.count));
#endif // ENABLE_GCODE_VIEWER_STATISTICS #endif // ENABLE_GCODE_VIEWER_STATISTICS
if (buffer.indices.count > 0) { if (ibuffer.count > 0) {
glsafe(::glGenBuffers(1, &buffer.indices.id)); glsafe(::glGenBuffers(1, &ibuffer.id));
glsafe(::glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, buffer.indices.id)); glsafe(::glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ibuffer.id));
glsafe(::glBufferData(GL_ELEMENT_ARRAY_BUFFER, buffer.indices.count * sizeof(unsigned int), buffer_indices.data(), GL_STATIC_DRAW)); 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)); glsafe(::glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0));
} }
} }
}
#if ENABLE_GCODE_VIEWER_STATISTICS #if ENABLE_GCODE_VIEWER_STATISTICS
for (const TBuffer& buffer : m_buffers) { for (const TBuffer& buffer : m_buffers) {
m_statistics.paths_size += SLIC3R_STDVEC_MEMSIZE(buffer.paths, Path); m_statistics.paths_size += SLIC3R_STDVEC_MEMSIZE(buffer.paths, Path);
} }
unsigned int travel_buffer_id = buffer_id(EMoveType::Travel); 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); 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 #endif // ENABLE_GCODE_VIEWER_STATISTICS
// layers zs / roles / extruder ids / cp color ids -> extract from result // 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; long long indices_size = 0;
for (size_t i = 0; i < indices.size(); ++i) { 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); log_memory_used("Loaded G-code extrusion paths, ", vertices_size + indices_size);
@ -1396,7 +1445,7 @@ void GCodeViewer::refresh_render_paths(bool keep_sequential_current_first, bool
m_sequential_view.current.last = m_moves_count; m_sequential_view.current.last = m_moves_count;
// first pass: collect visible paths and update sequential view data // first pass: collect visible paths and update sequential view data
std::vector<std::pair<TBuffer*, size_t>> paths; std::vector<std::tuple<TBuffer*, unsigned int, unsigned int>> paths;
for (TBuffer& buffer : m_buffers) { for (TBuffer& buffer : m_buffers) {
// reset render paths // reset render paths
buffer.render_paths.clear(); buffer.render_paths.clear();
@ -1417,7 +1466,7 @@ void GCodeViewer::refresh_render_paths(bool keep_sequential_current_first, bool
continue; continue;
// store valid path // store valid path
paths.push_back({ &buffer, i }); paths.push_back({ &buffer, path.first.b_id, static_cast<unsigned int>(i) });
m_sequential_view.endpoints.first = std::min(m_sequential_view.endpoints.first, path.first.s_id); 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); 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 // searches the path containing the current position
for (const Path& path : buffer.paths) { for (const Path& path : buffer.paths) {
if (path.contains(m_sequential_view.current.last)) { 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<unsigned int>(m_sequential_view.current.last - path.first.s_id);
if (offset > 0) { if (offset > 0) {
if (buffer.render_primitive_type == TBuffer::ERenderPrimitiveType::Line) if (buffer.render_primitive_type == TBuffer::ERenderPrimitiveType::Line)
offset = 2 * offset - 1; 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 = indices_count * (offset - 1) + (indices_count - 6);
} }
} }
offset += path.first.i_id; offset += static_cast<unsigned int>(path.first.i_id);
// gets the index from the index buffer on gpu // gets the index from the index buffer on gpu
unsigned int index = 0; 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<GLintptr>(offset * sizeof(unsigned int)), static_cast<GLsizeiptr>(sizeof(unsigned int)), static_cast<void*>(&index))); glsafe(::glGetBufferSubData(GL_ELEMENT_ARRAY_BUFFER, static_cast<GLintptr>(offset * sizeof(unsigned int)), static_cast<GLsizeiptr>(sizeof(unsigned int)), static_cast<void*>(&index)));
glsafe(::glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0)); 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 // second pass: filter paths by sequential data and collect them by color
for (const auto& [buffer, id] : paths) { for (const auto& [buffer, index_buffer_id, path_id] : paths) {
const Path& path = buffer->paths[id]; 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) if (m_sequential_view.current.last <= path.first.s_id || path.last.s_id <= m_sequential_view.current.first)
continue; continue;
@ -1477,11 +1526,14 @@ void GCodeViewer::refresh_render_paths(bool keep_sequential_current_first, bool
default: { color = { 0.0f, 0.0f, 0.0f }; break; } 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()) { if (it == buffer->render_paths.end()) {
it = buffer->render_paths.insert(buffer->render_paths.end(), RenderPath()); it = buffer->render_paths.insert(buffer->render_paths.end(), RenderPath());
it->color = color; 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 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;
@ -1531,7 +1583,8 @@ void GCodeViewer::render_toolpaths() const
shader.set_uniform("uniform_color", color4); 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<unsigned int>(color_id)], shader); set_uniform_color(Options_Colors[static_cast<unsigned int>(color_id)], shader);
shader.set_uniform("zoom", zoom); shader.set_uniform("zoom", zoom);
shader.set_uniform("percent_outline_radius", 0.0f); shader.set_uniform("percent_outline_radius", 0.0f);
@ -1543,35 +1596,41 @@ void GCodeViewer::render_toolpaths() const
glsafe(::glEnable(GL_POINT_SPRITE)); glsafe(::glEnable(GL_POINT_SPRITE));
for (const RenderPath& path : buffer.render_paths) { for (const RenderPath& path : buffer.render_paths) {
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())); 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 #if ENABLE_GCODE_VIEWER_STATISTICS
++m_statistics.gl_multi_points_calls_count; ++m_statistics.gl_multi_points_calls_count;
#endif // ENABLE_GCODE_VIEWER_STATISTICS #endif // ENABLE_GCODE_VIEWER_STATISTICS
} }
}
glsafe(::glDisable(GL_POINT_SPRITE)); glsafe(::glDisable(GL_POINT_SPRITE));
glsafe(::glDisable(GL_VERTEX_PROGRAM_POINT_SIZE)); 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); shader.set_uniform("light_intensity", light_intensity);
for (const RenderPath& path : buffer.render_paths) { for (const RenderPath& path : buffer.render_paths) {
if (path.index_buffer_id == index_buffer_id) {
set_uniform_color(path.color, shader); 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())); 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 #if ENABLE_GCODE_VIEWER_STATISTICS
++m_statistics.gl_multi_lines_calls_count; ++m_statistics.gl_multi_lines_calls_count;
#endif // ENABLE_GCODE_VIEWER_STATISTICS #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) { for (const RenderPath& path : buffer.render_paths) {
if (path.index_buffer_id == index_buffer_id) {
set_uniform_color(path.color, shader); 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())); 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 #if ENABLE_GCODE_VIEWER_STATISTICS
++m_statistics.gl_multi_triangles_calls_count; ++m_statistics.gl_multi_triangles_calls_count;
#endif // ENABLE_GCODE_VIEWER_STATISTICS #endif // ENABLE_GCODE_VIEWER_STATISTICS
} }
}
}; };
auto line_width = [](double zoom) { auto line_width = [](double zoom) {
@ -1585,10 +1644,7 @@ void GCodeViewer::render_toolpaths() const
for (unsigned char i = begin_id; i < end_id; ++i) { for (unsigned char i = begin_id; i < end_id; ++i) {
const TBuffer& buffer = m_buffers[i]; const TBuffer& buffer = m_buffers[i];
if (!buffer.visible) if (!buffer.visible || !buffer.has_data())
continue;
if (buffer.vertices.id == 0 || buffer.indices.id == 0)
continue; continue;
GLShaderProgram* shader = wxGetApp().get_shader(buffer.shader.c_str()); GLShaderProgram* shader = wxGetApp().get_shader(buffer.shader.c_str());
@ -1604,7 +1660,8 @@ void GCodeViewer::render_toolpaths() const
glsafe(::glEnableClientState(GL_NORMAL_ARRAY)); 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) switch (buffer.render_primitive_type)
{ {
@ -1620,22 +1677,23 @@ void GCodeViewer::render_toolpaths() const
case EMoveType::Retract: { color = EOptionsColors::Retractions; break; } case EMoveType::Retract: { color = EOptionsColors::Retractions; break; }
case EMoveType::Unretract: { color = EOptionsColors::Unretractions; break; } case EMoveType::Unretract: { color = EOptionsColors::Unretractions; break; }
} }
render_as_points(buffer, color, *shader); render_as_points(buffer, static_cast<unsigned int>(j), color, *shader);
break; break;
} }
case TBuffer::ERenderPrimitiveType::Line: case TBuffer::ERenderPrimitiveType::Line:
{ {
render_as_lines(buffer, *shader); render_as_lines(buffer, static_cast<unsigned int>(j), *shader);
break; break;
} }
case TBuffer::ERenderPrimitiveType::Triangle: case TBuffer::ERenderPrimitiveType::Triangle:
{ {
render_as_triangles(buffer, *shader); render_as_triangles(buffer, static_cast<unsigned int>(j), *shader);
break; break;
} }
} }
glsafe(::glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0)); glsafe(::glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0));
}
if (has_normals) if (has_normals)
glsafe(::glDisableClientState(GL_NORMAL_ARRAY)); glsafe(::glDisableClientState(GL_NORMAL_ARRAY));
@ -2237,7 +2295,7 @@ void GCodeViewer::render_legend() const
auto any_option_available = [this]() { auto any_option_available = [this]() {
auto available = [this](EMoveType type) { auto available = [this](EMoveType type) {
const TBuffer& buffer = m_buffers[buffer_id(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) || 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) { auto add_option = [this, append_item](EMoveType move_type, EOptionsColors color, const std::string& text) {
const TBuffer& buffer = m_buffers[buffer_id(move_type)]; 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<unsigned int>(color)], text); append_item((buffer.shader == "options_110") ? EItemType::Rect : EItemType::Circle, Options_Colors[static_cast<unsigned int>(color)], text);
}; };
@ -2276,7 +2334,7 @@ void GCodeViewer::render_legend() const
#if ENABLE_GCODE_VIEWER_STATISTICS #if ENABLE_GCODE_VIEWER_STATISTICS
void GCodeViewer::render_statistics() const void GCodeViewer::render_statistics() const
{ {
static const float offset = 230.0f; static const float offset = 250.0f;
ImGuiWrapper& imgui = *wxGetApp().imgui(); ImGuiWrapper& imgui = *wxGetApp().imgui();

View File

@ -18,6 +18,9 @@ namespace GUI {
class GCodeViewer class GCodeViewer
{ {
using Color = std::array<float, 3>; using Color = std::array<float, 3>;
using IndexBuffer = std::vector<unsigned int>;
using MultiIndexBuffer = std::vector<IndexBuffer>;
static const std::vector<Color> Extrusion_Role_Colors; static const std::vector<Color> Extrusion_Role_Colors;
static const std::vector<Color> Options_Colors; static const std::vector<Color> Options_Colors;
static const std::vector<Color> Travel_Colors; static const std::vector<Color> Travel_Colors;
@ -112,10 +115,12 @@ class GCodeViewer
{ {
struct Endpoint struct Endpoint
{ {
// index into the indices buffer // index of the index buffer
unsigned int i_id{ 0u }; unsigned int b_id{ 0 };
// sequential id // index into the index buffer
unsigned int s_id{ 0u }; size_t i_id{ 0 };
// sequential id (index into the vertex buffer)
size_t s_id{ 0 };
Vec3f position{ Vec3f::Zero() }; Vec3f position{ Vec3f::Zero() };
}; };
@ -134,14 +139,15 @@ class GCodeViewer
bool matches(const GCodeProcessor::MoveVertex& move) const; bool matches(const GCodeProcessor::MoveVertex& move) const;
size_t vertices_count() const { return last.s_id - first.s_id + 1; } 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 // Used to batch the indices needed to render paths
struct RenderPath struct RenderPath
{ {
Color color; Color color;
size_t path_id; unsigned int path_id;
unsigned int index_buffer_id;
std::vector<unsigned int> sizes; std::vector<unsigned int> sizes;
std::vector<size_t> offsets; // use size_t because we need an unsigned int whose size matches pointer's size (used in the call glMultiDrawElements()) std::vector<size_t> 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; ERenderPrimitiveType render_primitive_type;
VBuffer vertices; VBuffer vertices;
IBuffer indices; std::vector<IBuffer> indices;
std::string shader; std::string shader;
std::vector<Path> paths; std::vector<Path> paths;
@ -166,7 +172,10 @@ class GCodeViewer
bool visible{ false }; bool visible{ false };
void reset(); 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 { unsigned int indices_per_segment() const {
switch (render_primitive_type) switch (render_primitive_type)
{ {
@ -194,6 +203,8 @@ class GCodeViewer
default: { return 0; } default: { return 0; }
} }
} }
bool has_data() const { return vertices.id != 0 && !indices.empty() && indices.front().id != 0; }
}; };
// helper to render shells // helper to render shells
@ -350,8 +361,8 @@ public:
struct Endpoints struct Endpoints
{ {
unsigned int first{ 0 }; size_t first{ 0 };
unsigned int last{ 0 }; size_t last{ 0 };
}; };
Endpoints endpoints; Endpoints endpoints;