Use Vertex Buffer Objects for rendering of 3D volumes if possible.

This commit is contained in:
bubnikv 2017-03-16 14:02:28 +01:00
parent c32c7fa1dc
commit 7f7d2da5fe
8 changed files with 257 additions and 103 deletions

View File

@ -540,6 +540,10 @@ sub mouse_wheel_event {
# Reset selection. # Reset selection.
sub reset_objects { sub reset_objects {
my ($self) = @_; my ($self) = @_;
if ($self->{use_VBOs}) {
$self->GetContext;
$self->volumes->release_geometry;
}
$self->volumes->erase; $self->volumes->erase;
$self->_dirty(1); $self->_dirty(1);
} }
@ -944,6 +948,10 @@ sub InitGL {
return unless $self->GetContext; return unless $self->GetContext;
$self->init(1); $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); glClearColor(0, 0, 0, 1);
glColor3f(1, 0, 0); glColor3f(1, 0, 0);
glEnable(GL_DEPTH_TEST); glEnable(GL_DEPTH_TEST);
@ -983,12 +991,15 @@ sub InitGL {
glColorMaterial(GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE); glColorMaterial(GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE);
glEnable(GL_COLOR_MATERIAL); glEnable(GL_COLOR_MATERIAL);
glEnable(GL_MULTISAMPLE); glEnable(GL_MULTISAMPLE);
Slic3r::GUI::_3DScene::_glew_init;
} }
sub DestroyGL { sub DestroyGL {
my $self = shift; my $self = shift;
if ($self->init && $self->GetContext) { if ($self->init && $self->GetContext) {
delete $self->{shader}; delete $self->{shader};
$self->volumes->release_geometry;
} }
} }
@ -1251,58 +1262,7 @@ sub draw_volumes {
glColor4f(@{ $volume->color }); glColor4f(@{ $volume->color });
} }
glPushMatrix(); $volume->render;
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();
if ($shader_active) { if ($shader_active) {
glBindTexture(GL_TEXTURE_2D, 0); glBindTexture(GL_TEXTURE_2D, 0);

View File

@ -174,7 +174,7 @@ void* NSGLGetProcAddress (const GLubyte *name)
#if defined(GLEW_REGAL) #if defined(GLEW_REGAL)
# define glewGetProcAddress(name) regalGetProcAddress((const GLchar *) name) # define glewGetProcAddress(name) regalGetProcAddress((const GLchar *) name)
#elif defined(_WIN32) #elif defined(_WIN32)
# define glewGetProcAddress(name) ((LPCSTR)name) # define glewGetProcAddress(name) wglGetProcAddress((LPCSTR)name)
#elif defined(__APPLE__) && !defined(GLEW_APPLE_GLX) #elif defined(__APPLE__) && !defined(GLEW_APPLE_GLX)
# define glewGetProcAddress(name) NSGLGetProcAddress(name) # define glewGetProcAddress(name) NSGLGetProcAddress(name)
#elif defined(__sgi) || defined(__sun) || defined(__HAIKU__) #elif defined(__sgi) || defined(__sun) || defined(__HAIKU__)
@ -12105,8 +12105,10 @@ GLenum GLEWAPIENTRY wglewInit (WGLEW_CONTEXT_ARG_DEF_LIST)
extStart = (const GLubyte*)""; extStart = (const GLubyte*)"";
else else
extStart = (const GLubyte*)_wglewGetExtensionsStringEXT(); extStart = (const GLubyte*)_wglewGetExtensionsStringEXT();
else else {
extStart = (const GLubyte*)_wglewGetExtensionsStringARB(wglGetCurrentDC()); HDC dc = wglGetCurrentDC();
extStart = (const GLubyte*)_wglewGetExtensionsStringARB(dc);
}
extEnd = extStart + _glewStrLen(extStart); extEnd = extStart + _glewStrLen(extStart);
/* initialize extensions */ /* initialize extensions */
crippled = _wglewGetExtensionsStringARB == NULL && _wglewGetExtensionsStringEXT == NULL; crippled = _wglewGetExtensionsStringARB == NULL && _wglewGetExtensionsStringEXT == NULL;

View File

@ -1353,7 +1353,7 @@ Polygons EdgeGrid::Grid::contours_simplified(coord_t offset) const
return out; return out;
} }
#ifdef SLIC3R_GUI #if 0
void EdgeGrid::save_png(const EdgeGrid::Grid &grid, const BoundingBox &bbox, coord_t resolution, const char *path) 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; unsigned int w = (bbox.max.x - bbox.min.x + resolution - 1) / resolution;

