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