Tech ENABLE_GLINDEXEDVERTEXARRAY_REMOVAL - Replace GLIndexedVertexArray with GLModel: GLVolume geometry + removed class GLIndexedVertexArray from codebase

This commit is contained in:
enricoturri1966 2022-02-23 13:39:54 +01:00
parent 0835e117d5
commit 1eac357739
11 changed files with 1467 additions and 79 deletions

View file

@ -94,6 +94,12 @@ public:
// Called on initial G-code preview on OpenGL vertex buffer interleaved normals and vertices. // Called on initial G-code preview on OpenGL vertex buffer interleaved normals and vertices.
bool all_paths_inside_vertices_and_normals_interleaved(const std::vector<float>& paths, const Eigen::AlignedBox<float, 3>& bbox, bool ignore_bottom = true) const; bool all_paths_inside_vertices_and_normals_interleaved(const std::vector<float>& paths, const Eigen::AlignedBox<float, 3>& bbox, bool ignore_bottom = true) const;
#if ENABLE_GLINDEXEDVERTEXARRAY_REMOVAL
const std::pair<std::vector<Vec2d>, std::vector<Vec2d>>& top_bottom_convex_hull_decomposition_scene() const { return m_top_bottom_convex_hull_decomposition_scene; }
const std::pair<std::vector<Vec2d>, std::vector<Vec2d>>& top_bottom_convex_hull_decomposition_bed() const { return m_top_bottom_convex_hull_decomposition_bed; }
#endif // ENABLE_GLINDEXEDVERTEXARRAY_REMOVAL
private: private:
// Source definition of the print bed geometry (PrintConfig::bed_shape) // Source definition of the print bed geometry (PrintConfig::bed_shape)
std::vector<Vec2d> m_bed_shape; std::vector<Vec2d> m_bed_shape;

View file

