From 7f7d2da5fe550a256169f9b806369833a8aafbf8 Mon Sep 17 00:00:00 2001 From: bubnikv Date: Thu, 16 Mar 2017 14:02:28 +0100 Subject: [PATCH] Use Vertex Buffer Objects for rendering of 3D volumes if possible. --- lib/Slic3r/GUI/3DScene.pm | 64 ++--------- xs/src/glew/src/glew.c | 8 +- xs/src/libslic3r/EdgeGrid.cpp | 2 +- xs/src/libslic3r/EdgeGrid.hpp | 2 +- xs/src/libslic3r/SupportMaterial.cpp | 8 +- xs/src/slic3r/GUI/3DScene.cpp | 157 ++++++++++++++++++++++++++- xs/src/slic3r/GUI/3DScene.hpp | 97 ++++++++++++----- xs/xsp/GUI_3DScene.xsp | 22 ++-- 8 files changed, 257 insertions(+), 103 deletions(-) diff --git a/lib/Slic3r/GUI/3DScene.pm b/lib/Slic3r/GUI/3DScene.pm index f6b66a991..bee3bc0f6 100644 --- a/lib/Slic3r/GUI/3DScene.pm +++ b/lib/Slic3r/GUI/3DScene.pm @@ -540,6 +540,10 @@ sub mouse_wheel_event { # Reset selection. sub reset_objects { my ($self) = @_; + if ($self->{use_VBOs}) { + $self->GetContext; + $self->volumes->release_geometry; + } $self->volumes->erase; $self->_dirty(1); } @@ -944,6 +948,10 @@ sub InitGL { return unless $self->GetContext; $self->init(1); + my @gl_version = split(/\./, glGetString(GL_VERSION)); + $self->{use_VBOs} = int($gl_version[0]) >= 2; +# print "OpenGL major: $gl_version[0], minor: $gl_version[1]. Use VBOs: ", $self->{use_VBOs}, "\n"; + glClearColor(0, 0, 0, 1); glColor3f(1, 0, 0); glEnable(GL_DEPTH_TEST); @@ -983,12 +991,15 @@ sub InitGL { glColorMaterial(GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE); glEnable(GL_COLOR_MATERIAL); glEnable(GL_MULTISAMPLE); + + Slic3r::GUI::_3DScene::_glew_init; } sub DestroyGL { my $self = shift; if ($self->init && $self->GetContext) { delete $self->{shader}; + $self->volumes->release_geometry; } } @@ -1251,58 +1262,7 @@ sub draw_volumes { glColor4f(@{ $volume->color }); } - glPushMatrix(); - glTranslatef(@{$volume->origin}); - glCullFace(GL_BACK); - if (1) { - if ($volume->indexed) { - my $quads_cnt = $volume->indexed_quads_to_render_cnt; - my $triangles_cnt = $volume->indexed_triangles_to_render_cnt; - if ($quads_cnt + $triangles_cnt > 0) { - if ($self->{use_VBOs}) { - my ($name_geometry, $name_triangle_indices, $name_quad_indices) = glGenBuffersARB_p(3); - glBindBufferARB(GL_ARRAY_BUFFER_ARB, $name_geometry); - glBufferDataARB_c(GL_ARRAY_BUFFER_ARB, $volume->geometry_size, $volume->triangles_to_render_ptr, GL_STATIC_DRAW_ARB); - glInterleavedArrays_c(GL_N3F_V3F, 0, 0); - if ($quads_cnt) { - glBindBufferARB(GL_ELEMENT_ARRAY_BUFFER_ARB, $name_quad_indices); - glBufferDataARB_c(GL_ELEMENT_ARRAY_BUFFER_ARB, $volume->indexed_quads_cnt * 4, $volume->quad_indices_ptr, GL_STATIC_DRAW_ARB); - glDrawElements_c(GL_QUADS, $quads_cnt, GL_UNSIGNED_INT, $volume->quad_indices_to_render_offset * 4); - } - if ($triangles_cnt) { - glBindBufferARB(GL_ELEMENT_ARRAY_BUFFER_ARB, $name_triangle_indices); - glBufferDataARB_c(GL_ELEMENT_ARRAY_BUFFER_ARB, $volume->indexed_triangles_cnt * 4, $volume->triangle_indices_ptr, GL_STATIC_DRAW_ARB); - glDrawElements_c(GL_TRIANGLES, $triangles_cnt, GL_UNSIGNED_INT, $volume->triangle_indices_to_render_offset * 4); - } - glBindBufferARB(GL_ARRAY_BUFFER_ARB, 0); - glBindBufferARB(GL_ELEMENT_ARRAY_BUFFER_ARB, 0); - glDeleteBuffersARB_p(($name_geometry, $name_triangle_indices, $name_quad_indices)); - } else { - glInterleavedArrays_c(GL_N3F_V3F, 0, $volume->triangles_to_render_ptr); - glDrawElements_c(GL_QUADS, $quads_cnt, GL_UNSIGNED_INT, $volume->quad_indices_ptr + $volume->quad_indices_to_render_offset * 4) - if ($quads_cnt); - glDrawElements_c(GL_TRIANGLES, $triangles_cnt, GL_UNSIGNED_INT, $volume->triangle_indices_ptr + $volume->triangle_indices_to_render_offset * 4) - if ($triangles_cnt); - glInterleavedArrays_c(GL_N3F_V3F, 0, 0); - } - } - } elsif (! $volume->empty) { - if ($self->{use_VBOs}) { - my ($name_geometry) = glGenBuffersARB_p(1); - glBindBufferARB(GL_ARRAY_BUFFER_ARB, $name_geometry); - glBufferDataARB_c(GL_ARRAY_BUFFER_ARB, $volume->triangles_to_render_cnt * 6 * 4, $volume->triangles_to_render_ptr, GL_STATIC_DRAW_ARB); - glInterleavedArrays_c(GL_N3F_V3F, 0, 0); - glDrawArrays(GL_TRIANGLES, 0, $volume->triangles_to_render_cnt); - glBindBufferARB(GL_ARRAY_BUFFER_ARB, 0); - glDeleteBuffersARB_p(($name_geometry)); - } else { - glInterleavedArrays_c(GL_N3F_V3F, 0, $volume->triangles_to_render_ptr); - glDrawArrays(GL_TRIANGLES, 0, $volume->triangles_to_render_cnt); - glInterleavedArrays_c(GL_N3F_V3F, 0, 0); - } - } - } - glPopMatrix(); + $volume->render; if ($shader_active) { glBindTexture(GL_TEXTURE_2D, 0); diff --git a/xs/src/glew/src/glew.c b/xs/src/glew/src/glew.c index 1c81adc46..32dabb802 100644 --- a/xs/src/glew/src/glew.c +++ b/xs/src/glew/src/glew.c @@ -174,7 +174,7 @@ void* NSGLGetProcAddress (const GLubyte *name) #if defined(GLEW_REGAL) # define glewGetProcAddress(name) regalGetProcAddress((const GLchar *) name) #elif defined(_WIN32) -# define glewGetProcAddress(name) ((LPCSTR)name) +# define glewGetProcAddress(name) wglGetProcAddress((LPCSTR)name) #elif defined(__APPLE__) && !defined(GLEW_APPLE_GLX) # define glewGetProcAddress(name) NSGLGetProcAddress(name) #elif defined(__sgi) || defined(__sun) || defined(__HAIKU__) @@ -12105,8 +12105,10 @@ GLenum GLEWAPIENTRY wglewInit (WGLEW_CONTEXT_ARG_DEF_LIST) extStart = (const GLubyte*)""; else extStart = (const GLubyte*)_wglewGetExtensionsStringEXT(); - else - extStart = (const GLubyte*)_wglewGetExtensionsStringARB(wglGetCurrentDC()); + else { + HDC dc = wglGetCurrentDC(); + extStart = (const GLubyte*)_wglewGetExtensionsStringARB(dc); + } extEnd = extStart + _glewStrLen(extStart); /* initialize extensions */ crippled = _wglewGetExtensionsStringARB == NULL && _wglewGetExtensionsStringEXT == NULL; diff --git a/xs/src/libslic3r/EdgeGrid.cpp b/xs/src/libslic3r/EdgeGrid.cpp index 07d08f390..0799f8923 100644 --- a/xs/src/libslic3r/EdgeGrid.cpp +++ b/xs/src/libslic3r/EdgeGrid.cpp @@ -1353,7 +1353,7 @@ Polygons EdgeGrid::Grid::contours_simplified(coord_t offset) const return out; } -#ifdef SLIC3R_GUI +#if 0 void EdgeGrid::save_png(const EdgeGrid::Grid &grid, const BoundingBox &bbox, coord_t resolution, const char *path) { unsigned int w = (bbox.max.x - bbox.min.x + resolution - 1) / resolution; diff --git a/xs/src/libslic3r/EdgeGrid.hpp b/xs/src/libslic3r/EdgeGrid.hpp index a0b23211e..3eb741865 100644 --- a/xs/src/libslic3r/EdgeGrid.hpp +++ b/xs/src/libslic3r/EdgeGrid.hpp @@ -107,7 +107,7 @@ protected: std::vector m_signed_distance_field; }; -#ifdef SLIC3R_GUI +#if 0 // Debugging utility. Save the signed distance field. extern void save_png(const Grid &grid, const BoundingBox &bbox, coord_t resolution, const char *path); #endif /* SLIC3R_GUI */ diff --git a/xs/src/libslic3r/SupportMaterial.cpp b/xs/src/libslic3r/SupportMaterial.cpp index 0afd2114b..3710f88a3 100644 --- a/xs/src/libslic3r/SupportMaterial.cpp +++ b/xs/src/libslic3r/SupportMaterial.cpp @@ -940,7 +940,7 @@ PrintObjectSupportMaterial::MyLayersPtr PrintObjectSupportMaterial::bottom_conta ::Slic3r::SVG svg(debug_out_path("support-bottom-contacts-simplified-%d-%d.svg", iRun, layer_id), bbox); svg.draw(union_ex(projection, false), "blue", 0.5); svg.draw(union_ex(projection_simplified, false), "red", 0.5); - #ifdef SLIC3R_GUI + #if 0 bbox.min.x -= scale_(5.f); bbox.min.y -= scale_(5.f); bbox.max.x += scale_(5.f); @@ -1593,12 +1593,12 @@ struct MyLayerExtruded } // The source layer. It carries the height and extrusion type (bridging / non bridging, extrusion height). - PrintObjectSupportMaterial::MyLayer *layer; + PrintObjectSupportMaterial::MyLayer *layer; // Collect extrusions. They will be exported sorted by the bottom height. - ExtrusionEntitiesPtr extrusions; + ExtrusionEntitiesPtr extrusions; // In case the extrusions are non-empty, m_polygons_to_extrude may contain the rest areas yet to be filled by additional support. // This is useful mainly for the loop interfaces, which are generated before the zig-zag infills. - Polygons *m_polygons_to_extrude; + Polygons *m_polygons_to_extrude; }; typedef std::vector MyLayerExtrudedPtrs; diff --git a/xs/src/slic3r/GUI/3DScene.cpp b/xs/src/slic3r/GUI/3DScene.cpp index afef2e20d..3140aa85d 100644 --- a/xs/src/slic3r/GUI/3DScene.cpp +++ b/xs/src/slic3r/GUI/3DScene.cpp @@ -1,3 +1,5 @@ +#include + #include "3DScene.hpp" #include "../../libslic3r/libslic3r.h" @@ -21,6 +23,10 @@ namespace Slic3r { void GLIndexedVertexArray::load_mesh_flat_shading(const TriangleMesh &mesh) { + assert(triangle_indices.empty() && vertices_and_normals_interleaved_size == 0); + assert(quad_indices.empty() && triangle_indices_size == 0); + assert(vertices_and_normals_interleaved.size() % 6 == 0 && quad_indices_size == vertices_and_normals_interleaved.size()); + this->vertices_and_normals_interleaved.reserve(this->vertices_and_normals_interleaved.size() + 3 * 3 * 2 * mesh.facets_count()); for (int i = 0; i < mesh.stl.stats.number_of_facets; ++ i) { @@ -28,6 +34,130 @@ void GLIndexedVertexArray::load_mesh_flat_shading(const TriangleMesh &mesh) for (int j = 0; j < 3; ++ j) this->push_geometry(facet.vertex[j].x, facet.vertex[j].y, facet.vertex[j].z, facet.normal.x, facet.normal.y, facet.normal.z); } + + vertices_and_normals_interleaved_size = this->vertices_and_normals_interleaved.size(); +} + +void GLIndexedVertexArray::finalize_geometry(bool use_VBOs) +{ + assert(this->vertices_and_normals_interleaved_VBO_id == 0); + assert(this->triangle_indices_VBO_id == 0); + assert(this->quad_indices_VBO_id == 0); + + this->setup_sizes(); + + if (use_VBOs) { + if (! empty()) { + glGenBuffers(1, &this->vertices_and_normals_interleaved_VBO_id); + glBindBuffer(GL_ARRAY_BUFFER, this->vertices_and_normals_interleaved_VBO_id); + glBufferData(GL_ARRAY_BUFFER, this->vertices_and_normals_interleaved.size() * 4, this->vertices_and_normals_interleaved.data(), GL_STATIC_DRAW); + glBindBuffer(GL_ARRAY_BUFFER, 0); + this->vertices_and_normals_interleaved.clear(); + } + if (! this->triangle_indices.empty()) { + glGenBuffers(1, &this->triangle_indices_VBO_id); + glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, this->triangle_indices_VBO_id); + glBufferData(GL_ELEMENT_ARRAY_BUFFER, this->triangle_indices.size() * 4, this->triangle_indices.data(), GL_STATIC_DRAW); + this->triangle_indices.clear(); + } + if (! this->quad_indices.empty()) { + glGenBuffers(1, &this->quad_indices_VBO_id); + glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, this->quad_indices_VBO_id); + glBufferData(GL_ELEMENT_ARRAY_BUFFER, this->quad_indices.size() * 4, this->quad_indices.data(), GL_STATIC_DRAW); + this->quad_indices.clear(); + } + glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0); + } + this->shrink_to_fit(); +} + +void GLIndexedVertexArray::release_geometry() +{ + if (this->vertices_and_normals_interleaved_VBO_id) + glDeleteBuffers(1, &this->vertices_and_normals_interleaved_VBO_id); + if (this->triangle_indices_VBO_id) + glDeleteBuffers(1, &this->triangle_indices_VBO_id); + if (this->quad_indices_VBO_id) + glDeleteBuffers(1, &this->quad_indices_VBO_id); + this->clear(); + this->shrink_to_fit(); +} + +void GLIndexedVertexArray::render() const +{ + if (this->indexed()) { + if (this->vertices_and_normals_interleaved_VBO_id) { + // Render using the Vertex Buffer Objects. + glBindBuffer(GL_ARRAY_BUFFER, this->vertices_and_normals_interleaved_VBO_id); + glInterleavedArrays(GL_N3F_V3F, 0, nullptr); + if (this->triangle_indices_size > 0) { + glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, this->triangle_indices_VBO_id); + glDrawElements(GL_TRIANGLES, GLsizei(this->triangle_indices_size), GL_UNSIGNED_INT, nullptr); + } + if (this->quad_indices_size > 0) { + glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, this->quad_indices_VBO_id); + glDrawElements(GL_QUADS, GLsizei(this->quad_indices_size), GL_UNSIGNED_INT, nullptr); + } + glBindBuffer(GL_ARRAY_BUFFER, 0); + glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0); + } else { + // Render in an immediate mode. + glInterleavedArrays(GL_N3F_V3F, 0, this->vertices_and_normals_interleaved.data()); + // Due to issues with the Intel drivers, rather limit the amount of vertices processed per draw command. + if (! this->triangle_indices.empty()) + glDrawElements(GL_TRIANGLES, GLsizei(this->triangle_indices_size), GL_UNSIGNED_INT, this->triangle_indices.data()); + if (! this->quad_indices.empty()) + glDrawElements(GL_QUADS, GLsizei(this->quad_indices_size), GL_UNSIGNED_INT, this->quad_indices.data()); + } + } else { + if (this->vertices_and_normals_interleaved_VBO_id) { + // Render using the Vertex Buffer Objects. + glBindBuffer(GL_ARRAY_BUFFER, this->vertices_and_normals_interleaved_VBO_id); + glInterleavedArrays(GL_N3F_V3F, 0, nullptr); + glDrawArrays(GL_TRIANGLES, 0, GLsizei(this->vertices_and_normals_interleaved_size / 6)); + glBindBuffer(GL_ARRAY_BUFFER, 0); + } else { + // Render in an immediate mode. + glInterleavedArrays(GL_N3F_V3F, 0, this->vertices_and_normals_interleaved.data()); + glDrawArrays(GL_TRIANGLES, 0, GLsizei(this->vertices_and_normals_interleaved_size / 6)); + } + } + + glInterleavedArrays(GL_N3F_V3F, 0, nullptr); +} + +void GLIndexedVertexArray::render( + const std::pair &tverts_range, + const std::pair &qverts_range) const +{ + assert(this->indexed()); + if (! this->indexed()) + return; + + if (this->vertices_and_normals_interleaved_VBO_id) { + // Render using the Vertex Buffer Objects. + glBindBuffer(GL_ARRAY_BUFFER, this->vertices_and_normals_interleaved_VBO_id); + glInterleavedArrays(GL_N3F_V3F, 0, nullptr); + if (this->triangle_indices_size > 0) { + glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, this->triangle_indices_VBO_id); + glDrawElements(GL_TRIANGLES, GLsizei(std::min(this->triangle_indices_size, tverts_range.second - tverts_range.first)), GL_UNSIGNED_INT, (const void*)(tverts_range.first * 4)); + } + if (this->quad_indices_size > 0) { + glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, this->quad_indices_VBO_id); + glDrawElements(GL_QUADS, GLsizei(std::min(this->quad_indices_size, qverts_range.second - qverts_range.first)), GL_UNSIGNED_INT, (const void*)(qverts_range.first * 4)); + } + glBindBuffer(GL_ARRAY_BUFFER, 0); + glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0); + } else { + // Render in an immediate mode. + glInterleavedArrays(GL_N3F_V3F, 0, this->vertices_and_normals_interleaved.data()); + if (! this->triangle_indices.empty()) + glDrawElements(GL_TRIANGLES, GLsizei(std::min(this->triangle_indices_size, tverts_range.second - tverts_range.first)), GL_UNSIGNED_INT, (const void*)(this->triangle_indices.data() + tverts_range.first)); + if (! this->quad_indices.empty()) + glDrawElements(GL_QUADS, GLsizei(std::min(this->quad_indices_size, qverts_range.second - qverts_range.first)), GL_UNSIGNED_INT, (const void*)(this->quad_indices.data() + qverts_range.first)); + } + + glInterleavedArrays(GL_N3F_V3F, 0, nullptr); } void GLVolume::set_range(double min_z, double max_z) @@ -65,6 +195,18 @@ void GLVolume::set_range(double min_z, double max_z) } } +void GLVolume::render() const +{ + glCullFace(GL_BACK); + glPushMatrix(); + glTranslated(this->origin.x, this->origin.y, this->origin.z); + if (this->indexed_vertex_array.indexed()) + this->indexed_vertex_array.render(this->tverts_range, this->qverts_range); + else + this->indexed_vertex_array.render(); + glPopMatrix(); +} + void GLVolume::generate_layer_height_texture(PrintObject *print_object, bool force) { GLTexture *tex = this->layer_height_texture.get(); @@ -235,7 +377,6 @@ static void thick_lines_to_indexed_vertex_array( idx_a[BOTTOM] = idx_prev[BOTTOM]; } - bool sharp = true; if (ii == 0) { // Start of the 1st line segment. idx_a[LEFT ] = idx_last ++; @@ -490,6 +631,11 @@ static void extrusionentity_to_verts(const ExtrusionEntity *extrusion_entity, fl } } +void _3DScene::_glew_init() +{ + glewInit(); +} + // Create 3D thick extrusion lines for a skirt and brim. // Adds a new Slic3r::GUI::3DScene::Volume to volumes. void _3DScene::_load_print_toolpaths( @@ -539,6 +685,7 @@ void _3DScene::_load_print_toolpaths( auto bb = print->bounding_box(); volume.bounding_box.merge(Pointf3(unscale(bb.min.x), unscale(bb.min.y), 0.f)); volume.bounding_box.merge(Pointf3(unscale(bb.max.x), unscale(bb.max.y), 0.f)); + volume.indexed_vertex_array.finalize_geometry(use_VBOs); } // Create 3D thick extrusion lines for object forming extrusions. @@ -559,8 +706,10 @@ void _3DScene::_load_print_object_toolpaths( bool has_infill; bool has_support; -// static const size_t alloc_size_max () { return 32 * 1048576 / 4; } - static const size_t alloc_size_max () { return 4 * 1048576 / 4; } + // Number of vertices (each vertex is 6x4=24 bytes long) + static const size_t alloc_size_max () { return 131072; } // 3.15MB +// static const size_t alloc_size_max () { return 65536; } // 1.57MB +// static const size_t alloc_size_max () { return 32768; } // 786kB static const size_t alloc_size_reserve() { return alloc_size_max() * 2; } static const float* color_perimeters () { static float color[4] = { 1.0f, 1.0f, 0.0f, 1.f }; return color; } // yellow @@ -672,6 +821,8 @@ void _3DScene::_load_print_object_toolpaths( volume_ptr += v.volumes.size(); v.volumes.clear(); } + for (GLVolume *v : volumes->volumes) + v->indexed_vertex_array.finalize_geometry(use_VBOs); BOOST_LOG_TRIVIAL(debug) << "Loading print object toolpaths in parallel - end"; } diff --git a/xs/src/slic3r/GUI/3DScene.hpp b/xs/src/slic3r/GUI/3DScene.hpp index 07c8e785b..c6ec3b42c 100644 --- a/xs/src/slic3r/GUI/3DScene.hpp +++ b/xs/src/slic3r/GUI/3DScene.hpp @@ -17,31 +17,49 @@ class ModelObject; // possibly indexed by triangles and / or quads. class GLIndexedVertexArray { public: - GLIndexedVertexArray() {} + GLIndexedVertexArray() : + vertices_and_normals_interleaved_VBO_id(0), + triangle_indices_VBO_id(0), + quad_indices_VBO_id(0) + { this->setup_sizes(); } GLIndexedVertexArray(const GLIndexedVertexArray &rhs) : vertices_and_normals_interleaved(rhs.vertices_and_normals_interleaved), triangle_indices(rhs.triangle_indices), - quad_indices(rhs.quad_indices) - {} + quad_indices(rhs.quad_indices), + vertices_and_normals_interleaved_VBO_id(0), + triangle_indices_VBO_id(0), + quad_indices_VBO_id(0) + { this->setup_sizes(); } GLIndexedVertexArray(GLIndexedVertexArray &&rhs) : vertices_and_normals_interleaved(std::move(rhs.vertices_and_normals_interleaved)), triangle_indices(std::move(rhs.triangle_indices)), - quad_indices(std::move(rhs.quad_indices)) - {} + quad_indices(std::move(rhs.quad_indices)), + vertices_and_normals_interleaved_VBO_id(0), + triangle_indices_VBO_id(0), + quad_indices_VBO_id(0) + { this->setup_sizes(); } GLIndexedVertexArray& operator=(const GLIndexedVertexArray &rhs) { + assert(vertices_and_normals_interleaved_VBO_id == 0); + assert(triangle_indices_VBO_id == 0); + assert(triangle_indices_VBO_id == 0); this->vertices_and_normals_interleaved = rhs.vertices_and_normals_interleaved; this->triangle_indices = rhs.triangle_indices; this->quad_indices = rhs.quad_indices; + this->setup_sizes(); return *this; } GLIndexedVertexArray& operator=(GLIndexedVertexArray &&rhs) { + assert(vertices_and_normals_interleaved_VBO_id == 0); + assert(triangle_indices_VBO_id == 0); + assert(triangle_indices_VBO_id == 0); this->vertices_and_normals_interleaved = std::move(rhs.vertices_and_normals_interleaved); this->triangle_indices = std::move(rhs.triangle_indices); this->quad_indices = std::move(rhs.quad_indices); + this->setup_sizes(); return *this; } @@ -50,8 +68,22 @@ public: std::vector triangle_indices; std::vector quad_indices; + // When the geometry data is loaded into the graphics card as Vertex Buffer Objects, + // the above mentioned std::vectors are cleared and the following variables keep their original length. + size_t vertices_and_normals_interleaved_size; + size_t triangle_indices_size; + size_t quad_indices_size; + + // IDs of the Vertex Array Objects, into which the geometry has been loaded. + // Zero if the VBOs are not used. + unsigned int vertices_and_normals_interleaved_VBO_id; + unsigned int triangle_indices_VBO_id; + unsigned int quad_indices_VBO_id; + void load_mesh_flat_shading(const TriangleMesh &mesh); + inline bool has_VBOs() const { return vertices_and_normals_interleaved_VBO_id != 0; } + inline void reserve(size_t sz) { this->vertices_and_normals_interleaved.reserve(sz * 6); this->triangle_indices.reserve(sz * 3); @@ -72,23 +104,36 @@ public: push_geometry(float(x), float(y), float(z), float(nx), float(ny), float(nz)); } + // Finalize the initialization of the geometry & indices, + // upload the geometry and indices to OpenGL VBO objects + // and shrink the allocated data, possibly relasing it if it has been loaded into the VBOs. + void finalize_geometry(bool use_VBOs); + // Release the geometry data, release OpenGL VBOs. + void release_geometry(); + // Render either using an immediate mode, or the VBOs. + void render() const; + void render(const std::pair &tverts_range, const std::pair &qverts_range) const; + // Is there any geometry data stored? - bool empty() const { return vertices_and_normals_interleaved.empty(); } + bool empty() const { return vertices_and_normals_interleaved_size == 0; } // Is this object indexed, or is it just a set of triangles? - bool indexed() const { return ! this->empty() && (! this->triangle_indices.empty() || ! this->quad_indices.empty()); } + bool indexed() const { return ! this->empty() && this->triangle_indices_size + this->quad_indices_size > 0; } void clear() { this->vertices_and_normals_interleaved.clear(); this->triangle_indices.clear(); - this->quad_indices.clear(); + this->quad_indices.clear(); + this->setup_sizes(); } // Shrink the internal storage to tighly fit the data stored. void shrink_to_fit() { + if (! this->has_VBOs()) + this->setup_sizes(); this->vertices_and_normals_interleaved.shrink_to_fit(); this->triangle_indices.shrink_to_fit(); - this->quad_indices.shrink_to_fit(); + this->quad_indices.shrink_to_fit(); } BoundingBoxf3 bounding_box() const { @@ -109,6 +154,13 @@ public: } return bbox; } + +private: + inline void setup_sizes() { + vertices_and_normals_interleaved_size = this->vertices_and_normals_interleaved.size(); + triangle_indices_size = this->triangle_indices.size(); + quad_indices_size = this->quad_indices.size(); + } }; class GLTexture @@ -201,23 +253,8 @@ public: bool indexed() const { return this->indexed_vertex_array.indexed(); } void set_range(coordf_t low, coordf_t high); - - // Non-indexed interleaved vertices & normals, likely forming triangles. - void* triangles_to_render_ptr() { return indexed_vertex_array.vertices_and_normals_interleaved.data(); } - size_t triangles_to_render_cnt() { return indexed_vertex_array.vertices_and_normals_interleaved.size() / (3 * 2); } - // Indexed triangles & quads, complete set for storing into a vertex buffer. - size_t geometry_size() const { return indexed_vertex_array.vertices_and_normals_interleaved.size() * 4; } - void* triangle_indices_ptr() { return indexed_vertex_array.triangle_indices.data(); } - void* quad_indices_ptr() { return indexed_vertex_array.quad_indices.data(); } - size_t indexed_triangles_cnt() { return indexed_vertex_array.triangle_indices.size(); } - size_t indexed_quads_cnt() { return indexed_vertex_array.quad_indices.size(); } - // Indexed triangles & quads, to be painted in an immediate mode. - size_t triangle_indices_to_render_offset() const { return tverts_range.first; } - size_t quad_indices_to_render_offset() const { return qverts_range.first; } - size_t indexed_triangles_to_render_cnt() const { return std::min(indexed_vertex_array.triangle_indices.size(), tverts_range.second - tverts_range.first); } - size_t indexed_quads_to_render_cnt() const { return std::min(indexed_vertex_array.quad_indices.size(), qverts_range.second - qverts_range.first); } - - void render_VBOs() const; + void render() const; + void release_geometry() { this->indexed_vertex_array.release_geometry(); } /************************************************ Layer height texture ****************************************************/ std::shared_ptr layer_height_texture; @@ -261,10 +298,14 @@ public: const std::string &select_by, const std::string &drag_by); + // Release the geometry data assigned to the volumes. + // If OpenGL VBOs were allocated, an OpenGL context has to be active to release them. + void release_geometry() { for (auto *v : volumes) v->release_geometry(); } + // Clear the geometry void clear() { for (auto *v : volumes) delete v; volumes.clear(); } + bool empty() const { return volumes.empty(); } void set_range(double low, double high) { for (GLVolume *vol : this->volumes) vol->set_range(low, high); } - void render_VBOs() const { for (GLVolume *vol : this->volumes) vol->render_VBOs(); } private: GLVolumeCollection(const GLVolumeCollection &other); @@ -274,6 +315,8 @@ private: class _3DScene { public: + static void _glew_init(); + static void _load_print_toolpaths( const Print *print, GLVolumeCollection *volumes, diff --git a/xs/xsp/GUI_3DScene.xsp b/xs/xsp/GUI_3DScene.xsp index 4532b16ea..b70d99abe 100644 --- a/xs/xsp/GUI_3DScene.xsp +++ b/xs/xsp/GUI_3DScene.xsp @@ -38,17 +38,7 @@ bool empty() const; bool indexed() const; - void* triangles_to_render_ptr(); - size_t triangles_to_render_cnt(); - size_t geometry_size() const; - void* triangle_indices_ptr(); - void* quad_indices_ptr(); - size_t indexed_triangles_cnt(); - size_t indexed_quads_cnt(); - size_t triangle_indices_to_render_offset() const; - size_t quad_indices_to_render_offset() const; - size_t indexed_triangles_to_render_cnt() const; - size_t indexed_quads_to_render_cnt() const; + void render() const; bool has_layer_height_texture(); int layer_height_texture_width(); @@ -72,8 +62,10 @@ int count() %code{% RETVAL = THIS->volumes.size(); %}; - + void set_range(double low, double high); + + void release_geometry(); %{ SV* @@ -95,6 +87,12 @@ GLVolumeCollection::arrayref() %package{Slic3r::GUI::_3DScene}; %{ + +void +_glew_init() + CODE: + _3DScene::_glew_init(); + void _load_print_toolpaths(print, volumes, use_VBOs) Print *print;