GCodeViewer.hpp 29 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826
  1. #ifndef slic3r_GCodeViewer_hpp_
  2. #define slic3r_GCodeViewer_hpp_
  3. #include "3DScene.hpp"
  4. #include "libslic3r/GCode/GCodeProcessor.hpp"
  5. #include "GLModel.hpp"
  6. #include <boost/iostreams/device/mapped_file.hpp>
  7. #include <cstdint>
  8. #include <float.h>
  9. #include <set>
  10. #include <unordered_set>
  11. namespace Slic3r {
  12. class Print;
  13. class TriangleMesh;
  14. namespace GUI {
  15. class GCodeViewer
  16. {
  17. using IBufferType = unsigned short;
  18. using Color = std::array<float, 4>;
  19. using VertexBuffer = std::vector<float>;
  20. using MultiVertexBuffer = std::vector<VertexBuffer>;
  21. using IndexBuffer = std::vector<IBufferType>;
  22. using MultiIndexBuffer = std::vector<IndexBuffer>;
  23. using InstanceBuffer = std::vector<float>;
  24. using InstanceIdBuffer = std::vector<size_t>;
  25. using InstancesOffsets = std::vector<Vec3f>;
  26. std::vector<Color> Extrusion_Role_Colors;
  27. static const std::vector<Color> Options_Colors;
  28. static const std::vector<Color> Travel_Colors;
  29. static const std::vector<Color> Range_Colors;
  30. static const Color Wipe_Color;
  31. static const Color Neutral_Color;
  32. enum class EOptionsColors : unsigned char
  33. {
  34. Retractions,
  35. Unretractions,
  36. Seams,
  37. ToolChanges,
  38. ColorChanges,
  39. PausePrints,
  40. CustomGCodes
  41. };
  42. // vbo buffer containing vertices data used to render a specific toolpath type
  43. struct VBuffer
  44. {
  45. enum class EFormat : unsigned char
  46. {
  47. // vertex format: 3 floats -> position.x|position.y|position.z
  48. Position,
  49. // vertex format: 4 floats -> position.x|position.y|position.z|normal.x
  50. PositionNormal1,
  51. // vertex format: 6 floats -> position.x|position.y|position.z|normal.x|normal.y|normal.z
  52. PositionNormal3
  53. };
  54. EFormat format{ EFormat::Position };
  55. // vbos id
  56. std::vector<unsigned int> vbos;
  57. // sizes of the buffers, in bytes, used in export to obj
  58. std::vector<size_t> sizes;
  59. // count of vertices, updated after data are sent to gpu
  60. size_t count{ 0 };
  61. size_t data_size_bytes() const { return count * vertex_size_bytes(); }
  62. // We set 65536 as max count of vertices inside a vertex buffer to allow
  63. // to use unsigned short in place of unsigned int for indices in the index buffer, to save memory
  64. size_t max_size_bytes() const { return 65536 * vertex_size_bytes(); }
  65. size_t vertex_size_floats() const { return position_size_floats() + normal_size_floats(); }
  66. size_t vertex_size_bytes() const { return vertex_size_floats() * sizeof(float); }
  67. size_t position_offset_floats() const { return 0; }
  68. size_t position_offset_bytes() const { return position_offset_floats() * sizeof(float); }
  69. size_t position_size_floats() const { return 3; }
  70. size_t position_size_bytes() const { return position_size_floats() * sizeof(float); }
  71. size_t normal_offset_floats() const {
  72. assert(format == EFormat::PositionNormal1 || format == EFormat::PositionNormal3);
  73. return position_size_floats();
  74. }
  75. size_t normal_offset_bytes() const { return normal_offset_floats() * sizeof(float); }
  76. size_t normal_size_floats() const {
  77. switch (format)
  78. {
  79. case EFormat::PositionNormal1: { return 1; }
  80. case EFormat::PositionNormal3: { return 3; }
  81. default: { return 0; }
  82. }
  83. }
  84. size_t normal_size_bytes() const { return normal_size_floats() * sizeof(float); }
  85. void reset();
  86. };
  87. // buffer containing instances data used to render a toolpaths using instanced or batched models
  88. // instance record format:
  89. // instanced models: 5 floats -> position.x|position.y|position.z|width|height (which are sent to the shader as -> vec3 (offset) + vec2 (scales) in GLModel::render_instanced())
  90. // batched models: 3 floats -> position.x|position.y|position.z
  91. struct InstanceVBuffer
  92. {
  93. // ranges used to render only subparts of the intances
  94. struct Ranges
  95. {
  96. struct Range
  97. {
  98. // offset in bytes of the 1st instance to render
  99. unsigned int offset;
  100. // count of instances to render
  101. unsigned int count;
  102. // vbo id
  103. unsigned int vbo{ 0 };
  104. // Color to apply to the instances
  105. Color color;
  106. };
  107. std::vector<Range> ranges;
  108. void reset();
  109. };
  110. enum class EFormat : unsigned char
  111. {
  112. InstancedModel,
  113. BatchedModel
  114. };
  115. EFormat format;
  116. // cpu-side buffer containing all instances data
  117. InstanceBuffer buffer;
  118. // indices of the moves for all instances
  119. std::vector<size_t> s_ids;
  120. // position offsets, used to show the correct value of the tool position
  121. InstancesOffsets offsets;
  122. Ranges render_ranges;
  123. size_t data_size_bytes() const { return s_ids.size() * instance_size_bytes(); }
  124. size_t instance_size_floats() const {
  125. switch (format)
  126. {
  127. case EFormat::InstancedModel: { return 5; }
  128. case EFormat::BatchedModel: { return 3; }
  129. default: { return 0; }
  130. }
  131. }
  132. size_t instance_size_bytes() const { return instance_size_floats() * sizeof(float); }
  133. void reset();
  134. };
  135. // ibo buffer containing indices data (for lines/triangles) used to render a specific toolpath type
  136. struct IBuffer
  137. {
  138. // id of the associated vertex buffer
  139. unsigned int vbo{ 0 };
  140. // ibo id
  141. unsigned int ibo{ 0 };
  142. // count of indices, updated after data are sent to gpu
  143. size_t count{ 0 };
  144. void reset();
  145. };
  146. // Used to identify different toolpath sub-types inside a IBuffer
  147. struct Path
  148. {
  149. struct Endpoint
  150. {
  151. // index of the buffer in the multibuffer vector
  152. // the buffer type may change:
  153. // it is the vertex buffer while extracting vertices data,
  154. // the index buffer while extracting indices data
  155. unsigned int b_id{ 0 };
  156. // index into the buffer
  157. size_t i_id{ 0 };
  158. // move id
  159. size_t s_id{ 0 };
  160. Vec3f position{ Vec3f::Zero() };
  161. };
  162. struct Sub_Path
  163. {
  164. Endpoint first;
  165. Endpoint last;
  166. bool contains(size_t s_id) const {
  167. return first.s_id <= s_id && s_id <= last.s_id;
  168. }
  169. };
  170. EMoveType type{ EMoveType::Noop };
  171. ExtrusionRole role{ erNone };
  172. float delta_extruder{ 0.0f };
  173. float height{ 0.0f };
  174. float width{ 0.0f };
  175. float feedrate{ 0.0f };
  176. float fan_speed{ 0.0f };
  177. float temperature{ 0.0f };
  178. float volumetric_rate{ 0.0f };
  179. float volumetric_flow{ 0.0f };
  180. unsigned char extruder_id{ 0 };
  181. unsigned char cp_color_id{ 0 };
  182. std::vector<Sub_Path> sub_paths;
  183. float layer_time{ 0.0f };
  184. float elapsed_time{ 0.0f };
  185. bool matches(const GCodeProcessorResult::MoveVertex& move) const;
  186. size_t vertices_count() const {
  187. return sub_paths.empty() ? 0 : sub_paths.back().last.s_id - sub_paths.front().first.s_id + 1;
  188. }
  189. bool contains(size_t s_id) const {
  190. return sub_paths.empty() ? false : sub_paths.front().first.s_id <= s_id && s_id <= sub_paths.back().last.s_id;
  191. }
  192. int get_id_of_sub_path_containing(size_t s_id) const {
  193. if (sub_paths.empty())
  194. return -1;
  195. else {
  196. for (int i = 0; i < static_cast<int>(sub_paths.size()); ++i) {
  197. if (sub_paths[i].contains(s_id))
  198. return i;
  199. }
  200. return -1;
  201. }
  202. }
  203. void add_sub_path(const GCodeProcessorResult::MoveVertex& move, unsigned int b_id, size_t i_id, size_t s_id) {
  204. Endpoint endpoint = { b_id, i_id, s_id, move.position };
  205. sub_paths.push_back({ endpoint , endpoint });
  206. }
  207. };
  208. // Used to batch the indices needed to render the paths
  209. struct RenderPath
  210. {
  211. // Index of the parent tbuffer
  212. unsigned char tbuffer_id;
  213. // Render path property
  214. Color color;
  215. // Index of the buffer in TBuffer::indices
  216. unsigned int ibuffer_id;
  217. // Render path content
  218. // Index of the path in TBuffer::paths
  219. unsigned int path_id;
  220. std::vector<unsigned int> sizes;
  221. 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())
  222. bool contains(size_t offset) const {
  223. for (size_t i = 0; i < offsets.size(); ++i) {
  224. if (offsets[i] <= offset && offset <= offsets[i] + static_cast<size_t>(sizes[i] * sizeof(IBufferType)))
  225. return true;
  226. }
  227. return false;
  228. }
  229. };
  230. struct RenderPathPropertyLower {
  231. bool operator() (const RenderPath &l, const RenderPath &r) const {
  232. if (l.tbuffer_id < r.tbuffer_id)
  233. return true;
  234. for (int i = 0; i < 3; ++i) {
  235. if (l.color[i] < r.color[i])
  236. return true;
  237. else if (l.color[i] > r.color[i])
  238. return false;
  239. }
  240. return l.ibuffer_id < r.ibuffer_id;
  241. }
  242. };
  243. struct RenderPathPropertyEqual {
  244. bool operator() (const RenderPath &l, const RenderPath &r) const {
  245. return l.tbuffer_id == r.tbuffer_id && l.ibuffer_id == r.ibuffer_id && l.color == r.color;
  246. }
  247. };
  248. // buffer containing data for rendering a specific toolpath type
  249. struct TBuffer
  250. {
  251. enum class ERenderPrimitiveType : unsigned char
  252. {
  253. Point,
  254. Line,
  255. Triangle,
  256. InstancedModel,
  257. BatchedModel
  258. };
  259. ERenderPrimitiveType render_primitive_type;
  260. // buffers for point, line and triangle primitive types
  261. VBuffer vertices;
  262. std::vector<IBuffer> indices;
  263. struct Model
  264. {
  265. GLModel model;
  266. Color color;
  267. InstanceVBuffer instances;
  268. GLModel::InitializationData data;
  269. void reset();
  270. };
  271. // contain the buffer for model primitive types
  272. Model model;
  273. std::string shader;
  274. std::vector<Path> paths;
  275. std::vector<RenderPath> render_paths;
  276. bool visible{ false };
  277. void reset();
  278. // b_id index of buffer contained in this->indices
  279. // i_id index of first index contained in this->indices[b_id]
  280. // s_id index of first vertex contained in this->vertices
  281. void add_path(const GCodeProcessorResult::MoveVertex& move, unsigned int b_id, size_t i_id, size_t s_id);
  282. unsigned int max_vertices_per_segment() const {
  283. switch (render_primitive_type)
  284. {
  285. case ERenderPrimitiveType::Point: { return 1; }
  286. case ERenderPrimitiveType::Line: { return 2; }
  287. case ERenderPrimitiveType::Triangle: { return 8; }
  288. default: { return 0; }
  289. }
  290. }
  291. size_t max_vertices_per_segment_size_floats() const { return vertices.vertex_size_floats() * static_cast<size_t>(max_vertices_per_segment()); }
  292. size_t max_vertices_per_segment_size_bytes() const { return max_vertices_per_segment_size_floats() * sizeof(float); }
  293. unsigned int indices_per_segment() const {
  294. switch (render_primitive_type)
  295. {
  296. case ERenderPrimitiveType::Point: { return 1; }
  297. case ERenderPrimitiveType::Line: { return 2; }
  298. case ERenderPrimitiveType::Triangle: { return 30; } // 3 indices x 10 triangles
  299. default: { return 0; }
  300. }
  301. }
  302. size_t indices_per_segment_size_bytes() const { return static_cast<size_t>(indices_per_segment() * sizeof(IBufferType)); }
  303. unsigned int max_indices_per_segment() const {
  304. switch (render_primitive_type)
  305. {
  306. case ERenderPrimitiveType::Point: { return 1; }
  307. case ERenderPrimitiveType::Line: { return 2; }
  308. case ERenderPrimitiveType::Triangle: { return 36; } // 3 indices x 12 triangles
  309. default: { return 0; }
  310. }
  311. }
  312. size_t max_indices_per_segment_size_bytes() const { return max_indices_per_segment() * sizeof(IBufferType); }
  313. bool has_data() const {
  314. switch (render_primitive_type)
  315. {
  316. case ERenderPrimitiveType::Point:
  317. case ERenderPrimitiveType::Line:
  318. case ERenderPrimitiveType::Triangle: {
  319. return !vertices.vbos.empty() && vertices.vbos.front() != 0 && !indices.empty() && indices.front().ibo != 0;
  320. }
  321. case ERenderPrimitiveType::InstancedModel: { return model.model.is_initialized() && !model.instances.buffer.empty(); }
  322. case ERenderPrimitiveType::BatchedModel: {
  323. return model.data.vertices_count() > 0 && model.data.indices_count() &&
  324. !vertices.vbos.empty() && vertices.vbos.front() != 0 && !indices.empty() && indices.front().ibo != 0;
  325. }
  326. default: { return false; }
  327. }
  328. }
  329. };
  330. // helper to render shells
  331. struct Shells
  332. {
  333. GLVolumeCollection volumes;
  334. bool visible{ false };
  335. };
  336. // helper to render extrusion paths
  337. struct Extrusions
  338. {
  339. struct Range
  340. {
  341. float min;
  342. float max;
  343. unsigned int count;
  344. uint32_t counts[20];
  345. uint64_t total_count;
  346. float maxs[20];
  347. float mins[20];
  348. Range() { reset(); }
  349. void update_from(const float value);
  350. void reset();
  351. float get_max_no_outliers(float ratio_outlier = 0.01) const;
  352. float get_min_no_outliers(float ratio_outlier = 0.01) const;
  353. float step_size_no_outliers(float ratio_outlier = 0.01, bool log = false) const;
  354. Color get_color_at_no_outliers(float value, float ratio_outlier = 0.01, bool log = false) const;
  355. float step_size_with_outliers(float ratio_outlier = 0.01, bool log = false) const { return step_size(min, max, log); }
  356. Color get_color_at_with_outliers(float value, float ratio_outlier = 0.01, bool log = false) const { return get_color_at(min, max, value, log); }
  357. static float step_size(float min, float max, bool log = false);
  358. static Color get_color_at(float min, float max, float value, bool log = false);
  359. };
  360. struct Ranges
  361. {
  362. // Color mapping by layer height.
  363. Range height;
  364. // Color mapping by extrusion width.
  365. Range width;
  366. // Color mapping by feedrate.
  367. Range feedrate;
  368. // Color mapping by fan speed.
  369. Range fan_speed;
  370. // Color mapping by volumetric extrusion rate.
  371. Range volumetric_rate;
  372. // Color mapping by volumetric extrusion mm3/mm.
  373. Range volumetric_flow;
  374. // Color mapping by extrusion temperature.
  375. Range temperature;
  376. // Color mapping by layer time.
  377. Range layer_duration;
  378. // Color mapping by time.
  379. Range elapsed_time;
  380. void reset() {
  381. height.reset();
  382. width.reset();
  383. feedrate.reset();
  384. fan_speed.reset();
  385. volumetric_rate.reset();
  386. volumetric_flow.reset();
  387. temperature.reset();
  388. layer_duration.reset();
  389. elapsed_time.reset();
  390. }
  391. };
  392. unsigned int role_visibility_flags{ 0 };
  393. Ranges ranges;
  394. void reset_role_visibility_flags() {
  395. role_visibility_flags = 0;
  396. for (unsigned int i = 0; i < erCount; ++i) {
  397. role_visibility_flags |= 1 << i;
  398. }
  399. }
  400. void reset_ranges() { ranges.reset(); }
  401. };
  402. class Layers
  403. {
  404. public:
  405. struct Endpoints
  406. {
  407. size_t first{ 0 };
  408. size_t last{ 0 };
  409. bool operator == (const Endpoints& other) const { return first == other.first && last == other.last; }
  410. bool operator != (const Endpoints& other) const { return !operator==(other); }
  411. };
  412. private:
  413. std::vector<double> m_zs;
  414. std::vector<Endpoints> m_endpoints;
  415. public:
  416. void append(double z, Endpoints endpoints) {
  417. m_zs.emplace_back(z);
  418. m_endpoints.emplace_back(endpoints);
  419. }
  420. void reset() {
  421. m_zs = std::vector<double>();
  422. m_endpoints = std::vector<Endpoints>();
  423. }
  424. size_t size() const { return m_zs.size(); }
  425. bool empty() const { return m_zs.empty(); }
  426. const std::vector<double>& get_zs() const { return m_zs; }
  427. const std::vector<Endpoints>& get_endpoints() const { return m_endpoints; }
  428. std::vector<Endpoints>& get_endpoints() { return m_endpoints; }
  429. double get_z_at(unsigned int id) const { return (id < m_zs.size()) ? m_zs[id] : 0.0; }
  430. Endpoints get_endpoints_at(unsigned int id) const { return (id < m_endpoints.size()) ? m_endpoints[id] : Endpoints(); }
  431. bool operator != (const Layers& other) const {
  432. if (m_zs != other.m_zs)
  433. return true;
  434. if (m_endpoints != other.m_endpoints)
  435. return true;
  436. return false;
  437. }
  438. };
  439. // used to render the toolpath caps of the current sequential range
  440. // (i.e. when sliding on the horizontal slider)
  441. struct SequentialRangeCap
  442. {
  443. TBuffer* buffer{ nullptr };
  444. unsigned int ibo{ 0 };
  445. unsigned int vbo{ 0 };
  446. Color color;
  447. ~SequentialRangeCap();
  448. bool is_renderable() const { return buffer != nullptr; }
  449. void reset();
  450. size_t indices_count() const { return 6; }
  451. };
  452. #if ENABLE_GCODE_VIEWER_STATISTICS
  453. struct Statistics
  454. {
  455. // time
  456. int64_t results_time{ 0 };
  457. int64_t load_time{ 0 };
  458. int64_t load_vertices{ 0 };
  459. int64_t smooth_vertices{ 0 };
  460. int64_t load_indices{ 0 };
  461. int64_t refresh_time{ 0 };
  462. int64_t refresh_paths_time{ 0 };
  463. // opengl calls
  464. int64_t gl_multi_points_calls_count{ 0 };
  465. int64_t gl_multi_lines_calls_count{ 0 };
  466. int64_t gl_multi_triangles_calls_count{ 0 };
  467. int64_t gl_triangles_calls_count{ 0 };
  468. int64_t gl_instanced_models_calls_count{ 0 };
  469. int64_t gl_batched_models_calls_count{ 0 };
  470. // memory
  471. int64_t results_size{ 0 };
  472. int64_t total_vertices_gpu_size{ 0 };
  473. int64_t total_indices_gpu_size{ 0 };
  474. int64_t total_instances_gpu_size{ 0 };
  475. int64_t max_vbuffer_gpu_size{ 0 };
  476. int64_t max_ibuffer_gpu_size{ 0 };
  477. int64_t paths_size{ 0 };
  478. int64_t render_paths_size{ 0 };
  479. int64_t models_instances_size{ 0 };
  480. // other
  481. int64_t travel_segments_count{ 0 };
  482. int64_t wipe_segments_count{ 0 };
  483. int64_t extrude_segments_count{ 0 };
  484. int64_t instances_count{ 0 };
  485. int64_t batched_count{ 0 };
  486. int64_t vbuffers_count{ 0 };
  487. int64_t ibuffers_count{ 0 };
  488. void reset_all() {
  489. reset_times();
  490. reset_opengl();
  491. reset_sizes();
  492. reset_others();
  493. }
  494. void reset_times() {
  495. results_time = 0;
  496. load_time = 0;
  497. load_vertices = 0;
  498. smooth_vertices = 0;
  499. load_indices = 0;
  500. refresh_time = 0;
  501. refresh_paths_time = 0;
  502. }
  503. void reset_opengl() {
  504. gl_multi_points_calls_count = 0;
  505. gl_multi_lines_calls_count = 0;
  506. gl_multi_triangles_calls_count = 0;
  507. gl_triangles_calls_count = 0;
  508. gl_instanced_models_calls_count = 0;
  509. gl_batched_models_calls_count = 0;
  510. }
  511. void reset_sizes() {
  512. results_size = 0;
  513. total_vertices_gpu_size = 0;
  514. total_indices_gpu_size = 0;
  515. total_instances_gpu_size = 0;
  516. max_vbuffer_gpu_size = 0;
  517. max_ibuffer_gpu_size = 0;
  518. paths_size = 0;
  519. render_paths_size = 0;
  520. models_instances_size = 0;
  521. }
  522. void reset_others() {
  523. travel_segments_count = 0;
  524. wipe_segments_count = 0;
  525. extrude_segments_count = 0;
  526. instances_count = 0;
  527. batched_count = 0;
  528. vbuffers_count = 0;
  529. ibuffers_count = 0;
  530. }
  531. };
  532. #endif // ENABLE_GCODE_VIEWER_STATISTICS
  533. public:
  534. struct SequentialView
  535. {
  536. class Marker
  537. {
  538. GLModel m_model;
  539. Vec3f m_world_position;
  540. Transform3f m_world_transform;
  541. // for seams, the position of the marker is on the last endpoint of the toolpath containing it
  542. // the offset is used to show the correct value of tool position in the "ToolPosition" window
  543. // see implementation of render() method
  544. Vec3f m_world_offset;
  545. float m_z_offset{ 0.5f };
  546. bool m_visible{ true };
  547. public:
  548. void init();
  549. const BoundingBoxf3& get_bounding_box() const { return m_model.get_bounding_box(); }
  550. void set_world_position(const Vec3f& position);
  551. void set_world_offset(const Vec3f& offset) { m_world_offset = offset; }
  552. bool is_visible() const { return m_visible; }
  553. void set_visible(bool visible) { m_visible = visible; }
  554. void render() const;
  555. };
  556. class GCodeWindow
  557. {
  558. struct Line
  559. {
  560. std::string command;
  561. std::string parameters;
  562. std::string comment;
  563. };
  564. bool m_visible{ true };
  565. uint64_t m_selected_line_id{ 0 };
  566. size_t m_last_lines_size{ 0 };
  567. std::string m_filename;
  568. boost::iostreams::mapped_file_source m_file;
  569. // map for accessing data in file by line number
  570. std::vector<size_t> m_lines_ends;
  571. // current visible lines
  572. std::vector<Line> m_lines;
  573. public:
  574. GCodeWindow() = default;
  575. ~GCodeWindow() { stop_mapping_file(); }
  576. bool load_gcode(const std::string& filename, std::vector<size_t> &&lines_ends);
  577. void reset() {
  578. stop_mapping_file();
  579. m_lines_ends.clear();
  580. m_lines.clear();
  581. m_filename.clear();
  582. }
  583. void toggle_visibility() { m_visible = !m_visible; }
  584. void render(float top, float bottom, uint64_t curr_line_id) const;
  585. void stop_mapping_file();
  586. };
  587. struct Endpoints
  588. {
  589. size_t first{ 0 };
  590. size_t last{ 0 };
  591. };
  592. bool skip_invisible_moves{ false };
  593. Endpoints endpoints;
  594. Endpoints current;
  595. Endpoints last_current;
  596. Endpoints global;
  597. Vec3f current_position{ Vec3f::Zero() };
  598. Vec3f current_offset{ Vec3f::Zero() };
  599. Marker marker;
  600. GCodeWindow gcode_window;
  601. std::vector<unsigned int> gcode_ids;
  602. void render(float legend_height) const;
  603. };
  604. enum class EViewType : unsigned char
  605. {
  606. FeatureType,
  607. Height,
  608. Width,
  609. Feedrate,
  610. FanSpeed,
  611. Temperature,
  612. LayerTime,
  613. LayerTimeLog,
  614. Chronology,
  615. VolumetricRate,
  616. VolumetricFlow,
  617. Tool,
  618. Filament,
  619. ColorPrint,
  620. Count
  621. };
  622. private:
  623. bool m_gl_data_initialized{ false };
  624. unsigned int m_last_result_id{ 0 };
  625. size_t m_moves_count{ 0 };
  626. std::vector<TBuffer> m_buffers{ static_cast<size_t>(EMoveType::Extrude) };
  627. // bounding box of toolpaths
  628. BoundingBoxf3 m_paths_bounding_box;
  629. // bounding box of toolpaths + marker tools
  630. BoundingBoxf3 m_max_bounding_box;
  631. float m_max_print_height{ 0.0f };
  632. std::vector<Color> m_tool_colors;
  633. std::vector<Color> m_filament_colors;
  634. Layers m_layers;
  635. std::array<unsigned int, 2> m_layers_z_range;
  636. std::vector<ExtrusionRole> m_roles;
  637. size_t m_extruders_count;
  638. std::vector<unsigned char> m_extruder_ids;
  639. std::vector<float> m_filament_diameters;
  640. std::vector<float> m_filament_densities;
  641. Extrusions m_extrusions;
  642. SequentialView m_sequential_view;
  643. Shells m_shells;
  644. EViewType m_view_type{ EViewType::FeatureType };
  645. bool m_legend_enabled{ true };
  646. bool m_outliers_allowed{ true };
  647. PrintEstimatedStatistics m_print_statistics;
  648. PrintEstimatedStatistics::ETimeMode m_time_estimate_mode{ PrintEstimatedStatistics::ETimeMode::Normal };
  649. #if ENABLE_GCODE_VIEWER_STATISTICS
  650. Statistics m_statistics;
  651. #endif // ENABLE_GCODE_VIEWER_STATISTICS
  652. std::array<float, 2> m_detected_point_sizes = { 0.0f, 0.0f };
  653. GCodeProcessorResult::SettingsIds m_settings_ids;
  654. std::array<SequentialRangeCap, 2> m_sequential_range_caps;
  655. std::vector<CustomGCode::Item> m_custom_gcode_per_print_z;
  656. bool m_contained_in_bed{ true };
  657. public:
  658. GCodeViewer();
  659. ~GCodeViewer() { reset(); }
  660. void init();
  661. // extract rendering data from the given parameters
  662. void load(const GCodeProcessorResult& gcode_result, const Print& print, bool initialized);
  663. bool is_loaded(const GCodeProcessorResult& gcode_result);
  664. // recalculate ranges in dependence of what is visible and sets tool/print colors
  665. void refresh(const GCodeProcessorResult& gcode_result, const std::vector<std::string>& str_tool_colors);
  666. void refresh_render_paths();
  667. void update_shells_color_by_extruder(const DynamicPrintConfig* config);
  668. void reset();
  669. void render();
  670. bool has_data() const { return !m_roles.empty(); }
  671. bool can_export_toolpaths() const;
  672. const BoundingBoxf3& get_paths_bounding_box() const { return m_paths_bounding_box; }
  673. const BoundingBoxf3& get_max_bounding_box() const { return m_max_bounding_box; }
  674. const std::vector<double>& get_layers_zs() const { return m_layers.get_zs(); }
  675. const SequentialView& get_sequential_view() const { return m_sequential_view; }
  676. void update_sequential_view_current(unsigned int first, unsigned int last);
  677. bool is_contained_in_bed() const { return m_contained_in_bed; }
  678. EViewType get_view_type() const { return m_view_type; }
  679. void set_view_type(EViewType type) {
  680. if (type == EViewType::Count)
  681. type = EViewType::FeatureType;
  682. m_view_type = type;
  683. }
  684. bool is_toolpath_move_type_visible(EMoveType type) const;
  685. void set_toolpath_move_type_visible(EMoveType type, bool visible);
  686. unsigned int get_toolpath_role_visibility_flags() const { return m_extrusions.role_visibility_flags; }
  687. void set_toolpath_role_visibility_flags(unsigned int flags) { m_extrusions.role_visibility_flags = flags; }
  688. unsigned int get_options_visibility_flags() const;
  689. void set_options_visibility_from_flags(unsigned int flags);
  690. void set_layers_z_range(const std::array<unsigned int, 2>& layers_z_range);
  691. bool is_legend_enabled() const { return m_legend_enabled; }
  692. void enable_legend(bool enable) { m_legend_enabled = enable; }
  693. void export_toolpaths_to_obj(const char* filename) const;
  694. void toggle_gcode_window_visibility() { m_sequential_view.gcode_window.toggle_visibility(); }
  695. std::vector<CustomGCode::Item>& get_custom_gcode_per_print_z() { return m_custom_gcode_per_print_z; }
  696. size_t get_extruders_count() { return m_extruders_count; }
  697. const std::vector<Color>& get_extrusion_colors() const { return Extrusion_Role_Colors; }
  698. private:
  699. void load_toolpaths(const GCodeProcessorResult& gcode_result);
  700. void load_shells(const Print& print, bool initialized);
  701. void refresh_render_paths(bool keep_sequential_current_first, bool keep_sequential_current_last) const;
  702. void render_toolpaths();
  703. void render_shells();
  704. void render_legend(float& legend_height);
  705. #if ENABLE_GCODE_VIEWER_STATISTICS
  706. void render_statistics();
  707. #endif // ENABLE_GCODE_VIEWER_STATISTICS
  708. bool is_visible(ExtrusionRole role) const {
  709. return role < erCount && (m_extrusions.role_visibility_flags & (1 << role)) != 0;
  710. }
  711. bool is_visible(const Path& path) const { return is_visible(path.role); }
  712. void log_memory_used(const std::string& label, int64_t additional = 0) const;
  713. Color option_color(EMoveType move_type) const;
  714. };
  715. } // namespace GUI
  716. } // namespace Slic3r
  717. #endif // slic3r_GCodeViewer_hpp_