1 #ifndef slic3r_GCodeViewer_hpp_
2 #define slic3r_GCodeViewer_hpp_
3 
4 #include "3DScene.hpp"
5 #include "libslic3r/GCode/GCodeProcessor.hpp"
6 #include "GLModel.hpp"
7 
8 #include <cstdint>
9 #include <float.h>
10 #include <set>
11 #include <unordered_set>
12 
13 namespace Slic3r {
14 
15 class Print;
16 class TriangleMesh;
17 
18 namespace GUI {
19 
20 class GCodeViewer
21 {
22 #if ENABLE_SPLITTED_VERTEX_BUFFER
23     using IBufferType = unsigned short;
24 #endif // ENABLE_SPLITTED_VERTEX_BUFFER
25     using Color = std::array<float, 3>;
26     using VertexBuffer = std::vector<float>;
27 #if ENABLE_SPLITTED_VERTEX_BUFFER
28     using MultiVertexBuffer = std::vector<VertexBuffer>;
29     using IndexBuffer = std::vector<IBufferType>;
30 #else
31     using IndexBuffer = std::vector<unsigned int>;
32 #endif // ENABLE_SPLITTED_VERTEX_BUFFER
33     using MultiIndexBuffer = std::vector<IndexBuffer>;
34 
35     static const std::vector<Color> Extrusion_Role_Colors;
36     static const std::vector<Color> Options_Colors;
37     static const std::vector<Color> Travel_Colors;
38     static const Color              Wipe_Color;
39     static const std::vector<Color> Range_Colors;
40 
41     enum class EOptionsColors : unsigned char
42     {
43         Retractions,
44         Unretractions,
45         ToolChanges,
46         ColorChanges,
47         PausePrints,
48         CustomGCodes
49     };
50 
51     // vbo buffer containing vertices data used to render a specific toolpath type
52     struct VBuffer
53     {
54         enum class EFormat : unsigned char
55         {
56             // vertex format: 3 floats -> position.x|position.y|position.z
57             Position,
58             // vertex format: 4 floats -> position.x|position.y|position.z|normal.x
59             PositionNormal1,
60             // vertex format: 6 floats -> position.x|position.y|position.z|normal.x|normal.y|normal.z
61             PositionNormal3
62         };
63 
64         EFormat format{ EFormat::Position };
65 #if ENABLE_SPLITTED_VERTEX_BUFFER
66         // vbos id
67         std::vector<unsigned int> vbos;
68         // sizes of the buffers, in bytes, used in export to obj
69         std::vector<size_t> sizes;
70 #else
71         // vbo id
72         unsigned int id{ 0 };
73 #endif // ENABLE_SPLITTED_VERTEX_BUFFER
74         // count of vertices, updated after data are sent to gpu
75         size_t count{ 0 };
76 
data_size_bytesSlic3r::GUI::GCodeViewer::VBuffer77         size_t data_size_bytes() const { return count * vertex_size_bytes(); }
78 #if ENABLE_SPLITTED_VERTEX_BUFFER
79         // We set 65536 as max count of vertices inside a vertex buffer to allow
80         // to use unsigned short in place of unsigned int for indices in the index buffer, to save memory
max_size_bytesSlic3r::GUI::GCodeViewer::VBuffer81         size_t max_size_bytes() const { return 65536 * vertex_size_bytes(); }
82 #endif // ENABLE_SPLITTED_VERTEX_BUFFER
83 
vertex_size_floatsSlic3r::GUI::GCodeViewer::VBuffer84         size_t vertex_size_floats() const { return position_size_floats() + normal_size_floats(); }
vertex_size_bytesSlic3r::GUI::GCodeViewer::VBuffer85         size_t vertex_size_bytes() const { return vertex_size_floats() * sizeof(float); }
86 
position_offset_floatsSlic3r::GUI::GCodeViewer::VBuffer87         size_t position_offset_floats() const { return 0; }
position_offset_sizeSlic3r::GUI::GCodeViewer::VBuffer88         size_t position_offset_size() const { return position_offset_floats() * sizeof(float); }
position_size_floatsSlic3r::GUI::GCodeViewer::VBuffer89         size_t position_size_floats() const {
90             switch (format)
91             {
92             case EFormat::Position:
93             case EFormat::PositionNormal3: { return 3; }
94             case EFormat::PositionNormal1: { return 4; }
95             default:                       { return 0; }
96             }
97         }
position_size_bytesSlic3r::GUI::GCodeViewer::VBuffer98         size_t position_size_bytes() const { return position_size_floats() * sizeof(float); }
99 
normal_offset_floatsSlic3r::GUI::GCodeViewer::VBuffer100         size_t normal_offset_floats() const {
101             switch (format)
102             {
103             case EFormat::Position:
104             case EFormat::PositionNormal1: { return 0; }
105             case EFormat::PositionNormal3: { return 3; }
106             default:                       { return 0; }
107             }
108         }
normal_offset_sizeSlic3r::GUI::GCodeViewer::VBuffer109         size_t normal_offset_size() const { return normal_offset_floats() * sizeof(float); }
normal_size_floatsSlic3r::GUI::GCodeViewer::VBuffer110         size_t normal_size_floats() const {
111             switch (format)
112             {
113             default:
114             case EFormat::Position:
115             case EFormat::PositionNormal1: { return 0; }
116             case EFormat::PositionNormal3: { return 3; }
117             }
118         }
normal_size_bytesSlic3r::GUI::GCodeViewer::VBuffer119         size_t normal_size_bytes() const { return normal_size_floats() * sizeof(float); }
120 
121         void reset();
122     };
123 
124     // ibo buffer containing indices data (for lines/triangles) used to render a specific toolpath type
125     struct IBuffer
126     {
127 #if ENABLE_SPLITTED_VERTEX_BUFFER
128         // id of the associated vertex buffer
129         unsigned int vbo{ 0 };
130         // ibo id
131         unsigned int ibo{ 0 };
132 #else
133         // ibo id
134         unsigned int id{ 0 };
135 #endif // ENABLE_SPLITTED_VERTEX_BUFFER
136         // count of indices, updated after data are sent to gpu
137         size_t count{ 0 };
138 
139         void reset();
140     };
141 
142     // Used to identify different toolpath sub-types inside a IBuffer
143     struct Path
144     {
145         struct Endpoint
146         {
147             // index of the buffer in the multibuffer vector
148             // the buffer type may change:
149             // it is the vertex buffer while extracting vertices data,
150             // the index buffer while extracting indices data
151             unsigned int b_id{ 0 };
152             // index into the buffer
153             size_t i_id{ 0 };
154             // move id
155             size_t s_id{ 0 };
156             Vec3f position{ Vec3f::Zero() };
157         };
158 
159 #if ENABLE_SPLITTED_VERTEX_BUFFER
160         struct Sub_Path
161         {
162             Endpoint first;
163             Endpoint last;
164 
containsSlic3r::GUI::GCodeViewer::Path::Sub_Path165             bool contains(size_t s_id) const {
166                 return first.s_id <= s_id && s_id <= last.s_id;
167             }
168         };
169 #endif // ENABLE_SPLITTED_VERTEX_BUFFER
170 
171         EMoveType type{ EMoveType::Noop };
172         ExtrusionRole role{ erNone };
173 #if !ENABLE_SPLITTED_VERTEX_BUFFER
174         Endpoint first;
175         Endpoint last;
176 #endif // !ENABLE_SPLITTED_VERTEX_BUFFER
177         float delta_extruder{ 0.0f };
178         float height{ 0.0f };
179         float width{ 0.0f };
180         float feedrate{ 0.0f };
181         float fan_speed{ 0.0f };
182         float volumetric_rate{ 0.0f };
183         unsigned char extruder_id{ 0 };
184         unsigned char cp_color_id{ 0 };
185 #if ENABLE_SPLITTED_VERTEX_BUFFER
186         std::vector<Sub_Path> sub_paths;
187 #endif // ENABLE_SPLITTED_VERTEX_BUFFER
188 
189         bool matches(const GCodeProcessor::MoveVertex& move) const;
190 #if ENABLE_SPLITTED_VERTEX_BUFFER
vertices_countSlic3r::GUI::GCodeViewer::Path191         size_t vertices_count() const {
192             return sub_paths.empty() ? 0 : sub_paths.back().last.s_id - sub_paths.front().first.s_id + 1;
193         }
containsSlic3r::GUI::GCodeViewer::Path194         bool contains(size_t s_id) const {
195             return sub_paths.empty() ? false : sub_paths.front().first.s_id <= s_id && s_id <= sub_paths.back().last.s_id;
196         }
get_id_of_sub_path_containingSlic3r::GUI::GCodeViewer::Path197         int get_id_of_sub_path_containing(size_t s_id) const {
198             if (sub_paths.empty())
199                 return -1;
200             else {
201                 for (int i = 0; i < static_cast<int>(sub_paths.size()); ++i) {
202                     if (sub_paths[i].contains(s_id))
203                         return i;
204                 }
205                 return -1;
206             }
207         }
add_sub_pathSlic3r::GUI::GCodeViewer::Path208         void add_sub_path(const GCodeProcessor::MoveVertex& move, unsigned int b_id, size_t i_id, size_t s_id) {
209             Endpoint endpoint = { b_id, i_id, s_id, move.position };
210             sub_paths.push_back({ endpoint , endpoint });
211         }
212 #else
vertices_countSlic3r::GUI::GCodeViewer::Path213         size_t vertices_count() const { return last.s_id - first.s_id + 1; }
containsSlic3r::GUI::GCodeViewer::Path214         bool contains(size_t id) const { return first.s_id <= id && id <= last.s_id; }
215 #endif // ENABLE_SPLITTED_VERTEX_BUFFER
216     };
217 
218     // Used to batch the indices needed to render the paths
219     struct RenderPath
220     {
221 #if ENABLE_REDUCED_TOOLPATHS_SEGMENT_CAPS
222         // Index of the parent tbuffer
223         unsigned char               tbuffer_id;
224 #endif // ENABLE_REDUCED_TOOLPATHS_SEGMENT_CAPS
225         // Render path property
226         Color                       color;
227         // Index of the buffer in TBuffer::indices
228         unsigned int                ibuffer_id;
229         // Render path content
230         // Index of the path in TBuffer::paths
231         unsigned int                path_id;
232         std::vector<unsigned int>   sizes;
233         std::vector<size_t>         offsets; // use size_t because we need an unsigned integer whose size matches pointer's size (used in the call glMultiDrawElements())
234 #if ENABLE_REDUCED_TOOLPATHS_SEGMENT_CAPS
containsSlic3r::GUI::GCodeViewer::RenderPath235         bool contains(size_t offset) const {
236             for (size_t i = 0; i < offsets.size(); ++i) {
237                 if (offsets[i] <= offset && offset <= offsets[i] + static_cast<size_t>(sizes[i] * sizeof(IBufferType)))
238                     return true;
239             }
240             return false;
241         }
242 #endif // ENABLE_REDUCED_TOOLPATHS_SEGMENT_CAPS
243     };
244 //    // for unordered_set implementation of render_paths
245 //    struct RenderPathPropertyHash {
246 //        size_t operator() (const RenderPath &p) const {
247 //            // Convert the RGB value to an integer hash.
248 ////            return (size_t(int(p.color[0] * 255) + 255 * int(p.color[1] * 255) + (255 * 255) * int(p.color[2] * 255)) * 7919) ^ size_t(p.ibuffer_id);
249 //            return size_t(int(p.color[0] * 255) + 255 * int(p.color[1] * 255) + (255 * 255) * int(p.color[2] * 255)) ^ size_t(p.ibuffer_id);
250 //        }
251 //    };
252     struct RenderPathPropertyLower {
operator ()Slic3r::GUI::GCodeViewer::RenderPathPropertyLower253         bool operator() (const RenderPath &l, const RenderPath &r) const {
254 #if ENABLE_REDUCED_TOOLPATHS_SEGMENT_CAPS
255             if (l.tbuffer_id < r.tbuffer_id)
256                 return true;
257 #endif // ENABLE_REDUCED_TOOLPATHS_SEGMENT_CAPS
258             for (int i = 0; i < 3; ++i) {
259                 if (l.color[i] < r.color[i])
260                     return true;
261                 else if (l.color[i] > r.color[i])
262                     return false;
263             }
264             return l.ibuffer_id < r.ibuffer_id;
265         }
266     };
267     struct RenderPathPropertyEqual {
operator ()Slic3r::GUI::GCodeViewer::RenderPathPropertyEqual268         bool operator() (const RenderPath &l, const RenderPath &r) const {
269 #if ENABLE_REDUCED_TOOLPATHS_SEGMENT_CAPS
270             return l.tbuffer_id == r.tbuffer_id && l.ibuffer_id == r.ibuffer_id && l.color == r.color;
271 #else
272             return l.color == r.color && l.ibuffer_id == r.ibuffer_id;
273 #endif // ENABLE_REDUCED_TOOLPATHS_SEGMENT_CAPS
274         }
275     };
276 
277     // buffer containing data for rendering a specific toolpath type
278     struct TBuffer
279     {
280         enum class ERenderPrimitiveType : unsigned char
281         {
282             Point,
283             Line,
284             Triangle
285         };
286 
287         ERenderPrimitiveType render_primitive_type;
288         VBuffer vertices;
289         std::vector<IBuffer> indices;
290 
291         std::string shader;
292         std::vector<Path> paths;
293         // std::set seems to perform significantly better, at least on Windows.
294 //        std::unordered_set<RenderPath, RenderPathPropertyHash, RenderPathPropertyEqual> render_paths;
295         std::set<RenderPath, RenderPathPropertyLower> render_paths;
296         bool visible{ false };
297 
298         void reset();
299 
300         // b_id index of buffer contained in this->indices
301         // i_id index of first index contained in this->indices[b_id]
302         // s_id index of first vertex contained in this->vertices
303         void add_path(const GCodeProcessor::MoveVertex& move, unsigned int b_id, size_t i_id, size_t s_id);
304 
305 #if ENABLE_SPLITTED_VERTEX_BUFFER
max_vertices_per_segmentSlic3r::GUI::GCodeViewer::TBuffer306         unsigned int max_vertices_per_segment() const {
307             switch (render_primitive_type)
308             {
309             case ERenderPrimitiveType::Point:    { return 1; }
310             case ERenderPrimitiveType::Line:     { return 2; }
311             case ERenderPrimitiveType::Triangle: { return 8; }
312             default:                             { return 0; }
313             }
314         }
315 
max_vertices_per_segment_size_floatsSlic3r::GUI::GCodeViewer::TBuffer316         size_t max_vertices_per_segment_size_floats() const { return vertices.vertex_size_floats() * static_cast<size_t>(max_vertices_per_segment()); }
max_vertices_per_segment_size_bytesSlic3r::GUI::GCodeViewer::TBuffer317         size_t max_vertices_per_segment_size_bytes() const { return max_vertices_per_segment_size_floats() * sizeof(float); }
318 #endif // ENABLE_SPLITTED_VERTEX_BUFFER
indices_per_segmentSlic3r::GUI::GCodeViewer::TBuffer319         unsigned int indices_per_segment() const {
320             switch (render_primitive_type)
321             {
322             case ERenderPrimitiveType::Point:    { return 1; }
323             case ERenderPrimitiveType::Line:     { return 2; }
324 #if ENABLE_REDUCED_TOOLPATHS_SEGMENT_CAPS
325             case ERenderPrimitiveType::Triangle: { return 30; } // 3 indices x 10 triangles
326 #else
327             case ERenderPrimitiveType::Triangle: { return 42; } // 3 indices x 14 triangles
328 #endif // ENABLE_REDUCED_TOOLPATHS_SEGMENT_CAPS
329             default:                             { return 0; }
330             }
331         }
332 #if ENABLE_SPLITTED_VERTEX_BUFFER
indices_per_segment_size_bytesSlic3r::GUI::GCodeViewer::TBuffer333         size_t indices_per_segment_size_bytes() const { return static_cast<size_t>(indices_per_segment() * sizeof(IBufferType)); }
334 #endif // ENABLE_SPLITTED_VERTEX_BUFFER
335 #if ENABLE_REDUCED_TOOLPATHS_SEGMENT_CAPS
max_indices_per_segmentSlic3r::GUI::GCodeViewer::TBuffer336         unsigned int max_indices_per_segment() const {
337             switch (render_primitive_type)
338             {
339             case ERenderPrimitiveType::Point:    { return 1; }
340             case ERenderPrimitiveType::Line:     { return 2; }
341             case ERenderPrimitiveType::Triangle: { return 36; } // 3 indices x 12 triangles
342             default:                             { return 0; }
343             }
344         }
max_indices_per_segment_size_bytesSlic3r::GUI::GCodeViewer::TBuffer345         size_t max_indices_per_segment_size_bytes() const { return max_indices_per_segment() * sizeof(IBufferType); }
346 #endif // ENABLE_REDUCED_TOOLPATHS_SEGMENT_CAPS
347 
348 #if ENABLE_SPLITTED_VERTEX_BUFFER
has_dataSlic3r::GUI::GCodeViewer::TBuffer349         bool has_data() const {
350             return !vertices.vbos.empty() && vertices.vbos.front() != 0 && !indices.empty() && indices.front().ibo != 0;
351         }
352 #else
start_segment_vertex_offsetSlic3r::GUI::GCodeViewer::TBuffer353         unsigned int start_segment_vertex_offset() const { return 0; }
end_segment_vertex_offsetSlic3r::GUI::GCodeViewer::TBuffer354         unsigned int end_segment_vertex_offset() const {
355             switch (render_primitive_type)
356             {
357             case ERenderPrimitiveType::Point: { return 0; }
358             case ERenderPrimitiveType::Line: { return 1; }
359             case ERenderPrimitiveType::Triangle: { return 36; } // 1st vertex of 13th triangle
360             default: { return 0; }
361             }
362         }
363 
has_dataSlic3r::GUI::GCodeViewer::TBuffer364         bool has_data() const { return vertices.id != 0 && !indices.empty() && indices.front().id != 0; }
365 #endif // ENABLE_SPLITTED_VERTEX_BUFFER
366     };
367 
368     // helper to render shells
369     struct Shells
370     {
371         GLVolumeCollection volumes;
372         bool visible{ false };
373     };
374 
375     // helper to render extrusion paths
376     struct Extrusions
377     {
378         struct Range
379         {
380             float min;
381             float max;
382             unsigned int count;
383 
RangeSlic3r::GUI::GCodeViewer::Extrusions::Range384             Range() { reset(); }
385 
update_fromSlic3r::GUI::GCodeViewer::Extrusions::Range386             void update_from(const float value) {
387                 if (value != max && value != min)
388                     ++count;
389                 min = std::min(min, value);
390                 max = std::max(max, value);
391             }
resetSlic3r::GUI::GCodeViewer::Extrusions::Range392             void reset() { min = FLT_MAX; max = -FLT_MAX; count = 0; }
393 
step_sizeSlic3r::GUI::GCodeViewer::Extrusions::Range394             float step_size() const { return (max - min) / (static_cast<float>(Range_Colors.size()) - 1.0f); }
395             Color get_color_at(float value) const;
396         };
397 
398         struct Ranges
399         {
400             // Color mapping by layer height.
401             Range height;
402             // Color mapping by extrusion width.
403             Range width;
404             // Color mapping by feedrate.
405             Range feedrate;
406             // Color mapping by fan speed.
407             Range fan_speed;
408             // Color mapping by volumetric extrusion rate.
409             Range volumetric_rate;
410 
resetSlic3r::GUI::GCodeViewer::Extrusions::Ranges411             void reset() {
412                 height.reset();
413                 width.reset();
414                 feedrate.reset();
415                 fan_speed.reset();
416                 volumetric_rate.reset();
417             }
418         };
419 
420         unsigned int role_visibility_flags{ 0 };
421         Ranges ranges;
422 
reset_role_visibility_flagsSlic3r::GUI::GCodeViewer::Extrusions423         void reset_role_visibility_flags() {
424             role_visibility_flags = 0;
425             for (unsigned int i = 0; i < erCount; ++i) {
426                 role_visibility_flags |= 1 << i;
427             }
428         }
429 
reset_rangesSlic3r::GUI::GCodeViewer::Extrusions430         void reset_ranges() { ranges.reset(); }
431     };
432 
433     class Layers
434     {
435     public:
436         struct Endpoints
437         {
438             size_t first{ 0 };
439             size_t last{ 0 };
440 
441 #if ENABLE_SPLITTED_VERTEX_BUFFER
operator ==Slic3r::GUI::GCodeViewer::Layers::Endpoints442             bool operator == (const Endpoints& other) const {
443                 return first == other.first && last == other.last;
444             }
445 #endif // ENABLE_SPLITTED_VERTEX_BUFFER
446         };
447 
448     private:
449         std::vector<double> m_zs;
450         std::vector<Endpoints> m_endpoints;
451 
452     public:
append(double z,Endpoints endpoints)453         void append(double z, Endpoints endpoints) {
454             m_zs.emplace_back(z);
455             m_endpoints.emplace_back(endpoints);
456         }
457 
reset()458         void reset() {
459             m_zs = std::vector<double>();
460             m_endpoints = std::vector<Endpoints>();
461         }
462 
size() const463         size_t size() const { return m_zs.size(); }
empty() const464         bool empty() const { return m_zs.empty(); }
get_zs() const465         const std::vector<double>& get_zs() const { return m_zs; }
get_endpoints() const466         const std::vector<Endpoints>& get_endpoints() const { return m_endpoints; }
get_endpoints()467         std::vector<Endpoints>& get_endpoints() { return m_endpoints; }
get_z_at(unsigned int id) const468         double get_z_at(unsigned int id) const { return (id < m_zs.size()) ? m_zs[id] : 0.0; }
get_endpoints_at(unsigned int id) const469         Endpoints get_endpoints_at(unsigned int id) const { return (id < m_endpoints.size()) ? m_endpoints[id] : Endpoints(); }
470 
471 #if ENABLE_SPLITTED_VERTEX_BUFFER
operator !=(const Layers & other) const472         bool operator != (const Layers& other) const {
473             if (m_zs != other.m_zs)
474                 return true;
475             if (!(m_endpoints == other.m_endpoints))
476                 return true;
477 
478             return false;
479         }
480 #endif // ENABLE_SPLITTED_VERTEX_BUFFER
481     };
482 
483 #if ENABLE_REDUCED_TOOLPATHS_SEGMENT_CAPS
484     // used to render the toolpath caps of the current sequential range
485     // (i.e. when sliding on the horizontal slider)
486     struct SequentialRangeCap
487     {
488         TBuffer* buffer{ nullptr };
489         unsigned int ibo{ 0 };
490         unsigned int vbo{ 0 };
491         Color color;
492 
493         ~SequentialRangeCap();
is_renderableSlic3r::GUI::GCodeViewer::SequentialRangeCap494         bool is_renderable() const { return buffer != nullptr; }
495         void reset();
indices_countSlic3r::GUI::GCodeViewer::SequentialRangeCap496         size_t indices_count() const { return 6; }
497     };
498 #endif // ENABLE_REDUCED_TOOLPATHS_SEGMENT_CAPS
499 
500 #if ENABLE_GCODE_VIEWER_STATISTICS
501     struct Statistics
502     {
503         // time
504         int64_t results_time{ 0 };
505         int64_t load_time{ 0 };
506         int64_t load_vertices{ 0 };
507         int64_t smooth_vertices{ 0 };
508         int64_t load_indices{ 0 };
509         int64_t refresh_time{ 0 };
510         int64_t refresh_paths_time{ 0 };
511         // opengl calls
512         int64_t gl_multi_points_calls_count{ 0 };
513         int64_t gl_multi_lines_calls_count{ 0 };
514         int64_t gl_multi_triangles_calls_count{ 0 };
515 #if ENABLE_REDUCED_TOOLPATHS_SEGMENT_CAPS
516         int64_t gl_triangles_calls_count{ 0 };
517 #endif // ENABLE_REDUCED_TOOLPATHS_SEGMENT_CAPS
518         // memory
519         int64_t results_size{ 0 };
520         int64_t total_vertices_gpu_size{ 0 };
521         int64_t total_indices_gpu_size{ 0 };
522         int64_t max_vbuffer_gpu_size{ 0 };
523         int64_t max_ibuffer_gpu_size{ 0 };
524         int64_t paths_size{ 0 };
525         int64_t render_paths_size{ 0 };
526         // other
527         int64_t travel_segments_count{ 0 };
528         int64_t wipe_segments_count{ 0 };
529         int64_t extrude_segments_count{ 0 };
530         int64_t vbuffers_count{ 0 };
531         int64_t ibuffers_count{ 0 };
532 
reset_allSlic3r::GUI::GCodeViewer::Statistics533         void reset_all() {
534             reset_times();
535             reset_opengl();
536             reset_sizes();
537             reset_others();
538         }
539 
reset_timesSlic3r::GUI::GCodeViewer::Statistics540         void reset_times() {
541             results_time = 0;
542             load_time = 0;
543             load_vertices = 0;
544             smooth_vertices = 0;
545             load_indices = 0;
546             refresh_time = 0;
547             refresh_paths_time = 0;
548         }
549 
reset_openglSlic3r::GUI::GCodeViewer::Statistics550         void reset_opengl() {
551             gl_multi_points_calls_count = 0;
552             gl_multi_lines_calls_count = 0;
553             gl_multi_triangles_calls_count = 0;
554 #if ENABLE_REDUCED_TOOLPATHS_SEGMENT_CAPS
555             gl_triangles_calls_count = 0;
556 #endif // ENABLE_REDUCED_TOOLPATHS_SEGMENT_CAPS
557         }
558 
reset_sizesSlic3r::GUI::GCodeViewer::Statistics559         void reset_sizes() {
560             results_size = 0;
561             total_vertices_gpu_size = 0;
562             total_indices_gpu_size = 0;
563             max_vbuffer_gpu_size = 0;
564             max_ibuffer_gpu_size = 0;
565             paths_size = 0;
566             render_paths_size = 0;
567         }
568 
reset_othersSlic3r::GUI::GCodeViewer::Statistics569         void reset_others() {
570             travel_segments_count = 0;
571             wipe_segments_count = 0;
572             extrude_segments_count =  0;
573             vbuffers_count = 0;
574             ibuffers_count = 0;
575         }
576     };
577 #endif // ENABLE_GCODE_VIEWER_STATISTICS
578 
579 public:
580     struct SequentialView
581     {
582         class Marker
583         {
584             GLModel m_model;
585             Vec3f m_world_position;
586             Transform3f m_world_transform;
587             float m_z_offset{ 0.5f };
588             std::array<float, 4> m_color{ 1.0f, 1.0f, 1.0f, 0.5f };
589             bool m_visible{ true };
590 
591         public:
592             void init();
593 
get_bounding_box() const594             const BoundingBoxf3& get_bounding_box() const { return m_model.get_bounding_box(); }
595 
596             void set_world_position(const Vec3f& position);
set_color(const std::array<float,4> & color)597             void set_color(const std::array<float, 4>& color) { m_color = color; }
598 
is_visible() const599             bool is_visible() const { return m_visible; }
set_visible(bool visible)600             void set_visible(bool visible) { m_visible = visible; }
601 
602             void render() const;
603         };
604 
605         struct Endpoints
606         {
607             size_t first{ 0 };
608             size_t last{ 0 };
609         };
610 
611         bool skip_invisible_moves{ false };
612         Endpoints endpoints;
613         Endpoints current;
614         Endpoints last_current;
615         Vec3f current_position{ Vec3f::Zero() };
616         Marker marker;
617     };
618 
619     enum class EViewType : unsigned char
620     {
621         FeatureType,
622         Height,
623         Width,
624         Feedrate,
625         FanSpeed,
626         VolumetricRate,
627         Tool,
628         ColorPrint,
629         Count
630     };
631 
632 private:
633     bool m_gl_data_initialized{ false };
634     unsigned int m_last_result_id{ 0 };
635     size_t m_moves_count{ 0 };
636     std::vector<TBuffer> m_buffers{ static_cast<size_t>(EMoveType::Extrude) };
637     // bounding box of toolpaths
638     BoundingBoxf3 m_paths_bounding_box;
639     // bounding box of toolpaths + marker tools
640     BoundingBoxf3 m_max_bounding_box;
641     std::vector<Color> m_tool_colors;
642     Layers m_layers;
643     std::array<unsigned int, 2> m_layers_z_range;
644     std::vector<ExtrusionRole> m_roles;
645     size_t m_extruders_count;
646     std::vector<unsigned char> m_extruder_ids;
647     Extrusions m_extrusions;
648     SequentialView m_sequential_view;
649     Shells m_shells;
650     EViewType m_view_type{ EViewType::FeatureType };
651     bool m_legend_enabled{ true };
652     PrintEstimatedTimeStatistics m_time_statistics;
653     PrintEstimatedTimeStatistics::ETimeMode m_time_estimate_mode{ PrintEstimatedTimeStatistics::ETimeMode::Normal };
654 #if ENABLE_GCODE_VIEWER_STATISTICS
655     Statistics m_statistics;
656 #endif // ENABLE_GCODE_VIEWER_STATISTICS
657     std::array<float, 2> m_detected_point_sizes = { 0.0f, 0.0f };
658     GCodeProcessor::Result::SettingsIds m_settings_ids;
659 #if ENABLE_REDUCED_TOOLPATHS_SEGMENT_CAPS
660     std::array<SequentialRangeCap, 2> m_sequential_range_caps;
661 #endif // ENABLE_REDUCED_TOOLPATHS_SEGMENT_CAPS
662 
663 public:
664     GCodeViewer();
~GCodeViewer()665     ~GCodeViewer() { reset(); }
666 
667     // extract rendering data from the given parameters
668     void load(const GCodeProcessor::Result& gcode_result, const Print& print, bool initialized);
669     // recalculate ranges in dependence of what is visible and sets tool/print colors
670     void refresh(const GCodeProcessor::Result& gcode_result, const std::vector<std::string>& str_tool_colors);
671 #if ENABLE_RENDER_PATH_REFRESH_AFTER_OPTIONS_CHANGE
672     void refresh_render_paths();
673 #endif // ENABLE_RENDER_PATH_REFRESH_AFTER_OPTIONS_CHANGE
674     void update_shells_color_by_extruder(const DynamicPrintConfig* config);
675 
676     void reset();
677     void render() const;
678 
has_data() const679     bool has_data() const { return !m_roles.empty(); }
680 #if ENABLE_SPLITTED_VERTEX_BUFFER
681     bool can_export_toolpaths() const;
682 #endif // ENABLE_SPLITTED_VERTEX_BUFFER
683 
get_paths_bounding_box() const684     const BoundingBoxf3& get_paths_bounding_box() const { return m_paths_bounding_box; }
get_max_bounding_box() const685     const BoundingBoxf3& get_max_bounding_box() const { return m_max_bounding_box; }
get_layers_zs() const686     const std::vector<double>& get_layers_zs() const { return m_layers.get_zs(); }
687 
get_sequential_view() const688     const SequentialView& get_sequential_view() const { return m_sequential_view; }
689     void update_sequential_view_current(unsigned int first, unsigned int last);
690 
get_view_type() const691     EViewType get_view_type() const { return m_view_type; }
set_view_type(EViewType type)692     void set_view_type(EViewType type) {
693         if (type == EViewType::Count)
694             type = EViewType::FeatureType;
695 
696         m_view_type = type;
697     }
698 
699     bool is_toolpath_move_type_visible(EMoveType type) const;
700     void set_toolpath_move_type_visible(EMoveType type, bool visible);
get_toolpath_role_visibility_flags() const701     unsigned int get_toolpath_role_visibility_flags() const { return m_extrusions.role_visibility_flags; }
set_toolpath_role_visibility_flags(unsigned int flags)702     void set_toolpath_role_visibility_flags(unsigned int flags) { m_extrusions.role_visibility_flags = flags; }
703     unsigned int get_options_visibility_flags() const;
704     void set_options_visibility_from_flags(unsigned int flags);
705     void set_layers_z_range(const std::array<unsigned int, 2>& layers_z_range);
706 
is_legend_enabled() const707     bool is_legend_enabled() const { return m_legend_enabled; }
enable_legend(bool enable)708     void enable_legend(bool enable) { m_legend_enabled = enable; }
709 
710     void export_toolpaths_to_obj(const char* filename) const;
711 
712 private:
713     void load_toolpaths(const GCodeProcessor::Result& gcode_result);
714     void load_shells(const Print& print, bool initialized);
715     void refresh_render_paths(bool keep_sequential_current_first, bool keep_sequential_current_last) const;
716     void render_toolpaths() const;
717     void render_shells() const;
718     void render_legend() const;
719 #if ENABLE_GCODE_VIEWER_STATISTICS
720     void render_statistics() const;
721 #endif // ENABLE_GCODE_VIEWER_STATISTICS
is_visible(ExtrusionRole role) const722     bool is_visible(ExtrusionRole role) const {
723         return role < erCount && (m_extrusions.role_visibility_flags & (1 << role)) != 0;
724     }
is_visible(const Path & path) const725     bool is_visible(const Path& path) const { return is_visible(path.role); }
726     void log_memory_used(const std::string& label, int64_t additional = 0) const;
727 };
728 
729 } // namespace GUI
730 } // namespace Slic3r
731 
732 #endif // slic3r_GCodeViewer_hpp_
733 
734