diff --git a/src/slic3r/GUI/3DBed.cpp b/src/slic3r/GUI/3DBed.cpp index b5a34b2ee..450a538d0 100644 --- a/src/slic3r/GUI/3DBed.cpp +++ b/src/slic3r/GUI/3DBed.cpp @@ -358,14 +358,23 @@ void Bed3D::calc_bounding_boxes() const // extend to contain axes #if ENABLE_GCODE_VIEWER - m_extended_bounding_box.merge(m_axes.get_total_length() * Vec3d::Ones()); -#else - m_extended_bounding_box.merge(m_axes.length + Axes::ArrowLength * Vec3d::Ones()); -#endif // ENABLE_GCODE_VIEWER + m_extended_bounding_box.merge(m_axes.get_origin() + m_axes.get_total_length() * Vec3d::Ones()); + m_extended_bounding_box.merge(m_extended_bounding_box.min + Vec3d(-Axes::DefaultTipRadius, -Axes::DefaultTipRadius, m_extended_bounding_box.max(2))); + // extend to contain model, if any + BoundingBoxf3 model_bb = m_model.get_bounding_box(); + if (model_bb.defined) + { + model_bb.translate(m_model_offset); + m_extended_bounding_box.merge(model_bb); + } +#else + m_extended_bounding_box.merge(m_axes.get_total_length() * Vec3d::Ones()); + m_extended_bounding_box.merge(m_axes.length + Axes::ArrowLength * Vec3d::Ones()); // extend to contain model, if any if (!m_model.get_filename().empty()) m_extended_bounding_box.merge(m_model.get_transformed_bounding_box()); +#endif // ENABLE_GCODE_VIEWER } void Bed3D::calc_triangles(const ExPolygon& poly) @@ -621,7 +630,11 @@ void Bed3D::render_model() const // move the model so that its origin (0.0, 0.0, 0.0) goes into the bed shape center and a bit down to avoid z-fighting with the texture quad Vec3d shift = m_bounding_box.center(); shift(2) = -0.03; +#if ENABLE_GCODE_VIEWER + m_model_offset = shift; +#else m_model.set_offset(shift); +#endif // ENABLE_GCODE_VIEWER // update extended bounding box calc_bounding_boxes(); @@ -633,7 +646,15 @@ void Bed3D::render_model() const if (shader != nullptr) { shader->start_using(); +#if ENABLE_GCODE_VIEWER + shader->set_uniform("uniform_color", m_model_color); + ::glPushMatrix(); + ::glTranslated(m_model_offset(0), m_model_offset(1), m_model_offset(2)); +#endif // ENABLE_GCODE_VIEWER m_model.render(); +#if ENABLE_GCODE_VIEWER + ::glPopMatrix(); +#endif // ENABLE_GCODE_VIEWER shader->stop_using(); } } diff --git a/src/slic3r/GUI/3DBed.hpp b/src/slic3r/GUI/3DBed.hpp index 2487be2e4..b9e952c4a 100644 --- a/src/slic3r/GUI/3DBed.hpp +++ b/src/slic3r/GUI/3DBed.hpp @@ -8,6 +8,9 @@ #endif // ENABLE_GCODE_VIEWER #include +#if ENABLE_GCODE_VIEWER +#include +#endif // ENABLE_GCODE_VIEWER #if !ENABLE_GCODE_VIEWER class GLUquadric; @@ -52,10 +55,13 @@ class Bed3D #if ENABLE_GCODE_VIEWER class Axes { + public: static const float DefaultStemRadius; static const float DefaultStemLength; static const float DefaultTipRadius; static const float DefaultTipLength; + + private: #else struct Axes { @@ -67,7 +73,7 @@ class Bed3D #if ENABLE_GCODE_VIEWER Vec3d m_origin{ Vec3d::Zero() }; float m_stem_length{ DefaultStemLength }; - mutable GL_Model m_arrow; + mutable GLModel m_arrow; public: #else @@ -82,6 +88,7 @@ class Bed3D #endif // !ENABLE_GCODE_VIEWER #if ENABLE_GCODE_VIEWER + const Vec3d& get_origin() const { return m_origin; } void set_origin(const Vec3d& origin) { m_origin = origin; } void set_stem_length(float length); float get_total_length() const { return m_stem_length + DefaultTipLength; } @@ -113,7 +120,13 @@ private: GeometryBuffer m_triangles; GeometryBuffer m_gridlines; mutable GLTexture m_texture; +#if ENABLE_GCODE_VIEWER + mutable GLModel m_model; + mutable Vec3d m_model_offset{ Vec3d::Zero() }; + std::array m_model_color{ 0.235f, 0.235f, 0.235f, 1.0f }; +#else mutable GLBed m_model; +#endif // ENABLE_GCODE_VIEWER // temporary texture shown until the main texture has still no levels compressed mutable GLTexture m_temp_texture; mutable unsigned int m_vbo_id; diff --git a/src/slic3r/GUI/3DScene.cpp b/src/slic3r/GUI/3DScene.cpp index 49b1c255b..59be43271 100644 --- a/src/slic3r/GUI/3DScene.cpp +++ b/src/slic3r/GUI/3DScene.cpp @@ -1822,6 +1822,7 @@ void _3DScene::point3_to_verts(const Vec3crd& point, double width, double height thick_point_to_verts(point, width, height, volume); } +#if !ENABLE_GCODE_VIEWER GLModel::GLModel() : m_filename("") { @@ -1904,7 +1905,6 @@ void GLModel::render() const glsafe(::glDisable(GL_BLEND)); } -#if !ENABLE_GCODE_VIEWER bool GLArrow::on_init() { Pointf3s vertices; @@ -2076,7 +2076,6 @@ bool GLCurvedArrow::on_init() m_volume.indexed_vertex_array.finalize_geometry(true); return true; } -#endif // !ENABLE_GCODE_VIEWER bool GLBed::on_init_from_file(const std::string& filename) { @@ -2108,5 +2107,6 @@ bool GLBed::on_init_from_file(const std::string& filename) return true; } +#endif // !ENABLE_GCODE_VIEWER } // namespace Slic3r diff --git a/src/slic3r/GUI/3DScene.hpp b/src/slic3r/GUI/3DScene.hpp index fd74cd491..d7bd0c1b3 100644 --- a/src/slic3r/GUI/3DScene.hpp +++ b/src/slic3r/GUI/3DScene.hpp @@ -599,6 +599,7 @@ private: GLVolumeWithIdAndZList volumes_to_render(const GLVolumePtrs& volumes, GLVolumeCollection::ERenderType type, const Transform3d& view_matrix, std::function filter_func = nullptr); +#if !ENABLE_GCODE_VIEWER class GLModel { protected: @@ -636,7 +637,6 @@ protected: virtual bool on_init_from_file(const std::string& filename) { return false; } }; -#if !ENABLE_GCODE_VIEWER class GLArrow : public GLModel { protected: @@ -653,13 +653,13 @@ public: protected: bool on_init() override; }; -#endif // !ENABLE_GCODE_VIEWER class GLBed : public GLModel { protected: bool on_init_from_file(const std::string& filename) override; }; +#endif // !ENABLE_GCODE_VIEWER struct _3DScene { diff --git a/src/slic3r/GUI/GCodeViewer.hpp b/src/slic3r/GUI/GCodeViewer.hpp index e7c620fc5..1d940b66a 100644 --- a/src/slic3r/GUI/GCodeViewer.hpp +++ b/src/slic3r/GUI/GCodeViewer.hpp @@ -219,7 +219,7 @@ public: { class Marker { - GL_Model m_model; + GLModel m_model; Transform3f m_world_transform; BoundingBoxf3 m_world_bounding_box; std::array m_color{ 1.0f, 1.0f, 1.0f, 1.0f }; diff --git a/src/slic3r/GUI/GLModel.cpp b/src/slic3r/GUI/GLModel.cpp index e5b6cbdcb..e738aa3c4 100644 --- a/src/slic3r/GUI/GLModel.cpp +++ b/src/slic3r/GUI/GLModel.cpp @@ -3,13 +3,17 @@ #include "3DScene.hpp" #include "libslic3r/TriangleMesh.hpp" +#include "libslic3r/Model.hpp" + +#include +#include #include namespace Slic3r { namespace GUI { -void GL_Model::init_from(const GLModelInitializationData& data) +void GLModel::init_from(const GLModelInitializationData& data) { assert(!data.positions.empty() && !data.triangles.empty()); assert(data.positions.size() == data.normals.size()); @@ -20,8 +24,9 @@ void GL_Model::init_from(const GLModelInitializationData& data) // 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)); + size_t offset = i * 6; + ::memcpy(static_cast(&vertices[offset]), static_cast(data.positions[i].data()), 3 * sizeof(float)); + ::memcpy(static_cast(&vertices[3 + offset]), static_cast(data.normals[i].data()), 3 * sizeof(float)); } // indices data @@ -41,34 +46,26 @@ void GL_Model::init_from(const GLModelInitializationData& data) send_to_gpu(vertices, indices); } -void GL_Model::init_from(const TriangleMesh& mesh) +void GLModel::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 + std::vector vertices = std::vector(18 * mesh.stl.stats.number_of_facets); + std::vector indices = std::vector(3 * mesh.stl.stats.number_of_facets); - // 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]); + unsigned int vertices_count = 0; + for (uint32_t i = 0; i < mesh.stl.stats.number_of_facets; ++i) { + const stl_facet& facet = mesh.stl.facet_start[i]; + for (uint32_t j = 0; j < 3; ++j) { + uint32_t offset = i * 18 + j * 6; + ::memcpy(static_cast(&vertices[offset]), static_cast(facet.vertex[j].data()), 3 * sizeof(float)); + ::memcpy(static_cast(&vertices[3 + offset]), static_cast(facet.normal.data()), 3 * sizeof(float)); } - 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)); + for (uint32_t j = 0; j < 3; ++j) { + indices[i * 3 + j] = vertices_count + j; + } + vertices_count += 3; } m_indices_count = static_cast(indices.size()); @@ -77,7 +74,32 @@ void GL_Model::init_from(const TriangleMesh& mesh) send_to_gpu(vertices, indices); } -void GL_Model::reset() +bool GLModel::init_from_file(const std::string& filename) +{ + if (!boost::filesystem::exists(filename)) + return false; + + if (!boost::algorithm::iends_with(filename, ".stl")) + return false; + + Model model; + try + { + model = Model::read_from_file(filename); + } + catch (std::exception&) + { + return false; + } + + init_from(model.mesh()); + + m_filename = filename; + + return true; +} + +void GLModel::reset() { // release gpu memory if (m_ibo_id > 0) { @@ -92,9 +114,10 @@ void GL_Model::reset() m_indices_count = 0; m_bounding_box = BoundingBoxf3(); + m_filename = std::string(); } -void GL_Model::render() const +void GLModel::render() const { if (m_vbo_id == 0 || m_ibo_id == 0) return; @@ -116,7 +139,7 @@ void GL_Model::render() const glsafe(::glBindBuffer(GL_ARRAY_BUFFER, 0)); } -void GL_Model::send_to_gpu(const std::vector& vertices, const std::vector& indices) +void GLModel::send_to_gpu(const std::vector& vertices, const std::vector& indices) { // vertex data -> send to gpu glsafe(::glGenBuffers(1, &m_vbo_id)); diff --git a/src/slic3r/GUI/GLModel.hpp b/src/slic3r/GUI/GLModel.hpp index a11073b19..0b4a69bdb 100644 --- a/src/slic3r/GUI/GLModel.hpp +++ b/src/slic3r/GUI/GLModel.hpp @@ -4,6 +4,7 @@ #include "libslic3r/Point.hpp" #include "libslic3r/BoundingBox.hpp" #include +#include namespace Slic3r { @@ -18,24 +19,28 @@ namespace GUI { std::vector triangles; }; - class GL_Model + class GLModel { unsigned int m_vbo_id{ 0 }; unsigned int m_ibo_id{ 0 }; size_t m_indices_count{ 0 }; BoundingBoxf3 m_bounding_box; + std::string m_filename; public: - virtual ~GL_Model() { reset(); } + virtual ~GLModel() { reset(); } void init_from(const GLModelInitializationData& data); void init_from(const TriangleMesh& mesh); + bool init_from_file(const std::string& filename); void reset(); void render() const; const BoundingBoxf3& get_bounding_box() const { return m_bounding_box; } + const std::string& get_filename() const { return m_filename; } + private: void send_to_gpu(const std::vector& vertices, const std::vector& indices); }; @@ -44,8 +49,7 @@ namespace GUI { // create an arrow with cylindrical stem and conical tip, with the given dimensions and resolution // the origin of the arrow is in the center of the stem cap // the arrow has its axis of symmetry along the Z axis and is pointing upward - GLModelInitializationData stilized_arrow(int resolution, float tip_radius, float tip_height, - float stem_radius, float stem_height); + GLModelInitializationData stilized_arrow(int resolution, float tip_radius, float tip_height, float stem_radius, float stem_height); // create an arrow whose stem is a quarter of circle, with the given dimensions and resolution // the origin of the arrow is in the center of the circle diff --git a/src/slic3r/GUI/Selection.hpp b/src/slic3r/GUI/Selection.hpp index 34024875b..c4ba30ed5 100644 --- a/src/slic3r/GUI/Selection.hpp +++ b/src/slic3r/GUI/Selection.hpp @@ -207,8 +207,8 @@ private: GLUquadricObj* m_quadric; #endif // ENABLE_RENDER_SELECTION_CENTER #if ENABLE_GCODE_VIEWER - GL_Model m_arrow; - GL_Model m_curved_arrow; + GLModel m_arrow; + GLModel m_curved_arrow; #else mutable GLArrow m_arrow; mutable GLCurvedArrow m_curved_arrow;