#include "libslic3r/libslic3r.h" #include "GLModel.hpp" #include "3DScene.hpp" #include "libslic3r/TriangleMesh.hpp" #include namespace Slic3r { namespace GUI { void GL_Model::init_from(const GLModelInitializationData& data) { assert(!data.positions.empty() && !data.triangles.empty()); assert(data.positions.size() == data.normals.size()); if (m_vbo_id > 0) // call reset() if you want to reuse this model return; // vertices/normals data std::vector vertices(6 * data.positions.size()); for (size_t i = 0; i < data.positions.size(); ++i) { ::memcpy(static_cast(&vertices[i * 6]), static_cast(data.positions[i].data()), 3 * sizeof(float)); ::memcpy(static_cast(&vertices[3 + i * 6]), static_cast(data.normals[i].data()), 3 * sizeof(float)); } // indices data std::vector indices(3 * data.triangles.size()); for (size_t i = 0; i < data.triangles.size(); ++i) { for (size_t j = 0; j < 3; ++j) { indices[i * 3 + j] = static_cast(data.triangles[i][j]); } } m_indices_count = static_cast(indices.size()); m_bounding_box = BoundingBoxf3(); for (size_t i = 0; i < data.positions.size(); ++i) { m_bounding_box.merge(data.positions[i].cast()); } send_to_gpu(vertices, indices); } void GL_Model::init_from(const TriangleMesh& mesh) { auto get_normal = [](const std::array& triangle) { return (triangle[1] - triangle[0]).cross(triangle[2] - triangle[0]).normalized(); }; if (m_vbo_id > 0) // call reset() if you want to reuse this model return; assert(!mesh.its.vertices.empty() && !mesh.its.indices.empty()); // call require_shared_vertices() before to pass the mesh to this method // vertices data -> load from mesh std::vector vertices(6 * mesh.its.vertices.size()); for (size_t i = 0; i < mesh.its.vertices.size(); ++i) { ::memcpy(static_cast(&vertices[i * 6]), static_cast(mesh.its.vertices[i].data()), 3 * sizeof(float)); } // indices/normals data -> load from mesh std::vector indices(3 * mesh.its.indices.size()); for (size_t i = 0; i < mesh.its.indices.size(); ++i) { const stl_triangle_vertex_indices& triangle = mesh.its.indices[i]; for (size_t j = 0; j < 3; ++j) { indices[i * 3 + j] = static_cast(triangle[j]); } Vec3f normal = get_normal({ mesh.its.vertices[triangle[0]], mesh.its.vertices[triangle[1]], mesh.its.vertices[triangle[2]] }); ::memcpy(static_cast(&vertices[3 + static_cast(triangle[0]) * 6]), static_cast(normal.data()), 3 * sizeof(float)); ::memcpy(static_cast(&vertices[3 + static_cast(triangle[1]) * 6]), static_cast(normal.data()), 3 * sizeof(float)); ::memcpy(static_cast(&vertices[3 + static_cast(triangle[2]) * 6]), static_cast(normal.data()), 3 * sizeof(float)); } m_indices_count = static_cast(indices.size()); m_bounding_box = mesh.bounding_box(); send_to_gpu(vertices, indices); } void GL_Model::reset() { // release gpu memory if (m_ibo_id > 0) { glsafe(::glDeleteBuffers(1, &m_ibo_id)); m_ibo_id = 0; } if (m_vbo_id > 0) { glsafe(::glDeleteBuffers(1, &m_vbo_id)); m_vbo_id = 0; } m_indices_count = 0; m_bounding_box = BoundingBoxf3(); } void GL_Model::render() const { if (m_vbo_id == 0 || m_ibo_id == 0) return; glsafe(::glBindBuffer(GL_ARRAY_BUFFER, m_vbo_id)); glsafe(::glVertexPointer(3, GL_FLOAT, 6 * sizeof(float), (const void*)0)); glsafe(::glNormalPointer(GL_FLOAT, 6 * sizeof(float), (const void*)(3 * sizeof(float)))); glsafe(::glEnableClientState(GL_VERTEX_ARRAY)); glsafe(::glEnableClientState(GL_NORMAL_ARRAY)); glsafe(::glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, m_ibo_id)); glsafe(::glDrawElements(GL_TRIANGLES, static_cast(m_indices_count), GL_UNSIGNED_INT, (const void*)0)); glsafe(::glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0)); glsafe(::glDisableClientState(GL_NORMAL_ARRAY)); glsafe(::glDisableClientState(GL_VERTEX_ARRAY)); glsafe(::glBindBuffer(GL_ARRAY_BUFFER, 0)); } void GL_Model::send_to_gpu(const std::vector& vertices, const std::vector& indices) { // vertex data -> send to gpu glsafe(::glGenBuffers(1, &m_vbo_id)); glsafe(::glBindBuffer(GL_ARRAY_BUFFER, m_vbo_id)); glsafe(::glBufferData(GL_ARRAY_BUFFER, vertices.size() * sizeof(float), vertices.data(), GL_STATIC_DRAW)); glsafe(::glBindBuffer(GL_ARRAY_BUFFER, 0)); // indices data -> send to gpu glsafe(::glGenBuffers(1, &m_ibo_id)); glsafe(::glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, m_ibo_id)); glsafe(::glBufferData(GL_ELEMENT_ARRAY_BUFFER, indices.size() * sizeof(unsigned int), indices.data(), GL_STATIC_DRAW)); glsafe(::glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0)); } GLModelInitializationData stilized_arrow(int resolution, float tip_radius, float tip_height, float stem_radius, float stem_height) { GLModelInitializationData data; float angle_step = 2.0f * M_PI / static_cast(resolution); std::vector cosines(resolution); std::vector sines(resolution); for (int i = 0; i < resolution; ++i) { float angle = angle_step * static_cast(i); cosines[i] = ::cos(angle); sines[i] = -::sin(angle); } float total_height = tip_height + stem_height; // tip vertices/normals data.positions.emplace_back(0.0f, 0.0f, total_height); data.normals.emplace_back(Vec3f::UnitZ()); for (int i = 0; i < resolution; ++i) { data.positions.emplace_back(tip_radius * sines[i], tip_radius * cosines[i], stem_height); data.normals.emplace_back(sines[i], cosines[i], 0.0f); } // tip triangles for (int i = 0; i < resolution; ++i) { int v3 = (i < resolution - 1) ? i + 2 : 1; data.triangles.emplace_back(0, i + 1, v3); } // tip cap outer perimeter vertices for (int i = 0; i < resolution; ++i) { data.positions.emplace_back(tip_radius * sines[i], tip_radius * cosines[i], stem_height); data.normals.emplace_back(-Vec3f::UnitZ()); } // tip cap inner perimeter vertices for (int i = 0; i < resolution; ++i) { data.positions.emplace_back(stem_radius * sines[i], stem_radius * cosines[i], stem_height); data.normals.emplace_back(-Vec3f::UnitZ()); } // tip cap triangles for (int i = 0; i < resolution; ++i) { int v2 = (i < resolution - 1) ? i + resolution + 2 : resolution + 1; int v3 = (i < resolution - 1) ? i + 2 * resolution + 2 : 2 * resolution + 1; data.triangles.emplace_back(i + resolution + 1, v3, v2); data.triangles.emplace_back(i + resolution + 1, i + 2 * resolution + 1, v3); } // stem bottom vertices for (int i = 0; i < resolution; ++i) { data.positions.emplace_back(stem_radius * sines[i], stem_radius * cosines[i], stem_height); data.normals.emplace_back(sines[i], cosines[i], 0.0f); } // stem top vertices for (int i = 0; i < resolution; ++i) { data.positions.emplace_back(stem_radius * sines[i], stem_radius * cosines[i], 0.0f); data.normals.emplace_back(sines[i], cosines[i], 0.0f); } // stem triangles for (int i = 0; i < resolution; ++i) { int v2 = (i < resolution - 1) ? i + 3 * resolution + 2 : 3 * resolution + 1; int v3 = (i < resolution - 1) ? i + 4 * resolution + 2 : 4 * resolution + 1; data.triangles.emplace_back(i + 3 * resolution + 1, v3, v2); data.triangles.emplace_back(i + 3 * resolution + 1, i + 4 * resolution + 1, v3); } // stem cap vertices data.positions.emplace_back(0.0f, 0.0f, 0.0f); data.normals.emplace_back(-Vec3f::UnitZ()); for (int i = 0; i < resolution; ++i) { data.positions.emplace_back(stem_radius* sines[i], stem_radius* cosines[i], 0.0f); data.normals.emplace_back(-Vec3f::UnitZ()); } // stem cap triangles for (int i = 0; i < resolution; ++i) { int v3 = (i < resolution - 1) ? i + 5 * resolution + 3 : 5 * resolution + 2; data.triangles.emplace_back(5 * resolution + 1, v3, i + 5 * resolution + 2); } return data; } } // namespace GUI } // namespace Slic3r