diff --git a/src/slic3r/GUI/3DBed.cpp b/src/slic3r/GUI/3DBed.cpp index 6c070ca99a..4ef8679603 100644 --- a/src/slic3r/GUI/3DBed.cpp +++ b/src/slic3r/GUI/3DBed.cpp @@ -5,15 +5,24 @@ #include "libslic3r/Polygon.hpp" #include "libslic3r/ClipperUtils.hpp" #include "libslic3r/BoundingBox.hpp" +#if ENABLE_GCODE_VIEWER +#include "libslic3r/Geometry.hpp" +#endif // ENABLE_GCODE_VIEWER #include "GUI_App.hpp" #include "PresetBundle.hpp" #include "GLCanvas3D.hpp" +#if ENABLE_GCODE_VIEWER +#include "3DScene.hpp" +#endif // ENABLE_GCODE_VIEWER #include #include #include +#if ENABLE_GCODE_VIEWER +#include +#endif // ENABLE_GCODE_VIEWER static const float GROUND_Z = -0.02f; @@ -119,13 +128,25 @@ const float* GeometryBuffer::get_vertices_data() const return (m_vertices.size() > 0) ? (const float*)m_vertices.data() : nullptr; } +#if ENABLE_GCODE_VIEWER +const float Bed3D::Axes::DefaultStemRadius = 0.5f; +const float Bed3D::Axes::DefaultStemLength = 25.0f; +const float Bed3D::Axes::DefaultTipRadius = 2.5f * Bed3D::Axes::DefaultStemRadius; +const float Bed3D::Axes::DefaultTipLength = 5.0f; +#else const double Bed3D::Axes::Radius = 0.5; const double Bed3D::Axes::ArrowBaseRadius = 2.5 * Bed3D::Axes::Radius; const double Bed3D::Axes::ArrowLength = 5.0; +#endif // ENABLE_GCODE_VIEWER +#if ENABLE_GCODE_VIEWER +void Bed3D::Axes::set_stem_length(float length) +{ + m_stem_length = length; + m_arrow.reset(); +} +#else Bed3D::Axes::Axes() -: origin(Vec3d::Zero()) -, length(25.0 * Vec3d::Ones()) { m_quadric = ::gluNewQuadric(); if (m_quadric != nullptr) @@ -137,9 +158,46 @@ Bed3D::Axes::~Axes() if (m_quadric != nullptr) ::gluDeleteQuadric(m_quadric); } +#endif // ENABLE_GCODE_VIEWER void Bed3D::Axes::render() const { +#if ENABLE_GCODE_VIEWER + auto render_axis = [this](const Transform3f& transform, GLint color_id, const std::array& color) { + if (color_id >= 0) + glsafe(::glUniform4fv(color_id, 1, (const GLfloat*)color.data())); + + glsafe(::glPushMatrix()); + glsafe(::glMultMatrixf(transform.data())); + m_arrow.render(); + glsafe(::glPopMatrix()); + }; + + m_arrow.init_from(stilized_arrow(16, DefaultTipRadius, DefaultTipLength, DefaultStemRadius, m_stem_length)); + 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"; + + if (!m_shader.is_initialized()) + return; + + glsafe(::glEnable(GL_DEPTH_TEST)); + + m_shader.start_using(); + GLint color_id = ::glGetUniformLocation(m_shader.get_shader_program_id(), "uniform_color"); + + // x axis + render_axis(Geometry::assemble_transform(m_origin, { 0.0, 0.5 * M_PI, 0.0f }).cast(), color_id, { 0.75f, 0.0f, 0.0f, 1.0f }); + + // y axis + render_axis(Geometry::assemble_transform(m_origin, { -0.5 * M_PI, 0.0, 0.0f }).cast(), color_id, { 0.0f, 0.75f, 0.0f, 1.0f }); + + // z axis + render_axis(Geometry::assemble_transform(m_origin).cast(), color_id, { 0.0f, 0.0f, 0.75f, 1.0f }); + + m_shader.stop_using(); + + glsafe(::glDisable(GL_DEPTH_TEST)); +#else if (m_quadric == nullptr) return; @@ -171,8 +229,10 @@ void Bed3D::Axes::render() const glsafe(::glDisable(GL_LIGHTING)); glsafe(::glDisable(GL_DEPTH_TEST)); +#endif // !ENABLE_GCODE_VIEWER } +#if !ENABLE_GCODE_VIEWER void Bed3D::Axes::render_axis(double length) const { ::gluQuadricOrientation(m_quadric, GLU_OUTSIDE); @@ -185,6 +245,7 @@ void Bed3D::Axes::render_axis(double length) const ::gluQuadricOrientation(m_quadric, GLU_INSIDE); ::gluDisk(m_quadric, 0.0, ArrowBaseRadius, 32, 1); } +#endif // !ENABLE_GCODE_VIEWER Bed3D::Bed3D() : m_type(Custom) @@ -242,8 +303,13 @@ bool Bed3D::set_shape(const Pointfs& shape, const std::string& custom_texture, c m_model.reset(); // Set the origin and size for rendering the coordinate system axes. +#if ENABLE_GCODE_VIEWER + m_axes.set_origin({ 0.0, 0.0, static_cast(GROUND_Z) }); + m_axes.set_stem_length(0.1f * static_cast(m_bounding_box.max_size())); +#else m_axes.origin = Vec3d(0.0, 0.0, (double)GROUND_Z); m_axes.length = 0.1 * m_bounding_box.max_size() * Vec3d::Ones(); +#endif // ENABLE_GCODE_VIEWER // Let the calee to update the UI. return true; @@ -290,7 +356,11 @@ void Bed3D::calc_bounding_boxes() const m_extended_bounding_box = m_bounding_box; // 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 // extend to contain model, if any if (!m_model.get_filename().empty()) diff --git a/src/slic3r/GUI/3DBed.hpp b/src/slic3r/GUI/3DBed.hpp index abdfca1fe0..440468233c 100644 --- a/src/slic3r/GUI/3DBed.hpp +++ b/src/slic3r/GUI/3DBed.hpp @@ -4,11 +4,16 @@ #include "GLTexture.hpp" #include "3DScene.hpp" #include "GLShader.hpp" +#if ENABLE_GCODE_VIEWER +#include "GLModel.hpp" +#endif // ENABLE_GCODE_VIEWER #include +#if !ENABLE_GCODE_VIEWER class GLUquadric; typedef class GLUquadric GLUquadricObj; +#endif // !ENABLE_GCODE_VIEWER namespace Slic3r { namespace GUI { @@ -45,22 +50,50 @@ public: class Bed3D { +#if ENABLE_GCODE_VIEWER + class Axes + { + static const float DefaultStemRadius; + static const float DefaultStemLength; + static const float DefaultTipRadius; + static const float DefaultTipLength; +#else struct Axes { static const double Radius; static const double ArrowBaseRadius; static const double ArrowLength; +#endif // ENABLE_GCODE_VIEWER + +#if ENABLE_GCODE_VIEWER + Vec3d m_origin{ Vec3d::Zero() }; + float m_stem_length{ DefaultStemLength }; + mutable GL_Model m_arrow; + mutable Shader m_shader; + + public: +#else Vec3d origin; Vec3d length; GLUquadricObj* m_quadric; +#endif // ENABLE_GCODE_VIEWER +#if !ENABLE_GCODE_VIEWER Axes(); ~Axes(); +#endif // !ENABLE_GCODE_VIEWER +#if ENABLE_GCODE_VIEWER + 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; } +#endif // ENABLE_GCODE_VIEWER void render() const; +#if !ENABLE_GCODE_VIEWER private: void render_axis(double length) const; +#endif // !ENABLE_GCODE_VIEWER }; public: diff --git a/src/slic3r/GUI/GCodeViewer.cpp b/src/slic3r/GUI/GCodeViewer.cpp index ad3985c625..525a2fd5a1 100644 --- a/src/slic3r/GUI/GCodeViewer.cpp +++ b/src/slic3r/GUI/GCodeViewer.cpp @@ -147,7 +147,7 @@ GCodeViewer::Color GCodeViewer::Extrusions::Range::get_color_at(float value) con void GCodeViewer::SequentialView::Marker::init() { - m_model.init_from(stilized_arrow(16, 0.5f, 1.0f, 0.25f, 2.0f)); + m_model.init_from(stilized_arrow(16, 2.0f, 4.0f, 1.0f, 8.0f)); init_shader(); } @@ -320,7 +320,7 @@ void GCodeViewer::render() const glsafe(::glEnable(GL_DEPTH_TEST)); render_toolpaths(); - m_sequential_view.marker.set_world_transform(Geometry::assemble_transform(m_sequential_view.current_position.cast() + 0.5 * Vec3d::UnitZ(), { 0.0, 0.0, 0.0 }, { 4.0, 4.0, 4.0 }, { 1.0, 1.0, 1.0 }).cast()); + m_sequential_view.marker.set_world_transform(Geometry::assemble_transform(m_sequential_view.current_position.cast() + (0.5 + 12.0) * Vec3d::UnitZ(), { M_PI, 0.0, 0.0 }).cast()); m_sequential_view.marker.render(); render_shells(); render_legend(); @@ -437,6 +437,8 @@ void GCodeViewer::load_toolpaths(const GCodeProcessor::Result& gcode_result) ::memcpy(static_cast(&vertices_data[i * 3]), static_cast(move.position.data()), 3 * sizeof(float)); } + m_bounding_box.merge(m_bounding_box.max + m_sequential_view.marker.get_bounding_box().max[2] * Vec3d::UnitZ()); + #if ENABLE_GCODE_VIEWER_STATISTICS m_statistics.vertices_size = SLIC3R_STDVEC_MEMSIZE(vertices_data, float); m_statistics.vertices_gpu_size = vertices_data.size() * sizeof(float); diff --git a/src/slic3r/GUI/GCodeViewer.hpp b/src/slic3r/GUI/GCodeViewer.hpp index 44f23b2852..6f3ca47dba 100644 --- a/src/slic3r/GUI/GCodeViewer.hpp +++ b/src/slic3r/GUI/GCodeViewer.hpp @@ -162,6 +162,8 @@ class GCodeViewer public: void init(); + const BoundingBoxf3& get_bounding_box() const { return m_model.get_bounding_box(); } + void set_world_transform(const Transform3f& transform) { m_world_transform = transform; } void set_color(const std::array& color) { m_color = color; } diff --git a/src/slic3r/GUI/GLModel.cpp b/src/slic3r/GUI/GLModel.cpp index 336c699371..4b2ce4e9e9 100644 --- a/src/slic3r/GUI/GLModel.cpp +++ b/src/slic3r/GUI/GLModel.cpp @@ -9,12 +9,14 @@ namespace Slic3r { namespace GUI { -bool GL_Model::init_from(const GLModelInitializationData& data) +void GL_Model::init_from(const GLModelInitializationData& data) { + assert(!data.positions.empty() && !data.triangles.empty()); assert(data.positions.size() == data.normals.size()); - reset(); + 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()); @@ -32,19 +34,22 @@ bool GL_Model::init_from(const GLModelInitializationData& data) } 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); - - return true; } -bool GL_Model::init_from(const TriangleMesh& mesh) +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(); }; - reset(); + 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 @@ -68,10 +73,9 @@ bool GL_Model::init_from(const TriangleMesh& mesh) } m_indices_count = static_cast(indices.size()); + m_bounding_box = mesh.bounding_box(); send_to_gpu(vertices, indices); - - return true; } void GL_Model::reset() @@ -88,6 +92,7 @@ void GL_Model::reset() } m_indices_count = 0; + m_bounding_box = BoundingBoxf3(); } void GL_Model::render() const @@ -142,12 +147,14 @@ GLModelInitializationData stilized_arrow(int resolution, float tip_radius, float sines[i] = -::sin(angle); } + float total_height = tip_height + stem_height; + // tip vertices/normals - data.positions.emplace_back(0.0f, 0.0f, 0.0f); - data.normals.emplace_back(-Vec3f::UnitZ()); + 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], tip_height); + data.positions.emplace_back(tip_radius * sines[i], tip_radius * cosines[i], stem_height); data.normals.emplace_back(sines[i], cosines[i], 0.0f); } @@ -155,21 +162,21 @@ GLModelInitializationData stilized_arrow(int resolution, float tip_radius, float for (int i = 0; i < resolution; ++i) { int v3 = (i < resolution - 1) ? i + 2 : 1; - data.triangles.emplace_back(0, v3, i + 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], tip_height); - data.normals.emplace_back(Vec3f::UnitZ()); + 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], tip_height); - data.normals.emplace_back(Vec3f::UnitZ()); + data.positions.emplace_back(stem_radius * sines[i], stem_radius * cosines[i], stem_height); + data.normals.emplace_back(-Vec3f::UnitZ()); } // tip cap triangles @@ -177,23 +184,21 @@ GLModelInitializationData stilized_arrow(int resolution, float tip_radius, float { 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); + 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], tip_height); + data.positions.emplace_back(stem_radius * sines[i], stem_radius * cosines[i], stem_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.positions.emplace_back(stem_radius * sines[i], stem_radius * cosines[i], 0.0f); data.normals.emplace_back(sines[i], cosines[i], 0.0f); } @@ -202,24 +207,24 @@ GLModelInitializationData stilized_arrow(int resolution, float tip_radius, float { 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); + 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, total_height); - data.normals.emplace_back(Vec3f::UnitZ()); + 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], total_height); - data.normals.emplace_back(Vec3f::UnitZ()); + 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, i + 5 * resolution + 2, v3); + data.triangles.emplace_back(5 * resolution + 1, v3, i + 5 * resolution + 2); } return data; diff --git a/src/slic3r/GUI/GLModel.hpp b/src/slic3r/GUI/GLModel.hpp index 18e8bafbdd..7b135ada6b 100644 --- a/src/slic3r/GUI/GLModel.hpp +++ b/src/slic3r/GUI/GLModel.hpp @@ -2,6 +2,7 @@ #define slic3r_GLModel_hpp_ #include "libslic3r/Point.hpp" +#include "libslic3r/BoundingBox.hpp" #include namespace Slic3r { @@ -23,22 +24,26 @@ namespace GUI { unsigned int m_ibo_id{ 0 }; size_t m_indices_count{ 0 }; + BoundingBoxf3 m_bounding_box; + public: virtual ~GL_Model() { reset(); } - bool init_from(const GLModelInitializationData& data); - bool init_from(const TriangleMesh& mesh); + void init_from(const GLModelInitializationData& data); + void init_from(const TriangleMesh& mesh); void reset(); void render() const; + const BoundingBoxf3& get_bounding_box() const { return m_bounding_box; } + 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 + // 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);