From 769cca4b25410a2cdaf43af032ff301e443bbe43 Mon Sep 17 00:00:00 2001 From: enricoturri1966 Date: Mon, 11 May 2020 16:26:35 +0200 Subject: [PATCH] GCodeViewer -> Enhanced tool marker + refactoring (added new base class for OpenGL models) --- src/slic3r/CMakeLists.txt | 2 + src/slic3r/GUI/GCodeViewer.cpp | 129 +------------------ src/slic3r/GUI/GCodeViewer.hpp | 13 +- src/slic3r/GUI/GLModel.cpp | 229 +++++++++++++++++++++++++++++++++ src/slic3r/GUI/GLModel.hpp | 46 +++++++ 5 files changed, 286 insertions(+), 133 deletions(-) create mode 100644 src/slic3r/GUI/GLModel.cpp create mode 100644 src/slic3r/GUI/GLModel.hpp diff --git a/src/slic3r/CMakeLists.txt b/src/slic3r/CMakeLists.txt index fefc12ba87..b085fad456 100644 --- a/src/slic3r/CMakeLists.txt +++ b/src/slic3r/CMakeLists.txt @@ -55,6 +55,8 @@ set(SLIC3R_GUI_SOURCES GUI/Gizmos/GLGizmoHollow.hpp GUI/GLSelectionRectangle.cpp GUI/GLSelectionRectangle.hpp + GUI/GLModel.hpp + GUI/GLModel.cpp GUI/GLTexture.hpp GUI/GLTexture.cpp GUI/GLToolbar.hpp diff --git a/src/slic3r/GUI/GCodeViewer.cpp b/src/slic3r/GUI/GCodeViewer.cpp index 269780d950..ad3985c625 100644 --- a/src/slic3r/GUI/GCodeViewer.cpp +++ b/src/slic3r/GUI/GCodeViewer.cpp @@ -3,7 +3,6 @@ #if ENABLE_GCODE_VIEWER #include "libslic3r/Print.hpp" -#include "libslic3r/TriangleMesh.hpp" #include "libslic3r/Geometry.hpp" #include "GUI_App.hpp" #include "PresetBundle.hpp" @@ -148,92 +147,8 @@ GCodeViewer::Color GCodeViewer::Extrusions::Range::get_color_at(float value) con void GCodeViewer::SequentialView::Marker::init() { - Pointf3s vertices; - std::vector triangles; - - // arrow tip - vertices.emplace_back(0.0, 0.0, 0.0); - vertices.emplace_back(0.5, -0.5, 1.0); - vertices.emplace_back(0.5, 0.5, 1.0); - vertices.emplace_back(-0.5, 0.5, 1.0); - vertices.emplace_back(-0.5, -0.5, 1.0); - - triangles.emplace_back(0, 1, 4); - triangles.emplace_back(0, 2, 1); - triangles.emplace_back(0, 3, 2); - triangles.emplace_back(0, 4, 3); - triangles.emplace_back(1, 2, 4); - triangles.emplace_back(2, 3, 4); - - // arrow stem - vertices.emplace_back(0.25, -0.25, 1.0); - vertices.emplace_back(0.25, 0.25, 1.0); - vertices.emplace_back(-0.25, 0.25, 1.0); - vertices.emplace_back(-0.25, -0.25, 1.0); - vertices.emplace_back(0.25, -0.25, 3.0); - vertices.emplace_back(0.25, 0.25, 3.0); - vertices.emplace_back(-0.25, 0.25, 3.0); - vertices.emplace_back(-0.25, -0.25, 3.0); - - triangles.emplace_back(5, 9, 8); - triangles.emplace_back(8, 9, 12); - triangles.emplace_back(6, 10, 5); - triangles.emplace_back(5, 10, 9); - triangles.emplace_back(7, 11, 6); - triangles.emplace_back(6, 11, 10); - triangles.emplace_back(8, 12, 7); - triangles.emplace_back(7, 12, 11); - triangles.emplace_back(9, 10, 12); - triangles.emplace_back(12, 10, 11); - - TriangleMesh mesh(vertices, triangles); - mesh.require_shared_vertices(); - - init_from_mesh(mesh); -} - -bool GCodeViewer::SequentialView::Marker::init_from_mesh(const TriangleMesh& mesh) -{ - auto get_normal = [](const std::array& triangle) { - return (triangle[1] - triangle[0]).cross(triangle[2] - triangle[0]).normalized(); - }; - - reset(); - - // vertex 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()); - - // 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)); - - return init_shader(); + m_model.init_from(stilized_arrow(16, 0.5f, 1.0f, 0.25f, 2.0f)); + init_shader(); } void GCodeViewer::SequentialView::Marker::render() const @@ -249,56 +164,22 @@ void GCodeViewer::SequentialView::Marker::render() const if (color_id >= 0) glsafe(::glUniform4fv(color_id, 1, (const GLfloat*)m_color.data())); - 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(::glPushMatrix()); glsafe(::glMultMatrixf(m_world_transform.data())); - 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)); + m_model.render(); glsafe(::glPopMatrix()); - glsafe(::glDisableClientState(GL_NORMAL_ARRAY)); - glsafe(::glDisableClientState(GL_VERTEX_ARRAY)); - - glsafe(::glBindBuffer(GL_ARRAY_BUFFER, 0)); - m_shader.stop_using(); glsafe(::glDisable(GL_BLEND)); } -void GCodeViewer::SequentialView::Marker::reset() +void GCodeViewer::SequentialView::Marker::init_shader() { - // 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; -} - -bool GCodeViewer::SequentialView::Marker::init_shader() -{ - if (!m_shader.init("gouraud_light.vs", "gouraud_light.fs")) { + if (!m_shader.init("gouraud_light.vs", "gouraud_light.fs")) BOOST_LOG_TRIVIAL(error) << "Unable to initialize gouraud_light shader: please, check that the files gouraud_light.vs and gouraud_light.fs are available"; - return false; - } - - return true; } const std::vector GCodeViewer::Extrusion_Role_Colors {{ diff --git a/src/slic3r/GUI/GCodeViewer.hpp b/src/slic3r/GUI/GCodeViewer.hpp index d34e8ee4bd..44f23b2852 100644 --- a/src/slic3r/GUI/GCodeViewer.hpp +++ b/src/slic3r/GUI/GCodeViewer.hpp @@ -5,6 +5,7 @@ #include "GLShader.hpp" #include "3DScene.hpp" #include "libslic3r/GCode/GCodeProcessor.hpp" +#include "GLModel.hpp" #include @@ -152,31 +153,25 @@ class GCodeViewer { class Marker { - unsigned int m_vbo_id{ 0 }; - unsigned int m_ibo_id{ 0 }; - size_t m_indices_count{ 0 }; + GL_Model m_model; Transform3f m_world_transform; std::array m_color{ 1.0f, 1.0f, 1.0f, 1.0f }; bool m_visible{ false }; Shader m_shader; public: - ~Marker() { reset(); } - void init(); - bool init_from_mesh(const TriangleMesh& mesh); void set_world_transform(const Transform3f& transform) { m_world_transform = transform; } - void set_color(const std::array& color) { m_color = color; } bool is_visible() const { return m_visible; } void set_visible(bool visible) { m_visible = visible; } + void render() const; - void reset(); private: - bool init_shader(); + void init_shader(); }; unsigned int first{ 0 }; diff --git a/src/slic3r/GUI/GLModel.cpp b/src/slic3r/GUI/GLModel.cpp new file mode 100644 index 0000000000..336c699371 --- /dev/null +++ b/src/slic3r/GUI/GLModel.cpp @@ -0,0 +1,229 @@ +#include "libslic3r/libslic3r.h" +#include "GLModel.hpp" + +#include "3DScene.hpp" +#include "libslic3r/TriangleMesh.hpp" + +#include + +namespace Slic3r { +namespace GUI { + +bool GL_Model::init_from(const GLModelInitializationData& data) +{ + assert(!data.positions.empty() && !data.triangles.empty()); + assert(data.positions.size() == data.normals.size()); + + reset(); + + // 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()); + + send_to_gpu(vertices, indices); + + return true; +} + +bool 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(); + }; + + reset(); + + 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()); + + send_to_gpu(vertices, indices); + + return true; +} + +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; +} + +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); + } + + // tip vertices/normals + 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(tip_radius * sines[i], tip_radius * cosines[i], tip_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, v3, i + 1); + } + + // tip cap outer perimeter vertices + for (int i = 0; i < resolution; ++i) + { + data.positions.emplace_back(tip_radius * sines[i], tip_radius * cosines[i], tip_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], tip_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, v2, v3); + data.triangles.emplace_back(i + resolution + 1, v3, i + 2 * resolution + 1); + } + + // stem bottom vertices + for (int i = 0; i < resolution; ++i) + { + data.positions.emplace_back(stem_radius * sines[i], stem_radius * cosines[i], tip_height); + data.normals.emplace_back(sines[i], cosines[i], 0.0f); + } + + float total_height = tip_height + stem_height; + + // stem top vertices + for (int i = 0; i < resolution; ++i) + { + data.positions.emplace_back(stem_radius * sines[i], stem_radius * cosines[i], total_height); + 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, v2, v3); + data.triangles.emplace_back(i + 3 * resolution + 1, v3, i + 4 * resolution + 1); + } + + // stem cap vertices + 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(stem_radius * sines[i], stem_radius * cosines[i], total_height); + 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, i + 5 * resolution + 2, v3); + } + + return data; +} + +} // namespace GUI +} // namespace Slic3r diff --git a/src/slic3r/GUI/GLModel.hpp b/src/slic3r/GUI/GLModel.hpp new file mode 100644 index 0000000000..f294531abb --- /dev/null +++ b/src/slic3r/GUI/GLModel.hpp @@ -0,0 +1,46 @@ +#ifndef slic3r_GLModel_hpp_ +#define slic3r_GLModel_hpp_ + +namespace Slic3r { + +class TriangleMesh; + +namespace GUI { + + struct GLModelInitializationData + { + std::vector positions; + std::vector normals; + std::vector triangles; + }; + + class GL_Model + { + unsigned int m_vbo_id{ 0 }; + unsigned int m_ibo_id{ 0 }; + size_t m_indices_count{ 0 }; + + public: + virtual ~GL_Model() { reset(); } + + bool init_from(const GLModelInitializationData& data); + bool init_from(const TriangleMesh& mesh); + void reset(); + void render() const; + + private: + void send_to_gpu(const std::vector& vertices, const std::vector& indices); + }; + + + // create an arrow with cylindrical stem and conical tip, with the given dimensions and resolution + // the arrow tip is at 0,0,0 + // the arrow has its axis of symmetry along the Z axis and is pointing downward + GLModelInitializationData stilized_arrow(int resolution, float tip_radius, float tip_height, + float stem_radius, float stem_height); + +} // namespace GUI +} // namespace Slic3r + +#endif // slic3r_GLModel_hpp_ +