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
src/slic3r/GUI

View file

@ -8,15 +8,56 @@
#include "libslic3r/TriangleMesh.hpp"
#include "libslic3r/Model.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/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>
namespace Slic3r {
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
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) };
}
#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
{
if (format.index_type != EIndexType::UINT) {
@ -219,7 +291,7 @@ unsigned int GLModel::Geometry::extract_uint_index(size_t id) const
return -1;
}
unsigned int ret = -1;
unsigned int ret = (unsigned int)-1;
::memcpy(&ret, indices.data() + id * index_stride_bytes(format), sizeof(unsigned int));
return ret;
}
@ -236,11 +308,23 @@ unsigned short GLModel::Geometry::extract_ushort_index(size_t id) const
return -1;
}
unsigned short ret = -1;
unsigned short ret = (unsigned short)-1;
::memcpy(&ret, indices.data() + id * index_stride_bytes(format), sizeof(unsigned short));
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)
{
switch (format.vertex_layout)
@ -461,10 +545,58 @@ void GLModel::init_from(const Geometry& data)
}
#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)
{
init_from(mesh.its);
}
#endif // ENABLE_SMOOTH_NORMALS
void GLModel::init_from(const indexed_triangle_set& its)
#else
@ -484,21 +616,24 @@ void GLModel::init_from(const indexed_triangle_set& its, const BoundingBoxf3 &bb
}
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_indices(3 * its.indices.size());
// vertices + indices
unsigned int vertices_counter = 0;
for (uint32_t i = 0; i < its.indices.size(); ++i) {
stl_triangle_vertex_indices face = its.indices[i];
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_triangle_vertex_indices face = its.indices[i];
const stl_vertex vertex[3] = { its.vertices[face[0]], its.vertices[face[1]], its.vertices[face[2]] };
const stl_vertex n = face_normal_normalized(vertex);
for (size_t j = 0; j < 3; ++j) {
data.add_vertex(vertex[j], n);
}
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
@ -721,6 +856,9 @@ void GLModel::render()
void GLModel::render() const
#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();
#if ENABLE_GLBEGIN_GLEND_REMOVAL
@ -809,8 +947,71 @@ void GLModel::render() const
glsafe(::glBindBuffer(GL_ARRAY_BUFFER, 0));
}
#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
void GLModel::render_instanced(unsigned int instances_vbo, unsigned int instances_count)
#else
@ -1027,6 +1228,62 @@ static void append_triangle(GLModel::Geometry& data, unsigned short v1, unsigned
}
#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)
{
#if !ENABLE_GLBEGIN_GLEND_REMOVAL