2020-04-14 10:02:08 +02:00
#ifndef slic3r_GCodeViewer_hpp_
#define slic3r_GCodeViewer_hpp_
2020-04-15 14:31:39 +02:00
#include "3DScene.hpp"
2020-04-14 10:02:08 +02:00
#include "libslic3r/GCode/GCodeProcessor.hpp"
2020-05-11 16:26:35 +02:00
#include "GLModel.hpp"
2020-04-14 10:02:08 +02:00
2021-03-08 10:20:07 +01:00
#if ENABLE_GCODE_WINDOW
2021-03-08 08:35:32 +01:00
#include <boost/iostreams/device/mapped_file.hpp>
2021-03-08 10:20:07 +01:00
#endif // ENABLE_GCODE_WINDOW
2021-03-08 08:35:32 +01:00
2020-12-10 08:40:08 +01:00
#include <cstdint>
2020-04-20 10:52:16 +02:00
#include <float.h>
2021-01-06 15:32:22 +01:00
#include <set>
#include <unordered_set>
2020-04-20 10:52:16 +02:00
2020-04-14 10:02:08 +02:00
namespace Slic3r {
2020-05-11 13:09:26 +02:00
2020-04-15 14:31:39 +02:00
class Print ;
2020-05-11 13:09:26 +02:00
class TriangleMesh ;
2020-04-14 10:02:08 +02:00
namespace GUI {
class GCodeViewer
{
2021-01-26 13:32:27 +01:00
#if ENABLE_SPLITTED_VERTEX_BUFFER
2021-01-20 13:47:48 +01:00
using IBufferType = unsigned short ;
2021-01-26 13:32:27 +01:00
#endif // ENABLE_SPLITTED_VERTEX_BUFFER
2020-05-05 12:09:11 +02:00
using Color = std :: array < float , 3 > ;
2021-01-07 11:13:07 +01:00
using VertexBuffer = std :: vector < float > ;
2021-01-12 09:03:35 +01:00
#if ENABLE_SPLITTED_VERTEX_BUFFER
using MultiVertexBuffer = std :: vector < VertexBuffer > ;
2021-01-20 13:47:48 +01:00
using IndexBuffer = std :: vector < IBufferType > ;
#else
2020-09-16 15:45:53 +02:00
using IndexBuffer = std :: vector < unsigned int > ;
2021-01-26 13:32:27 +01:00
#endif // ENABLE_SPLITTED_VERTEX_BUFFER
2020-09-16 15:45:53 +02:00
using MultiIndexBuffer = std :: vector < IndexBuffer > ;
2020-05-05 12:09:11 +02:00
static const std :: vector < Color > Extrusion_Role_Colors ;
2020-05-22 11:52:07 +02:00
static const std :: vector < Color > Options_Colors ;
2020-05-05 12:09:11 +02:00
static const std :: vector < Color > Travel_Colors ;
2020-11-21 10:36:10 +01:00
static const Color Wipe_Color ;
2020-05-05 12:09:11 +02:00
static const std :: vector < Color > Range_Colors ;
2020-04-16 15:09:04 +02:00
2020-05-22 11:52:07 +02:00
enum class EOptionsColors : unsigned char
{
Retractions ,
Unretractions ,
2021-04-27 09:45:15 +02:00
#if ENABLE_SEAMS_VISUALIZATION
Seams ,
#endif // ENABLE_SEAMS_VISUALIZATION
2020-05-22 11:52:07 +02:00
ToolChanges ,
ColorChanges ,
PausePrints ,
CustomGCodes
};
2021-01-12 09:03:35 +01:00
// vbo buffer containing vertices data used to render a specific toolpath type
2020-04-15 16:29:11 +02:00
struct VBuffer
2020-04-14 10:02:08 +02:00
{
2020-06-29 14:00:08 +02:00
enum class EFormat : unsigned char
{
2020-08-26 15:29:33 +02:00
// vertex format: 3 floats -> position.x|position.y|position.z
2020-06-29 14:00:08 +02:00
Position ,
2020-08-26 15:29:33 +02:00
// vertex format: 4 floats -> position.x|position.y|position.z|normal.x
PositionNormal1 ,
// vertex format: 6 floats -> position.x|position.y|position.z|normal.x|normal.y|normal.z
PositionNormal3
2020-06-29 14:00:08 +02:00
};
2020-04-15 16:29:11 +02:00
2020-06-29 14:00:08 +02:00
EFormat format { EFormat :: Position };
2021-01-12 09:03:35 +01:00
#if ENABLE_SPLITTED_VERTEX_BUFFER
// vbos id
2021-01-13 10:45:52 +01:00
std :: vector < unsigned int > vbos ;
// sizes of the buffers, in bytes, used in export to obj
std :: vector < size_t > sizes ;
2021-01-12 09:03:35 +01:00
#else
2020-06-29 14:00:08 +02:00
// vbo id
unsigned int id { 0 };
2021-01-12 09:03:35 +01:00
#endif // ENABLE_SPLITTED_VERTEX_BUFFER
2020-06-29 14:00:08 +02:00
// count of vertices, updated after data are sent to gpu
size_t count { 0 };
size_t data_size_bytes () const { return count * vertex_size_bytes (); }
2021-01-26 13:32:27 +01:00
#if ENABLE_SPLITTED_VERTEX_BUFFER
2021-01-20 13:47:48 +01:00
// We set 65536 as max count of vertices inside a vertex buffer to allow
// to use unsigned short in place of unsigned int for indices in the index buffer, to save memory
size_t max_size_bytes () const { return 65536 * vertex_size_bytes (); }
2021-01-26 13:32:27 +01:00
#endif // ENABLE_SPLITTED_VERTEX_BUFFER
2020-08-26 15:29:33 +02:00
size_t vertex_size_floats () const { return position_size_floats () + normal_size_floats (); }
size_t vertex_size_bytes () const { return vertex_size_floats () * sizeof ( float ); }
size_t position_offset_floats () const { return 0 ; }
2021-04-01 08:24:19 +02:00
size_t position_offset_bytes () const { return position_offset_floats () * sizeof ( float ); }
size_t position_size_floats () const { return 3 ; }
2020-08-26 15:29:33 +02:00
size_t position_size_bytes () const { return position_size_floats () * sizeof ( float ); }
2021-04-01 08:24:19 +02:00
size_t normal_offset_floats () const { return position_size_floats (); }
size_t normal_offset_bytes () const { return normal_offset_floats () * sizeof ( float ); }
2020-08-26 15:29:33 +02:00
size_t normal_size_floats () const {
switch ( format )
{
2021-04-01 08:24:19 +02:00
case EFormat :: PositionNormal1 : { return 1 ; }
2020-08-26 15:29:33 +02:00
case EFormat :: PositionNormal3 : { return 3 ; }
2021-04-01 08:24:19 +02:00
default : { return 0 ; }
2020-08-26 15:29:33 +02:00
}
}
size_t normal_size_bytes () const { return normal_size_floats () * sizeof ( float ); }
2020-04-14 10:02:08 +02:00
2020-04-14 16:40:08 +02:00
void reset ();
2020-06-29 14:00:08 +02:00
};
2020-04-14 10:02:08 +02:00
2021-01-12 09:03:35 +01:00
// ibo buffer containing indices data (for lines/triangles) used to render a specific toolpath type
2020-06-29 14:00:08 +02:00
struct IBuffer
{
2021-01-12 09:03:35 +01:00
#if ENABLE_SPLITTED_VERTEX_BUFFER
// id of the associated vertex buffer
unsigned int vbo { 0 };
// ibo id
unsigned int ibo { 0 };
#else
2020-06-29 14:00:08 +02:00
// ibo id
unsigned int id { 0 };
2021-01-12 09:03:35 +01:00
#endif // ENABLE_SPLITTED_VERTEX_BUFFER
2020-06-29 14:00:08 +02:00
// count of indices, updated after data are sent to gpu
size_t count { 0 };
void reset ();
2020-04-14 10:02:08 +02:00
};
2020-04-20 10:52:16 +02:00
// Used to identify different toolpath sub-types inside a IBuffer
2020-04-16 15:09:04 +02:00
struct Path
{
2020-04-28 12:24:03 +02:00
struct Endpoint
{
2021-01-18 11:37:23 +01:00
// index of the buffer in the multibuffer vector
// the buffer type may change:
// it is the vertex buffer while extracting vertices data,
// the index buffer while extracting indices data
2020-09-16 15:45:53 +02:00
unsigned int b_id { 0 };
2021-01-18 11:37:23 +01:00
// index into the buffer
2020-09-16 15:45:53 +02:00
size_t i_id { 0 };
2021-01-12 14:03:58 +01:00
// move id
2020-09-16 15:45:53 +02:00
size_t s_id { 0 };
2020-05-04 09:37:06 +02:00
Vec3f position { Vec3f :: Zero () };
2020-04-28 12:24:03 +02:00
};
2021-01-12 09:03:35 +01:00
#if ENABLE_SPLITTED_VERTEX_BUFFER
struct Sub_Path
{
Endpoint first ;
Endpoint last ;
bool contains ( size_t s_id ) const {
return first . s_id <= s_id && s_id <= last . s_id ;
}
};
#endif // ENABLE_SPLITTED_VERTEX_BUFFER
2020-08-03 13:57:10 +02:00
EMoveType type { EMoveType :: Noop };
2020-04-16 15:09:04 +02:00
ExtrusionRole role { erNone };
2021-01-12 09:03:35 +01:00
#if !ENABLE_SPLITTED_VERTEX_BUFFER
2020-04-28 12:24:03 +02:00
Endpoint first ;
Endpoint last ;
2021-01-12 09:03:35 +01:00
#endif // !ENABLE_SPLITTED_VERTEX_BUFFER
2020-04-24 08:46:31 +02:00
float delta_extruder { 0.0f };
2020-04-20 10:52:16 +02:00
float height { 0.0f };
2020-04-20 13:24:25 +02:00
float width { 0.0f };
2020-04-20 16:04:59 +02:00
float feedrate { 0.0f };
2020-04-21 09:06:43 +02:00
float fan_speed { 0.0f };
2021-02-26 14:17:53 +01:00
float temperature { 0.0f };
2020-04-21 11:38:42 +02:00
float volumetric_rate { 0.0f };
2020-04-21 15:55:26 +02:00
unsigned char extruder_id { 0 };
2020-04-22 16:29:07 +02:00
unsigned char cp_color_id { 0 };
2021-01-12 09:03:35 +01:00
#if ENABLE_SPLITTED_VERTEX_BUFFER
std :: vector < Sub_Path > sub_paths ;
#endif // ENABLE_SPLITTED_VERTEX_BUFFER
2020-04-16 15:09:04 +02:00
2020-05-04 09:37:06 +02:00
bool matches ( const GCodeProcessor :: MoveVertex & move ) const ;
2021-01-12 09:03:35 +01:00
#if ENABLE_SPLITTED_VERTEX_BUFFER
size_t vertices_count () const {
return sub_paths . empty () ? 0 : sub_paths . back (). last . s_id - sub_paths . front (). first . s_id + 1 ;
}
bool contains ( size_t s_id ) const {
return sub_paths . empty () ? false : sub_paths . front (). first . s_id <= s_id && s_id <= sub_paths . back (). last . s_id ;
}
int get_id_of_sub_path_containing ( size_t s_id ) const {
if ( sub_paths . empty ())
return - 1 ;
else {
for ( int i = 0 ; i < static_cast < int > ( sub_paths . size ()); ++ i ) {
if ( sub_paths [ i ]. contains ( s_id ))
return i ;
}
return - 1 ;
}
}
void add_sub_path ( const GCodeProcessor :: MoveVertex & move , unsigned int b_id , size_t i_id , size_t s_id ) {
Endpoint endpoint = { b_id , i_id , s_id , move . position };
sub_paths . push_back ({ endpoint , endpoint });
}
#else
2020-08-28 12:28:21 +02:00
size_t vertices_count () const { return last . s_id - first . s_id + 1 ; }
2020-09-16 15:45:53 +02:00
bool contains ( size_t id ) const { return first . s_id <= id && id <= last . s_id ; }
2021-01-12 09:03:35 +01:00
#endif // ENABLE_SPLITTED_VERTEX_BUFFER
2020-04-16 15:09:04 +02:00
};
2021-01-12 09:03:35 +01:00
// Used to batch the indices needed to render the paths
2020-04-28 15:08:36 +02:00
struct RenderPath
{
2021-02-22 15:27:40 +01:00
#if ENABLE_REDUCED_TOOLPATHS_SEGMENT_CAPS
// Index of the parent tbuffer
unsigned char tbuffer_id ;
#endif // ENABLE_REDUCED_TOOLPATHS_SEGMENT_CAPS
2021-01-06 15:32:22 +01:00
// Render path property
Color color ;
2021-01-21 09:44:02 +01:00
// Index of the buffer in TBuffer::indices
2021-02-22 15:27:40 +01:00
unsigned int ibuffer_id ;
2021-01-06 15:32:22 +01:00
// Render path content
2021-02-22 15:27:40 +01:00
// Index of the path in TBuffer::paths
2021-01-06 15:32:22 +01:00
unsigned int path_id ;
std :: vector < unsigned int > sizes ;
2021-02-22 15:27:40 +01:00
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())
2021-02-05 11:53:39 +01:00
#if ENABLE_REDUCED_TOOLPATHS_SEGMENT_CAPS
bool contains ( size_t offset ) const {
for ( size_t i = 0 ; i < offsets . size (); ++ i ) {
if ( offsets [ i ] <= offset && offset <= offsets [ i ] + static_cast < size_t > ( sizes [ i ] * sizeof ( IBufferType )))
return true ;
}
return false ;
}
#endif // ENABLE_REDUCED_TOOLPATHS_SEGMENT_CAPS
2021-01-06 15:32:22 +01:00
};
2021-02-22 15:27:40 +01:00
// // for unordered_set implementation of render_paths
// struct RenderPathPropertyHash {
// size_t operator() (const RenderPath &p) const {
// // Convert the RGB value to an integer hash.
//// 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);
// 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);
// }
// };
2021-01-06 15:32:22 +01:00
struct RenderPathPropertyLower {
bool operator () ( const RenderPath & l , const RenderPath & r ) const {
2021-02-22 15:27:40 +01:00
#if ENABLE_REDUCED_TOOLPATHS_SEGMENT_CAPS
if ( l . tbuffer_id < r . tbuffer_id )
return true ;
#endif // ENABLE_REDUCED_TOOLPATHS_SEGMENT_CAPS
for ( int i = 0 ; i < 3 ; ++ i ) {
2021-01-06 15:32:22 +01:00
if ( l . color [ i ] < r . color [ i ])
return true ;
else if ( l . color [ i ] > r . color [ i ])
return false ;
2021-02-22 15:27:40 +01:00
}
return l . ibuffer_id < r . ibuffer_id ;
2021-01-06 15:32:22 +01:00
}
};
struct RenderPathPropertyEqual {
bool operator () ( const RenderPath & l , const RenderPath & r ) const {
2021-02-22 15:27:40 +01:00
#if ENABLE_REDUCED_TOOLPATHS_SEGMENT_CAPS
return l . tbuffer_id == r . tbuffer_id && l . ibuffer_id == r . ibuffer_id && l . color == r . color ;
#else
return l . color == r . color && l . ibuffer_id == r . ibuffer_id ;
#endif // ENABLE_REDUCED_TOOLPATHS_SEGMENT_CAPS
2021-01-06 15:32:22 +01:00
}
2020-04-28 15:08:36 +02:00
};
2020-06-29 14:00:08 +02:00
// buffer containing data for rendering a specific toolpath type
struct TBuffer
2020-04-15 16:29:11 +02:00
{
2020-09-01 08:29:06 +02:00
enum class ERenderPrimitiveType : unsigned char
2020-08-26 15:29:33 +02:00
{
Point ,
Line ,
Triangle
};
2020-09-01 08:29:06 +02:00
ERenderPrimitiveType render_primitive_type ;
2020-06-29 14:00:08 +02:00
VBuffer vertices ;
2020-09-16 15:45:53 +02:00
std :: vector < IBuffer > indices ;
2020-06-29 14:00:08 +02:00
2020-05-20 14:11:22 +02:00
std :: string shader ;
2020-04-16 15:09:04 +02:00
std :: vector < Path > paths ;
2021-01-07 09:57:37 +01:00
// std::set seems to perform significantly better, at least on Windows.
2021-01-06 15:32:22 +01:00
// std::unordered_set<RenderPath, RenderPathPropertyHash, RenderPathPropertyEqual> render_paths;
std :: set < RenderPath , RenderPathPropertyLower > render_paths ;
2020-04-15 16:29:11 +02:00
bool visible { false };
void reset ();
2021-01-12 09:03:35 +01:00
2020-09-16 15:45:53 +02:00
// b_id index of buffer contained in this->indices
// i_id index of first index contained in this->indices[b_id]
// s_id index of first vertex contained in this->vertices
void add_path ( const GCodeProcessor :: MoveVertex & move , unsigned int b_id , size_t i_id , size_t s_id );
2021-01-12 09:03:35 +01:00
#if ENABLE_SPLITTED_VERTEX_BUFFER
unsigned int max_vertices_per_segment () const {
switch ( render_primitive_type )
{
case ERenderPrimitiveType :: Point : { return 1 ; }
case ERenderPrimitiveType :: Line : { return 2 ; }
case ERenderPrimitiveType :: Triangle : { return 8 ; }
default : { return 0 ; }
}
}
size_t max_vertices_per_segment_size_floats () const { return vertices . vertex_size_floats () * static_cast < size_t > ( max_vertices_per_segment ()); }
size_t max_vertices_per_segment_size_bytes () const { return max_vertices_per_segment_size_floats () * sizeof ( float ); }
#endif // ENABLE_SPLITTED_VERTEX_BUFFER
2020-09-01 08:29:06 +02:00
unsigned int indices_per_segment () const {
switch ( render_primitive_type )
{
case ERenderPrimitiveType :: Point : { return 1 ; }
case ERenderPrimitiveType :: Line : { return 2 ; }
2021-02-05 11:53:39 +01:00
#if ENABLE_REDUCED_TOOLPATHS_SEGMENT_CAPS
case ERenderPrimitiveType :: Triangle : { return 30 ; } // 3 indices x 10 triangles
#else
2020-09-01 08:29:06 +02:00
case ERenderPrimitiveType :: Triangle : { return 42 ; } // 3 indices x 14 triangles
2021-02-05 11:53:39 +01:00
#endif // ENABLE_REDUCED_TOOLPATHS_SEGMENT_CAPS
2020-09-01 08:29:06 +02:00
default : { return 0 ; }
}
}
2021-01-12 09:03:35 +01:00
#if ENABLE_SPLITTED_VERTEX_BUFFER
2021-01-20 13:47:48 +01:00
size_t indices_per_segment_size_bytes () const { return static_cast < size_t > ( indices_per_segment () * sizeof ( IBufferType )); }
2021-01-12 09:03:35 +01:00
#endif // ENABLE_SPLITTED_VERTEX_BUFFER
2021-02-05 11:53:39 +01:00
#if ENABLE_REDUCED_TOOLPATHS_SEGMENT_CAPS
unsigned int max_indices_per_segment () const {
2020-09-01 14:35:42 +02:00
switch ( render_primitive_type )
{
2021-02-05 11:53:39 +01:00
case ERenderPrimitiveType :: Point : { return 1 ; }
case ERenderPrimitiveType :: Line : { return 2 ; }
case ERenderPrimitiveType :: Triangle : { return 36 ; } // 3 indices x 12 triangles
2020-09-01 14:35:42 +02:00
default : { return 0 ; }
}
}
2021-02-05 11:53:39 +01:00
size_t max_indices_per_segment_size_bytes () const { return max_indices_per_segment () * sizeof ( IBufferType ); }
#endif // ENABLE_REDUCED_TOOLPATHS_SEGMENT_CAPS
2020-09-16 15:45:53 +02:00
2021-01-12 09:03:35 +01:00
#if ENABLE_SPLITTED_VERTEX_BUFFER
bool has_data () const {
2021-01-13 10:45:52 +01:00
return ! vertices . vbos . empty () && vertices . vbos . front () != 0 && ! indices . empty () && indices . front (). ibo != 0 ;
2021-01-12 09:03:35 +01:00
}
#else
2021-02-05 11:53:39 +01:00
unsigned int start_segment_vertex_offset () const { return 0 ; }
unsigned int end_segment_vertex_offset () const {
switch ( render_primitive_type )
{
case ERenderPrimitiveType :: Point : { return 0 ; }
case ERenderPrimitiveType :: Line : { return 1 ; }
case ERenderPrimitiveType :: Triangle : { return 36 ; } // 1st vertex of 13th triangle
default : { return 0 ; }
}
}
2020-09-16 15:45:53 +02:00
bool has_data () const { return vertices . id != 0 && ! indices . empty () && indices . front (). id != 0 ; }
2021-01-12 09:03:35 +01:00
#endif // ENABLE_SPLITTED_VERTEX_BUFFER
2020-04-15 16:29:11 +02:00
};
2020-05-06 11:18:37 +02:00
// helper to render shells
2020-04-15 14:31:39 +02:00
struct Shells
{
GLVolumeCollection volumes ;
bool visible { false };
};
2020-04-20 10:52:16 +02:00
// helper to render extrusion paths
2020-04-17 10:43:29 +02:00
struct Extrusions
{
2020-04-20 10:52:16 +02:00
struct Range
{
float min ;
float max ;
2020-08-13 12:51:50 +02:00
unsigned int count ;
2020-04-20 10:52:16 +02:00
Range () { reset (); }
2020-08-13 12:51:50 +02:00
void update_from ( const float value ) {
if ( value != max && value != min )
++ count ;
min = std :: min ( min , value );
max = std :: max ( max , value );
}
void reset () { min = FLT_MAX ; max = - FLT_MAX ; count = 0 ; }
2020-04-20 10:52:16 +02:00
2020-04-22 16:29:07 +02:00
float step_size () const { return ( max - min ) / ( static_cast < float > ( Range_Colors . size ()) - 1.0f ); }
2020-05-05 12:09:11 +02:00
Color get_color_at ( float value ) const ;
2020-04-20 10:52:16 +02:00
};
struct Ranges
{
// Color mapping by layer height.
Range height ;
2020-04-20 13:24:25 +02:00
// Color mapping by extrusion width.
Range width ;
2020-04-20 16:04:59 +02:00
// Color mapping by feedrate.
Range feedrate ;
2020-04-21 09:06:43 +02:00
// Color mapping by fan speed.
Range fan_speed ;
2020-04-21 11:38:42 +02:00
// Color mapping by volumetric extrusion rate.
Range volumetric_rate ;
2021-02-26 14:17:53 +01:00
// Color mapping by extrusion temperature.
Range temperature ;
2020-04-20 10:52:16 +02:00
void reset () {
height . reset ();
2020-04-20 13:24:25 +02:00
width . reset ();
2020-04-20 16:04:59 +02:00
feedrate . reset ();
2020-04-21 09:06:43 +02:00
fan_speed . reset ();
2020-04-21 11:38:42 +02:00
volumetric_rate . reset ();
2021-02-26 14:17:53 +01:00
temperature . reset ();
2020-04-20 10:52:16 +02:00
}
};
2020-04-17 10:43:29 +02:00
unsigned int role_visibility_flags { 0 };
2020-04-20 10:52:16 +02:00
Ranges ranges ;
2020-04-17 10:43:29 +02:00
void reset_role_visibility_flags () {
role_visibility_flags = 0 ;
2020-08-26 15:29:33 +02:00
for ( unsigned int i = 0 ; i < erCount ; ++ i ) {
2020-04-17 10:43:29 +02:00
role_visibility_flags |= 1 << i ;
}
}
2020-04-20 10:52:16 +02:00
void reset_ranges () { ranges . reset (); }
2020-04-17 10:43:29 +02:00
};
2020-11-11 16:22:09 +01:00
class Layers
{
public :
struct Endpoints
{
size_t first { 0 };
size_t last { 0 };
2021-01-12 14:34:52 +01:00
2021-01-12 09:03:35 +01:00
#if ENABLE_SPLITTED_VERTEX_BUFFER
bool operator == ( const Endpoints & other ) const {
return first == other . first && last == other . last ;
}
#endif // ENABLE_SPLITTED_VERTEX_BUFFER
2020-11-11 16:22:09 +01:00
};
private :
std :: vector < double > m_zs ;
std :: vector < Endpoints > m_endpoints ;
public :
2021-01-12 09:03:35 +01:00
void append ( double z , Endpoints endpoints ) {
2020-11-11 16:22:09 +01:00
m_zs . emplace_back ( z );
m_endpoints . emplace_back ( endpoints );
}
2021-01-12 09:03:35 +01:00
void reset () {
2020-11-11 16:22:09 +01:00
m_zs = std :: vector < double > ();
m_endpoints = std :: vector < Endpoints > ();
}
size_t size () const { return m_zs . size (); }
bool empty () const { return m_zs . empty (); }
const std :: vector < double >& get_zs () const { return m_zs ; }
const std :: vector < Endpoints >& get_endpoints () const { return m_endpoints ; }
std :: vector < Endpoints >& get_endpoints () { return m_endpoints ; }
2020-11-12 16:29:44 +01:00
double get_z_at ( unsigned int id ) const { return ( id < m_zs . size ()) ? m_zs [ id ] : 0.0 ; }
2020-11-11 16:22:09 +01:00
Endpoints get_endpoints_at ( unsigned int id ) const { return ( id < m_endpoints . size ()) ? m_endpoints [ id ] : Endpoints (); }
2021-01-12 09:03:35 +01:00
#if ENABLE_SPLITTED_VERTEX_BUFFER
bool operator != ( const Layers & other ) const {
if ( m_zs != other . m_zs )
return true ;
if ( ! ( m_endpoints == other . m_endpoints ))
return true ;
return false ;
}
#endif // ENABLE_SPLITTED_VERTEX_BUFFER
2020-11-11 16:22:09 +01:00
};
2021-02-05 11:53:39 +01:00
#if ENABLE_REDUCED_TOOLPATHS_SEGMENT_CAPS
// used to render the toolpath caps of the current sequential range
// (i.e. when sliding on the horizontal slider)
struct SequentialRangeCap
{
TBuffer * buffer { nullptr };
unsigned int ibo { 0 };
unsigned int vbo { 0 };
Color color ;
~ SequentialRangeCap ();
bool is_renderable () const { return buffer != nullptr ; }
void reset ();
size_t indices_count () const { return 6 ; }
};
#endif // ENABLE_REDUCED_TOOLPATHS_SEGMENT_CAPS
2020-04-27 14:10:18 +02:00
#if ENABLE_GCODE_VIEWER_STATISTICS
struct Statistics
{
2020-09-11 15:19:23 +02:00
// time
2020-12-10 08:40:08 +01:00
int64_t results_time { 0 };
int64_t load_time { 0 };
2021-02-05 11:53:39 +01:00
int64_t load_vertices { 0 };
int64_t smooth_vertices { 0 };
int64_t load_indices { 0 };
2020-12-10 08:40:08 +01:00
int64_t refresh_time { 0 };
int64_t refresh_paths_time { 0 };
2020-06-24 16:57:09 +02:00
// opengl calls
2020-12-10 08:40:08 +01:00
int64_t gl_multi_points_calls_count { 0 };
int64_t gl_multi_lines_calls_count { 0 };
int64_t gl_multi_triangles_calls_count { 0 };
2021-02-05 11:53:39 +01:00
#if ENABLE_REDUCED_TOOLPATHS_SEGMENT_CAPS
int64_t gl_triangles_calls_count { 0 };
#endif // ENABLE_REDUCED_TOOLPATHS_SEGMENT_CAPS
2020-06-24 16:57:09 +02:00
// memory
2020-12-10 08:40:08 +01:00
int64_t results_size { 0 };
2020-12-11 11:58:08 +01:00
int64_t total_vertices_gpu_size { 0 };
int64_t total_indices_gpu_size { 0 };
int64_t max_vbuffer_gpu_size { 0 };
int64_t max_ibuffer_gpu_size { 0 };
2020-12-10 08:40:08 +01:00
int64_t paths_size { 0 };
int64_t render_paths_size { 0 };
2020-09-11 15:19:23 +02:00
// other
2020-12-10 08:40:08 +01:00
int64_t travel_segments_count { 0 };
int64_t wipe_segments_count { 0 };
int64_t extrude_segments_count { 0 };
2020-12-11 11:58:08 +01:00
int64_t vbuffers_count { 0 };
int64_t ibuffers_count { 0 };
2020-04-27 14:10:18 +02:00
void reset_all () {
reset_times ();
reset_opengl ();
reset_sizes ();
2020-09-11 15:19:23 +02:00
reset_others ();
2020-04-27 14:10:18 +02:00
}
void reset_times () {
2020-06-29 14:00:08 +02:00
results_time = 0 ;
2020-04-27 14:10:18 +02:00
load_time = 0 ;
2021-02-05 11:53:39 +01:00
load_vertices = 0 ;
smooth_vertices = 0 ;
load_indices = 0 ;
2020-04-27 14:10:18 +02:00
refresh_time = 0 ;
2020-05-05 13:57:51 +02:00
refresh_paths_time = 0 ;
2020-04-27 14:10:18 +02:00
}
void reset_opengl () {
2020-04-28 15:08:36 +02:00
gl_multi_points_calls_count = 0 ;
2020-08-26 15:29:33 +02:00
gl_multi_lines_calls_count = 0 ;
gl_multi_triangles_calls_count = 0 ;
2021-02-05 11:53:39 +01:00
#if ENABLE_REDUCED_TOOLPATHS_SEGMENT_CAPS
gl_triangles_calls_count = 0 ;
#endif // ENABLE_REDUCED_TOOLPATHS_SEGMENT_CAPS
2020-04-27 14:10:18 +02:00
}
void reset_sizes () {
2020-04-28 10:29:25 +02:00
results_size = 0 ;
2020-12-11 11:58:08 +01:00
total_vertices_gpu_size = 0 ;
total_indices_gpu_size = 0 ;
max_vbuffer_gpu_size = 0 ;
max_ibuffer_gpu_size = 0 ;
2020-06-29 14:00:08 +02:00
paths_size = 0 ;
2020-05-05 12:09:11 +02:00
render_paths_size = 0 ;
2020-04-27 14:10:18 +02:00
}
2020-06-29 14:00:08 +02:00
2020-09-11 15:19:23 +02:00
void reset_others () {
2020-06-29 14:00:08 +02:00
travel_segments_count = 0 ;
2020-11-21 10:36:10 +01:00
wipe_segments_count = 0 ;
2020-06-29 14:00:08 +02:00
extrude_segments_count = 0 ;
2020-12-11 11:58:08 +01:00
vbuffers_count = 0 ;
ibuffers_count = 0 ;
2020-06-29 14:00:08 +02:00
}
2020-04-27 14:10:18 +02:00
};
#endif // ENABLE_GCODE_VIEWER_STATISTICS
2020-04-16 15:59:36 +02:00
public :
2020-05-15 09:22:51 +02:00
struct SequentialView
{
class Marker
{
2020-05-27 08:06:02 +02:00
GLModel m_model ;
2020-06-09 08:12:51 +02:00
Vec3f m_world_position ;
2020-05-15 09:22:51 +02:00
Transform3f m_world_transform ;
2020-06-09 08:12:51 +02:00
float m_z_offset { 0.5f };
2020-10-09 12:21:00 +02:00
std :: array < float , 4 > m_color { 1.0f , 1.0f , 1.0f , 0.5f };
2020-11-03 09:27:18 +01:00
bool m_visible { true };
2020-05-15 09:22:51 +02:00
public :
void init ();
2020-06-24 16:57:09 +02:00
const BoundingBoxf3 & get_bounding_box () const { return m_model . get_bounding_box (); }
2020-05-15 09:22:51 +02:00
2020-05-22 10:43:59 +02:00
void set_world_position ( const Vec3f & position );
2020-05-15 09:22:51 +02:00
void set_color ( const std :: array < float , 4 >& color ) { m_color = color ; }
bool is_visible () const { return m_visible ; }
void set_visible ( bool visible ) { m_visible = visible ; }
void render () const ;
};
2021-03-02 10:01:06 +01:00
#if ENABLE_GCODE_WINDOW
class GCodeWindow
{
2021-03-04 13:23:24 +01:00
struct Line
{
std :: string command ;
std :: string parameters ;
std :: string comment ;
};
2021-03-03 09:03:07 +01:00
bool m_visible { true };
2021-03-08 08:35:32 +01:00
uint64_t m_selected_line_id { 0 };
2021-03-04 13:23:24 +01:00
size_t m_last_lines_size { 0 };
2021-03-02 10:01:06 +01:00
std :: string m_filename ;
2021-03-08 08:35:32 +01:00
boost :: iostreams :: mapped_file_source m_file ;
// map for accessing data in file by line number
std :: vector < std :: pair < uint64_t , uint64_t >> m_lines_map ;
// current visible lines
std :: vector < Line > m_lines ;
2021-03-02 10:01:06 +01:00
public :
2021-03-08 08:35:32 +01:00
GCodeWindow () = default ;
~ GCodeWindow () { stop_mapping_file (); }
2021-03-02 10:01:06 +01:00
void set_filename ( const std :: string & filename ) { m_filename = filename ; }
void load_gcode ();
2021-03-08 08:35:32 +01:00
void reset () {
stop_mapping_file ();
m_lines_map . clear ();
m_lines . clear ();
m_filename . clear ();
}
2021-03-02 10:01:06 +01:00
void toggle_visibility () { m_visible = ! m_visible ; }
2021-03-08 08:35:32 +01:00
void render ( float top , float bottom , uint64_t curr_line_id ) const ;
private :
void stop_mapping_file ();
2021-03-02 10:01:06 +01:00
};
#endif // ENABLE_GCODE_WINDOW
2020-05-18 13:24:07 +02:00
struct Endpoints
{
2020-09-16 15:45:53 +02:00
size_t first { 0 };
size_t last { 0 };
2020-05-18 13:24:07 +02:00
};
2020-10-09 13:00:20 +02:00
bool skip_invisible_moves { false };
2020-05-18 13:24:07 +02:00
Endpoints endpoints ;
Endpoints current ;
2020-10-07 13:19:44 +02:00
Endpoints last_current ;
2020-05-15 09:22:51 +02:00
Vec3f current_position { Vec3f :: Zero () };
Marker marker ;
2021-03-02 10:01:06 +01:00
#if ENABLE_GCODE_WINDOW
GCodeWindow gcode_window ;
#endif // ENABLE_GCODE_WINDOW
2021-02-16 10:07:05 +01:00
#if ENABLE_GCODE_LINES_ID_IN_H_SLIDER
std :: vector < unsigned int > gcode_ids ;
#endif // ENABLE_GCODE_LINES_ID_IN_H_SLIDER
2021-03-02 10:01:06 +01:00
#if ENABLE_GCODE_WINDOW
2021-03-03 09:03:07 +01:00
void render ( float legend_height ) const ;
2021-03-02 10:01:06 +01:00
#endif // ENABLE_GCODE_WINDOW
2020-05-15 09:22:51 +02:00
};
2020-04-16 15:59:36 +02:00
enum class EViewType : unsigned char
{
FeatureType ,
Height ,
Width ,
Feedrate ,
FanSpeed ,
2021-02-26 14:17:53 +01:00
Temperature ,
2020-04-16 15:59:36 +02:00
VolumetricRate ,
Tool ,
ColorPrint ,
Count
};
private :
2021-02-05 11:53:39 +01:00
bool m_gl_data_initialized { false };
2020-04-21 15:55:26 +02:00
unsigned int m_last_result_id { 0 };
2020-09-14 09:18:20 +02:00
size_t m_moves_count { 0 };
2021-02-05 11:53:39 +01:00
std :: vector < TBuffer > m_buffers { static_cast < size_t > ( EMoveType :: Extrude ) };
2020-06-24 16:57:09 +02:00
// bounding box of toolpaths
BoundingBoxf3 m_paths_bounding_box ;
// bounding box of toolpaths + marker tools
BoundingBoxf3 m_max_bounding_box ;
2020-05-05 12:09:11 +02:00
std :: vector < Color > m_tool_colors ;
2020-11-11 16:22:09 +01:00
Layers m_layers ;
2020-11-12 16:29:44 +01:00
std :: array < unsigned int , 2 > m_layers_z_range ;
2020-04-18 10:41:37 +02:00
std :: vector < ExtrusionRole > m_roles ;
2020-11-09 13:06:20 +01:00
size_t m_extruders_count ;
2020-04-22 16:29:07 +02:00
std :: vector < unsigned char > m_extruder_ids ;
2021-02-05 11:53:39 +01:00
Extrusions m_extrusions ;
SequentialView m_sequential_view ;
2020-04-15 14:31:39 +02:00
Shells m_shells ;
2020-04-24 10:59:03 +02:00
EViewType m_view_type { EViewType :: FeatureType };
2020-04-18 10:41:37 +02:00
bool m_legend_enabled { true };
2020-08-03 13:57:10 +02:00
PrintEstimatedTimeStatistics m_time_statistics ;
2021-02-05 11:53:39 +01:00
PrintEstimatedTimeStatistics :: ETimeMode m_time_estimate_mode { PrintEstimatedTimeStatistics :: ETimeMode :: Normal };
2020-04-27 14:10:18 +02:00
#if ENABLE_GCODE_VIEWER_STATISTICS
2021-02-05 11:53:39 +01:00
Statistics m_statistics ;
2020-04-27 14:10:18 +02:00
#endif // ENABLE_GCODE_VIEWER_STATISTICS
2021-02-05 11:53:39 +01:00
std :: array < float , 2 > m_detected_point_sizes = { 0.0f , 0.0f };
2020-11-09 08:41:14 +01:00
GCodeProcessor :: Result :: SettingsIds m_settings_ids ;
2021-02-05 11:53:39 +01:00
#if ENABLE_REDUCED_TOOLPATHS_SEGMENT_CAPS
std :: array < SequentialRangeCap , 2 > m_sequential_range_caps ;
#endif // ENABLE_REDUCED_TOOLPATHS_SEGMENT_CAPS
2020-04-16 15:59:36 +02:00
2020-04-14 10:02:08 +02:00
public :
2021-01-07 09:57:37 +01:00
GCodeViewer ();
2020-04-14 16:40:08 +02:00
~ GCodeViewer () { reset (); }
2020-04-14 10:02:08 +02:00
2020-04-21 15:55:26 +02:00
// extract rendering data from the given parameters
2020-04-22 16:29:07 +02:00
void load ( const GCodeProcessor :: Result & gcode_result , const Print & print , bool initialized );
// recalculate ranges in dependence of what is visible and sets tool/print colors
void refresh ( const GCodeProcessor :: Result & gcode_result , const std :: vector < std :: string >& str_tool_colors );
2020-12-11 14:59:58 +01:00
void refresh_render_paths ();
2020-12-18 09:03:18 +01:00
void update_shells_color_by_extruder ( const DynamicPrintConfig * config );
2020-04-20 16:04:59 +02:00
2020-04-14 16:40:08 +02:00
void reset ();
2020-04-14 10:02:08 +02:00
void render () const ;
2020-05-05 12:09:11 +02:00
bool has_data () const { return ! m_roles . empty (); }
2021-01-13 10:45:52 +01:00
#if ENABLE_SPLITTED_VERTEX_BUFFER
bool can_export_toolpaths () const ;
#endif // ENABLE_SPLITTED_VERTEX_BUFFER
2020-05-05 12:09:11 +02:00
2020-06-24 16:57:09 +02:00
const BoundingBoxf3 & get_paths_bounding_box () const { return m_paths_bounding_box ; }
const BoundingBoxf3 & get_max_bounding_box () const { return m_max_bounding_box ; }
2021-01-29 07:39:27 +01:00
const std :: vector < double >& get_layers_zs () const { return m_layers . get_zs (); }
2020-04-14 16:40:08 +02:00
2020-05-15 09:22:51 +02:00
const SequentialView & get_sequential_view () const { return m_sequential_view ; }
2020-10-07 13:19:44 +02:00
void update_sequential_view_current ( unsigned int first , unsigned int last );
2020-05-15 09:22:51 +02:00
2020-04-16 15:59:36 +02:00
EViewType get_view_type () const { return m_view_type ; }
void set_view_type ( EViewType type ) {
if ( type == EViewType :: Count )
type = EViewType :: FeatureType ;
m_view_type = type ;
}
2020-08-03 13:57:10 +02:00
bool is_toolpath_move_type_visible ( EMoveType type ) const ;
void set_toolpath_move_type_visible ( EMoveType type , bool visible );
2020-04-28 08:50:52 +02:00
unsigned int get_toolpath_role_visibility_flags () const { return m_extrusions . role_visibility_flags ; }
2020-04-17 10:43:29 +02:00
void set_toolpath_role_visibility_flags ( unsigned int flags ) { m_extrusions . role_visibility_flags = flags ; }
2020-04-28 08:50:52 +02:00
unsigned int get_options_visibility_flags () const ;
2020-04-24 16:12:38 +02:00
void set_options_visibility_from_flags ( unsigned int flags );
2020-11-11 16:22:09 +01:00
void set_layers_z_range ( const std :: array < unsigned int , 2 >& layers_z_range );
2020-04-15 14:31:39 +02:00
2020-04-18 10:41:37 +02:00
bool is_legend_enabled () const { return m_legend_enabled ; }
void enable_legend ( bool enable ) { m_legend_enabled = enable ; }
2020-07-03 12:17:12 +02:00
void export_toolpaths_to_obj ( const char * filename ) const ;
2021-03-02 10:01:06 +01:00
#if ENABLE_GCODE_WINDOW
void toggle_gcode_window_visibility () { m_sequential_view . gcode_window . toggle_visibility (); }
#endif // ENABLE_GCODE_WINDOW
2020-04-14 10:02:08 +02:00
private :
2020-04-15 14:31:39 +02:00
void load_toolpaths ( const GCodeProcessor :: Result & gcode_result );
void load_shells ( const Print & print , bool initialized );
2020-10-15 10:25:13 +02:00
void refresh_render_paths ( bool keep_sequential_current_first , bool keep_sequential_current_last ) const ;
2020-04-15 14:31:39 +02:00
void render_toolpaths () const ;
void render_shells () const ;
2021-03-03 09:03:07 +01:00
#if ENABLE_GCODE_WINDOW
void render_legend ( float & legend_height ) const ;
#else
2020-04-27 14:10:18 +02:00
void render_legend () const ;
2021-03-03 09:03:07 +01:00
#endif // ENABLE_GCODE_WINDOW
2020-04-27 14:10:18 +02:00
#if ENABLE_GCODE_VIEWER_STATISTICS
void render_statistics () const ;
#endif // ENABLE_GCODE_VIEWER_STATISTICS
2020-04-27 12:43:51 +02:00
bool is_visible ( ExtrusionRole role ) const {
return role < erCount && ( m_extrusions . role_visibility_flags & ( 1 << role )) != 0 ;
}
bool is_visible ( const Path & path ) const { return is_visible ( path . role ); }
2020-12-10 08:40:08 +01:00
void log_memory_used ( const std :: string & label , int64_t additional = 0 ) const ;
2020-04-14 10:02:08 +02:00
};
} // namespace GUI
} // namespace Slic3r
#endif // slic3r_GCodeViewer_hpp_