View File

@ -107,7 +107,7 @@ protected:
std::vector<float> m_signed_distance_field; std::vector<float> m_signed_distance_field;
}; };
#ifdef SLIC3R_GUI #if 0
// Debugging utility. Save the signed distance field. // Debugging utility. Save the signed distance field.
extern void save_png(const Grid &grid, const BoundingBox &bbox, coord_t resolution, const char *path); extern void save_png(const Grid &grid, const BoundingBox &bbox, coord_t resolution, const char *path);
#endif /* SLIC3R_GUI */ #endif /* SLIC3R_GUI */

View File

@ -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); ::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, false), "blue", 0.5);
svg.draw(union_ex(projection_simplified, false), "red", 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.x -= scale_(5.f);
bbox.min.y -= scale_(5.f); bbox.min.y -= scale_(5.f);
bbox.max.x += 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). // 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. // 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. // 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. // 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<MyLayerExtruded*> MyLayerExtrudedPtrs; typedef std::vector<MyLayerExtruded*> MyLayerExtrudedPtrs;

View File

@ -1,3 +1,5 @@
#include <GL/glew.h>
#include "3DScene.hpp" #include "3DScene.hpp"
#include "../../libslic3r/libslic3r.h" #include "../../libslic3r/libslic3r.h"
@ -21,6 +23,10 @@ namespace Slic3r {
void GLIndexedVertexArray::load_mesh_flat_shading(const TriangleMesh &mesh) 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()); 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) { 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) 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); 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<size_t, size_t> &tverts_range,
const std::pair<size_t, size_t> &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) 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) void GLVolume::generate_layer_height_texture(PrintObject *print_object, bool force)
{ {
GLTexture *tex = this->layer_height_texture.get(); 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]; idx_a[BOTTOM] = idx_prev[BOTTOM];
} }
bool sharp = true;
if (ii == 0) { if (ii == 0) {
// Start of the 1st line segment. // Start of the 1st line segment.
idx_a[LEFT ] = idx_last ++; 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. // Create 3D thick extrusion lines for a skirt and brim.
// Adds a new Slic3r::GUI::3DScene::Volume to volumes. // Adds a new Slic3r::GUI::3DScene::Volume to volumes.
void _3DScene::_load_print_toolpaths( void _3DScene::_load_print_toolpaths(
@ -539,6 +685,7 @@ void _3DScene::_load_print_toolpaths(
auto bb = print->bounding_box(); 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.min.x), unscale(bb.min.y), 0.f));
volume.bounding_box.merge(Pointf3(unscale(bb.max.x), unscale(bb.max.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. // Create 3D thick extrusion lines for object forming extrusions.
@ -559,8 +706,10 @@ void _3DScene::_load_print_object_toolpaths(
bool has_infill; bool has_infill;
bool has_support; bool has_support;
// static const size_t alloc_size_max () { return 32 * 1048576 / 4; } // Number of vertices (each vertex is 6x4=24 bytes long)
static const size_t alloc_size_max () { return 4 * 1048576 / 4; } 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 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 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(); volume_ptr += v.volumes.size();
v.volumes.clear(); 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"; BOOST_LOG_TRIVIAL(debug) << "Loading print object toolpaths in parallel - end";
} }

View File

@ -17,31 +17,49 @@ class ModelObject;
// possibly indexed by triangles and / or quads. // possibly indexed by triangles and / or quads.
class GLIndexedVertexArray { class GLIndexedVertexArray {
public: 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) : GLIndexedVertexArray(const GLIndexedVertexArray &rhs) :
vertices_and_normals_interleaved(rhs.vertices_and_normals_interleaved), vertices_and_normals_interleaved(rhs.vertices_and_normals_interleaved),
triangle_indices(rhs.triangle_indices), 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) : GLIndexedVertexArray(GLIndexedVertexArray &&rhs) :
vertices_and_normals_interleaved(std::move(rhs.vertices_and_normals_interleaved)), vertices_and_normals_interleaved(std::move(rhs.vertices_and_normals_interleaved)),
triangle_indices(std::move(rhs.triangle_indices)), 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) 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->vertices_and_normals_interleaved = rhs.vertices_and_normals_interleaved;
this->triangle_indices = rhs.triangle_indices; this->triangle_indices = rhs.triangle_indices;
this->quad_indices = rhs.quad_indices; this->quad_indices = rhs.quad_indices;
this->setup_sizes();
return *this; return *this;
} }
GLIndexedVertexArray& operator=(GLIndexedVertexArray &&rhs) 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->vertices_and_normals_interleaved = std::move(rhs.vertices_and_normals_interleaved);
this->triangle_indices = std::move(rhs.triangle_indices); this->triangle_indices = std::move(rhs.triangle_indices);
this->quad_indices = std::move(rhs.quad_indices); this->quad_indices = std::move(rhs.quad_indices);
this->setup_sizes();
return *this; return *this;
} }
@ -50,8 +68,22 @@ public:
std::vector<int> triangle_indices; std::vector<int> triangle_indices;
std::vector<int> quad_indices; std::vector<int> 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); 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) { inline void reserve(size_t sz) {
this->vertices_and_normals_interleaved.reserve(sz * 6); this->vertices_and_normals_interleaved.reserve(sz * 6);
this->triangle_indices.reserve(sz * 3); 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)); 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<size_t, size_t> &tverts_range, const std::pair<size_t, size_t> &qverts_range) const;
// Is there any geometry data stored? // 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? // 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() { void clear() {
this->vertices_and_normals_interleaved.clear(); this->vertices_and_normals_interleaved.clear();
this->triangle_indices.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. // Shrink the internal storage to tighly fit the data stored.
void shrink_to_fit() { void shrink_to_fit() {
if (! this->has_VBOs())
this->setup_sizes();
this->vertices_and_normals_interleaved.shrink_to_fit(); this->vertices_and_normals_interleaved.shrink_to_fit();
this->triangle_indices.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 { BoundingBoxf3 bounding_box() const {
@ -109,6 +154,13 @@ public:
} }
return bbox; 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 class GLTexture
@ -201,23 +253,8 @@ public:
bool indexed() const { return this->indexed_vertex_array.indexed(); } bool indexed() const { return this->indexed_vertex_array.indexed(); }
void set_range(coordf_t low, coordf_t high); void set_range(coordf_t low, coordf_t high);
void render() const;
// Non-indexed interleaved vertices & normals, likely forming triangles. void release_geometry() { this->indexed_vertex_array.release_geometry(); }
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;
/************************************************ Layer height texture ****************************************************/ /************************************************ Layer height texture ****************************************************/
std::shared_ptr<GLTexture> layer_height_texture; std::shared_ptr<GLTexture> layer_height_texture;
@ -261,10 +298,14 @@ public:
const std::string &select_by, const std::string &select_by,
const std::string &drag_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(); } 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 render_VBOs() const { for (GLVolume *vol : this->volumes) vol->render_VBOs(); }
private: private:
GLVolumeCollection(const GLVolumeCollection &other); GLVolumeCollection(const GLVolumeCollection &other);
@ -274,6 +315,8 @@ private:
class _3DScene class _3DScene
{ {
public: public:
static void _glew_init();
static void _load_print_toolpaths( static void _load_print_toolpaths(
const Print *print, const Print *print,
GLVolumeCollection *volumes, GLVolumeCollection *volumes,

View File

@ -38,17 +38,7 @@
bool empty() const; bool empty() const;
bool indexed() const; bool indexed() const;
void* triangles_to_render_ptr(); void render() const;
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;
bool has_layer_height_texture(); bool has_layer_height_texture();
int layer_height_texture_width(); int layer_height_texture_width();
@ -72,8 +62,10 @@
int count() int count()
%code{% RETVAL = THIS->volumes.size(); %}; %code{% RETVAL = THIS->volumes.size(); %};
void set_range(double low, double high); void set_range(double low, double high);
void release_geometry();
%{ %{
SV* SV*
@ -95,6 +87,12 @@ GLVolumeCollection::arrayref()
%package{Slic3r::GUI::_3DScene}; %package{Slic3r::GUI::_3DScene};
%{ %{
void
_glew_init()
CODE:
_3DScene::_glew_init();
void void
_load_print_toolpaths(print, volumes, use_VBOs) _load_print_toolpaths(print, volumes, use_VBOs)
Print *print; Print *print;