@ -1,10 +1,12 @@
#include <GL/glew.h> #include <GL/glew.h>
#if !ENABLE_GLINDEXEDVERTEXARRAY_REMOVAL
#if ENABLE_SMOOTH_NORMALS #if ENABLE_SMOOTH_NORMALS
#include <igl/per_face_normals.h> #include <igl/per_face_normals.h>
#include <igl/per_corner_normals.h> #include <igl/per_corner_normals.h>
#include <igl/per_vertex_normals.h> #include <igl/per_vertex_normals.h>
#endif // ENABLE_SMOOTH_NORMALS #endif // ENABLE_SMOOTH_NORMALS
#endif // !ENABLE_GLINDEXEDVERTEXARRAY_REMOVAL
#include "3DScene.hpp" #include "3DScene.hpp"
#include "GLShader.hpp" #include "GLShader.hpp"
@ -69,6 +71,7 @@ void glAssertRecentCallImpl(const char* file_name, unsigned int line, const char
namespace Slic3r { namespace Slic3r {
#if !ENABLE_GLINDEXEDVERTEXARRAY_REMOVAL
#if ENABLE_SMOOTH_NORMALS #if ENABLE_SMOOTH_NORMALS
static void smooth_normals_corner(TriangleMesh& mesh, std::vector<stl_normal>& normals) static void smooth_normals_corner(TriangleMesh& mesh, std::vector<stl_normal>& normals)
{ {
@ -287,6 +290,7 @@ void GLIndexedVertexArray::render(
glsafe(::glBindBuffer(GL_ARRAY_BUFFER, 0)); glsafe(::glBindBuffer(GL_ARRAY_BUFFER, 0));
} }
#endif // !ENABLE_GLINDEXEDVERTEXARRAY_REMOVAL
const float GLVolume::SinkingContours::HalfWidth = 0.25f; const float GLVolume::SinkingContours::HalfWidth = 0.25f;
@ -483,7 +487,9 @@ GLVolume::GLVolume(float r, float g, float b, float a)
, force_neutral_color(false) , force_neutral_color(false)
, force_sinking_contours(false) , force_sinking_contours(false)
, tverts_range(0, size_t(-1)) , tverts_range(0, size_t(-1))
#if !ENABLE_GLINDEXEDVERTEXARRAY_REMOVAL
, qverts_range(0, size_t(-1)) , qverts_range(0, size_t(-1))
#endif // !ENABLE_GLINDEXEDVERTEXARRAY_REMOVAL
{ {
color = { r, g, b, a }; color = { r, g, b, a };
set_render_color(color); set_render_color(color);
@ -599,6 +605,36 @@ const BoundingBoxf3& GLVolume::transformed_non_sinking_bounding_box() const
return *m_transformed_non_sinking_bounding_box; return *m_transformed_non_sinking_bounding_box;
} }
#if ENABLE_GLINDEXEDVERTEXARRAY_REMOVAL
void GLVolume::set_range(double min_z, double max_z)
{
this->tverts_range.first = 0;
this->tverts_range.second = this->model.indices_count();
if (!this->print_zs.empty()) {
// The Z layer range is specified.
// First test whether the Z span of this object is not out of (min_z, max_z) completely.
if (this->print_zs.front() > max_z || this->print_zs.back() < min_z)
this->tverts_range.second = 0;
else {
// Then find the lowest layer to be displayed.
size_t i = 0;
for (; i < this->print_zs.size() && this->print_zs[i] < min_z; ++i);
if (i == this->print_zs.size())
// This shall not happen.
this->tverts_range.second = 0;
else {
// Remember start of the layer.
this->tverts_range.first = this->offsets[i];
// Some layers are above $min_z. Which?
for (; i < this->print_zs.size() && this->print_zs[i] <= max_z; ++i);
if (i < this->print_zs.size())
this->tverts_range.second = this->offsets[i];
}
}
}
}
#else
void GLVolume::set_range(double min_z, double max_z) void GLVolume::set_range(double min_z, double max_z)
{ {
this->qverts_range.first = 0; this->qverts_range.first = 0;
@ -611,7 +647,8 @@ void GLVolume::set_range(double min_z, double max_z)
if (this->print_zs.front() > max_z || this->print_zs.back() < min_z) { if (this->print_zs.front() > max_z || this->print_zs.back() < min_z) {
this->qverts_range.second = 0; this->qverts_range.second = 0;
this->tverts_range.second = 0; this->tverts_range.second = 0;
} else { }
else {
// Then find the lowest layer to be displayed. // Then find the lowest layer to be displayed.
size_t i = 0; size_t i = 0;
for (; i < this->print_zs.size() && this->print_zs[i] < min_z; ++ i); for (; i < this->print_zs.size() && this->print_zs[i] < min_z; ++ i);
@ -619,7 +656,8 @@ void GLVolume::set_range(double min_z, double max_z)
// This shall not happen. // This shall not happen.
this->qverts_range.second = 0; this->qverts_range.second = 0;
this->tverts_range.second = 0; this->tverts_range.second = 0;
} else { }
else {
// Remember start of the layer. // Remember start of the layer.
this->qverts_range.first = this->offsets[i * 2]; this->qverts_range.first = this->offsets[i * 2];
this->tverts_range.first = this->offsets[i * 2 + 1]; this->tverts_range.first = this->offsets[i * 2 + 1];
@ -633,8 +671,9 @@ void GLVolume::set_range(double min_z, double max_z)
} }
} }
} }
#endif // ENABLE_GLINDEXEDVERTEXARRAY_REMOVAL
void GLVolume::render() const void GLVolume::render()
{ {
if (!is_active) if (!is_active)
return; return;
@ -645,7 +684,14 @@ void GLVolume::render() const
glsafe(::glPushMatrix()); glsafe(::glPushMatrix());
glsafe(::glMultMatrixd(world_matrix().data())); glsafe(::glMultMatrixd(world_matrix().data()));
#if ENABLE_GLINDEXEDVERTEXARRAY_REMOVAL
if (tverts_range == std::make_pair<size_t, size_t>(0, -1))
model.render();
else
model.render(this->tverts_range);
#else
this->indexed_vertex_array.render(this->tverts_range, this->qverts_range); this->indexed_vertex_array.render(this->tverts_range, this->qverts_range);
#endif // ENABLE_GLINDEXEDVERTEXARRAY_REMOVAL
glsafe(::glPopMatrix()); glsafe(::glPopMatrix());
if (this->is_left_handed()) if (this->is_left_handed())
@ -680,25 +726,44 @@ void GLVolume::render_non_manifold_edges()
} }
#endif // ENABLE_SHOW_NON_MANIFOLD_EDGES #endif // ENABLE_SHOW_NON_MANIFOLD_EDGES
#if ENABLE_GLINDEXEDVERTEXARRAY_REMOVAL
std::vector<int> GLVolumeCollection::load_object(
const ModelObject* model_object,
int obj_idx,
const std::vector<int>& instance_idxs)
#else
std::vector<int> GLVolumeCollection::load_object( std::vector<int> GLVolumeCollection::load_object(
const ModelObject *model_object, const ModelObject *model_object,
int obj_idx, int obj_idx,
const std::vector<int> &instance_idxs, const std::vector<int> &instance_idxs,
bool opengl_initialized) bool opengl_initialized)
#endif // ENABLE_GLINDEXEDVERTEXARRAY_REMOVAL
{ {
std::vector<int> volumes_idx; std::vector<int> volumes_idx;
for (int volume_idx = 0; volume_idx < int(model_object->volumes.size()); ++volume_idx) for (int volume_idx = 0; volume_idx < int(model_object->volumes.size()); ++volume_idx)
for (int instance_idx : instance_idxs) for (int instance_idx : instance_idxs)
#if ENABLE_GLINDEXEDVERTEXARRAY_REMOVAL
volumes_idx.emplace_back(this->GLVolumeCollection::load_object_volume(model_object, obj_idx, volume_idx, instance_idx));
#else
volumes_idx.emplace_back(this->GLVolumeCollection::load_object_volume(model_object, obj_idx, volume_idx, instance_idx, opengl_initialized)); volumes_idx.emplace_back(this->GLVolumeCollection::load_object_volume(model_object, obj_idx, volume_idx, instance_idx, opengl_initialized));
#endif // ENABLE_GLINDEXEDVERTEXARRAY_REMOVAL
return volumes_idx; return volumes_idx;
} }
#if ENABLE_GLINDEXEDVERTEXARRAY_REMOVAL
int GLVolumeCollection::load_object_volume(
const ModelObject* model_object,
int obj_idx,
int volume_idx,
int instance_idx)
#else
int GLVolumeCollection::load_object_volume( int GLVolumeCollection::load_object_volume(
const ModelObject *model_object, const ModelObject *model_object,
int obj_idx, int obj_idx,
int volume_idx, int volume_idx,
int instance_idx, int instance_idx,
bool opengl_initialized) bool opengl_initialized)
#endif // ENABLE_GLINDEXEDVERTEXARRAY_REMOVAL
{ {
const ModelVolume *model_volume = model_object->volumes[volume_idx]; const ModelVolume *model_volume = model_object->volumes[volume_idx];
const int extruder_id = model_volume->extruder_id(); const int extruder_id = model_volume->extruder_id();
@ -706,6 +771,14 @@ int GLVolumeCollection::load_object_volume(
const TriangleMesh &mesh = model_volume->mesh(); const TriangleMesh &mesh = model_volume->mesh();
this->volumes.emplace_back(new GLVolume()); this->volumes.emplace_back(new GLVolume());
GLVolume& v = *this->volumes.back(); GLVolume& v = *this->volumes.back();
#if ENABLE_GLINDEXEDVERTEXARRAY_REMOVAL
#if ENABLE_SMOOTH_NORMALS
v.model.init_from(mesh, true);
#else
v.model.init_from(mesh);
#endif // ENABLE_SMOOTH_NORMALS
v.model.set_color(color_from_model_volume(*model_volume));
#else
v.set_color(color_from_model_volume(*model_volume)); v.set_color(color_from_model_volume(*model_volume));
#if ENABLE_SMOOTH_NORMALS #if ENABLE_SMOOTH_NORMALS
v.indexed_vertex_array.load_mesh(mesh, true); v.indexed_vertex_array.load_mesh(mesh, true);
@ -713,9 +786,9 @@ int GLVolumeCollection::load_object_volume(
v.indexed_vertex_array.load_mesh(mesh); v.indexed_vertex_array.load_mesh(mesh);
#endif // ENABLE_SMOOTH_NORMALS #endif // ENABLE_SMOOTH_NORMALS
v.indexed_vertex_array.finalize_geometry(opengl_initialized); v.indexed_vertex_array.finalize_geometry(opengl_initialized);
#endif // ENABLE_GLINDEXEDVERTEXARRAY_REMOVAL
v.composite_id = GLVolume::CompositeID(obj_idx, volume_idx, instance_idx); v.composite_id = GLVolume::CompositeID(obj_idx, volume_idx, instance_idx);
if (model_volume->is_model_part()) if (model_volume->is_model_part()) {
{
// GLVolume will reference a convex hull from model_volume! // GLVolume will reference a convex hull from model_volume!
v.set_convex_hull(model_volume->get_convex_hull_shared_ptr()); v.set_convex_hull(model_volume->get_convex_hull_shared_ptr());
if (extruder_id != -1) if (extruder_id != -1)
@ -732,6 +805,16 @@ int GLVolumeCollection::load_object_volume(
// Load SLA auxiliary GLVolumes (for support trees or pad). // Load SLA auxiliary GLVolumes (for support trees or pad).
// This function produces volumes for multiple instances in a single shot, // This function produces volumes for multiple instances in a single shot,
// as some object specific mesh conversions may be expensive. // as some object specific mesh conversions may be expensive.
#if ENABLE_GLINDEXEDVERTEXARRAY_REMOVAL
void GLVolumeCollection::load_object_auxiliary(
const SLAPrintObject* print_object,
int obj_idx,
// pairs of <instance_idx, print_instance_idx>
const std::vector<std::pair<size_t, size_t>>& instances,
SLAPrintObjectStep milestone,
// Timestamp of the last change of the milestone
size_t timestamp)
#else
void GLVolumeCollection::load_object_auxiliary( void GLVolumeCollection::load_object_auxiliary(
const SLAPrintObject *print_object, const SLAPrintObject *print_object,
int obj_idx, int obj_idx,
@ -741,6 +824,7 @@ void GLVolumeCollection::load_object_auxiliary(
// Timestamp of the last change of the milestone // Timestamp of the last change of the milestone
size_t timestamp, size_t timestamp,
bool opengl_initialized) bool opengl_initialized)
#endif // ENABLE_GLINDEXEDVERTEXARRAY_REMOVAL
{ {
assert(print_object->is_step_done(milestone)); assert(print_object->is_step_done(milestone));
Transform3d mesh_trafo_inv = print_object->trafo().inverse(); Transform3d mesh_trafo_inv = print_object->trafo().inverse();
@ -753,12 +837,21 @@ void GLVolumeCollection::load_object_auxiliary(
const ModelInstance& model_instance = *print_object->model_object()->instances[instance_idx.first]; const ModelInstance& model_instance = *print_object->model_object()->instances[instance_idx.first];
this->volumes.emplace_back(new GLVolume((milestone == slaposPad) ? GLVolume::SLA_PAD_COLOR : GLVolume::SLA_SUPPORT_COLOR)); this->volumes.emplace_back(new GLVolume((milestone == slaposPad) ? GLVolume::SLA_PAD_COLOR : GLVolume::SLA_SUPPORT_COLOR));
GLVolume& v = *this->volumes.back(); GLVolume& v = *this->volumes.back();
#if ENABLE_GLINDEXEDVERTEXARRAY_REMOVAL
#if ENABLE_SMOOTH_NORMALS
v.model.init_from(mesh, true);
#else
v.model.init_from(mesh);
#endif // ENABLE_SMOOTH_NORMALS
v.model.set_color((milestone == slaposPad) ? GLVolume::SLA_PAD_COLOR : GLVolume::SLA_SUPPORT_COLOR);
#else
#if ENABLE_SMOOTH_NORMALS #if ENABLE_SMOOTH_NORMALS
v.indexed_vertex_array.load_mesh(mesh, true); v.indexed_vertex_array.load_mesh(mesh, true);
#else #else
v.indexed_vertex_array.load_mesh(mesh); v.indexed_vertex_array.load_mesh(mesh);
#endif // ENABLE_SMOOTH_NORMALS #endif // ENABLE_SMOOTH_NORMALS
v.indexed_vertex_array.finalize_geometry(opengl_initialized); v.indexed_vertex_array.finalize_geometry(opengl_initialized);
#endif // ENABLE_GLINDEXEDVERTEXARRAY_REMOVAL
v.composite_id = GLVolume::CompositeID(obj_idx, -int(milestone), (int)instance_idx.first); v.composite_id = GLVolume::CompositeID(obj_idx, -int(milestone), (int)instance_idx.first);
v.geometry_id = std::pair<size_t, size_t>(timestamp, model_instance.id().id); v.geometry_id = std::pair<size_t, size_t>(timestamp, model_instance.id().id);
// Create a copy of the convex hull mesh for each instance. Use a move operator on the last instance. // Create a copy of the convex hull mesh for each instance. Use a move operator on the last instance.
@ -774,6 +867,17 @@ void GLVolumeCollection::load_object_auxiliary(
} }
} }
#if ENABLE_GLINDEXEDVERTEXARRAY_REMOVAL
#if ENABLE_WIPETOWER_OBJECTID_1000_REMOVAL
int GLVolumeCollection::load_wipe_tower_preview(
float pos_x, float pos_y, float width, float depth, float height,
float rotation_angle, bool size_unknown, float brim_width)
#else
int GLVolumeCollection::load_wipe_tower_preview(
int obj_idx, float pos_x, float pos_y, float width, float depth, float height,
float rotation_angle, bool size_unknown, float brim_width)
#endif // ENABLE_WIPETOWER_OBJECTID_1000_REMOVAL
#else
#if ENABLE_WIPETOWER_OBJECTID_1000_REMOVAL #if ENABLE_WIPETOWER_OBJECTID_1000_REMOVAL
int GLVolumeCollection::load_wipe_tower_preview( int GLVolumeCollection::load_wipe_tower_preview(
float pos_x, float pos_y, float width, float depth, float height, float pos_x, float pos_y, float width, float depth, float height,
@ -783,6 +887,7 @@ int GLVolumeCollection::load_wipe_tower_preview(
int obj_idx, float pos_x, float pos_y, float width, float depth, float height, int obj_idx, float pos_x, float pos_y, float width, float depth, float height,
float rotation_angle, bool size_unknown, float brim_width, bool opengl_initialized) float rotation_angle, bool size_unknown, float brim_width, bool opengl_initialized)
#endif // ENABLE_WIPETOWER_OBJECTID_1000_REMOVAL #endif // ENABLE_WIPETOWER_OBJECTID_1000_REMOVAL
#endif // ENABLE_GLINDEXEDVERTEXARRAY_REMOVAL
{ {
if (depth < 0.01f) if (depth < 0.01f)
return int(this->volumes.size() - 1); return int(this->volumes.size() - 1);
@ -839,9 +944,16 @@ int GLVolumeCollection::load_wipe_tower_preview(
volumes.emplace_back(new GLVolume(color)); volumes.emplace_back(new GLVolume(color));
GLVolume& v = *volumes.back(); GLVolume& v = *volumes.back();
#if ENABLE_GLINDEXEDVERTEXARRAY_REMOVAL
v.model.init_from(mesh);
v.model.set_color(color);
#else
v.indexed_vertex_array.load_mesh(mesh); v.indexed_vertex_array.load_mesh(mesh);
#endif // ENABLE_GLINDEXEDVERTEXARRAY_REMOVAL
v.set_convex_hull(mesh.convex_hull_3d()); v.set_convex_hull(mesh.convex_hull_3d());
#if !ENABLE_GLINDEXEDVERTEXARRAY_REMOVAL
v.indexed_vertex_array.finalize_geometry(opengl_initialized); v.indexed_vertex_array.finalize_geometry(opengl_initialized);
#endif // !ENABLE_GLINDEXEDVERTEXARRAY_REMOVAL
v.set_volume_offset(Vec3d(pos_x, pos_y, 0.0)); v.set_volume_offset(Vec3d(pos_x, pos_y, 0.0));
v.set_volume_rotation(Vec3d(0., 0., (M_PI / 180.) * rotation_angle)); v.set_volume_rotation(Vec3d(0., 0., (M_PI / 180.) * rotation_angle));
#if ENABLE_WIPETOWER_OBJECTID_1000_REMOVAL #if ENABLE_WIPETOWER_OBJECTID_1000_REMOVAL
@ -856,6 +968,22 @@ int GLVolumeCollection::load_wipe_tower_preview(
return int(volumes.size() - 1); return int(volumes.size() - 1);
} }
#if ENABLE_GLINDEXEDVERTEXARRAY_REMOVAL
GLVolume* GLVolumeCollection::new_toolpath_volume(const ColorRGBA& rgba)
{
GLVolume* out = new_nontoolpath_volume(rgba);
out->is_extrusion_path = true;
return out;
}
GLVolume* GLVolumeCollection::new_nontoolpath_volume(const ColorRGBA& rgba)
{
GLVolume* out = new GLVolume(rgba);
out->is_extrusion_path = false;
this->volumes.emplace_back(out);
return out;
}
#else
GLVolume* GLVolumeCollection::new_toolpath_volume(const ColorRGBA& rgba, size_t reserve_vbo_floats) GLVolume* GLVolumeCollection::new_toolpath_volume(const ColorRGBA& rgba, size_t reserve_vbo_floats)
{ {
GLVolume *out = new_nontoolpath_volume(rgba, reserve_vbo_floats); GLVolume *out = new_nontoolpath_volume(rgba, reserve_vbo_floats);
@ -872,6 +1000,7 @@ GLVolume* GLVolumeCollection::new_nontoolpath_volume(const ColorRGBA& rgba, size
this->volumes.emplace_back(out); this->volumes.emplace_back(out);
return out; return out;
} }
#endif // ENABLE_GLINDEXEDVERTEXARRAY_REMOVAL
GLVolumeWithIdAndZList volumes_to_render(const GLVolumePtrs& volumes, GLVolumeCollection::ERenderType type, const Transform3d& view_matrix, std::function<bool(const GLVolume&)> filter_func) GLVolumeWithIdAndZList volumes_to_render(const GLVolumePtrs& volumes, GLVolumeCollection::ERenderType type, const Transform3d& view_matrix, std::function<bool(const GLVolume&)> filter_func)
{ {
@ -960,7 +1089,10 @@ void GLVolumeCollection::render(GLVolumeCollection::ERenderType type, bool disab
glsafe(::glEnableClientState(GL_VERTEX_ARRAY)); glsafe(::glEnableClientState(GL_VERTEX_ARRAY));
glsafe(::glEnableClientState(GL_NORMAL_ARRAY)); glsafe(::glEnableClientState(GL_NORMAL_ARRAY));
shader->set_uniform("uniform_color", volume.first->render_color); #if ENABLE_GLINDEXEDVERTEXARRAY_REMOVAL
if (!volume.first->model.is_initialized())
#endif // !ENABLE_GLINDEXEDVERTEXARRAY_REMOVAL
shader->set_uniform("uniform_color", volume.first->render_color);
shader->set_uniform("z_range", m_z_range, 2); shader->set_uniform("z_range", m_z_range, 2);
shader->set_uniform("clipping_plane", m_clipping_plane, 4); shader->set_uniform("clipping_plane", m_clipping_plane, 4);
shader->set_uniform("print_volume.type", static_cast<int>(m_print_volume.type)); shader->set_uniform("print_volume.type", static_cast<int>(m_print_volume.type));
@ -980,6 +1112,10 @@ void GLVolumeCollection::render(GLVolumeCollection::ERenderType type, bool disab
#endif // ENABLE_ENVIRONMENT_MAP #endif // ENABLE_ENVIRONMENT_MAP
glcheck(); glcheck();
#if ENABLE_GLINDEXEDVERTEXARRAY_REMOVAL
if (volume.first->model.is_initialized())
volume.first->model.set_color(volume.first->render_color);
#endif // ENABLE_GLINDEXEDVERTEXARRAY_REMOVAL
volume.first->render(); volume.first->render();
#if ENABLE_ENVIRONMENT_MAP #if ENABLE_ENVIRONMENT_MAP
@ -1215,6 +1351,466 @@ std::string GLVolumeCollection::log_memory_info() const
return " (GLVolumeCollection RAM: " + format_memsize_MB(this->cpu_memory_used()) + " GPU: " + format_memsize_MB(this->gpu_memory_used()) + " Both: " + format_memsize_MB(this->gpu_memory_used()) + ")"; return " (GLVolumeCollection RAM: " + format_memsize_MB(this->cpu_memory_used()) + " GPU: " + format_memsize_MB(this->gpu_memory_used()) + " Both: " + format_memsize_MB(this->gpu_memory_used()) + ")";
} }
#if ENABLE_GLINDEXEDVERTEXARRAY_REMOVAL
static void thick_lines_to_geometry(
const Lines& lines,
const std::vector<double>& widths,
const std::vector<double>& heights,
bool closed,
double top_z,
GUI::GLModel::Geometry& geometry)
{
assert(!lines.empty());
if (lines.empty())
return;
enum Direction : unsigned char
{
Left,
Right,
Top,
Bottom
};
// right, left, top, bottom
std::array<int, 4> idx_prev = { -1, -1, -1, -1 };
std::array<int, 4> idx_initial = { -1, -1, -1, -1 };
double bottom_z_prev = 0.0;
Vec2d b1_prev(Vec2d::Zero());
Vec2d v_prev(Vec2d::Zero());
double len_prev = 0.0;
double width_initial = 0.0;
double bottom_z_initial = 0.0;
// loop once more in case of closed loops
const size_t lines_end = closed ? (lines.size() + 1) : lines.size();
for (size_t ii = 0; ii < lines_end; ++ii) {
const size_t i = (ii == lines.size()) ? 0 : ii;
const Line& line = lines[i];
const double bottom_z = top_z - heights[i];
const double middle_z = 0.5 * (top_z + bottom_z);
const double width = widths[i];
const bool is_first = (ii == 0);
const bool is_last = (ii == lines_end - 1);
const bool is_closing = closed && is_last;
const Vec2d v = unscale(line.vector()).normalized();
const double len = unscale<double>(line.length());
const Vec2d a = unscale(line.a);
const Vec2d b = unscale(line.b);
Vec2d a1 = a;
Vec2d a2 = a;
Vec2d b1 = b;
Vec2d b2 = b;
{
const double dist = 0.5 * width; // scaled
const double dx = dist * v.x();
const double dy = dist * v.y();
a1 += Vec2d(+dy, -dx);
a2 += Vec2d(-dy, +dx);
b1 += Vec2d(+dy, -dx);
b2 += Vec2d(-dy, +dx);
}
// calculate new XY normals
const Vec2d xy_right_normal = unscale(line.normal()).normalized();
std::array<int, 4> idx_a = { 0, 0, 0, 0 };
std::array<int, 4> idx_b = { 0, 0, 0, 0 };
int idx_last = int(geometry.vertices_count());
const bool bottom_z_different = bottom_z_prev != bottom_z;
bottom_z_prev = bottom_z;
if (!is_first && bottom_z_different) {
// Found a change of the layer thickness -> Add a cap at the end of the previous segment.
geometry.add_uint_triangle(idx_b[Bottom], idx_b[Left], idx_b[Top]);
geometry.add_uint_triangle(idx_b[Bottom], idx_b[Top], idx_b[Right]);
}
// Share top / bottom vertices if possible.
if (is_first) {
idx_a[Top] = idx_last++;
geometry.add_vertex(Vec3f(a.x(), a.y(), top_z), Vec3f(0.0f, 0.0f, 1.0f));
}
else
idx_a[Top] = idx_prev[Top];
if (is_first || bottom_z_different) {
// Start of the 1st line segment or a change of the layer thickness while maintaining the print_z.
idx_a[Bottom] = idx_last++;
geometry.add_vertex(Vec3f(a.x(), a.y(), bottom_z), Vec3f(0.0f, 0.0f, -1.0f));
idx_a[Left] = idx_last++;
geometry.add_vertex(Vec3f(a2.x(), a2.y(), middle_z), Vec3f(-xy_right_normal.x(), -xy_right_normal.y(), 0.0f));
idx_a[Right] = idx_last++;
geometry.add_vertex(Vec3f(a1.x(), a1.y(), middle_z), Vec3f(xy_right_normal.x(), xy_right_normal.y(), 0.0f));
}
else
idx_a[Bottom] = idx_prev[Bottom];
if (is_first) {
// Start of the 1st line segment.
width_initial = width;
bottom_z_initial = bottom_z;
idx_initial = idx_a;
}
else {
// Continuing a previous segment.
// Share left / right vertices if possible.
const double v_dot = v_prev.dot(v);
// To reduce gpu memory usage, we try to reuse vertices
// To reduce the visual artifacts, due to averaged normals, we allow to reuse vertices only when any of two adjacent edges
// is longer than a fixed threshold.
// The following value is arbitrary, it comes from tests made on a bunch of models showing the visual artifacts
const double len_threshold = 2.5;
// Generate new vertices if the angle between adjacent edges is greater than 45 degrees or thresholds conditions are met
const bool sharp = (v_dot < 0.707) || (len_prev > len_threshold) || (len > len_threshold);
if (sharp) {
if (!bottom_z_different) {
// Allocate new left / right points for the start of this segment as these points will receive their own normals to indicate a sharp turn.
idx_a[Right] = idx_last++;
geometry.add_vertex(Vec3f(a1.x(), a1.y(), middle_z), Vec3f(xy_right_normal.x(), xy_right_normal.y(), 0.0f));
idx_a[Left] = idx_last++;
geometry.add_vertex(Vec3f(a2.x(), a2.y(), middle_z), Vec3f(-xy_right_normal.x(), -xy_right_normal.y(), 0.0f));
if (cross2(v_prev, v) > 0.0) {
// Right turn. Fill in the right turn wedge.
geometry.add_uint_triangle(idx_prev[Right], idx_a[Right], idx_prev[Top]);
geometry.add_uint_triangle(idx_prev[Right], idx_prev[Bottom], idx_a[Right]);
}
else {
// Left turn. Fill in the left turn wedge.
geometry.add_uint_triangle(idx_prev[Left], idx_prev[Top], idx_a[Left]);
geometry.add_uint_triangle(idx_prev[Left], idx_a[Left], idx_prev[Bottom]);
}
}
}
else {
if (!bottom_z_different) {
// The two successive segments are nearly collinear.
idx_a[Left] = idx_prev[Left];
idx_a[Right] = idx_prev[Right];
}
}
if (is_closing) {
if (!sharp) {
if (!bottom_z_different) {
// Closing a loop with smooth transition. Unify the closing left / right vertices.
geometry.set_vertex(idx_initial[Left], geometry.extract_position_3(idx_prev[Left]), geometry.extract_normal_3(idx_prev[Left]));
geometry.set_vertex(idx_initial[Right], geometry.extract_position_3(idx_prev[Right]), geometry.extract_normal_3(idx_prev[Right]));
geometry.remove_vertex(geometry.vertices_count() - 1);
geometry.remove_vertex(geometry.vertices_count() - 1);
// Replace the left / right vertex indices to point to the start of the loop.
const size_t indices_count = geometry.indices_count();
for (size_t u = indices_count - 24; u < indices_count; ++u) {
const unsigned int id = geometry.extract_uint_index(u);
if (id == (unsigned int)idx_prev[Left])
geometry.set_uint_index(u, (unsigned int)idx_initial[Left]);
else if (id == (unsigned int)idx_prev[Right])
geometry.set_uint_index(u, (unsigned int)idx_initial[Right]);
}
}
}
// This is the last iteration, only required to solve the transition.
break;
}
}
// Only new allocate top / bottom vertices, if not closing a loop.
if (is_closing)
idx_b[Top] = idx_initial[Top];
else {
idx_b[Top] = idx_last++;
geometry.add_vertex(Vec3f(b.x(), b.y(), top_z), Vec3f(0.0f, 0.0f, 1.0f));
}
if (is_closing && width == width_initial && bottom_z == bottom_z_initial)
idx_b[Bottom] = idx_initial[Bottom];
else {
idx_b[Bottom] = idx_last++;
geometry.add_vertex(Vec3f(b.x(), b.y(), bottom_z), Vec3f(0.0f, 0.0f, -1.0f));
}
// Generate new vertices for the end of this line segment.
idx_b[Left] = idx_last++;
geometry.add_vertex(Vec3f(b2.x(), b2.y(), middle_z), Vec3f(-xy_right_normal.x(), -xy_right_normal.y(), 0.0f));
idx_b[Right] = idx_last++;
geometry.add_vertex(Vec3f(b1.x(), b1.y(), middle_z), Vec3f(xy_right_normal.x(), xy_right_normal.y(), 0.0f));
idx_prev = idx_b;
bottom_z_prev = bottom_z;
b1_prev = b1;
v_prev = v;
len_prev = len;
if (bottom_z_different && (closed || (!is_first && !is_last))) {
// Found a change of the layer thickness -> Add a cap at the beginning of this segment.
geometry.add_uint_triangle(idx_a[Bottom], idx_a[Right], idx_a[Top]);
geometry.add_uint_triangle(idx_a[Bottom], idx_a[Top], idx_a[Left]);
}
if (!closed) {
// Terminate open paths with caps.
if (is_first) {
geometry.add_uint_triangle(idx_a[Bottom], idx_a[Right], idx_a[Top]);
geometry.add_uint_triangle(idx_a[Bottom], idx_a[Top], idx_a[Left]);
}
// We don't use 'else' because both cases are true if we have only one line.
if (is_last) {
geometry.add_uint_triangle(idx_b[Bottom], idx_b[Left], idx_b[Top]);
geometry.add_uint_triangle(idx_b[Bottom], idx_b[Top], idx_b[Right]);
}
}
// Add quads for a straight hollow tube-like segment.
// bottom-right face
geometry.add_uint_triangle(idx_a[Bottom], idx_b[Bottom], idx_b[Right]);
geometry.add_uint_triangle(idx_a[Bottom], idx_b[Right], idx_a[Right]);
// top-right face
geometry.add_uint_triangle(idx_a[Right], idx_b[Right], idx_b[Top]);
geometry.add_uint_triangle(idx_a[Right], idx_b[Top], idx_a[Top]);
// top-left face
geometry.add_uint_triangle(idx_a[Top], idx_b[Top], idx_b[Left]);
geometry.add_uint_triangle(idx_a[Top], idx_b[Left], idx_a[Left]);
// bottom-left face
geometry.add_uint_triangle(idx_a[Left], idx_b[Left], idx_b[Bottom]);
geometry.add_uint_triangle(idx_a[Left], idx_b[Bottom], idx_a[Bottom]);
}
}
// caller is responsible for supplying NO lines with zero length
static void thick_lines_to_geometry(
const Lines3& lines,
const std::vector<double>& widths,
const std::vector<double>& heights,
bool closed,
GUI::GLModel::Geometry& geometry)
{
assert(!lines.empty());
if (lines.empty())
return;
enum Direction : unsigned char
{
Left,
Right,
Top,
Bottom
};
// left, right, top, bottom
std::array<int, 4> idx_prev = { -1, -1, -1, -1 };
std::array<int, 4> idx_initial = { -1, -1, -1, -1 };
double z_prev = 0.0;
double len_prev = 0.0;
Vec3d n_right_prev = Vec3d::Zero();
Vec3d n_top_prev = Vec3d::Zero();
Vec3d unit_v_prev = Vec3d::Zero();
double width_initial = 0.0;
// new vertices around the line endpoints
// left, right, top, bottom
std::array<Vec3d, 4> a = { Vec3d::Zero(), Vec3d::Zero(), Vec3d::Zero(), Vec3d::Zero() };
std::array<Vec3d, 4> b = { Vec3d::Zero(), Vec3d::Zero(), Vec3d::Zero(), Vec3d::Zero() };
// loop once more in case of closed loops
const size_t lines_end = closed ? (lines.size() + 1) : lines.size();
for (size_t ii = 0; ii < lines_end; ++ii) {
const size_t i = (ii == lines.size()) ? 0 : ii;
const Line3& line = lines[i];
const double height = heights[i];
const double width = widths[i];
const Vec3d unit_v = unscale(line.vector()).normalized();
const double len = unscale<double>(line.length());
Vec3d n_top = Vec3d::Zero();
Vec3d n_right = Vec3d::Zero();
if (line.a.x() == line.b.x() && line.a.y() == line.b.y()) {
// vertical segment
n_top = Vec3d::UnitY();
n_right = Vec3d::UnitX();
if (line.a.z() < line.b.z())
n_right = -n_right;
}
else {
// horizontal segment
n_right = unit_v.cross(Vec3d::UnitZ()).normalized();
n_top = n_right.cross(unit_v).normalized();
}
const Vec3d rl_displacement = 0.5 * width * n_right;
const Vec3d tb_displacement = 0.5 * height * n_top;
const Vec3d l_a = unscale(line.a);
const Vec3d l_b = unscale(line.b);
a[Right] = l_a + rl_displacement;
a[Left] = l_a - rl_displacement;
a[Top] = l_a + tb_displacement;
a[Bottom] = l_a - tb_displacement;
b[Right] = l_b + rl_displacement;
b[Left] = l_b - rl_displacement;
b[Top] = l_b + tb_displacement;
b[Bottom] = l_b - tb_displacement;
const Vec3d n_bottom = -n_top;
const Vec3d n_left = -n_right;
std::array<int, 4> idx_a = { 0, 0, 0, 0};
std::array<int, 4> idx_b = { 0, 0, 0, 0 };
int idx_last = int(geometry.vertices_count());
const bool z_different = (z_prev != l_a.z());
z_prev = l_b.z();
// Share top / bottom vertices if possible.
if (ii == 0) {
idx_a[Top] = idx_last++;
geometry.add_vertex((Vec3f)a[Top].cast<float>(), (Vec3f)n_top.cast<float>());
}
else
idx_a[Top] = idx_prev[Top];
if (ii == 0 || z_different) {
// Start of the 1st line segment or a change of the layer thickness while maintaining the print_z.
idx_a[Bottom] = idx_last++;
geometry.add_vertex((Vec3f)a[Bottom].cast<float>(), (Vec3f)n_bottom.cast<float>());
idx_a[Left] = idx_last++;
geometry.add_vertex((Vec3f)a[Left].cast<float>(), (Vec3f)n_left.cast<float>());
idx_a[Right] = idx_last++;
geometry.add_vertex((Vec3f)a[Right].cast<float>(), (Vec3f)n_right.cast<float>());
}
else
idx_a[Bottom] = idx_prev[Bottom];
if (ii == 0) {
// Start of the 1st line segment.
width_initial = width;
idx_initial = idx_a;
}
else {
// Continuing a previous segment.
// Share left / right vertices if possible.
const double v_dot = unit_v_prev.dot(unit_v);
const bool is_right_turn = n_top_prev.dot(unit_v_prev.cross(unit_v)) > 0.0;
// To reduce gpu memory usage, we try to reuse vertices
// To reduce the visual artifacts, due to averaged normals, we allow to reuse vertices only when any of two adjacent edges
// is longer than a fixed threshold.
// The following value is arbitrary, it comes from tests made on a bunch of models showing the visual artifacts
const double len_threshold = 2.5;
// Generate new vertices if the angle between adjacent edges is greater than 45 degrees or thresholds conditions are met
const bool is_sharp = v_dot < 0.707 || len_prev > len_threshold || len > len_threshold;
if (is_sharp) {
// Allocate new left / right points for the start of this segment as these points will receive their own normals to indicate a sharp turn.
idx_a[Right] = idx_last++;
geometry.add_vertex((Vec3f)a[Right].cast<float>(), (Vec3f)n_right.cast<float>());
idx_a[Left] = idx_last++;
geometry.add_vertex((Vec3f)a[Left].cast<float>(), (Vec3f)n_left.cast<float>());
if (is_right_turn) {
// Right turn. Fill in the right turn wedge.
geometry.add_uint_triangle(idx_prev[Right], idx_a[Right], idx_prev[Top]);
geometry.add_uint_triangle(idx_prev[Right], idx_prev[Bottom], idx_a[Right]);
}
else {
// Left turn. Fill in the left turn wedge.
geometry.add_uint_triangle(idx_prev[Left], idx_prev[Top], idx_a[Left]);
geometry.add_uint_triangle(idx_prev[Left], idx_a[Left], idx_prev[Bottom]);
}
}
else {
// The two successive segments are nearly collinear.
idx_a[Left] = idx_prev[Left];
idx_a[Right] = idx_prev[Right];
}
if (ii == lines.size()) {
if (!is_sharp) {
// Closing a loop with smooth transition. Unify the closing left / right vertices.
geometry.set_vertex(idx_initial[Left], geometry.extract_position_3(idx_prev[Left]), geometry.extract_normal_3(idx_prev[Left]));
geometry.set_vertex(idx_initial[Right], geometry.extract_position_3(idx_prev[Right]), geometry.extract_normal_3(idx_prev[Right]));
geometry.remove_vertex(geometry.vertices_count() - 1);
geometry.remove_vertex(geometry.vertices_count() - 1);
// Replace the left / right vertex indices to point to the start of the loop.
const size_t indices_count = geometry.indices_count();
for (size_t u = indices_count - 24; u < indices_count; ++u) {
const unsigned int id = geometry.extract_uint_index(u);
if (id == (unsigned int)idx_prev[Left])
geometry.set_uint_index(u, (unsigned int)idx_initial[Left]);
else if (id == (unsigned int)idx_prev[Right])
geometry.set_uint_index(u, (unsigned int)idx_initial[Right]);
}
}
// This is the last iteration, only required to solve the transition.
break;
}
}
// Only new allocate top / bottom vertices, if not closing a loop.
if (closed && ii + 1 == lines.size())
idx_b[Top] = idx_initial[Top];
else {
idx_b[Top] = idx_last++;
geometry.add_vertex((Vec3f)b[Top].cast<float>(), (Vec3f)n_top.cast<float>());
}
if (closed && ii + 1 == lines.size() && width == width_initial)
idx_b[Bottom] = idx_initial[Bottom];
else {
idx_b[Bottom] = idx_last++;
geometry.add_vertex((Vec3f)b[Bottom].cast<float>(), (Vec3f)n_bottom.cast<float>());
}
// Generate new vertices for the end of this line segment.
idx_b[Left] = idx_last++;
geometry.add_vertex((Vec3f)b[Left].cast<float>(), (Vec3f)n_left.cast<float>());
idx_b[Right] = idx_last++;
geometry.add_vertex((Vec3f)b[Right].cast<float>(), (Vec3f)n_right.cast<float>());
idx_prev = idx_b;
n_right_prev = n_right;
n_top_prev = n_top;
unit_v_prev = unit_v;
len_prev = len;
if (!closed) {
// Terminate open paths with caps.
if (i == 0) {
geometry.add_uint_triangle(idx_a[Bottom], idx_a[Right], idx_a[Top]);
geometry.add_uint_triangle(idx_a[Bottom], idx_a[Top], idx_a[Left]);
}
// We don't use 'else' because both cases are true if we have only one line.
if (i + 1 == lines.size()) {
geometry.add_uint_triangle(idx_b[Bottom], idx_b[Left], idx_b[Top]);
geometry.add_uint_triangle(idx_b[Bottom], idx_b[Top], idx_b[Right]);
}
}
// Add quads for a straight hollow tube-like segment.
// bottom-right face
geometry.add_uint_triangle(idx_a[Bottom], idx_b[Bottom], idx_b[Right]);
geometry.add_uint_triangle(idx_a[Bottom], idx_b[Right], idx_a[Right]);
// top-right face
geometry.add_uint_triangle(idx_a[Right], idx_b[Right], idx_b[Top]);
geometry.add_uint_triangle(idx_a[Right], idx_b[Top], idx_a[Top]);
// top-left face
geometry.add_uint_triangle(idx_a[Top], idx_b[Top], idx_b[Left]);
geometry.add_uint_triangle(idx_a[Top], idx_b[Left], idx_a[Left]);
// bottom-left face
geometry.add_uint_triangle(idx_a[Left], idx_b[Left], idx_b[Bottom]);
geometry.add_uint_triangle(idx_a[Left], idx_b[Bottom], idx_a[Bottom]);
}
}
#else
// caller is responsible for supplying NO lines with zero length // caller is responsible for supplying NO lines with zero length
static void thick_lines_to_indexed_vertex_array( static void thick_lines_to_indexed_vertex_array(
const Lines &lines, const Lines &lines,
@ -1724,7 +2320,30 @@ static void point_to_indexed_vertex_array(const Vec3crd& point,
volume.push_triangle(idxs[3], idxs[1], idxs[4]); volume.push_triangle(idxs[3], idxs[1], idxs[4]);
volume.push_triangle(idxs[0], idxs[3], idxs[4]); volume.push_triangle(idxs[0], idxs[3], idxs[4]);
} }
#endif // ENABLE_GLINDEXEDVERTEXARRAY_REMOVAL
#if ENABLE_GLINDEXEDVERTEXARRAY_REMOVAL
void _3DScene::thick_lines_to_verts(
const Lines& lines,
const std::vector<double>& widths,
const std::vector<double>& heights,
bool closed,
double top_z,
GUI::GLModel::Geometry& geometry)
{
thick_lines_to_geometry(lines, widths, heights, closed, top_z, geometry);
}
void _3DScene::thick_lines_to_verts(
const Lines3& lines,
const std::vector<double>& widths,
const std::vector<double>& heights,
bool closed,
GUI::GLModel::Geometry& geometry)
{
thick_lines_to_geometry(lines, widths, heights, closed, geometry);
}
#else
void _3DScene::thick_lines_to_verts( void _3DScene::thick_lines_to_verts(
const Lines &lines, const Lines &lines,
const std::vector<double> &widths, const std::vector<double> &widths,
@ -1766,8 +2385,21 @@ void _3DScene::extrusionentity_to_verts(const ExtrusionPath &extrusion_path, flo
{ {
extrusionentity_to_verts(extrusion_path.polyline, extrusion_path.width, extrusion_path.height, print_z, volume); extrusionentity_to_verts(extrusion_path.polyline, extrusion_path.width, extrusion_path.height, print_z, volume);
} }
#endif // ENABLE_GLINDEXEDVERTEXARRAY_REMOVAL
// Fill in the qverts and tverts with quads and triangles for the extrusion_path. // Fill in the qverts and tverts with quads and triangles for the extrusion_path.
#if ENABLE_GLINDEXEDVERTEXARRAY_REMOVAL
void _3DScene::extrusionentity_to_verts(const ExtrusionPath& extrusion_path, float print_z, const Point& copy, GUI::GLModel::Geometry& geometry)
{
Polyline polyline = extrusion_path.polyline;
polyline.remove_duplicate_points();
polyline.translate(copy);
const Lines lines = polyline.lines();
std::vector<double> widths(lines.size(), extrusion_path.width);
std::vector<double> heights(lines.size(), extrusion_path.height);
thick_lines_to_verts(lines, widths, heights, false, print_z, geometry);
}
#else
void _3DScene::extrusionentity_to_verts(const ExtrusionPath &extrusion_path, float print_z, const Point &copy, GLVolume &volume) void _3DScene::extrusionentity_to_verts(const ExtrusionPath &extrusion_path, float print_z, const Point &copy, GLVolume &volume)
{ {
Polyline polyline = extrusion_path.polyline; Polyline polyline = extrusion_path.polyline;
@ -1778,8 +2410,27 @@ void _3DScene::extrusionentity_to_verts(const ExtrusionPath &extrusion_path, flo
std::vector<double> heights(lines.size(), extrusion_path.height); std::vector<double> heights(lines.size(), extrusion_path.height);
thick_lines_to_verts(lines, widths, heights, false, print_z, volume); thick_lines_to_verts(lines, widths, heights, false, print_z, volume);
} }
#endif // ENABLE_GLINDEXEDVERTEXARRAY_REMOVAL
// Fill in the qverts and tverts with quads and triangles for the extrusion_loop. // Fill in the qverts and tverts with quads and triangles for the extrusion_loop.
#if ENABLE_GLINDEXEDVERTEXARRAY_REMOVAL
void _3DScene::extrusionentity_to_verts(const ExtrusionLoop& extrusion_loop, float print_z, const Point& copy, GUI::GLModel::Geometry& geometry)
{
Lines lines;
std::vector<double> widths;
std::vector<double> heights;
for (const ExtrusionPath& extrusion_path : extrusion_loop.paths) {
Polyline polyline = extrusion_path.polyline;
polyline.remove_duplicate_points();
polyline.translate(copy);
const Lines lines_this = polyline.lines();
append(lines, lines_this);
widths.insert(widths.end(), lines_this.size(), extrusion_path.width);
heights.insert(heights.end(), lines_this.size(), extrusion_path.height);
}
thick_lines_to_verts(lines, widths, heights, true, print_z, geometry);
}
#else
void _3DScene::extrusionentity_to_verts(const ExtrusionLoop &extrusion_loop, float print_z, const Point &copy, GLVolume &volume) void _3DScene::extrusionentity_to_verts(const ExtrusionLoop &extrusion_loop, float print_z, const Point &copy, GLVolume &volume)
{ {
Lines lines; Lines lines;
@ -1796,8 +2447,27 @@ void _3DScene::extrusionentity_to_verts(const ExtrusionLoop &extrusion_loop, flo
} }
thick_lines_to_verts(lines, widths, heights, true, print_z, volume); thick_lines_to_verts(lines, widths, heights, true, print_z, volume);
} }
#endif // ENABLE_GLINDEXEDVERTEXARRAY_REMOVAL
// Fill in the qverts and tverts with quads and triangles for the extrusion_multi_path. // Fill in the qverts and tverts with quads and triangles for the extrusion_multi_path.
#if ENABLE_GLINDEXEDVERTEXARRAY_REMOVAL
void _3DScene::extrusionentity_to_verts(const ExtrusionMultiPath& extrusion_multi_path, float print_z, const Point& copy, GUI::GLModel::Geometry& geometry)
{
Lines lines;
std::vector<double> widths;
std::vector<double> heights;
for (const ExtrusionPath& extrusion_path : extrusion_multi_path.paths) {
Polyline polyline = extrusion_path.polyline;
polyline.remove_duplicate_points();
polyline.translate(copy);
const Lines lines_this = polyline.lines();
append(lines, lines_this);
widths.insert(widths.end(), lines_this.size(), extrusion_path.width);
heights.insert(heights.end(), lines_this.size(), extrusion_path.height);
}
thick_lines_to_verts(lines, widths, heights, false, print_z, geometry);
}
#else
void _3DScene::extrusionentity_to_verts(const ExtrusionMultiPath &extrusion_multi_path, float print_z, const Point &copy, GLVolume &volume) void _3DScene::extrusionentity_to_verts(const ExtrusionMultiPath &extrusion_multi_path, float print_z, const Point &copy, GLVolume &volume)
{ {
Lines lines; Lines lines;
@ -1814,13 +2484,49 @@ void _3DScene::extrusionentity_to_verts(const ExtrusionMultiPath &extrusion_mult
} }
thick_lines_to_verts(lines, widths, heights, false, print_z, volume); thick_lines_to_verts(lines, widths, heights, false, print_z, volume);
} }
#endif // ENABLE_GLINDEXEDVERTEXARRAY_REMOVAL
#if ENABLE_GLINDEXEDVERTEXARRAY_REMOVAL
void _3DScene::extrusionentity_to_verts(const ExtrusionEntityCollection& extrusion_entity_collection, float print_z, const Point& copy, GUI::GLModel::Geometry& geometry)
{
for (const ExtrusionEntity* extrusion_entity : extrusion_entity_collection.entities)
extrusionentity_to_verts(extrusion_entity, print_z, copy, geometry);
}
#else
void _3DScene::extrusionentity_to_verts(const ExtrusionEntityCollection &extrusion_entity_collection, float print_z, const Point &copy, GLVolume &volume) void _3DScene::extrusionentity_to_verts(const ExtrusionEntityCollection &extrusion_entity_collection, float print_z, const Point &copy, GLVolume &volume)
{ {
for (const ExtrusionEntity *extrusion_entity : extrusion_entity_collection.entities) for (const ExtrusionEntity *extrusion_entity : extrusion_entity_collection.entities)
extrusionentity_to_verts(extrusion_entity, print_z, copy, volume); extrusionentity_to_verts(extrusion_entity, print_z, copy, volume);
} }
#endif // ENABLE_GLINDEXEDVERTEXARRAY_REMOVAL
#if ENABLE_GLINDEXEDVERTEXARRAY_REMOVAL
void _3DScene::extrusionentity_to_verts(const ExtrusionEntity* extrusion_entity, float print_z, const Point& copy, GUI::GLModel::Geometry& geometry)
{
if (extrusion_entity != nullptr) {
auto* extrusion_path = dynamic_cast<const ExtrusionPath*>(extrusion_entity);
if (extrusion_path != nullptr)
extrusionentity_to_verts(*extrusion_path, print_z, copy, geometry);
else {
auto* extrusion_loop = dynamic_cast<const ExtrusionLoop*>(extrusion_entity);
if (extrusion_loop != nullptr)
extrusionentity_to_verts(*extrusion_loop, print_z, copy, geometry);
else {
auto* extrusion_multi_path = dynamic_cast<const ExtrusionMultiPath*>(extrusion_entity);
if (extrusion_multi_path != nullptr)
extrusionentity_to_verts(*extrusion_multi_path, print_z, copy, geometry);
else {
auto* extrusion_entity_collection = dynamic_cast<const ExtrusionEntityCollection*>(extrusion_entity);
if (extrusion_entity_collection != nullptr)
extrusionentity_to_verts(*extrusion_entity_collection, print_z, copy, geometry);
else
throw Slic3r::RuntimeError("Unexpected extrusion_entity type in to_verts()");
}
}
}
}
}
#else
void _3DScene::extrusionentity_to_verts(const ExtrusionEntity *extrusion_entity, float print_z, const Point &copy, GLVolume &volume) void _3DScene::extrusionentity_to_verts(const ExtrusionEntity *extrusion_entity, float print_z, const Point &copy, GLVolume &volume)
{ {
if (extrusion_entity != nullptr) { if (extrusion_entity != nullptr) {
@ -1839,9 +2545,8 @@ void _3DScene::extrusionentity_to_verts(const ExtrusionEntity *extrusion_entity,
auto *extrusion_entity_collection = dynamic_cast<const ExtrusionEntityCollection*>(extrusion_entity); auto *extrusion_entity_collection = dynamic_cast<const ExtrusionEntityCollection*>(extrusion_entity);
if (extrusion_entity_collection != nullptr) if (extrusion_entity_collection != nullptr)
extrusionentity_to_verts(*extrusion_entity_collection, print_z, copy, volume); extrusionentity_to_verts(*extrusion_entity_collection, print_z, copy, volume);
else { else
throw Slic3r::RuntimeError("Unexpected extrusion_entity type in to_verts()"); throw Slic3r::RuntimeError("Unexpected extrusion_entity type in to_verts()");
}
} }
} }
} }
@ -1860,5 +2565,6 @@ void _3DScene::point3_to_verts(const Vec3crd& point, double width, double height
{ {
thick_point_to_verts(point, width, height, volume); thick_point_to_verts(point, width, height, volume);
} }
#endif // ENABLE_GLINDEXEDVERTEXARRAY_REMOVAL
} // namespace Slic3r } // namespace Slic3r

View file

@ -46,6 +46,7 @@ enum ModelInstanceEPrintVolumeState : unsigned char;
// Return appropriate color based on the ModelVolume. // Return appropriate color based on the ModelVolume.
extern ColorRGBA color_from_model_volume(const ModelVolume& model_volume); extern ColorRGBA color_from_model_volume(const ModelVolume& model_volume);
#if !ENABLE_GLINDEXEDVERTEXARRAY_REMOVAL
// A container for interleaved arrays of 3D vertices and normals, // A container for interleaved arrays of 3D vertices and normals,
// possibly indexed by triangles and / or quads. // possibly indexed by triangles and / or quads.
class GLIndexedVertexArray { class GLIndexedVertexArray {
@ -246,6 +247,7 @@ public:
private: private:
BoundingBox m_bounding_box; BoundingBox m_bounding_box;
}; };
#endif // !ENABLE_GLINDEXEDVERTEXARRAY_REMOVAL
class GLVolume { class GLVolume {
public: public:
@ -388,11 +390,17 @@ public:
// Is mouse or rectangle selection over this object to select/deselect it ? // Is mouse or rectangle selection over this object to select/deselect it ?
EHoverState hover; EHoverState hover;
#if ENABLE_GLINDEXEDVERTEXARRAY_REMOVAL
GUI::GLModel model;
#else
// Interleaved triangles & normals with indexed triangles & quads. // Interleaved triangles & normals with indexed triangles & quads.
GLIndexedVertexArray indexed_vertex_array; GLIndexedVertexArray indexed_vertex_array;
#endif // ENABLE_GLINDEXEDVERTEXARRAY_REMOVAL
// Ranges of triangle and quad indices to be rendered. // Ranges of triangle and quad indices to be rendered.
std::pair<size_t, size_t> tverts_range; std::pair<size_t, size_t> tverts_range;
#if !ENABLE_GLINDEXEDVERTEXARRAY_REMOVAL
std::pair<size_t, size_t> qverts_range; std::pair<size_t, size_t> qverts_range;
#endif // !ENABLE_GLINDEXEDVERTEXARRAY_REMOVAL
// If the qverts or tverts contain thick extrusions, then offsets keeps pointers of the starts // If the qverts or tverts contain thick extrusions, then offsets keeps pointers of the starts
// of the extrusions per layer. // of the extrusions per layer.
@ -402,13 +410,17 @@ public:
// Bounding box of this volume, in unscaled coordinates. // Bounding box of this volume, in unscaled coordinates.
BoundingBoxf3 bounding_box() const { BoundingBoxf3 bounding_box() const {
#if ENABLE_GLINDEXEDVERTEXARRAY_REMOVAL
return this->model.get_bounding_box();
#else
BoundingBoxf3 out; BoundingBoxf3 out;
if (! this->indexed_vertex_array.bounding_box().isEmpty()) { if (!this->indexed_vertex_array.bounding_box().isEmpty()) {
out.min = this->indexed_vertex_array.bounding_box().min().cast<double>(); out.min = this->indexed_vertex_array.bounding_box().min().cast<double>();
out.max = this->indexed_vertex_array.bounding_box().max().cast<double>(); out.max = this->indexed_vertex_array.bounding_box().max().cast<double>();
out.defined = true; out.defined = true;
}; }
return out; return out;
#endif // ENABLE_GLINDEXEDVERTEXARRAY_REMOVAL
} }
void set_color(const ColorRGBA& rgba) { color = rgba; } void set_color(const ColorRGBA& rgba) { color = rgba; }
@ -498,14 +510,20 @@ public:
// convex hull // convex hull
const TriangleMesh* convex_hull() const { return m_convex_hull.get(); } const TriangleMesh* convex_hull() const { return m_convex_hull.get(); }
#if ENABLE_GLINDEXEDVERTEXARRAY_REMOVAL
bool empty() const { return this->model.is_empty(); }
#else
bool empty() const { return this->indexed_vertex_array.empty(); } bool empty() const { return this->indexed_vertex_array.empty(); }
#endif // ENABLE_GLINDEXEDVERTEXARRAY_REMOVAL
void set_range(double low, double high); void set_range(double low, double high);
void render() const; void render();
#if !ENABLE_GLINDEXEDVERTEXARRAY_REMOVAL
void finalize_geometry(bool opengl_initialized) { this->indexed_vertex_array.finalize_geometry(opengl_initialized); } void finalize_geometry(bool opengl_initialized) { this->indexed_vertex_array.finalize_geometry(opengl_initialized); }
void release_geometry() { this->indexed_vertex_array.release_geometry(); } void release_geometry() { this->indexed_vertex_array.release_geometry(); }
#endif // !ENABLE_GLINDEXEDVERTEXARRAY_REMOVAL
void set_bounding_boxes_as_dirty() { void set_bounding_boxes_as_dirty() {
m_transformed_bounding_box.reset(); m_transformed_bounding_box.reset();
@ -524,12 +542,20 @@ public:
#endif // ENABLE_SHOW_NON_MANIFOLD_EDGES #endif // ENABLE_SHOW_NON_MANIFOLD_EDGES
// Return an estimate of the memory consumed by this class. // Return an estimate of the memory consumed by this class.
size_t cpu_memory_used() const { size_t cpu_memory_used() const {
//FIXME what to do wih m_convex_hull? #if ENABLE_GLINDEXEDVERTEXARRAY_REMOVAL
return sizeof(*this) + this->model.cpu_memory_used() + this->print_zs.capacity() * sizeof(coordf_t) +
this->offsets.capacity() * sizeof(size_t);
}
// Return an estimate of the memory held by GPU vertex buffers.
size_t gpu_memory_used() const { return this->model.gpu_memory_used(); }
#else
//FIXME what to do wih m_convex_hull?
return sizeof(*this) - sizeof(this->indexed_vertex_array) + this->indexed_vertex_array.cpu_memory_used() + this->print_zs.capacity() * sizeof(coordf_t) + this->offsets.capacity() * sizeof(size_t); return sizeof(*this) - sizeof(this->indexed_vertex_array) + this->indexed_vertex_array.cpu_memory_used() + this->print_zs.capacity() * sizeof(coordf_t) + this->offsets.capacity() * sizeof(size_t);
} }
// Return an estimate of the memory held by GPU vertex buffers. // Return an estimate of the memory held by GPU vertex buffers.
size_t gpu_memory_used() const { return this->indexed_vertex_array.gpu_memory_used(); } size_t gpu_memory_used() const { return this->indexed_vertex_array.gpu_memory_used(); }
#endif // ENABLE_GLINDEXEDVERTEXARRAY_REMOVAL
size_t total_memory_used() const { return this->cpu_memory_used() + this->gpu_memory_used(); } size_t total_memory_used() const { return this->cpu_memory_used() + this->gpu_memory_used(); }
}; };
@ -589,6 +615,36 @@ public:
GLVolumeCollection() { set_default_slope_normal_z(); } GLVolumeCollection() { set_default_slope_normal_z(); }
~GLVolumeCollection() { clear(); } ~GLVolumeCollection() { clear(); }
#if ENABLE_GLINDEXEDVERTEXARRAY_REMOVAL
std::vector<int> load_object(
const ModelObject* model_object,
int obj_idx,
const std::vector<int>& instance_idxs);
int load_object_volume(
const ModelObject* model_object,
int obj_idx,
int volume_idx,
int instance_idx);
// Load SLA auxiliary GLVolumes (for support trees or pad).
void load_object_auxiliary(
const SLAPrintObject* print_object,
int obj_idx,
// pairs of <instance_idx, print_instance_idx>
const std::vector<std::pair<size_t, size_t>>& instances,
SLAPrintObjectStep milestone,
// Timestamp of the last change of the milestone
size_t timestamp);
#if ENABLE_WIPETOWER_OBJECTID_1000_REMOVAL
int load_wipe_tower_preview(
float pos_x, float pos_y, float width, float depth, float height, float rotation_angle, bool size_unknown, float brim_width);
#else
int load_wipe_tower_preview(
int obj_idx, float pos_x, float pos_y, float width, float depth, float height, float rotation_angle, bool size_unknown, float brim_width);
#endif // ENABLE_WIPETOWER_OBJECTID_1000_REMOVAL
#else
std::vector<int> load_object( std::vector<int> load_object(
const ModelObject *model_object, const ModelObject *model_object,
int obj_idx, int obj_idx,
@ -620,13 +676,20 @@ public:
int load_wipe_tower_preview( int load_wipe_tower_preview(
int obj_idx, float pos_x, float pos_y, float width, float depth, float height, float rotation_angle, bool size_unknown, float brim_width, bool opengl_initialized); int obj_idx, float pos_x, float pos_y, float width, float depth, float height, float rotation_angle, bool size_unknown, float brim_width, bool opengl_initialized);
#endif // ENABLE_WIPETOWER_OBJECTID_1000_REMOVAL #endif // ENABLE_WIPETOWER_OBJECTID_1000_REMOVAL
#endif // ENABLE_GLINDEXEDVERTEXARRAY_REMOVAL
#if ENABLE_GLINDEXEDVERTEXARRAY_REMOVAL
GLVolume* new_toolpath_volume(const ColorRGBA& rgba);
GLVolume* new_nontoolpath_volume(const ColorRGBA& rgba);
#else
GLVolume* new_toolpath_volume(const ColorRGBA& rgba, size_t reserve_vbo_floats = 0); GLVolume* new_toolpath_volume(const ColorRGBA& rgba, size_t reserve_vbo_floats = 0);
GLVolume* new_nontoolpath_volume(const ColorRGBA& rgba, size_t reserve_vbo_floats = 0); GLVolume* new_nontoolpath_volume(const ColorRGBA& rgba, size_t reserve_vbo_floats = 0);
#endif // ENABLE_GLINDEXEDVERTEXARRAY_REMOVAL
// Render the volumes by OpenGL. // Render the volumes by OpenGL.
void render(ERenderType type, bool disable_cullface, const Transform3d& view_matrix, std::function<bool(const GLVolume&)> filter_func = std::function<bool(const GLVolume&)>()) const; void render(ERenderType type, bool disable_cullface, const Transform3d& view_matrix, std::function<bool(const GLVolume&)> filter_func = std::function<bool(const GLVolume&)>()) const;
#if !ENABLE_GLINDEXEDVERTEXARRAY_REMOVAL
// Finalize the initialization of the geometry & indices, // Finalize the initialization of the geometry & indices,
// upload the geometry and indices to OpenGL VBO objects // upload the geometry and indices to OpenGL VBO objects
// and shrink the allocated data, possibly relasing it if it has been loaded into the VBOs. // and shrink the allocated data, possibly relasing it if it has been loaded into the VBOs.
@ -634,11 +697,12 @@ public:
// Release the geometry data assigned to the volumes. // Release the geometry data assigned to the volumes.
// If OpenGL VBOs were allocated, an OpenGL context has to be active to release them. // If OpenGL VBOs were allocated, an OpenGL context has to be active to release them.
void release_geometry() { for (auto *v : volumes) v->release_geometry(); } void release_geometry() { for (auto *v : volumes) v->release_geometry(); }
#endif // !ENABLE_GLINDEXEDVERTEXARRAY_REMOVAL
// Clear the geometry // Clear the geometry
void clear() { for (auto *v : volumes) delete v; volumes.clear(); } void clear() { for (auto *v : volumes) delete v; volumes.clear(); }
bool empty() const { return volumes.empty(); } bool empty() const { return volumes.empty(); }
void set_range(double low, double high) { for (GLVolume *vol : this->volumes) vol->set_range(low, high); } void set_range(double low, double high) { for (GLVolume* vol : this->volumes) vol->set_range(low, high); }
void set_print_volume(const PrintVolume& print_volume) { m_print_volume = print_volume; } void set_print_volume(const PrintVolume& print_volume) { m_print_volume = print_volume; }
@ -683,9 +747,18 @@ GLVolumeWithIdAndZList volumes_to_render(const GLVolumePtrs& volumes, GLVolumeCo
struct _3DScene struct _3DScene
{ {
#if ENABLE_GLINDEXEDVERTEXARRAY_REMOVAL
static void thick_lines_to_verts(const Lines& lines, const std::vector<double>& widths, const std::vector<double>& heights, bool closed, double top_z, GUI::GLModel::Geometry& geometry);
static void thick_lines_to_verts(const Lines3& lines, const std::vector<double>& widths, const std::vector<double>& heights, bool closed, GUI::GLModel::Geometry& geometry);
static void extrusionentity_to_verts(const ExtrusionPath& extrusion_path, float print_z, const Point& copy, GUI::GLModel::Geometry& geometry);
static void extrusionentity_to_verts(const ExtrusionLoop& extrusion_loop, float print_z, const Point& copy, GUI::GLModel::Geometry& geometry);
static void extrusionentity_to_verts(const ExtrusionMultiPath& extrusion_multi_path, float print_z, const Point& copy, GUI::GLModel::Geometry& geometry);
static void extrusionentity_to_verts(const ExtrusionEntityCollection& extrusion_entity_collection, float print_z, const Point& copy, GUI::GLModel::Geometry& geometry);
static void extrusionentity_to_verts(const ExtrusionEntity* extrusion_entity, float print_z, const Point& copy, GUI::GLModel::Geometry& geometry);
#else
static void thick_lines_to_verts(const Lines& lines, const std::vector<double>& widths, const std::vector<double>& heights, bool closed, double top_z, GLVolume& volume); static void thick_lines_to_verts(const Lines& lines, const std::vector<double>& widths, const std::vector<double>& heights, bool closed, double top_z, GLVolume& volume);
static void thick_lines_to_verts(const Lines3& lines, const std::vector<double>& widths, const std::vector<double>& heights, bool closed, GLVolume& volume); static void thick_lines_to_verts(const Lines3& lines, const std::vector<double>& widths, const std::vector<double>& heights, bool closed, GLVolume& volume);
static void extrusionentity_to_verts(const Polyline &polyline, float width, float height, float print_z, GLVolume& volume); static void extrusionentity_to_verts(const Polyline& polyline, float width, float height, float print_z, GLVolume& volume);
static void extrusionentity_to_verts(const ExtrusionPath& extrusion_path, float print_z, GLVolume& volume); static void extrusionentity_to_verts(const ExtrusionPath& extrusion_path, float print_z, GLVolume& volume);
static void extrusionentity_to_verts(const ExtrusionPath& extrusion_path, float print_z, const Point& copy, GLVolume& volume); static void extrusionentity_to_verts(const ExtrusionPath& extrusion_path, float print_z, const Point& copy, GLVolume& volume);
static void extrusionentity_to_verts(const ExtrusionLoop& extrusion_loop, float print_z, const Point& copy, GLVolume& volume); static void extrusionentity_to_verts(const ExtrusionLoop& extrusion_loop, float print_z, const Point& copy, GLVolume& volume);
@ -694,6 +767,7 @@ struct _3DScene
static void extrusionentity_to_verts(const ExtrusionEntity* extrusion_entity, float print_z, const Point& copy, GLVolume& volume); static void extrusionentity_to_verts(const ExtrusionEntity* extrusion_entity, float print_z, const Point& copy, GLVolume& volume);
static void polyline3_to_verts(const Polyline3& polyline, double width, double height, GLVolume& volume); static void polyline3_to_verts(const Polyline3& polyline, double width, double height, GLVolume& volume);
static void point3_to_verts(const Vec3crd& point, double width, double height, GLVolume& volume); static void point3_to_verts(const Vec3crd& point, double width, double height, GLVolume& volume);
#endif // ENABLE_GLINDEXEDVERTEXARRAY_REMOVAL
}; };
} }

View file

@ -711,7 +711,11 @@ void GCodeViewer::init()
m_gl_data_initialized = true; m_gl_data_initialized = true;
} }
#if ENABLE_GLINDEXEDVERTEXARRAY_REMOVAL
void GCodeViewer::load(const GCodeProcessorResult& gcode_result, const Print& print)
#else
void GCodeViewer::load(const GCodeProcessorResult& gcode_result, const Print& print, bool initialized) void GCodeViewer::load(const GCodeProcessorResult& gcode_result, const Print& print, bool initialized)
#endif // ENABLE_GLINDEXEDVERTEXARRAY_REMOVAL
{ {
// avoid processing if called with the same gcode_result // avoid processing if called with the same gcode_result
#if ENABLE_VOLUMETRIC_RATE_TOOLPATHS_RECALC #if ENABLE_VOLUMETRIC_RATE_TOOLPATHS_RECALC
@ -750,7 +754,11 @@ void GCodeViewer::load(const GCodeProcessorResult& gcode_result, const Print& pr
m_filament_densities = gcode_result.filament_densities; m_filament_densities = gcode_result.filament_densities;
if (wxGetApp().is_editor()) if (wxGetApp().is_editor())
#if ENABLE_GLINDEXEDVERTEXARRAY_REMOVAL
load_shells(print);
#else
load_shells(print, initialized); load_shells(print, initialized);
#endif // ENABLE_GLINDEXEDVERTEXARRAY_REMOVAL
else { else {
Pointfs bed_shape; Pointfs bed_shape;
std::string texture; std::string texture;
@ -2289,7 +2297,11 @@ void GCodeViewer::load_toolpaths(const GCodeProcessorResult& gcode_result)
progress_dialog->Destroy(); progress_dialog->Destroy();
} }
#if ENABLE_GLINDEXEDVERTEXARRAY_REMOVAL
void GCodeViewer::load_shells(const Print& print)
#else
void GCodeViewer::load_shells(const Print& print, bool initialized) void GCodeViewer::load_shells(const Print& print, bool initialized)
#endif // ENABLE_GLINDEXEDVERTEXARRAY_REMOVAL
{ {
if (print.objects().empty()) if (print.objects().empty())
// no shells, return // no shells, return
@ -2306,7 +2318,11 @@ void GCodeViewer::load_shells(const Print& print, bool initialized)
} }
size_t current_volumes_count = m_shells.volumes.volumes.size(); size_t current_volumes_count = m_shells.volumes.volumes.size();
#if ENABLE_GLINDEXEDVERTEXARRAY_REMOVAL
m_shells.volumes.load_object(model_obj, object_id, instance_ids);
#else
m_shells.volumes.load_object(model_obj, object_id, instance_ids, initialized); m_shells.volumes.load_object(model_obj, object_id, instance_ids, initialized);
#endif // ENABLE_GLINDEXEDVERTEXARRAY_REMOVAL
// adjust shells' z if raft is present // adjust shells' z if raft is present
const SlicingParameters& slicing_parameters = obj->slicing_parameters(); const SlicingParameters& slicing_parameters = obj->slicing_parameters();
@ -2330,6 +2346,15 @@ void GCodeViewer::load_shells(const Print& print, bool initialized)
const float depth = print.wipe_tower_data(extruders_count).depth; const float depth = print.wipe_tower_data(extruders_count).depth;
const float brim_width = print.wipe_tower_data(extruders_count).brim_width; const float brim_width = print.wipe_tower_data(extruders_count).brim_width;
#if ENABLE_GLINDEXEDVERTEXARRAY_REMOVAL
#if ENABLE_WIPETOWER_OBJECTID_1000_REMOVAL
m_shells.volumes.load_wipe_tower_preview(config.wipe_tower_x, config.wipe_tower_y, config.wipe_tower_width, depth, max_z, config.wipe_tower_rotation_angle,
!print.is_step_done(psWipeTower), brim_width);
#else
m_shells.volumes.load_wipe_tower_preview(1000, config.wipe_tower_x, config.wipe_tower_y, config.wipe_tower_width, depth, max_z, config.wipe_tower_rotation_angle,
!print.is_step_done(psWipeTower), brim_width);
#endif // ENABLE_WIPETOWER_OBJECTID_1000_REMOVAL
#else
#if ENABLE_WIPETOWER_OBJECTID_1000_REMOVAL #if ENABLE_WIPETOWER_OBJECTID_1000_REMOVAL
m_shells.volumes.load_wipe_tower_preview(config.wipe_tower_x, config.wipe_tower_y, config.wipe_tower_width, depth, max_z, config.wipe_tower_rotation_angle, m_shells.volumes.load_wipe_tower_preview(config.wipe_tower_x, config.wipe_tower_y, config.wipe_tower_width, depth, max_z, config.wipe_tower_rotation_angle,
!print.is_step_done(psWipeTower), brim_width, initialized); !print.is_step_done(psWipeTower), brim_width, initialized);
@ -2337,6 +2362,7 @@ void GCodeViewer::load_shells(const Print& print, bool initialized)
m_shells.volumes.load_wipe_tower_preview(1000, config.wipe_tower_x, config.wipe_tower_y, config.wipe_tower_width, depth, max_z, config.wipe_tower_rotation_angle, m_shells.volumes.load_wipe_tower_preview(1000, config.wipe_tower_x, config.wipe_tower_y, config.wipe_tower_width, depth, max_z, config.wipe_tower_rotation_angle,
!print.is_step_done(psWipeTower), brim_width, initialized); !print.is_step_done(psWipeTower), brim_width, initialized);
#endif // ENABLE_WIPETOWER_OBJECTID_1000_REMOVAL #endif // ENABLE_WIPETOWER_OBJECTID_1000_REMOVAL
#endif // ENABLE_GLINDEXEDVERTEXARRAY_REMOVAL
} }
} }
@ -3199,6 +3225,7 @@ void GCodeViewer::render_shells()
if (shader == nullptr) if (shader == nullptr)
return; return;
#if !ENABLE_GLINDEXEDVERTEXARRAY_REMOVAL
// when the background processing is enabled, it may happen that the shells data have been loaded // when the background processing is enabled, it may happen that the shells data have been loaded
// before opengl has been initialized for the preview canvas. // before opengl has been initialized for the preview canvas.
// when this happens, the volumes' data have not been sent to gpu yet. // when this happens, the volumes' data have not been sent to gpu yet.
@ -3206,6 +3233,7 @@ void GCodeViewer::render_shells()
if (!v->indexed_vertex_array.has_VBOs()) if (!v->indexed_vertex_array.has_VBOs())
v->finalize_geometry(true); v->finalize_geometry(true);
} }
#endif // !ENABLE_GLINDEXEDVERTEXARRAY_REMOVAL
// glsafe(::glDepthMask(GL_FALSE)); // glsafe(::glDepthMask(GL_FALSE));

View file

@ -823,7 +823,11 @@ public:
void init(); void init();
// extract rendering data from the given parameters // extract rendering data from the given parameters
#if ENABLE_GLINDEXEDVERTEXARRAY_REMOVAL
void load(const GCodeProcessorResult& gcode_result, const Print& print);
#else
void load(const GCodeProcessorResult& gcode_result, const Print& print, bool initialized); void load(const GCodeProcessorResult& gcode_result, const Print& print, bool initialized);
#endif // ENABLE_GLINDEXEDVERTEXARRAY_REMOVAL
// recalculate ranges in dependence of what is visible and sets tool/print colors // recalculate ranges in dependence of what is visible and sets tool/print colors
void refresh(const GCodeProcessorResult& gcode_result, const std::vector<std::string>& str_tool_colors); void refresh(const GCodeProcessorResult& gcode_result, const std::vector<std::string>& str_tool_colors);
#if ENABLE_PREVIEW_LAYOUT #if ENABLE_PREVIEW_LAYOUT
@ -883,7 +887,11 @@ public:
private: private:
void load_toolpaths(const GCodeProcessorResult& gcode_result); void load_toolpaths(const GCodeProcessorResult& gcode_result);
#if ENABLE_GLINDEXEDVERTEXARRAY_REMOVAL
void load_shells(const Print& print);
#else
void load_shells(const Print& print, bool initialized); void load_shells(const Print& print, bool initialized);
#endif // ENABLE_GLINDEXEDVERTEXARRAY_REMOVAL
#if !ENABLE_PREVIEW_LAYOUT #if !ENABLE_PREVIEW_LAYOUT
void refresh_render_paths(bool keep_sequential_current_first, bool keep_sequential_current_last) const; void refresh_render_paths(bool keep_sequential_current_first, bool keep_sequential_current_last) const;
#endif // !ENABLE_PREVIEW_LAYOUT #endif // !ENABLE_PREVIEW_LAYOUT

View file

@ -526,7 +526,7 @@ void GLCanvas3D::LayersEditing::render_volumes(const GLCanvas3D& canvas, const G
glsafe(::glTexImage2D(GL_TEXTURE_2D, 1, GL_RGBA, half_w, half_h, 0, GL_RGBA, GL_UNSIGNED_BYTE, 0)); glsafe(::glTexImage2D(GL_TEXTURE_2D, 1, GL_RGBA, half_w, half_h, 0, GL_RGBA, GL_UNSIGNED_BYTE, 0));
glsafe(::glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, w, h, GL_RGBA, GL_UNSIGNED_BYTE, m_layers_texture.data.data())); glsafe(::glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, w, h, GL_RGBA, GL_UNSIGNED_BYTE, m_layers_texture.data.data()));
glsafe(::glTexSubImage2D(GL_TEXTURE_2D, 1, 0, 0, half_w, half_h, GL_RGBA, GL_UNSIGNED_BYTE, m_layers_texture.data.data() + m_layers_texture.width * m_layers_texture.height * 4)); glsafe(::glTexSubImage2D(GL_TEXTURE_2D, 1, 0, 0, half_w, half_h, GL_RGBA, GL_UNSIGNED_BYTE, m_layers_texture.data.data() + m_layers_texture.width * m_layers_texture.height * 4));
for (const GLVolume* glvolume : volumes.volumes) { for (GLVolume* glvolume : volumes.volumes) {
// Render the object using the layer editing shader and texture. // Render the object using the layer editing shader and texture.
if (!glvolume->is_active || glvolume->composite_id.object_id != this->last_object_id || glvolume->is_modifier) if (!glvolume->is_active || glvolume->composite_id.object_id != this->last_object_id || glvolume->is_modifier)
continue; continue;
@ -1192,9 +1192,11 @@ bool GLCanvas3D::init()
if (m_main_toolbar.is_enabled()) if (m_main_toolbar.is_enabled())
m_layers_editing.init(); m_layers_editing.init();
#if !ENABLE_GLINDEXEDVERTEXARRAY_REMOVAL
// on linux the gl context is not valid until the canvas is not shown on screen // on linux the gl context is not valid until the canvas is not shown on screen
// we defer the geometry finalization of volumes until the first call to render() // we defer the geometry finalization of volumes until the first call to render()
m_volumes.finalize_geometry(true); m_volumes.finalize_geometry(true);
#endif // !ENABLE_GLINDEXEDVERTEXARRAY_REMOVAL
if (m_gizmos.is_enabled() && !m_gizmos.init()) if (m_gizmos.is_enabled() && !m_gizmos.init())
std::cout << "Unable to initialize gizmos: please, check that all the required textures are available" << std::endl; std::cout << "Unable to initialize gizmos: please, check that all the required textures are available" << std::endl;
@ -1799,7 +1801,11 @@ std::vector<int> GLCanvas3D::load_object(const ModelObject& model_object, int ob
instance_idxs.emplace_back(i); instance_idxs.emplace_back(i);
} }
} }
#if ENABLE_GLINDEXEDVERTEXARRAY_REMOVAL
return m_volumes.load_object(&model_object, obj_idx, instance_idxs);
#else
return m_volumes.load_object(&model_object, obj_idx, instance_idxs, m_initialized); return m_volumes.load_object(&model_object, obj_idx, instance_idxs, m_initialized);
#endif // ENABLE_GLINDEXEDVERTEXARRAY_REMOVAL
} }
std::vector<int> GLCanvas3D::load_object(const Model& model, int obj_idx) std::vector<int> GLCanvas3D::load_object(const Model& model, int obj_idx)
@ -2024,7 +2030,11 @@ void GLCanvas3D::reload_scene(bool refresh_immediately, bool force_full_scene_re
// Note the index of the loaded volume, so that we can reload the main model GLVolume with the hollowed mesh // Note the index of the loaded volume, so that we can reload the main model GLVolume with the hollowed mesh
// later in this function. // later in this function.
it->volume_idx = m_volumes.volumes.size(); it->volume_idx = m_volumes.volumes.size();
#if ENABLE_GLINDEXEDVERTEXARRAY_REMOVAL
m_volumes.load_object_volume(&model_object, obj_idx, volume_idx, instance_idx);
#else
m_volumes.load_object_volume(&model_object, obj_idx, volume_idx, instance_idx, m_initialized); m_volumes.load_object_volume(&model_object, obj_idx, volume_idx, instance_idx, m_initialized);
#endif // ENABLE_GLINDEXEDVERTEXARRAY_REMOVAL
m_volumes.volumes.back()->geometry_id = key.geometry_id; m_volumes.volumes.back()->geometry_id = key.geometry_id;
update_object_list = true; update_object_list = true;
} else { } else {
@ -2081,31 +2091,55 @@ void GLCanvas3D::reload_scene(bool refresh_immediately, bool force_full_scene_re
GLVolume &volume = *m_volumes.volumes[it->volume_idx]; GLVolume &volume = *m_volumes.volumes[it->volume_idx];
if (! volume.offsets.empty() && state.step[istep].timestamp != volume.offsets.front()) { if (! volume.offsets.empty() && state.step[istep].timestamp != volume.offsets.front()) {
// The backend either produced a new hollowed mesh, or it invalidated the one that the front end has seen. // The backend either produced a new hollowed mesh, or it invalidated the one that the front end has seen.
#if ENABLE_GLINDEXEDVERTEXARRAY_REMOVAL
volume.model.reset();
#else
volume.indexed_vertex_array.release_geometry(); volume.indexed_vertex_array.release_geometry();
if (state.step[istep].state == PrintStateBase::DONE) { #endif // ENABLE_GLINDEXEDVERTEXARRAY_REMOVAL
if (state.step[istep].state == PrintStateBase::DONE) {
TriangleMesh mesh = print_object->get_mesh(slaposDrillHoles); TriangleMesh mesh = print_object->get_mesh(slaposDrillHoles);
assert(! mesh.empty()); assert(! mesh.empty());
mesh.transform(sla_print->sla_trafo(*m_model->objects[volume.object_idx()]).inverse()); mesh.transform(sla_print->sla_trafo(*m_model->objects[volume.object_idx()]).inverse());
#if ENABLE_SMOOTH_NORMALS #if ENABLE_SMOOTH_NORMALS
#if ENABLE_GLINDEXEDVERTEXARRAY_REMOVAL
volume.model.init_from(mesh, true);
#else
volume.indexed_vertex_array.load_mesh(mesh, true); volume.indexed_vertex_array.load_mesh(mesh, true);
#endif // ENABLE_GLINDEXEDVERTEXARRAY_REMOVAL
#else
#if ENABLE_GLINDEXEDVERTEXARRAY_REMOVAL
volume.model.init_from(mesh);
#else #else
volume.indexed_vertex_array.load_mesh(mesh); volume.indexed_vertex_array.load_mesh(mesh);
#endif // ENABLE_SMOOTH_NORMALS #endif // ENABLE_GLINDEXEDVERTEXARRAY_REMOVAL
} else {
// Reload the original volume.
#if ENABLE_SMOOTH_NORMALS
volume.indexed_vertex_array.load_mesh(m_model->objects[volume.object_idx()]->volumes[volume.volume_idx()]->mesh(), true);
#else
volume.indexed_vertex_array.load_mesh(m_model->objects[volume.object_idx()]->volumes[volume.volume_idx()]->mesh());
#endif // ENABLE_SMOOTH_NORMALS #endif // ENABLE_SMOOTH_NORMALS
} }
else {
// Reload the original volume.
#if ENABLE_SMOOTH_NORMALS
#if ENABLE_GLINDEXEDVERTEXARRAY_REMOVAL
volume.model.init_from(m_model->objects[volume.object_idx()]->volumes[volume.volume_idx()]->mesh(), true);
#else
volume.indexed_vertex_array.load_mesh(m_model->objects[volume.object_idx()]->volumes[volume.volume_idx()]->mesh(), true);
#endif // ENABLE_GLINDEXEDVERTEXARRAY_REMOVAL
#else
#if ENABLE_GLINDEXEDVERTEXARRAY_REMOVAL
volume.model.init_from(m_model->objects[volume.object_idx()]->volumes[volume.volume_idx()]->mesh());
#else
volume.indexed_vertex_array.load_mesh(m_model->objects[volume.object_idx()]->volumes[volume.volume_idx()]->mesh());
#endif // ENABLE_GLINDEXEDVERTEXARRAY_REMOVAL
#endif // ENABLE_SMOOTH_NORMALS
}
#if !ENABLE_GLINDEXEDVERTEXARRAY_REMOVAL
volume.finalize_geometry(true); volume.finalize_geometry(true);
} #endif // !ENABLE_GLINDEXEDVERTEXARRAY_REMOVAL
}
//FIXME it is an ugly hack to write the timestamp into the "offsets" field to not have to add another member variable //FIXME it is an ugly hack to write the timestamp into the "offsets" field to not have to add another member variable
// to the GLVolume. We should refactor GLVolume significantly, so that the GLVolume will not contain member variables // to the GLVolume. We should refactor GLVolume significantly, so that the GLVolume will not contain member variables
// of various concenrs (model vs. 3D print path). // of various concenrs (model vs. 3D print path).
volume.offsets = { state.step[istep].timestamp }; volume.offsets = { state.step[istep].timestamp };
} else if (state.step[istep].state == PrintStateBase::DONE) { }
else if (state.step[istep].state == PrintStateBase::DONE) {
// Check whether there is an existing auxiliary volume to be updated, or a new auxiliary volume to be created. // Check whether there is an existing auxiliary volume to be updated, or a new auxiliary volume to be created.
ModelVolumeState key(state.step[istep].timestamp, instance.instance_id.id); ModelVolumeState key(state.step[istep].timestamp, instance.instance_id.id);
auto it = std::lower_bound(aux_volume_state.begin(), aux_volume_state.end(), key, model_volume_state_lower); auto it = std::lower_bound(aux_volume_state.begin(), aux_volume_state.end(), key, model_volume_state_lower);
@ -2117,7 +2151,8 @@ void GLCanvas3D::reload_scene(bool refresh_immediately, bool force_full_scene_re
instances[istep].emplace_back(std::pair<size_t, size_t>(instance_idx, print_instance_idx)); instances[istep].emplace_back(std::pair<size_t, size_t>(instance_idx, print_instance_idx));
else else
shift_zs[object_idx] = 0.; shift_zs[object_idx] = 0.;
} else { }
else {
// Recycling an old GLVolume. Update the Object/Instance indices into the current Model. // Recycling an old GLVolume. Update the Object/Instance indices into the current Model.
m_volumes.volumes[it->volume_idx]->composite_id = GLVolume::CompositeID(object_idx, m_volumes.volumes[it->volume_idx]->volume_idx(), instance_idx); m_volumes.volumes[it->volume_idx]->composite_id = GLVolume::CompositeID(object_idx, m_volumes.volumes[it->volume_idx]->volume_idx(), instance_idx);
m_volumes.volumes[it->volume_idx]->set_instance_transformation(model_object->instances[instance_idx]->get_transformation()); m_volumes.volumes[it->volume_idx]->set_instance_transformation(model_object->instances[instance_idx]->get_transformation());
@ -2127,7 +2162,11 @@ void GLCanvas3D::reload_scene(bool refresh_immediately, bool force_full_scene_re
for (size_t istep = 0; istep < sla_steps.size(); ++istep) for (size_t istep = 0; istep < sla_steps.size(); ++istep)
if (!instances[istep].empty()) if (!instances[istep].empty())
#if ENABLE_GLINDEXEDVERTEXARRAY_REMOVAL
m_volumes.load_object_auxiliary(print_object, object_idx, instances[istep], sla_steps[istep], state.step[istep].timestamp);
#else
m_volumes.load_object_auxiliary(print_object, object_idx, instances[istep], sla_steps[istep], state.step[istep].timestamp, m_initialized); m_volumes.load_object_auxiliary(print_object, object_idx, instances[istep], sla_steps[istep], state.step[istep].timestamp, m_initialized);
#endif // ENABLE_GLINDEXEDVERTEXARRAY_REMOVAL
} }
// Shift-up all volumes of the object so that it has the right elevation with respect to the print bed // Shift-up all volumes of the object so that it has the right elevation with respect to the print bed
@ -2157,6 +2196,17 @@ void GLCanvas3D::reload_scene(bool refresh_immediately, bool force_full_scene_re
float depth = print->wipe_tower_data(extruders_count).depth; float depth = print->wipe_tower_data(extruders_count).depth;
float brim_width = print->wipe_tower_data(extruders_count).brim_width; float brim_width = print->wipe_tower_data(extruders_count).brim_width;
#if ENABLE_GLINDEXEDVERTEXARRAY_REMOVAL
#if ENABLE_WIPETOWER_OBJECTID_1000_REMOVAL
int volume_idx_wipe_tower_new = m_volumes.load_wipe_tower_preview(
x, y, w, depth, (float)height, a, !print->is_step_done(psWipeTower),
brim_width);
#else
int volume_idx_wipe_tower_new = m_volumes.load_wipe_tower_preview(
1000, x, y, w, depth, (float)height, a, !print->is_step_done(psWipeTower),
brim_width);
#endif // ENABLE_WIPETOWER_OBJECTID_1000_REMOVAL
#else
#if ENABLE_WIPETOWER_OBJECTID_1000_REMOVAL #if ENABLE_WIPETOWER_OBJECTID_1000_REMOVAL
int volume_idx_wipe_tower_new = m_volumes.load_wipe_tower_preview( int volume_idx_wipe_tower_new = m_volumes.load_wipe_tower_preview(
x, y, w, depth, (float)height, a, !print->is_step_done(psWipeTower), x, y, w, depth, (float)height, a, !print->is_step_done(psWipeTower),
@ -2166,6 +2216,7 @@ void GLCanvas3D::reload_scene(bool refresh_immediately, bool force_full_scene_re
1000, x, y, w, depth, (float)height, a, !print->is_step_done(psWipeTower), 1000, x, y, w, depth, (float)height, a, !print->is_step_done(psWipeTower),
brim_width, m_initialized); brim_width, m_initialized);
#endif // ENABLE_WIPETOWER_OBJECTID_1000_REMOVAL #endif // ENABLE_WIPETOWER_OBJECTID_1000_REMOVAL
#endif // ENABLE_GLINDEXEDVERTEXARRAY_REMOVAL
if (volume_idx_wipe_tower_old != -1) if (volume_idx_wipe_tower_old != -1)
map_glvolume_old_to_new[volume_idx_wipe_tower_old] = volume_idx_wipe_tower_new; map_glvolume_old_to_new[volume_idx_wipe_tower_old] = volume_idx_wipe_tower_new;
} }
@ -2225,9 +2276,10 @@ void GLCanvas3D::reload_scene(bool refresh_immediately, bool force_full_scene_re
m_dirty = true; m_dirty = true;
} }
#if !ENABLE_GLINDEXEDVERTEXARRAY_REMOVAL
static void reserve_new_volume_finalize_old_volume(GLVolume& vol_new, GLVolume& vol_old, bool gl_initialized, size_t prealloc_size = VERTEX_BUFFER_RESERVE_SIZE) static void reserve_new_volume_finalize_old_volume(GLVolume& vol_new, GLVolume& vol_old, bool gl_initialized, size_t prealloc_size = VERTEX_BUFFER_RESERVE_SIZE)
{ {
// Assign the large pre-allocated buffers to the new GLVolume. // Assign the large pre-allocated buffers to the new GLVolume.
vol_new.indexed_vertex_array = std::move(vol_old.indexed_vertex_array); vol_new.indexed_vertex_array = std::move(vol_old.indexed_vertex_array);
// Copy the content back to the old GLVolume. // Copy the content back to the old GLVolume.
vol_old.indexed_vertex_array = vol_new.indexed_vertex_array; vol_old.indexed_vertex_array = vol_new.indexed_vertex_array;
@ -2239,10 +2291,15 @@ static void reserve_new_volume_finalize_old_volume(GLVolume& vol_new, GLVolume&
// Finalize the old geometry, possibly move data to the graphics card. // Finalize the old geometry, possibly move data to the graphics card.
vol_old.finalize_geometry(gl_initialized); vol_old.finalize_geometry(gl_initialized);
} }
#endif // !ENABLE_GLINDEXEDVERTEXARRAY_REMOVAL
void GLCanvas3D::load_gcode_preview(const GCodeProcessorResult& gcode_result, const std::vector<std::string>& str_tool_colors) void GLCanvas3D::load_gcode_preview(const GCodeProcessorResult& gcode_result, const std::vector<std::string>& str_tool_colors)
{ {
#if ENABLE_GLINDEXEDVERTEXARRAY_REMOVAL
m_gcode_viewer.load(gcode_result, *this->fff_print());
#else
m_gcode_viewer.load(gcode_result, *this->fff_print(), m_initialized); m_gcode_viewer.load(gcode_result, *this->fff_print(), m_initialized);
#endif // ENABLE_GLINDEXEDVERTEXARRAY_REMOVAL
if (wxGetApp().is_editor()) { if (wxGetApp().is_editor()) {
m_gcode_viewer.update_shells_color_by_extruder(m_config); m_gcode_viewer.update_shells_color_by_extruder(m_config);
@ -4356,7 +4413,11 @@ void GLCanvas3D::_render_thumbnail_internal(ThumbnailData& thumbnail_data, const
shader->set_uniform("emission_factor", 0.0f); shader->set_uniform("emission_factor", 0.0f);
for (GLVolume* vol : visible_volumes) { for (GLVolume* vol : visible_volumes) {
#if ENABLE_GLINDEXEDVERTEXARRAY_REMOVAL
vol->model.set_color((vol->printable && !vol->is_outside) ? (current_printer_technology() == ptSLA ? vol->color : ColorRGBA::ORANGE()) : ColorRGBA::GRAY());
#else
shader->set_uniform("uniform_color", (vol->printable && !vol->is_outside) ? (current_printer_technology() == ptSLA ? vol->color : ColorRGBA::ORANGE()) : ColorRGBA::GRAY()); shader->set_uniform("uniform_color", (vol->printable && !vol->is_outside) ? (current_printer_technology() == ptSLA ? vol->color : ColorRGBA::ORANGE()) : ColorRGBA::GRAY());
#endif // ENABLE_GLINDEXEDVERTEXARRAY_REMOVAL
// the volume may have been deactivated by an active gizmo // the volume may have been deactivated by an active gizmo
bool is_active = vol->is_active; bool is_active = vol->is_active;
vol->is_active = true; vol->is_active = true;
@ -5562,6 +5623,12 @@ void GLCanvas3D::_render_overlays()
void GLCanvas3D::_render_volumes_for_picking() const void GLCanvas3D::_render_volumes_for_picking() const
{ {
#if ENABLE_GLINDEXEDVERTEXARRAY_REMOVAL
GLShaderProgram* shader = wxGetApp().get_shader("flat");
if (shader == nullptr)
return;
#endif // ENABLE_GLINDEXEDVERTEXARRAY_REMOVAL
// do not cull backfaces to show broken geometry, if any // do not cull backfaces to show broken geometry, if any
glsafe(::glDisable(GL_CULL_FACE)); glsafe(::glDisable(GL_CULL_FACE));
@ -5577,9 +5644,17 @@ void GLCanvas3D::_render_volumes_for_picking() const
// we reserve color = (0,0,0) for occluders (as the printbed) // we reserve color = (0,0,0) for occluders (as the printbed)
// so we shift volumes' id by 1 to get the proper color // so we shift volumes' id by 1 to get the proper color
const unsigned int id = 1 + volume.second.first; const unsigned int id = 1 + volume.second.first;
#if ENABLE_GLINDEXEDVERTEXARRAY_REMOVAL
volume.first->model.set_color(picking_decode(id));
shader->start_using();
#else
glsafe(::glColor4fv(picking_decode(id).data())); glsafe(::glColor4fv(picking_decode(id).data()));
#endif // ENABLE_GLINDEXEDVERTEXARRAY_REMOVAL
volume.first->render(); volume.first->render();
} #if ENABLE_GLINDEXEDVERTEXARRAY_REMOVAL
shader->stop_using();
#endif // ENABLE_GLINDEXEDVERTEXARRAY_REMOVAL
}
} }
glsafe(::glDisableClientState(GL_NORMAL_ARRAY)); glsafe(::glDisableClientState(GL_NORMAL_ARRAY));
@ -6165,23 +6240,48 @@ void GLCanvas3D::_load_print_toolpaths(const BuildVolume &build_volume)
skirt_height = std::min(skirt_height, print_zs.size()); skirt_height = std::min(skirt_height, print_zs.size());
print_zs.erase(print_zs.begin() + skirt_height, print_zs.end()); print_zs.erase(print_zs.begin() + skirt_height, print_zs.end());
#if ENABLE_GLINDEXEDVERTEXARRAY_REMOVAL
GLVolume* volume = m_volumes.new_toolpath_volume(color);
GLModel::Geometry init_data;
init_data.format = { GLModel::Geometry::EPrimitiveType::Triangles, GLModel::Geometry::EVertexLayout::P3N3, GLModel::Geometry::EIndexType::UINT };
#else
GLVolume *volume = m_volumes.new_toolpath_volume(color, VERTEX_BUFFER_RESERVE_SIZE); GLVolume *volume = m_volumes.new_toolpath_volume(color, VERTEX_BUFFER_RESERVE_SIZE);
#endif // ENABLE_GLINDEXEDVERTEXARRAY_REMOVAL
for (size_t i = 0; i < skirt_height; ++ i) { for (size_t i = 0; i < skirt_height; ++ i) {
volume->print_zs.emplace_back(print_zs[i]); volume->print_zs.emplace_back(print_zs[i]);
#if ENABLE_GLINDEXEDVERTEXARRAY_REMOVAL
volume->offsets.emplace_back(init_data.indices_count());
if (i == 0)
_3DScene::extrusionentity_to_verts(print->brim(), print_zs[i], Point(0, 0), init_data);
_3DScene::extrusionentity_to_verts(print->skirt(), print_zs[i], Point(0, 0), init_data);
#else
volume->offsets.emplace_back(volume->indexed_vertex_array.quad_indices.size()); volume->offsets.emplace_back(volume->indexed_vertex_array.quad_indices.size());
volume->offsets.emplace_back(volume->indexed_vertex_array.triangle_indices.size()); volume->offsets.emplace_back(volume->indexed_vertex_array.triangle_indices.size());
if (i == 0) if (i == 0)
_3DScene::extrusionentity_to_verts(print->brim(), print_zs[i], Point(0, 0), *volume); _3DScene::extrusionentity_to_verts(print->brim(), print_zs[i], Point(0, 0), *volume);
_3DScene::extrusionentity_to_verts(print->skirt(), print_zs[i], Point(0, 0), *volume); _3DScene::extrusionentity_to_verts(print->skirt(), print_zs[i], Point(0, 0), *volume);
#endif // ENABLE_GLINDEXEDVERTEXARRAY_REMOVAL
// Ensure that no volume grows over the limits. If the volume is too large, allocate a new one. // Ensure that no volume grows over the limits. If the volume is too large, allocate a new one.
#if ENABLE_GLINDEXEDVERTEXARRAY_REMOVAL
if (init_data.vertices_size_bytes() > MAX_VERTEX_BUFFER_SIZE) {
volume->model.init_from(std::move(init_data));
#else
if (volume->indexed_vertex_array.vertices_and_normals_interleaved.size() > MAX_VERTEX_BUFFER_SIZE) { if (volume->indexed_vertex_array.vertices_and_normals_interleaved.size() > MAX_VERTEX_BUFFER_SIZE) {
GLVolume &vol = *volume; #endif // ENABLE_GLINDEXEDVERTEXARRAY_REMOVAL
GLVolume &vol = *volume;
volume = m_volumes.new_toolpath_volume(vol.color); volume = m_volumes.new_toolpath_volume(vol.color);
#if !ENABLE_GLINDEXEDVERTEXARRAY_REMOVAL
reserve_new_volume_finalize_old_volume(*volume, vol, m_initialized); reserve_new_volume_finalize_old_volume(*volume, vol, m_initialized);
#endif // !ENABLE_GLINDEXEDVERTEXARRAY_REMOVAL
} }
} }
#if ENABLE_GLINDEXEDVERTEXARRAY_REMOVAL
volume->model.init_from(std::move(init_data));
volume->is_outside = !contains(build_volume, volume->model);
#else
volume->is_outside = ! build_volume.all_paths_inside_vertices_and_normals_interleaved(volume->indexed_vertex_array.vertices_and_normals_interleaved, volume->indexed_vertex_array.bounding_box()); volume->is_outside = ! build_volume.all_paths_inside_vertices_and_normals_interleaved(volume->indexed_vertex_array.vertices_and_normals_interleaved, volume->indexed_vertex_array.bounding_box());
volume->indexed_vertex_array.finalize_geometry(m_initialized); volume->indexed_vertex_array.finalize_geometry(m_initialized);
#endif // ENABLE_GLINDEXEDVERTEXARRAY_REMOVAL
} }
void GLCanvas3D::_load_print_object_toolpaths(const PrintObject& print_object, const BuildVolume& build_volume, const std::vector<std::string>& str_tool_colors, const std::vector<CustomGCode::Item>& color_print_values) void GLCanvas3D::_load_print_object_toolpaths(const PrintObject& print_object, const BuildVolume& build_volume, const std::vector<std::string>& str_tool_colors, const std::vector<CustomGCode::Item>& color_print_values)
@ -6353,7 +6453,12 @@ void GLCanvas3D::_load_print_object_toolpaths(const PrintObject& print_object, c
// Allocate the volume before locking. // Allocate the volume before locking.
GLVolume *volume = new GLVolume(color); GLVolume *volume = new GLVolume(color);
volume->is_extrusion_path = true; volume->is_extrusion_path = true;
tbb::spin_mutex::scoped_lock lock; #if ENABLE_GLINDEXEDVERTEXARRAY_REMOVAL
// to prevent sending data to gpu (in the main thread) while
// editing the model geometry
volume->model.disable_render();
#endif // ENABLE_GLINDEXEDVERTEXARRAY_REMOVAL
tbb::spin_mutex::scoped_lock lock;
// Lock by ROII, so if the emplace_back() fails, the lock will be released. // Lock by ROII, so if the emplace_back() fails, the lock will be released.
lock.acquire(new_volume_mutex); lock.acquire(new_volume_mutex);
m_volumes.volumes.emplace_back(volume); m_volumes.volumes.emplace_back(volume);
@ -6365,31 +6470,57 @@ void GLCanvas3D::_load_print_object_toolpaths(const PrintObject& print_object, c
tbb::blocked_range<size_t>(0, ctxt.layers.size(), grain_size), tbb::blocked_range<size_t>(0, ctxt.layers.size(), grain_size),
[&ctxt, &new_volume, is_selected_separate_extruder, this](const tbb::blocked_range<size_t>& range) { [&ctxt, &new_volume, is_selected_separate_extruder, this](const tbb::blocked_range<size_t>& range) {
GLVolumePtrs vols; GLVolumePtrs vols;
auto volume = [&ctxt, &vols](size_t layer_idx, int extruder, int feature) -> GLVolume& { #if ENABLE_GLINDEXEDVERTEXARRAY_REMOVAL
return *vols[ctxt.color_by_color_print()? std::vector<GLModel::Geometry> geometries;
auto select_geometry = [&ctxt, &geometries](size_t layer_idx, int extruder, int feature) -> GLModel::Geometry& {
return geometries[ctxt.color_by_color_print() ?
ctxt.color_print_color_idx_by_layer_idx_and_extruder(layer_idx, extruder) : ctxt.color_print_color_idx_by_layer_idx_and_extruder(layer_idx, extruder) :
ctxt.color_by_tool() ? ctxt.color_by_tool() ?
std::min<int>(ctxt.number_tools() - 1, std::max<int>(extruder - 1, 0)) : std::min<int>(ctxt.number_tools() - 1, std::max<int>(extruder - 1, 0)) :
feature feature
]; ];
}; };
#else
auto volume = [&ctxt, &vols](size_t layer_idx, int extruder, int feature) -> GLVolume& {
return *vols[ctxt.color_by_color_print() ?
ctxt.color_print_color_idx_by_layer_idx_and_extruder(layer_idx, extruder) :
ctxt.color_by_tool() ?
std::min<int>(ctxt.number_tools() - 1, std::max<int>(extruder - 1, 0)) :
feature
];
};
#endif // ENABLE_GLINDEXEDVERTEXARRAY_REMOVAL
if (ctxt.color_by_color_print() || ctxt.color_by_tool()) { if (ctxt.color_by_color_print() || ctxt.color_by_tool()) {
for (size_t i = 0; i < ctxt.number_tools(); ++i) for (size_t i = 0; i < ctxt.number_tools(); ++i) {
vols.emplace_back(new_volume(ctxt.color_tool(i))); vols.emplace_back(new_volume(ctxt.color_tool(i)));
#if ENABLE_GLINDEXEDVERTEXARRAY_REMOVAL
geometries.emplace_back(GLModel::Geometry());
#endif // ENABLE_GLINDEXEDVERTEXARRAY_REMOVAL
}
} }
else else {
vols = { new_volume(ctxt.color_perimeters()), new_volume(ctxt.color_infill()), new_volume(ctxt.color_support()) }; vols = { new_volume(ctxt.color_perimeters()), new_volume(ctxt.color_infill()), new_volume(ctxt.color_support()) };
#if ENABLE_GLINDEXEDVERTEXARRAY_REMOVAL
geometries = { GLModel::Geometry(), GLModel::Geometry(), GLModel::Geometry() };
#endif // ENABLE_GLINDEXEDVERTEXARRAY_REMOVAL
}
#if ENABLE_GLINDEXEDVERTEXARRAY_REMOVAL
assert(vols.size() == geometries.size());
for (GLModel::Geometry& g : geometries) {
g.format = { GLModel::Geometry::EPrimitiveType::Triangles, GLModel::Geometry::EVertexLayout::P3N3, GLModel::Geometry::EIndexType::UINT };
}
#else
for (GLVolume *vol : vols) for (GLVolume *vol : vols)
// Reserving number of vertices (3x position + 3x color) // Reserving number of vertices (3x position + 3x color)
vol->indexed_vertex_array.reserve(VERTEX_BUFFER_RESERVE_SIZE / 6); vol->indexed_vertex_array.reserve(VERTEX_BUFFER_RESERVE_SIZE / 6);
#endif // ENABLE_GLINDEXEDVERTEXARRAY_REMOVAL
for (size_t idx_layer = range.begin(); idx_layer < range.end(); ++ idx_layer) { for (size_t idx_layer = range.begin(); idx_layer < range.end(); ++ idx_layer) {
const Layer *layer = ctxt.layers[idx_layer]; const Layer *layer = ctxt.layers[idx_layer];
if (is_selected_separate_extruder) if (is_selected_separate_extruder) {
{
bool at_least_one_has_correct_extruder = false; bool at_least_one_has_correct_extruder = false;
for (const LayerRegion* layerm : layer->regions()) for (const LayerRegion* layerm : layer->regions()) {
{
if (layerm->slices.surfaces.empty()) if (layerm->slices.surfaces.empty())
continue; continue;
const PrintRegionConfig& cfg = layerm->region().config(); const PrintRegionConfig& cfg = layerm->region().config();
@ -6404,17 +6535,27 @@ void GLCanvas3D::_load_print_object_toolpaths(const PrintObject& print_object, c
continue; continue;
} }
for (GLVolume *vol : vols) #if ENABLE_GLINDEXEDVERTEXARRAY_REMOVAL
for (size_t i = 0; i < vols.size(); ++i) {
GLVolume* vol = vols[i];
if (vol->print_zs.empty() || vol->print_zs.back() != layer->print_z) {
vol->print_zs.emplace_back(layer->print_z);
vol->offsets.emplace_back(geometries[i].indices_count());
}
}
#else
for (GLVolume* vol : vols)
if (vol->print_zs.empty() || vol->print_zs.back() != layer->print_z) { if (vol->print_zs.empty() || vol->print_zs.back() != layer->print_z) {
vol->print_zs.emplace_back(layer->print_z); vol->print_zs.emplace_back(layer->print_z);
vol->offsets.emplace_back(vol->indexed_vertex_array.quad_indices.size()); vol->offsets.emplace_back(vol->indexed_vertex_array.quad_indices.size());
vol->offsets.emplace_back(vol->indexed_vertex_array.triangle_indices.size()); vol->offsets.emplace_back(vol->indexed_vertex_array.triangle_indices.size());
} }
#endif // ENABLE_GLINDEXEDVERTEXARRAY_REMOVAL
for (const PrintInstance &instance : *ctxt.shifted_copies) { for (const PrintInstance &instance : *ctxt.shifted_copies) {
const Point &copy = instance.shift; const Point &copy = instance.shift;
for (const LayerRegion *layerm : layer->regions()) { for (const LayerRegion *layerm : layer->regions()) {
if (is_selected_separate_extruder) if (is_selected_separate_extruder) {
{
const PrintRegionConfig& cfg = layerm->region().config(); const PrintRegionConfig& cfg = layerm->region().config();
if (cfg.perimeter_extruder.value != m_selected_extruder || if (cfg.perimeter_extruder.value != m_selected_extruder ||
cfg.infill_extruder.value != m_selected_extruder || cfg.infill_extruder.value != m_selected_extruder ||
@ -6422,19 +6563,31 @@ void GLCanvas3D::_load_print_object_toolpaths(const PrintObject& print_object, c
continue; continue;
} }
if (ctxt.has_perimeters) if (ctxt.has_perimeters)
#if ENABLE_GLINDEXEDVERTEXARRAY_REMOVAL
_3DScene::extrusionentity_to_verts(layerm->perimeters, float(layer->print_z), copy,
select_geometry(idx_layer, layerm->region().config().perimeter_extruder.value, 0));
#else
_3DScene::extrusionentity_to_verts(layerm->perimeters, float(layer->print_z), copy, _3DScene::extrusionentity_to_verts(layerm->perimeters, float(layer->print_z), copy,
volume(idx_layer, layerm->region().config().perimeter_extruder.value, 0)); volume(idx_layer, layerm->region().config().perimeter_extruder.value, 0));
#endif // ENABLE_GLINDEXEDVERTEXARRAY_REMOVAL
if (ctxt.has_infill) { if (ctxt.has_infill) {
for (const ExtrusionEntity *ee : layerm->fills.entities) { for (const ExtrusionEntity *ee : layerm->fills.entities) {
// fill represents infill extrusions of a single island. // fill represents infill extrusions of a single island.
const auto *fill = dynamic_cast<const ExtrusionEntityCollection*>(ee); const auto *fill = dynamic_cast<const ExtrusionEntityCollection*>(ee);
if (! fill->entities.empty()) if (! fill->entities.empty())
#if ENABLE_GLINDEXEDVERTEXARRAY_REMOVAL
_3DScene::extrusionentity_to_verts(*fill, float(layer->print_z), copy,
select_geometry(idx_layer, is_solid_infill(fill->entities.front()->role()) ?
layerm->region().config().solid_infill_extruder :
layerm->region().config().infill_extruder, 1));
#else
_3DScene::extrusionentity_to_verts(*fill, float(layer->print_z), copy, _3DScene::extrusionentity_to_verts(*fill, float(layer->print_z), copy,
volume(idx_layer, volume(idx_layer,
is_solid_infill(fill->entities.front()->role()) ? is_solid_infill(fill->entities.front()->role()) ?
layerm->region().config().solid_infill_extruder : layerm->region().config().solid_infill_extruder :
layerm->region().config().infill_extruder, layerm->region().config().infill_extruder,
1)); 1));
#endif // ENABLE_GLINDEXEDVERTEXARRAY_REMOVAL
} }
} }
} }
@ -6442,28 +6595,50 @@ void GLCanvas3D::_load_print_object_toolpaths(const PrintObject& print_object, c
const SupportLayer *support_layer = dynamic_cast<const SupportLayer*>(layer); const SupportLayer *support_layer = dynamic_cast<const SupportLayer*>(layer);
if (support_layer) { if (support_layer) {
for (const ExtrusionEntity *extrusion_entity : support_layer->support_fills.entities) for (const ExtrusionEntity *extrusion_entity : support_layer->support_fills.entities)
#if ENABLE_GLINDEXEDVERTEXARRAY_REMOVAL
_3DScene::extrusionentity_to_verts(extrusion_entity, float(layer->print_z), copy,
select_geometry(idx_layer, (extrusion_entity->role() == erSupportMaterial) ?
support_layer->object()->config().support_material_extruder :
support_layer->object()->config().support_material_interface_extruder, 2));
#else
_3DScene::extrusionentity_to_verts(extrusion_entity, float(layer->print_z), copy, _3DScene::extrusionentity_to_verts(extrusion_entity, float(layer->print_z), copy,
volume(idx_layer, volume(idx_layer,
(extrusion_entity->role() == erSupportMaterial) ? (extrusion_entity->role() == erSupportMaterial) ?
support_layer->object()->config().support_material_extruder : support_layer->object()->config().support_material_extruder :
support_layer->object()->config().support_material_interface_extruder, support_layer->object()->config().support_material_interface_extruder,
2)); 2));
#endif // ENABLE_GLINDEXEDVERTEXARRAY_REMOVAL
} }
} }
} }
// Ensure that no volume grows over the limits. If the volume is too large, allocate a new one. // Ensure that no volume grows over the limits. If the volume is too large, allocate a new one.
for (size_t i = 0; i < vols.size(); ++i) { for (size_t i = 0; i < vols.size(); ++i) {
GLVolume &vol = *vols[i]; GLVolume &vol = *vols[i];
if (vol.indexed_vertex_array.vertices_and_normals_interleaved.size() > MAX_VERTEX_BUFFER_SIZE) { #if ENABLE_GLINDEXEDVERTEXARRAY_REMOVAL
vols[i] = new_volume(vol.color); if (geometries[i].vertices_size_bytes() > MAX_VERTEX_BUFFER_SIZE) {
reserve_new_volume_finalize_old_volume(*vols[i], vol, false); vol.model.init_from(std::move(geometries[i]));
} #else
if (vol.indexed_vertex_array.vertices_and_normals_interleaved.size() > MAX_VERTEX_BUFFER_SIZE) {
#endif // ENABLE_GLINDEXEDVERTEXARRAY_REMOVAL
vols[i] = new_volume(vol.color);
#if !ENABLE_GLINDEXEDVERTEXARRAY_REMOVAL
reserve_new_volume_finalize_old_volume(*vols[i], vol, false);
#endif // !ENABLE_GLINDEXEDVERTEXARRAY_REMOVAL
}
} }
} }
#if ENABLE_GLINDEXEDVERTEXARRAY_REMOVAL
for (size_t i = 0; i < vols.size(); ++i) {
if (!geometries[i].is_empty())
vols[i]->model.init_from(std::move(geometries[i]));
}
#else
for (GLVolume *vol : vols) for (GLVolume *vol : vols)
// Ideally one would call vol->indexed_vertex_array.finalize() here to move the buffers to the OpenGL driver, // Ideally one would call vol->indexed_vertex_array.finalize() here to move the buffers to the OpenGL driver,
// but this code runs in parallel and the OpenGL driver is not thread safe. // but this code runs in parallel and the OpenGL driver is not thread safe.
vol->indexed_vertex_array.shrink_to_fit(); vol->indexed_vertex_array.shrink_to_fit();
#endif // ENABLE_GLINDEXEDVERTEXARRAY_REMOVAL
}); });
BOOST_LOG_TRIVIAL(debug) << "Loading print object toolpaths in parallel - finalizing results" << m_volumes.log_memory_info() << log_memory_info(); BOOST_LOG_TRIVIAL(debug) << "Loading print object toolpaths in parallel - finalizing results" << m_volumes.log_memory_info() << log_memory_info();
@ -6478,8 +6653,14 @@ void GLCanvas3D::_load_print_object_toolpaths(const PrintObject& print_object, c
} }
for (size_t i = volumes_cnt_initial; i < m_volumes.volumes.size(); ++i) { for (size_t i = volumes_cnt_initial; i < m_volumes.volumes.size(); ++i) {
GLVolume* v = m_volumes.volumes[i]; GLVolume* v = m_volumes.volumes[i];
#if ENABLE_GLINDEXEDVERTEXARRAY_REMOVAL
v->is_outside = !contains(build_volume, v->model);
// We are done editinig the model, now it can be sent to gpu
v->model.enable_render();
#else
v->is_outside = ! build_volume.all_paths_inside_vertices_and_normals_interleaved(v->indexed_vertex_array.vertices_and_normals_interleaved, v->indexed_vertex_array.bounding_box()); v->is_outside = ! build_volume.all_paths_inside_vertices_and_normals_interleaved(v->indexed_vertex_array.vertices_and_normals_interleaved, v->indexed_vertex_array.bounding_box());
v->indexed_vertex_array.finalize_geometry(m_initialized); v->indexed_vertex_array.finalize_geometry(m_initialized);
#endif // ENABLE_GLINDEXEDVERTEXARRAY_REMOVAL
} }
BOOST_LOG_TRIVIAL(debug) << "Loading print object toolpaths in parallel - end" << m_volumes.log_memory_info() << log_memory_info(); BOOST_LOG_TRIVIAL(debug) << "Loading print object toolpaths in parallel - end" << m_volumes.log_memory_info() << log_memory_info();
@ -6499,10 +6680,10 @@ void GLCanvas3D::_load_wipe_tower_toolpaths(const BuildVolume& build_volume, con
struct Ctxt struct Ctxt
{ {
const Print *print; const Print *print;
const std::vector<ColorRGBA>* tool_colors; const std::vector<ColorRGBA> *tool_colors;
Vec2f wipe_tower_pos; Vec2f wipe_tower_pos;
float wipe_tower_angle; float wipe_tower_angle;
static ColorRGBA color_support() { return ColorRGBA::GREENISH(); } static ColorRGBA color_support() { return ColorRGBA::GREENISH(); }
@ -6544,6 +6725,11 @@ void GLCanvas3D::_load_wipe_tower_toolpaths(const BuildVolume& build_volume, con
auto new_volume = [this, &new_volume_mutex](const ColorRGBA& color) { auto new_volume = [this, &new_volume_mutex](const ColorRGBA& color) {
auto *volume = new GLVolume(color); auto *volume = new GLVolume(color);
volume->is_extrusion_path = true; volume->is_extrusion_path = true;
#if ENABLE_GLINDEXEDVERTEXARRAY_REMOVAL
// to prevent sending data to gpu (in the main thread) while
// editing the model geometry
volume->model.disable_render();
#endif // ENABLE_GLINDEXEDVERTEXARRAY_REMOVAL
tbb::spin_mutex::scoped_lock lock; tbb::spin_mutex::scoped_lock lock;
lock.acquire(new_volume_mutex); lock.acquire(new_volume_mutex);
m_volumes.volumes.emplace_back(volume); m_volumes.volumes.emplace_back(volume);
@ -6557,23 +6743,46 @@ void GLCanvas3D::_load_wipe_tower_toolpaths(const BuildVolume& build_volume, con
[&ctxt, &new_volume](const tbb::blocked_range<size_t>& range) { [&ctxt, &new_volume](const tbb::blocked_range<size_t>& range) {
// Bounding box of this slab of a wipe tower. // Bounding box of this slab of a wipe tower.
GLVolumePtrs vols; GLVolumePtrs vols;
#if ENABLE_GLINDEXEDVERTEXARRAY_REMOVAL
std::vector<GLModel::Geometry> geometries;
#endif // ENABLE_GLINDEXEDVERTEXARRAY_REMOVAL
if (ctxt.color_by_tool()) { if (ctxt.color_by_tool()) {
for (size_t i = 0; i < ctxt.number_tools(); ++i) for (size_t i = 0; i < ctxt.number_tools(); ++i) {
vols.emplace_back(new_volume(ctxt.color_tool(i))); vols.emplace_back(new_volume(ctxt.color_tool(i)));
#if ENABLE_GLINDEXEDVERTEXARRAY_REMOVAL
geometries.emplace_back(GLModel::Geometry());
#endif // ENABLE_GLINDEXEDVERTEXARRAY_REMOVAL
}
} }
else else {
vols = { new_volume(ctxt.color_support()) }; vols = { new_volume(ctxt.color_support()) };
#if ENABLE_GLINDEXEDVERTEXARRAY_REMOVAL
geometries = { GLModel::Geometry() };
#endif // ENABLE_GLINDEXEDVERTEXARRAY_REMOVAL
}
#if ENABLE_GLINDEXEDVERTEXARRAY_REMOVAL
assert(vols.size() == geometries.size());
for (GLModel::Geometry& g : geometries) {
g.format = { GLModel::Geometry::EPrimitiveType::Triangles, GLModel::Geometry::EVertexLayout::P3N3, GLModel::Geometry::EIndexType::UINT };
}
#else
for (GLVolume *volume : vols) for (GLVolume *volume : vols)
// Reserving number of vertices (3x position + 3x color) // Reserving number of vertices (3x position + 3x color)
volume->indexed_vertex_array.reserve(VERTEX_BUFFER_RESERVE_SIZE / 6); volume->indexed_vertex_array.reserve(VERTEX_BUFFER_RESERVE_SIZE / 6);
#endif // ENABLE_GLINDEXEDVERTEXARRAY_REMOVAL
for (size_t idx_layer = range.begin(); idx_layer < range.end(); ++idx_layer) { for (size_t idx_layer = range.begin(); idx_layer < range.end(); ++idx_layer) {
const std::vector<WipeTower::ToolChangeResult> &layer = ctxt.tool_change(idx_layer); const std::vector<WipeTower::ToolChangeResult> &layer = ctxt.tool_change(idx_layer);
for (size_t i = 0; i < vols.size(); ++i) { for (size_t i = 0; i < vols.size(); ++i) {
GLVolume &vol = *vols[i]; GLVolume &vol = *vols[i];
if (vol.print_zs.empty() || vol.print_zs.back() != layer.front().print_z) { if (vol.print_zs.empty() || vol.print_zs.back() != layer.front().print_z) {
vol.print_zs.emplace_back(layer.front().print_z); vol.print_zs.emplace_back(layer.front().print_z);
#if ENABLE_GLINDEXEDVERTEXARRAY_REMOVAL
vol.offsets.emplace_back(geometries[i].indices_count());
#else
vol.offsets.emplace_back(vol.indexed_vertex_array.quad_indices.size()); vol.offsets.emplace_back(vol.indexed_vertex_array.quad_indices.size());
vol.offsets.emplace_back(vol.indexed_vertex_array.triangle_indices.size()); vol.offsets.emplace_back(vol.indexed_vertex_array.triangle_indices.size());
#endif // ENABLE_GLINDEXEDVERTEXARRAY_REMOVAL
} }
} }
for (const WipeTower::ToolChangeResult &extrusions : layer) { for (const WipeTower::ToolChangeResult &extrusions : layer) {
@ -6615,21 +6824,42 @@ void GLCanvas3D::_load_wipe_tower_toolpaths(const BuildVolume& build_volume, con
e_prev = e; e_prev = e;
} }
#if ENABLE_GLINDEXEDVERTEXARRAY_REMOVAL
_3DScene::thick_lines_to_verts(lines, widths, heights, lines.front().a == lines.back().b, extrusions.print_z,
geometries[ctxt.volume_idx(e.tool, 0)]);
#else
_3DScene::thick_lines_to_verts(lines, widths, heights, lines.front().a == lines.back().b, extrusions.print_z, _3DScene::thick_lines_to_verts(lines, widths, heights, lines.front().a == lines.back().b, extrusions.print_z,
*vols[ctxt.volume_idx(e.tool, 0)]); *vols[ctxt.volume_idx(e.tool, 0)]);
#endif // ENABLE_GLINDEXEDVERTEXARRAY_REMOVAL
} }
} }
} }
for (size_t i = 0; i < vols.size(); ++i) { for (size_t i = 0; i < vols.size(); ++i) {
GLVolume &vol = *vols[i]; GLVolume &vol = *vols[i];
#if ENABLE_GLINDEXEDVERTEXARRAY_REMOVAL
if (geometries[i].vertices_size_bytes() > MAX_VERTEX_BUFFER_SIZE) {
vol.model.init_from(std::move(geometries[i]));
#else
if (vol.indexed_vertex_array.vertices_and_normals_interleaved.size() > MAX_VERTEX_BUFFER_SIZE) { if (vol.indexed_vertex_array.vertices_and_normals_interleaved.size() > MAX_VERTEX_BUFFER_SIZE) {
#endif // ENABLE_GLINDEXEDVERTEXARRAY_REMOVAL
vols[i] = new_volume(vol.color); vols[i] = new_volume(vol.color);
#if !ENABLE_GLINDEXEDVERTEXARRAY_REMOVAL
reserve_new_volume_finalize_old_volume(*vols[i], vol, false); reserve_new_volume_finalize_old_volume(*vols[i], vol, false);
#endif // !ENABLE_GLINDEXEDVERTEXARRAY_REMOVAL
} }
} }
#if ENABLE_GLINDEXEDVERTEXARRAY_REMOVAL
for (size_t i = 0; i < vols.size(); ++i) {
if (!geometries[i].is_empty())
vols[i]->model.init_from(std::move(geometries[i]));
}
#else
for (GLVolume *vol : vols) for (GLVolume *vol : vols)
vol->indexed_vertex_array.shrink_to_fit(); vol->indexed_vertex_array.shrink_to_fit();
}); #endif // ENABLE_GLINDEXEDVERTEXARRAY_REMOVAL
});
BOOST_LOG_TRIVIAL(debug) << "Loading wipe tower toolpaths in parallel - finalizing results" << m_volumes.log_memory_info() << log_memory_info(); BOOST_LOG_TRIVIAL(debug) << "Loading wipe tower toolpaths in parallel - finalizing results" << m_volumes.log_memory_info() << log_memory_info();
// Remove empty volumes from the newly added volumes. // Remove empty volumes from the newly added volumes.
@ -6643,8 +6873,14 @@ void GLCanvas3D::_load_wipe_tower_toolpaths(const BuildVolume& build_volume, con
} }
for (size_t i = volumes_cnt_initial; i < m_volumes.volumes.size(); ++i) { for (size_t i = volumes_cnt_initial; i < m_volumes.volumes.size(); ++i) {
GLVolume* v = m_volumes.volumes[i]; GLVolume* v = m_volumes.volumes[i];
#if ENABLE_GLINDEXEDVERTEXARRAY_REMOVAL
v->is_outside = !contains(build_volume, v->model);
// We are done editinig the model, now it can be sent to gpu
v->model.enable_render();
#else
v->is_outside = ! build_volume.all_paths_inside_vertices_and_normals_interleaved(v->indexed_vertex_array.vertices_and_normals_interleaved, v->indexed_vertex_array.bounding_box()); v->is_outside = ! build_volume.all_paths_inside_vertices_and_normals_interleaved(v->indexed_vertex_array.vertices_and_normals_interleaved, v->indexed_vertex_array.bounding_box());
v->indexed_vertex_array.finalize_geometry(m_initialized); v->indexed_vertex_array.finalize_geometry(m_initialized);
#endif // ENABLE_GLINDEXEDVERTEXARRAY_REMOVAL
} }
BOOST_LOG_TRIVIAL(debug) << "Loading wipe tower toolpaths in parallel - end" << m_volumes.log_memory_info() << log_memory_info(); BOOST_LOG_TRIVIAL(debug) << "Loading wipe tower toolpaths in parallel - end" << m_volumes.log_memory_info() << log_memory_info();
@ -6668,11 +6904,21 @@ void GLCanvas3D::_load_sla_shells()
m_volumes.volumes.emplace_back(new GLVolume(color)); m_volumes.volumes.emplace_back(new GLVolume(color));
GLVolume& v = *m_volumes.volumes.back(); GLVolume& v = *m_volumes.volumes.back();
#if ENABLE_SMOOTH_NORMALS #if ENABLE_SMOOTH_NORMALS
#if ENABLE_GLINDEXEDVERTEXARRAY_REMOVAL
v.model.init_from(mesh, true);
#else
v.indexed_vertex_array.load_mesh(mesh, true); v.indexed_vertex_array.load_mesh(mesh, true);
#endif // ENABLE_GLINDEXEDVERTEXARRAY_REMOVAL
#else
#if ENABLE_GLINDEXEDVERTEXARRAY_REMOVAL
v.model.init_from(mesh);
#else #else
v.indexed_vertex_array.load_mesh(mesh); v.indexed_vertex_array.load_mesh(mesh);
#endif // ENABLE_GLINDEXEDVERTEXARRAY_REMOVAL
#endif // ENABLE_SMOOTH_NORMALS #endif // ENABLE_SMOOTH_NORMALS
#if !ENABLE_GLINDEXEDVERTEXARRAY_REMOVAL
v.indexed_vertex_array.finalize_geometry(m_initialized); v.indexed_vertex_array.finalize_geometry(m_initialized);
#endif // !ENABLE_GLINDEXEDVERTEXARRAY_REMOVAL
v.shader_outside_printer_detection_enabled = outside_printer_detection_enabled; v.shader_outside_printer_detection_enabled = outside_printer_detection_enabled;
v.composite_id.volume_id = volume_id; v.composite_id.volume_id = volume_id;
v.set_instance_offset(unscale(instance.shift.x(), instance.shift.y(), 0.0)); v.set_instance_offset(unscale(instance.shift.x(), instance.shift.y(), 0.0));

View file

@ -8,15 +8,56 @@
#include "libslic3r/TriangleMesh.hpp" #include "libslic3r/TriangleMesh.hpp"
#include "libslic3r/Model.hpp" #include "libslic3r/Model.hpp"
#include "libslic3r/Polygon.hpp" #include "libslic3r/Polygon.hpp"
#if ENABLE_GLINDEXEDVERTEXARRAY_REMOVAL
#include "libslic3r/BuildVolume.hpp"
#include "libslic3r/Geometry/ConvexHull.hpp"
#endif // ENABLE_GLINDEXEDVERTEXARRAY_REMOVAL
#include <boost/filesystem/operations.hpp> #include <boost/filesystem/operations.hpp>
#include <boost/algorithm/string/predicate.hpp> #include <boost/algorithm/string/predicate.hpp>
#if ENABLE_GLINDEXEDVERTEXARRAY_REMOVAL
#if ENABLE_SMOOTH_NORMALS
#include <igl/per_face_normals.h>
#include <igl/per_corner_normals.h>
#include <igl/per_vertex_normals.h>
#endif // ENABLE_SMOOTH_NORMALS
#endif // ENABLE_GLINDEXEDVERTEXARRAY_REMOVAL
#include <GL/glew.h> #include <GL/glew.h>
namespace Slic3r { namespace Slic3r {
namespace GUI { namespace GUI {
#if ENABLE_GLINDEXEDVERTEXARRAY_REMOVAL
#if ENABLE_SMOOTH_NORMALS
static void smooth_normals_corner(const TriangleMesh& mesh, std::vector<stl_normal>& normals)
{
using MapMatrixXfUnaligned = Eigen::Map<const Eigen::Matrix<float, Eigen::Dynamic, Eigen::Dynamic, Eigen::RowMajor | Eigen::DontAlign>>;
using MapMatrixXiUnaligned = Eigen::Map<const Eigen::Matrix<int, Eigen::Dynamic, Eigen::Dynamic, Eigen::RowMajor | Eigen::DontAlign>>;
std::vector<Vec3f> face_normals = its_face_normals(mesh.its);
Eigen::MatrixXd vertices = MapMatrixXfUnaligned(mesh.its.vertices.front().data(),
Eigen::Index(mesh.its.vertices.size()), 3).cast<double>();
Eigen::MatrixXi indices = MapMatrixXiUnaligned(mesh.its.indices.front().data(),
Eigen::Index(mesh.its.indices.size()), 3);
Eigen::MatrixXd in_normals = MapMatrixXfUnaligned(face_normals.front().data(),
Eigen::Index(face_normals.size()), 3).cast<double>();
Eigen::MatrixXd out_normals;
igl::per_corner_normals(vertices, indices, in_normals, 1.0, out_normals);
normals = std::vector<stl_normal>(mesh.its.vertices.size());
for (size_t i = 0; i < mesh.its.indices.size(); ++i) {
for (size_t j = 0; j < 3; ++j) {
normals[mesh.its.indices[i][j]] = out_normals.row(i * 3 + j).cast<float>();
}
}
}
#endif // ENABLE_SMOOTH_NORMALS
#endif // ENABLE_GLINDEXEDVERTEXARRAY_REMOVAL
#if ENABLE_GLBEGIN_GLEND_REMOVAL #if ENABLE_GLBEGIN_GLEND_REMOVAL
void GLModel::Geometry::reserve_vertices(size_t vertices_count) void GLModel::Geometry::reserve_vertices(size_t vertices_count)
{ {
@ -207,6 +248,37 @@ Vec2f GLModel::Geometry::extract_tex_coord_2(size_t id) const
return { *(start + 0), *(start + 1) }; return { *(start + 0), *(start + 1) };
} }
#if ENABLE_GLINDEXEDVERTEXARRAY_REMOVAL
void GLModel::Geometry::set_vertex(size_t id, const Vec3f& position, const Vec3f& normal)
{
assert(format.vertex_layout == EVertexLayout::P3N3);
assert(id < vertices_count());
if (id < vertices_count()) {
float* start = &vertices[id * vertex_stride_floats(format)];
*(start + 0) = position.x();
*(start + 1) = position.y();
*(start + 2) = position.z();
*(start + 3) = normal.x();
*(start + 4) = normal.y();
*(start + 5) = normal.z();
}
}
void GLModel::Geometry::set_ushort_index(size_t id, unsigned short index)
{
assert(id < indices_count());
if (id < indices_count())
::memcpy(indices.data() + id * sizeof(unsigned short), &index, sizeof(unsigned short));
}
void GLModel::Geometry::set_uint_index(size_t id, unsigned int index)
{
assert(id < indices_count());
if (id < indices_count())
::memcpy(indices.data() + id * sizeof(unsigned int), &index, sizeof(unsigned int));
}
#endif // ENABLE_GLINDEXEDVERTEXARRAY_REMOVAL
unsigned int GLModel::Geometry::extract_uint_index(size_t id) const unsigned int GLModel::Geometry::extract_uint_index(size_t id) const
{ {
if (format.index_type != EIndexType::UINT) { if (format.index_type != EIndexType::UINT) {
@ -219,7 +291,7 @@ unsigned int GLModel::Geometry::extract_uint_index(size_t id) const
return -1; return -1;
} }
unsigned int ret = -1; unsigned int ret = (unsigned int)-1;
::memcpy(&ret, indices.data() + id * index_stride_bytes(format), sizeof(unsigned int)); ::memcpy(&ret, indices.data() + id * index_stride_bytes(format), sizeof(unsigned int));
return ret; return ret;
} }
@ -236,11 +308,23 @@ unsigned short GLModel::Geometry::extract_ushort_index(size_t id) const
return -1; return -1;
} }
unsigned short ret = -1; unsigned short ret = (unsigned short)-1;
::memcpy(&ret, indices.data() + id * index_stride_bytes(format), sizeof(unsigned short)); ::memcpy(&ret, indices.data() + id * index_stride_bytes(format), sizeof(unsigned short));
return ret; return ret;
} }
#if ENABLE_GLINDEXEDVERTEXARRAY_REMOVAL
void GLModel::Geometry::remove_vertex(size_t id)
{
assert(id < vertices_count());
if (id < vertices_count()) {
size_t stride = vertex_stride_floats(format);
std::vector<float>::iterator it = vertices.begin() + id * stride;
vertices.erase(it, it + stride);
}
}
#endif // ENABLE_GLINDEXEDVERTEXARRAY_REMOVAL
size_t GLModel::Geometry::vertex_stride_floats(const Format& format) size_t GLModel::Geometry::vertex_stride_floats(const Format& format)
{ {
switch (format.vertex_layout) switch (format.vertex_layout)
@ -461,10 +545,58 @@ void GLModel::init_from(const Geometry& data)
} }
#if ENABLE_GLBEGIN_GLEND_REMOVAL #if ENABLE_GLBEGIN_GLEND_REMOVAL
#if ENABLE_SMOOTH_NORMALS
void GLModel::init_from(const TriangleMesh& mesh, bool smooth_normals)
{
if (smooth_normals) {
if (is_initialized()) {
// call reset() if you want to reuse this model
assert(false);
return;
}
if (mesh.its.vertices.empty() || mesh.its.indices.empty()) {
assert(false);
return;
}
std::vector<stl_normal> normals;
smooth_normals_corner(mesh, normals);
const indexed_triangle_set& its = mesh.its;
Geometry& data = m_render_data.geometry;
data.format = { Geometry::EPrimitiveType::Triangles, Geometry::EVertexLayout::P3N3, GLModel::Geometry::index_type(3 * its.indices.size()) };
data.reserve_vertices(3 * its.indices.size());
data.reserve_indices(3 * its.indices.size());
// vertices
for (size_t i = 0; i < its.vertices.size(); ++i) {
data.add_vertex(its.vertices[i], normals[i]);
}
// indices
for (size_t i = 0; i < its.indices.size(); ++i) {
const stl_triangle_vertex_indices& idx = its.indices[i];
if (data.format.index_type == GLModel::Geometry::EIndexType::USHORT)
data.add_ushort_triangle((unsigned short)idx(0), (unsigned short)idx(1), (unsigned short)idx(2));
else
data.add_uint_triangle((unsigned int)idx(0), (unsigned int)idx(1), (unsigned int)idx(2));
}
// update bounding box
for (size_t i = 0; i < vertices_count(); ++i) {
m_bounding_box.merge(m_render_data.geometry.extract_position_3(i).cast<double>());
}
}
else
init_from(mesh.its);
}
#else
void GLModel::init_from(const TriangleMesh& mesh) void GLModel::init_from(const TriangleMesh& mesh)
{ {
init_from(mesh.its); init_from(mesh.its);
} }
#endif // ENABLE_SMOOTH_NORMALS
void GLModel::init_from(const indexed_triangle_set& its) void GLModel::init_from(const indexed_triangle_set& its)
#else #else
@ -484,21 +616,24 @@ void GLModel::init_from(const indexed_triangle_set& its, const BoundingBoxf3 &bb
} }
Geometry& data = m_render_data.geometry; Geometry& data = m_render_data.geometry;
data.format = { Geometry::EPrimitiveType::Triangles, Geometry::EVertexLayout::P3N3, Geometry::EIndexType::UINT }; data.format = { Geometry::EPrimitiveType::Triangles, Geometry::EVertexLayout::P3N3, GLModel::Geometry::index_type(3 * its.indices.size()) };
data.reserve_vertices(3 * its.indices.size()); data.reserve_vertices(3 * its.indices.size());
data.reserve_indices(3 * its.indices.size()); data.reserve_indices(3 * its.indices.size());
// vertices + indices // vertices + indices
unsigned int vertices_counter = 0; unsigned int vertices_counter = 0;
for (uint32_t i = 0; i < its.indices.size(); ++i) { for (uint32_t i = 0; i < its.indices.size(); ++i) {
stl_triangle_vertex_indices face = its.indices[i]; const stl_triangle_vertex_indices face = its.indices[i];
stl_vertex vertex[3] = { its.vertices[face[0]], its.vertices[face[1]], its.vertices[face[2]] }; const stl_vertex vertex[3] = { its.vertices[face[0]], its.vertices[face[1]], its.vertices[face[2]] };
stl_vertex n = face_normal_normalized(vertex); const stl_vertex n = face_normal_normalized(vertex);
for (size_t j = 0; j < 3; ++j) { for (size_t j = 0; j < 3; ++j) {
data.add_vertex(vertex[j], n); data.add_vertex(vertex[j], n);
} }
vertices_counter += 3; vertices_counter += 3;
data.add_uint_triangle(vertices_counter - 3, vertices_counter - 2, vertices_counter - 1); if (data.format.index_type == GLModel::Geometry::EIndexType::USHORT)
data.add_ushort_triangle((unsigned short)vertices_counter - 3, (unsigned short)vertices_counter - 2, (unsigned short)vertices_counter - 1);
else
data.add_uint_triangle(vertices_counter - 3, vertices_counter - 2, vertices_counter - 1);
} }
// update bounding box // update bounding box
@ -721,6 +856,9 @@ void GLModel::render()
void GLModel::render() const void GLModel::render() const
#endif // ENABLE_GLBEGIN_GLEND_REMOVAL #endif // ENABLE_GLBEGIN_GLEND_REMOVAL
{ {
#if ENABLE_GLINDEXEDVERTEXARRAY_REMOVAL
render(std::make_pair<size_t, size_t>(0, indices_count()));
#else
GLShaderProgram* shader = wxGetApp().get_current_shader(); GLShaderProgram* shader = wxGetApp().get_current_shader();
#if ENABLE_GLBEGIN_GLEND_REMOVAL #if ENABLE_GLBEGIN_GLEND_REMOVAL
@ -809,8 +947,71 @@ void GLModel::render() const
glsafe(::glBindBuffer(GL_ARRAY_BUFFER, 0)); glsafe(::glBindBuffer(GL_ARRAY_BUFFER, 0));
} }
#endif // ENABLE_GLBEGIN_GLEND_REMOVAL #endif // ENABLE_GLBEGIN_GLEND_REMOVAL
#endif // ENABLE_GLINDEXEDVERTEXARRAY_REMOVAL
} }
#if ENABLE_GLINDEXEDVERTEXARRAY_REMOVAL
void GLModel::render(const std::pair<size_t, size_t>& range)
{
if (m_render_disabled)
return;
if (range.second == range.first)
return;
GLShaderProgram* shader = wxGetApp().get_current_shader();
if (shader == nullptr)
return;
// sends data to gpu if not done yet
if (m_render_data.vbo_id == 0 || m_render_data.ibo_id == 0) {
if (m_render_data.geometry.vertices_count() > 0 && m_render_data.geometry.indices_count() > 0 && !send_to_gpu())
return;
}
const Geometry& data = m_render_data.geometry;
const GLenum mode = get_primitive_mode(data.format);
const GLenum index_type = get_index_type(data.format);
const size_t vertex_stride_bytes = Geometry::vertex_stride_bytes(data.format);
const bool position = Geometry::has_position(data.format);
const bool normal = Geometry::has_normal(data.format);
const bool tex_coord = Geometry::has_tex_coord(data.format);
glsafe(::glBindBuffer(GL_ARRAY_BUFFER, m_render_data.vbo_id));
if (position) {
glsafe(::glVertexPointer(Geometry::position_stride_floats(data.format), GL_FLOAT, vertex_stride_bytes, (const void*)Geometry::position_offset_bytes(data.format)));
glsafe(::glEnableClientState(GL_VERTEX_ARRAY));
}
if (normal) {
glsafe(::glNormalPointer(GL_FLOAT, vertex_stride_bytes, (const void*)Geometry::normal_offset_bytes(data.format)));
glsafe(::glEnableClientState(GL_NORMAL_ARRAY));
}
if (tex_coord) {
glsafe(::glTexCoordPointer(Geometry::tex_coord_stride_floats(data.format), GL_FLOAT, vertex_stride_bytes, (const void*)Geometry::tex_coord_offset_bytes(data.format)));
glsafe(::glEnableClientState(GL_TEXTURE_COORD_ARRAY));
}
shader->set_uniform("uniform_color", data.color);
glsafe(::glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, m_render_data.ibo_id));
glsafe(::glDrawElements(mode, range.second - range.first + 1, index_type, (const void*)(range.first * Geometry::index_stride_bytes(data.format))));
glsafe(::glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0));
if (tex_coord)
glsafe(::glDisableClientState(GL_TEXTURE_COORD_ARRAY));
if (normal)
glsafe(::glDisableClientState(GL_NORMAL_ARRAY));
if (position)
glsafe(::glDisableClientState(GL_VERTEX_ARRAY));
glsafe(::glBindBuffer(GL_ARRAY_BUFFER, 0));
}
#endif // ENABLE_GLINDEXEDVERTEXARRAY_REMOVAL
#if ENABLE_GLBEGIN_GLEND_REMOVAL #if ENABLE_GLBEGIN_GLEND_REMOVAL
void GLModel::render_instanced(unsigned int instances_vbo, unsigned int instances_count) void GLModel::render_instanced(unsigned int instances_vbo, unsigned int instances_count)
#else #else
@ -1027,6 +1228,62 @@ static void append_triangle(GLModel::Geometry& data, unsigned short v1, unsigned
} }
#endif // ENABLE_GLBEGIN_GLEND_REMOVAL #endif // ENABLE_GLBEGIN_GLEND_REMOVAL
#if ENABLE_GLINDEXEDVERTEXARRAY_REMOVAL
template<typename Fn>
inline bool all_vertices_inside(const GLModel::Geometry& geometry, Fn fn)
{
const size_t position_stride_floats = geometry.position_stride_floats(geometry.format);
const size_t position_offset_floats = geometry.position_offset_floats(geometry.format);
assert(position_stride_floats == 3);
if (geometry.vertices.empty() || position_stride_floats != 3)
return false;
for (auto it = geometry.vertices.begin(); it != geometry.vertices.end(); ) {
it += position_offset_floats;
if (!fn({ *it, *(it + 1), *(it + 2) }))
return false;
it += (geometry.vertex_stride_floats(geometry.format) - position_offset_floats - position_stride_floats);
}
return true;
}
bool contains(const BuildVolume& volume, const GLModel& model, bool ignore_bottom)
{
static constexpr const double epsilon = BuildVolume::BedEpsilon;
switch (volume.type()) {
case BuildVolume::Type::Rectangle:
{
BoundingBox3Base<Vec3d> build_volume = volume.bounding_volume().inflated(epsilon);
if (volume.max_print_height() == 0.0)
build_volume.max.z() = std::numeric_limits<double>::max();
if (ignore_bottom)
build_volume.min.z() = -std::numeric_limits<double>::max();
const BoundingBoxf3& model_box = model.get_bounding_box();
return build_volume.contains(model_box.min) && build_volume.contains(model_box.max);
}
case BuildVolume::Type::Circle:
{
const Geometry::Circled& circle = volume.circle();
const Vec2f c = unscaled<float>(circle.center);
const float r = unscaled<double>(circle.radius) + float(epsilon);
const float r2 = sqr(r);
return volume.max_print_height() == 0.0 ?
all_vertices_inside(model.get_geometry(), [c, r2](const Vec3f& p) { return (to_2d(p) - c).squaredNorm() <= r2; }) :
all_vertices_inside(model.get_geometry(), [c, r2, z = volume.max_print_height() + epsilon](const Vec3f& p) { return (to_2d(p) - c).squaredNorm() <= r2 && p.z() <= z; });
}
case BuildVolume::Type::Convex:
//FIXME doing test on convex hull until we learn to do test on non-convex polygons efficiently.
case BuildVolume::Type::Custom:
return volume.max_print_height() == 0.0 ?
all_vertices_inside(model.get_geometry(), [&volume](const Vec3f& p) { return Geometry::inside_convex_polygon(volume.top_bottom_convex_hull_decomposition_bed(), to_2d(p).cast<double>()); }) :
all_vertices_inside(model.get_geometry(), [&volume, z = volume.max_print_height() + epsilon](const Vec3f& p) { return Geometry::inside_convex_polygon(volume.top_bottom_convex_hull_decomposition_bed(), to_2d(p).cast<double>()) && p.z() <= z; });
default:
return true;
}
}
#endif // ENABLE_GLINDEXEDVERTEXARRAY_REMOVAL
GLModel::Geometry stilized_arrow(unsigned short resolution, float tip_radius, float tip_height, float stem_radius, float stem_height) GLModel::Geometry stilized_arrow(unsigned short resolution, float tip_radius, float tip_height, float stem_radius, float stem_height)
{ {
#if !ENABLE_GLBEGIN_GLEND_REMOVAL #if !ENABLE_GLBEGIN_GLEND_REMOVAL

View file

@ -14,6 +14,9 @@ namespace Slic3r {
class TriangleMesh; class TriangleMesh;
class Polygon; class Polygon;
using Polygons = std::vector<Polygon>; using Polygons = std::vector<Polygon>;
#if ENABLE_GLINDEXEDVERTEXARRAY_REMOVAL
class BuildVolume;
#endif // ENABLE_GLINDEXEDVERTEXARRAY_REMOVAL
namespace GUI { namespace GUI {
@ -89,6 +92,13 @@ namespace GUI {
void add_vertex(const Vec3f& position, const Vec2f& tex_coord); // EVertexLayout::P3T2 void add_vertex(const Vec3f& position, const Vec2f& tex_coord); // EVertexLayout::P3T2
void add_vertex(const Vec3f& position, const Vec3f& normal); // EVertexLayout::P3N3 void add_vertex(const Vec3f& position, const Vec3f& normal); // EVertexLayout::P3N3
#if ENABLE_GLINDEXEDVERTEXARRAY_REMOVAL
void set_vertex(size_t id, const Vec3f& position, const Vec3f& normal); // EVertexLayout::P3N3
void set_ushort_index(size_t id, unsigned short index);
void set_uint_index(size_t id, unsigned int index);
#endif // ENABLE_GLINDEXEDVERTEXARRAY_REMOVAL
void add_ushort_index(unsigned short id); void add_ushort_index(unsigned short id);
void add_uint_index(unsigned int id); void add_uint_index(unsigned int id);
@ -106,7 +116,11 @@ namespace GUI {
unsigned int extract_uint_index(size_t id) const; unsigned int extract_uint_index(size_t id) const;
unsigned short extract_ushort_index(size_t id) const; unsigned short extract_ushort_index(size_t id) const;
bool is_empty() const { return vertices.empty() || indices.empty(); } #if ENABLE_GLINDEXEDVERTEXARRAY_REMOVAL
void remove_vertex(size_t id);
#endif // ENABLE_GLINDEXEDVERTEXARRAY_REMOVAL
bool is_empty() const { return vertices_count() == 0 || indices_count() == 0; }
size_t vertices_count() const { return vertices.size() / vertex_stride_floats(format); } size_t vertices_count() const { return vertices.size() / vertex_stride_floats(format); }
size_t indices_count() const { return indices.size() / index_stride_bytes(format); } size_t indices_count() const { return indices.size() / index_stride_bytes(format); }
@ -179,6 +193,16 @@ namespace GUI {
std::vector<RenderData> m_render_data; std::vector<RenderData> m_render_data;
#endif // ENABLE_GLBEGIN_GLEND_REMOVAL #endif // ENABLE_GLBEGIN_GLEND_REMOVAL
#if ENABLE_GLINDEXEDVERTEXARRAY_REMOVAL
// By default the vertex and index buffers data are sent to gpu at the first call to render() method.
// If you need to initialize a model from outside the main thread, so that a call to render() may happen
// before the initialization is complete, use the methods:
// disable_render()
// ... do your initialization ...
// enable_render()
// to keep the data on cpu side until needed.
bool m_render_disabled{ false };
#endif // ENABLE_GLINDEXEDVERTEXARRAY_REMOVAL
BoundingBoxf3 m_bounding_box; BoundingBoxf3 m_bounding_box;
std::string m_filename; std::string m_filename;
@ -197,8 +221,16 @@ namespace GUI {
size_t indices_size_bytes() const { return indices_count() * Geometry::index_stride_bytes(m_render_data.geometry.format); } size_t indices_size_bytes() const { return indices_count() * Geometry::index_stride_bytes(m_render_data.geometry.format); }
#if ENABLE_GLINDEXEDVERTEXARRAY_REMOVAL
const Geometry& get_geometry() const { return m_render_data.geometry; }
#endif // ENABLE_GLINDEXEDVERTEXARRAY_REMOVAL
void init_from(Geometry&& data); void init_from(Geometry&& data);
#if ENABLE_SMOOTH_NORMALS
void init_from(const TriangleMesh& mesh, bool smooth_normals = false);
#else
void init_from(const TriangleMesh& mesh); void init_from(const TriangleMesh& mesh);
#endif // ENABLE_SMOOTH_NORMALS
#else #else
void init_from(const Geometry& data); void init_from(const Geometry& data);
void init_from(const indexed_triangle_set& its, const BoundingBoxf3& bbox); void init_from(const indexed_triangle_set& its, const BoundingBoxf3& bbox);
@ -219,9 +251,15 @@ namespace GUI {
void reset(); void reset();
#if ENABLE_GLBEGIN_GLEND_REMOVAL #if ENABLE_GLBEGIN_GLEND_REMOVAL
void render(); void render();
#if ENABLE_GLINDEXEDVERTEXARRAY_REMOVAL
void render(const std::pair<size_t, size_t>& range);
#endif // ENABLE_GLINDEXEDVERTEXARRAY_REMOVAL
void render_instanced(unsigned int instances_vbo, unsigned int instances_count); void render_instanced(unsigned int instances_vbo, unsigned int instances_count);
bool is_initialized() const { return vertices_count() > 0 && indices_count() > 0; } bool is_initialized() const { return vertices_count() > 0 && indices_count() > 0; }
#if ENABLE_GLINDEXEDVERTEXARRAY_REMOVAL
bool is_empty() const { return m_render_data.geometry.is_empty(); }
#endif // ENABLE_GLINDEXEDVERTEXARRAY_REMOVAL
#else #else
void render() const; void render() const;
void render_instanced(unsigned int instances_vbo, unsigned int instances_count) const; void render_instanced(unsigned int instances_vbo, unsigned int instances_count) const;
@ -232,6 +270,29 @@ namespace GUI {
const BoundingBoxf3& get_bounding_box() const { return m_bounding_box; } const BoundingBoxf3& get_bounding_box() const { return m_bounding_box; }
const std::string& get_filename() const { return m_filename; } const std::string& get_filename() const { return m_filename; }
#if ENABLE_GLINDEXEDVERTEXARRAY_REMOVAL
bool is_render_disabled() const { return m_render_disabled; }
void enable_render() { m_render_disabled = false; }
void disable_render() { m_render_disabled = true; }
size_t cpu_memory_used() const {
size_t ret = 0;
if (!m_render_data.geometry.vertices.empty())
ret += vertices_size_bytes();
if (!m_render_data.geometry.indices.empty())
ret += indices_size_bytes();
return ret;
}
size_t gpu_memory_used() const {
size_t ret = 0;
if (m_render_data.geometry.vertices.empty())
ret += vertices_size_bytes();
if (m_render_data.geometry.indices.empty())
ret += indices_size_bytes();
return ret;
}
#endif // ENABLE_GLINDEXEDVERTEXARRAY_REMOVAL
private: private:
#if ENABLE_GLBEGIN_GLEND_REMOVAL #if ENABLE_GLBEGIN_GLEND_REMOVAL
bool send_to_gpu(); bool send_to_gpu();
@ -240,6 +301,10 @@ namespace GUI {
#endif // ENABLE_GLBEGIN_GLEND_REMOVAL #endif // ENABLE_GLBEGIN_GLEND_REMOVAL
}; };
#if ENABLE_GLINDEXEDVERTEXARRAY_REMOVAL
bool contains(const BuildVolume& volume, const GLModel& model, bool ignore_bottom = true);
#endif // ENABLE_GLINDEXEDVERTEXARRAY_REMOVAL
// create an arrow with cylindrical stem and conical tip, with the given dimensions and resolution // create an arrow with cylindrical stem and conical tip, with the given dimensions and resolution
// the origin of the arrow is in the center of the stem cap // the origin of the arrow is in the center of the stem cap
// the arrow has its axis of symmetry along the Z axis and is pointing upward // the arrow has its axis of symmetry along the Z axis and is pointing upward

View file

@ -98,7 +98,7 @@ namespace GUI {
color[1] = (m_state == Select) ? 1.0f : 0.3f; color[1] = (m_state == Select) ? 1.0f : 0.3f;
color[2] = 0.3f; color[2] = 0.3f;
glsafe(::glColor3fv(color)); glsafe(::glColor3fv(color));
#endif // ENABLE_GLBEGIN_GLEND_REMOVAL #endif // !ENABLE_GLBEGIN_GLEND_REMOVAL
glsafe(::glDisable(GL_DEPTH_TEST)); glsafe(::glDisable(GL_DEPTH_TEST));

View file

@ -274,9 +274,13 @@ static void generate_thumbnail_from_model(const std::string& filename)
GLVolumeCollection volumes; GLVolumeCollection volumes;
volumes.volumes.push_back(new GLVolume()); volumes.volumes.push_back(new GLVolume());
GLVolume* volume = volumes.volumes[0]; GLVolume* volume = volumes.volumes.back();
#if ENABLE_GLINDEXEDVERTEXARRAY_REMOVAL
volume->model.init_from(model.mesh());
#else
volume->indexed_vertex_array.load_mesh(model.mesh()); volume->indexed_vertex_array.load_mesh(model.mesh());
volume->indexed_vertex_array.finalize_geometry(true); volume->indexed_vertex_array.finalize_geometry(true);
#endif // ENABLE_GLINDEXEDVERTEXARRAY_REMOVAL
volume->set_instance_transformation(model.objects[0]->instances[0]->get_transformation()); volume->set_instance_transformation(model.objects[0]->instances[0]->get_transformation());
volume->set_volume_transformation(model.objects[0]->volumes[0]->get_transformation()); volume->set_volume_transformation(model.objects[0]->volumes[0]->get_transformation());

View file

@ -1444,8 +1444,8 @@ void ImGuiWrapper::render_draw_data(ImDrawData *draw_data)
{ {
// Avoid rendering when minimized, scale coordinates for retina displays (screen coordinates != framebuffer coordinates) // Avoid rendering when minimized, scale coordinates for retina displays (screen coordinates != framebuffer coordinates)
ImGuiIO& io = ImGui::GetIO(); ImGuiIO& io = ImGui::GetIO();
int fb_width = (int)(draw_data->DisplaySize.x * io.DisplayFramebufferScale.x); const int fb_width = (int)(draw_data->DisplaySize.x * io.DisplayFramebufferScale.x);
int fb_height = (int)(draw_data->DisplaySize.y * io.DisplayFramebufferScale.y); const int fb_height = (int)(draw_data->DisplaySize.y * io.DisplayFramebufferScale.y);
if (fb_width == 0 || fb_height == 0) if (fb_width == 0 || fb_height == 0)
return; return;
draw_data->ScaleClipRects(io.DisplayFramebufferScale); draw_data->ScaleClipRects(io.DisplayFramebufferScale);
@ -1488,8 +1488,7 @@ void ImGuiWrapper::render_draw_data(ImDrawData *draw_data)
// Render command lists // Render command lists
ImVec2 pos = draw_data->DisplayPos; ImVec2 pos = draw_data->DisplayPos;
for (int n = 0; n < draw_data->CmdListsCount; n++) for (int n = 0; n < draw_data->CmdListsCount; ++n) {
{
const ImDrawList* cmd_list = draw_data->CmdLists[n]; const ImDrawList* cmd_list = draw_data->CmdLists[n];
const ImDrawVert* vtx_buffer = cmd_list->VtxBuffer.Data; const ImDrawVert* vtx_buffer = cmd_list->VtxBuffer.Data;
const ImDrawIdx* idx_buffer = cmd_list->IdxBuffer.Data; const ImDrawIdx* idx_buffer = cmd_list->IdxBuffer.Data;
@ -1497,19 +1496,14 @@ void ImGuiWrapper::render_draw_data(ImDrawData *draw_data)
glsafe(::glTexCoordPointer(2, GL_FLOAT, sizeof(ImDrawVert), (const GLvoid*)((const char*)vtx_buffer + IM_OFFSETOF(ImDrawVert, uv)))); glsafe(::glTexCoordPointer(2, GL_FLOAT, sizeof(ImDrawVert), (const GLvoid*)((const char*)vtx_buffer + IM_OFFSETOF(ImDrawVert, uv))));
glsafe(::glColorPointer(4, GL_UNSIGNED_BYTE, sizeof(ImDrawVert), (const GLvoid*)((const char*)vtx_buffer + IM_OFFSETOF(ImDrawVert, col)))); glsafe(::glColorPointer(4, GL_UNSIGNED_BYTE, sizeof(ImDrawVert), (const GLvoid*)((const char*)vtx_buffer + IM_OFFSETOF(ImDrawVert, col))));
for (int cmd_i = 0; cmd_i < cmd_list->CmdBuffer.Size; cmd_i++) for (int cmd_i = 0; cmd_i < cmd_list->CmdBuffer.Size; ++cmd_i) {
{
const ImDrawCmd* pcmd = &cmd_list->CmdBuffer[cmd_i]; const ImDrawCmd* pcmd = &cmd_list->CmdBuffer[cmd_i];
if (pcmd->UserCallback) if (pcmd->UserCallback)
{
// User callback (registered via ImDrawList::AddCallback) // User callback (registered via ImDrawList::AddCallback)
pcmd->UserCallback(cmd_list, pcmd); pcmd->UserCallback(cmd_list, pcmd);
} else {
else
{
ImVec4 clip_rect = ImVec4(pcmd->ClipRect.x - pos.x, pcmd->ClipRect.y - pos.y, pcmd->ClipRect.z - pos.x, pcmd->ClipRect.w - pos.y); ImVec4 clip_rect = ImVec4(pcmd->ClipRect.x - pos.x, pcmd->ClipRect.y - pos.y, pcmd->ClipRect.z - pos.x, pcmd->ClipRect.w - pos.y);
if (clip_rect.x < fb_width && clip_rect.y < fb_height && clip_rect.z >= 0.0f && clip_rect.w >= 0.0f) if (clip_rect.x < fb_width && clip_rect.y < fb_height && clip_rect.z >= 0.0f && clip_rect.w >= 0.0f) {
{
// Apply scissor/clipping rectangle // Apply scissor/clipping rectangle
glsafe(::glScissor((int)clip_rect.x, (int)(fb_height - clip_rect.w), (int)(clip_rect.z - clip_rect.x), (int)(clip_rect.w - clip_rect.y))); glsafe(::glScissor((int)clip_rect.x, (int)(fb_height - clip_rect.w), (int)(clip_rect.z - clip_rect.x), (int)(clip_rect.w - clip_rect.y)));