2020-04-14 10:02:08 +02:00
#include "libslic3r/libslic3r.h"
#include "GCodeViewer.hpp"
#if ENABLE_GCODE_VIEWER
2020-04-15 14:31:39 +02:00
#include "libslic3r/Print.hpp"
2020-05-11 13:09:26 +02:00
#include "libslic3r/Geometry.hpp"
2020-04-15 14:31:39 +02:00
#include "GUI_App.hpp"
2020-06-08 09:12:20 +02:00
#if ENABLE_GCODE_VIEWER_AS_STATE
#include "MainFrame.hpp"
#endif // ENABLE_GCODE_VIEWER_AS_STATE
2020-05-27 15:28:24 +02:00
#include "Plater.hpp"
2020-04-15 14:31:39 +02:00
#include "PresetBundle.hpp"
#include "Camera.hpp"
2020-04-18 10:41:37 +02:00
#include "I18N.hpp"
2020-04-21 15:55:26 +02:00
#include "GUI_Utils.hpp"
2020-04-22 16:29:07 +02:00
#include "DoubleSlider.hpp"
2020-04-23 14:02:47 +02:00
#include "GLCanvas3D.hpp"
2020-05-05 12:09:11 +02:00
#include "GLToolbar.hpp"
2020-05-18 13:24:07 +02:00
#include "GUI_Preview.hpp"
2020-04-22 16:29:07 +02:00
#include "libslic3r/Model.hpp"
2020-04-27 14:10:18 +02:00
#if ENABLE_GCODE_VIEWER_STATISTICS
#include <imgui/imgui_internal.h>
#endif // ENABLE_GCODE_VIEWER_STATISTICS
2020-04-14 10:02:08 +02:00
#include <GL/glew.h>
#include <boost/log/trivial.hpp>
#include <array>
2020-04-14 16:40:08 +02:00
#include <algorithm>
#include <chrono>
2020-04-14 10:02:08 +02:00
namespace Slic3r {
namespace GUI {
static unsigned char buffer_id ( GCodeProcessor :: EMoveType type ) {
return static_cast < unsigned char > ( type ) - static_cast < unsigned char > ( GCodeProcessor :: EMoveType :: Retract );
}
static GCodeProcessor :: EMoveType buffer_type ( unsigned char id ) {
return static_cast < GCodeProcessor :: EMoveType > ( static_cast < unsigned char > ( GCodeProcessor :: EMoveType :: Retract ) + id );
}
2020-05-05 12:09:11 +02:00
std :: vector < std :: array < float , 3 >> decode_colors ( const std :: vector < std :: string > & colors ) {
2020-04-21 15:55:26 +02:00
static const float INV_255 = 1.0f / 255.0f ;
2020-05-05 12:09:11 +02:00
std :: vector < std :: array < float , 3 >> output ( colors . size (), { 0.0f , 0.0f , 0.0f });
2020-04-21 15:55:26 +02:00
for ( size_t i = 0 ; i < colors . size (); ++ i )
{
const std :: string & color = colors [ i ];
const char * c = color . data () + 1 ;
2020-04-23 10:24:03 +02:00
if (( color . size () == 7 ) && ( color . front () == '#' )) {
for ( size_t j = 0 ; j < 3 ; ++ j ) {
2020-04-21 15:55:26 +02:00
int digit1 = hex_digit_to_int ( * c ++ );
int digit2 = hex_digit_to_int ( * c ++ );
if (( digit1 == - 1 ) || ( digit2 == - 1 ))
break ;
output [ i ][ j ] = float ( digit1 * 16 + digit2 ) * INV_255 ;
}
}
}
return output ;
}
2020-04-15 16:29:11 +02:00
void GCodeViewer :: VBuffer :: reset ()
2020-04-14 16:40:08 +02:00
{
// release gpu memory
2020-04-23 10:24:03 +02:00
if ( vbo_id > 0 ) {
2020-04-14 16:40:08 +02:00
glsafe ( :: glDeleteBuffers ( 1 , & vbo_id ));
2020-04-21 11:38:42 +02:00
vbo_id = 0 ;
}
2020-04-14 16:40:08 +02:00
2020-04-15 16:29:11 +02:00
vertices_count = 0 ;
}
2020-05-04 09:37:06 +02:00
bool GCodeViewer :: Path :: matches ( const GCodeProcessor :: MoveVertex & move ) const
{
switch ( move . type )
{
case GCodeProcessor :: EMoveType :: Tool_change :
case GCodeProcessor :: EMoveType :: Color_change :
case GCodeProcessor :: EMoveType :: Pause_Print :
case GCodeProcessor :: EMoveType :: Custom_GCode :
case GCodeProcessor :: EMoveType :: Retract :
case GCodeProcessor :: EMoveType :: Unretract :
case GCodeProcessor :: EMoveType :: Extrude :
{
return type == move . type && role == move . extrusion_role && height == move . height && width == move . width &&
feedrate == move . feedrate && fan_speed == move . fan_speed && volumetric_rate == move . volumetric_rate () &&
extruder_id == move . extruder_id && cp_color_id == move . cp_color_id ;
}
case GCodeProcessor :: EMoveType :: Travel :
{
return type == move . type && feedrate == move . feedrate && extruder_id == move . extruder_id && cp_color_id == move . cp_color_id ;
}
default : { return false ; }
}
}
2020-04-15 16:29:11 +02:00
void GCodeViewer :: IBuffer :: reset ()
{
// release gpu memory
2020-04-23 10:24:03 +02:00
if ( ibo_id > 0 ) {
2020-04-15 16:29:11 +02:00
glsafe ( :: glDeleteBuffers ( 1 , & ibo_id ));
2020-04-21 11:38:42 +02:00
ibo_id = 0 ;
}
2020-04-15 16:29:11 +02:00
2020-04-14 16:40:08 +02:00
// release cpu memory
2020-05-06 11:18:37 +02:00
indices_count = 0 ;
2020-04-16 15:09:04 +02:00
paths = std :: vector < Path > ();
2020-05-05 12:09:11 +02:00
render_paths = std :: vector < RenderPath > ();
2020-04-14 16:40:08 +02:00
}
2020-05-06 11:18:37 +02:00
void GCodeViewer :: IBuffer :: add_path ( const GCodeProcessor :: MoveVertex & move , unsigned int i_id , unsigned int s_id )
2020-04-16 15:09:04 +02:00
{
2020-05-06 11:18:37 +02:00
Path :: Endpoint endpoint = { i_id , s_id , move . position };
2020-04-28 12:24:03 +02:00
paths . push_back ({ move . type , move . extrusion_role , endpoint , endpoint , move . delta_extruder , move . height , move . width , move . feedrate , move . fan_speed , move . volumetric_rate (), move . extruder_id , move . cp_color_id });
2020-04-20 10:52:16 +02:00
}
2020-05-05 12:09:11 +02:00
GCodeViewer :: Color GCodeViewer :: Extrusions :: Range :: get_color_at ( float value ) const
2020-04-20 10:52:16 +02:00
{
2020-04-21 09:06:43 +02:00
// Input value scaled to the colors range
2020-04-20 10:52:16 +02:00
const float step = step_size ();
const float global_t = ( step != 0.0f ) ? std :: max ( 0.0f , value - min ) / step : 0.0f ; // lower limit of 0.0f
2020-04-21 12:51:58 +02:00
const size_t color_max_idx = Range_Colors . size () - 1 ;
2020-04-20 10:52:16 +02:00
// Compute the two colors just below (low) and above (high) the input value
2020-04-20 13:24:25 +02:00
const size_t color_low_idx = std :: clamp < size_t > ( static_cast < size_t > ( global_t ), 0 , color_max_idx );
const size_t color_high_idx = std :: clamp < size_t > ( color_low_idx + 1 , 0 , color_max_idx );
2020-04-20 10:52:16 +02:00
// Compute how far the value is between the low and high colors so that they can be interpolated
2020-04-20 16:04:59 +02:00
const float local_t = std :: clamp ( global_t - static_cast < float > ( color_low_idx ), 0.0f , 1.0f );
2020-04-20 10:52:16 +02:00
2020-04-21 09:06:43 +02:00
// Interpolate between the low and high colors to find exactly which color the input value should get
2020-05-05 12:09:11 +02:00
Color ret ;
2020-04-23 10:24:03 +02:00
for ( unsigned int i = 0 ; i < 3 ; ++ i ) {
2020-04-21 12:51:58 +02:00
ret [ i ] = lerp ( Range_Colors [ color_low_idx ][ i ], Range_Colors [ color_high_idx ][ i ], local_t );
2020-04-20 10:52:16 +02:00
}
return ret ;
2020-04-16 15:09:04 +02:00
}
2020-05-06 11:18:37 +02:00
void GCodeViewer :: SequentialView :: Marker :: init ()
{
2020-05-12 11:33:50 +02:00
m_model . init_from ( stilized_arrow ( 16 , 2.0f , 4.0f , 1.0f , 8.0f ));
2020-05-06 11:18:37 +02:00
}
2020-05-22 10:43:59 +02:00
void GCodeViewer :: SequentialView :: Marker :: set_world_position ( const Vec3f & position )
2020-06-09 08:12:51 +02:00
{
m_world_position = position ;
m_world_transform = ( Geometry :: assemble_transform (( position + m_z_offset * Vec3f :: UnitZ ()). cast < double > ()) * Geometry :: assemble_transform ( m_model . get_bounding_box (). size ()[ 2 ] * Vec3d :: UnitZ (), { M_PI , 0.0 , 0.0 })). cast < float > ();
2020-05-22 10:43:59 +02:00
m_world_bounding_box = m_model . get_bounding_box (). transformed ( m_world_transform . cast < double > ());
}
2020-05-06 11:18:37 +02:00
void GCodeViewer :: SequentialView :: Marker :: render () const
{
2020-05-20 14:11:22 +02:00
if ( ! m_visible )
return ;
GLShaderProgram * shader = wxGetApp (). get_shader ( "gouraud_light" );
if ( shader == nullptr )
return ;
glsafe ( :: glEnable ( GL_BLEND ));
glsafe ( :: glBlendFunc ( GL_SRC_ALPHA , GL_ONE_MINUS_SRC_ALPHA ));
shader -> start_using ();
shader -> set_uniform ( "uniform_color" , m_color );
2020-05-11 13:09:26 +02:00
glsafe ( :: glPushMatrix ());
glsafe ( :: glMultMatrixf ( m_world_transform . data ()));
2020-05-11 16:26:35 +02:00
m_model . render ();
2020-05-11 13:09:26 +02:00
glsafe ( :: glPopMatrix ());
2020-05-20 14:11:22 +02:00
shader -> stop_using ();
2020-05-11 13:09:26 +02:00
glsafe ( :: glDisable ( GL_BLEND ));
2020-06-09 08:12:51 +02:00
static float last_window_width = 0.0f ;
static size_t last_text_length = 0 ;
static const ImVec4 ORANGE ( 1.0f , 0.49f , 0.22f , 1.0f );
ImGuiWrapper & imgui = * wxGetApp (). imgui ();
Size cnv_size = wxGetApp (). plater () -> get_current_canvas3D () -> get_canvas_size ();
imgui . set_next_window_pos ( static_cast < float > ( cnv_size . get_width ()), static_cast < float > ( cnv_size . get_height ()), ImGuiCond_Always , 1.0f , 1.0f );
ImGui :: PushStyleVar ( ImGuiStyleVar_WindowRounding , 0.0f );
ImGui :: SetNextWindowBgAlpha ( 0.25f );
imgui . begin ( std :: string ( "ToolPosition" ), ImGuiWindowFlags_AlwaysAutoResize | ImGuiWindowFlags_NoDecoration | ImGuiWindowFlags_NoMove );
ImGui :: PushStyleColor ( ImGuiCol_Text , ORANGE );
imgui . text ( _u8L ( "Tool position" ) + ":" );
ImGui :: PopStyleColor ();
ImGui :: SameLine ();
char buf [ 1024 ];
sprintf ( buf , "X: %.2f, Y: %.2f, Z: %.2f" , m_world_position ( 0 ), m_world_position ( 1 ), m_world_position ( 2 ));
imgui . text ( std :: string ( buf ));
// force extra frame to automatically update window size
float width = ImGui :: GetWindowWidth ();
size_t length = strlen ( buf );
if ( width != last_window_width || length != last_text_length ) {
last_window_width = width ;
last_text_length = length ;
wxGetApp (). plater () -> get_current_canvas3D () -> set_as_dirty ();
wxGetApp (). plater () -> get_current_canvas3D () -> request_extra_frame ();
}
imgui . end ();
ImGui :: PopStyleVar ();
2020-05-06 11:18:37 +02:00
}
2020-05-11 13:09:26 +02:00
const std :: vector < GCodeViewer :: Color > GCodeViewer :: Extrusion_Role_Colors {{
2020-04-22 16:29:07 +02:00
{ 0.50f , 0.50f , 0.50f }, // erNone
2020-04-20 13:44:14 +02:00
{ 1.00f , 1.00f , 0.40f }, // erPerimeter
{ 1.00f , 0.65f , 0.00f }, // erExternalPerimeter
{ 0.00f , 0.00f , 1.00f }, // erOverhangPerimeter
{ 0.69f , 0.19f , 0.16f }, // erInternalInfill
{ 0.84f , 0.20f , 0.84f }, // erSolidInfill
{ 1.00f , 0.10f , 0.10f }, // erTopSolidInfill
2020-05-07 10:49:12 +02:00
{ 1.00f , 0.55f , 0.41f }, // erIroning
2020-04-20 13:44:14 +02:00
{ 0.60f , 0.60f , 1.00f }, // erBridgeInfill
{ 1.00f , 1.00f , 1.00f }, // erGapFill
{ 0.52f , 0.48f , 0.13f }, // erSkirt
{ 0.00f , 1.00f , 0.00f }, // erSupportMaterial
{ 0.00f , 0.50f , 0.00f }, // erSupportMaterialInterface
{ 0.70f , 0.89f , 0.67f }, // erWipeTower
{ 0.16f , 0.80f , 0.58f }, // erCustom
{ 0.00f , 0.00f , 0.00f } // erMixed
2020-04-16 15:09:04 +02:00
}};
2020-05-22 11:52:07 +02:00
const std :: vector < GCodeViewer :: Color > GCodeViewer :: Options_Colors {{
{ 1.00f , 0.00f , 1.00f }, // Retractions
{ 0.00f , 1.00f , 1.00f }, // Unretractions
{ 1.00f , 1.00f , 1.00f }, // ToolChanges
{ 1.00f , 0.00f , 0.00f }, // ColorChanges
{ 0.00f , 1.00f , 0.00f }, // PausePrints
{ 0.00f , 0.00f , 1.00f } // CustomGCodes
}};
2020-05-11 13:09:26 +02:00
const std :: vector < GCodeViewer :: Color > GCodeViewer :: Travel_Colors {{
2020-04-24 08:46:31 +02:00
{ 0.0f , 0.0f , 0.5f }, // Move
{ 0.0f , 0.5f , 0.0f }, // Extrude
{ 0.5f , 0.0f , 0.0f } // Retract
}};
2020-05-11 13:09:26 +02:00
const std :: vector < GCodeViewer :: Color > GCodeViewer :: Range_Colors {{
2020-04-21 09:06:43 +02:00
{ 0.043f , 0.173f , 0.478f }, // bluish
2020-04-20 13:44:14 +02:00
{ 0.075f , 0.349f , 0.522f },
{ 0.110f , 0.533f , 0.569f },
{ 0.016f , 0.839f , 0.059f },
{ 0.667f , 0.949f , 0.000f },
{ 0.988f , 0.975f , 0.012f },
{ 0.961f , 0.808f , 0.039f },
{ 0.890f , 0.533f , 0.125f },
{ 0.820f , 0.408f , 0.188f },
2020-04-21 09:06:43 +02:00
{ 0.761f , 0.322f , 0.235f } // reddish
2020-04-20 10:52:16 +02:00
}};
2020-05-26 08:16:08 +02:00
bool GCodeViewer :: init ()
{
set_toolpath_move_type_visible ( GCodeProcessor :: EMoveType :: Extrude , true );
m_sequential_view . marker . init ();
init_shaders ();
std :: array < int , 2 > point_sizes ;
:: glGetIntegerv ( GL_ALIASED_POINT_SIZE_RANGE , point_sizes . data ());
m_detected_point_sizes = { static_cast < float > ( point_sizes [ 0 ]), static_cast < float > ( point_sizes [ 1 ]) };
return true ;
}
2020-04-22 16:29:07 +02:00
void GCodeViewer :: load ( const GCodeProcessor :: Result & gcode_result , const Print & print , bool initialized )
2020-04-14 10:02:08 +02:00
{
2020-04-21 15:55:26 +02:00
// avoid processing if called with the same gcode_result
2020-04-14 10:02:08 +02:00
if ( m_last_result_id == gcode_result . id )
return ;
m_last_result_id = gcode_result . id ;
// release gpu memory, if used
2020-04-14 16:40:08 +02:00
reset ();
2020-04-14 10:02:08 +02:00
2020-04-15 14:31:39 +02:00
load_toolpaths ( gcode_result );
2020-06-22 09:10:41 +02:00
#if ENABLE_GCODE_VIEWER_AS_STATE
if ( wxGetApp (). mainframe -> get_mode () != MainFrame :: EMode :: GCodeViewer )
#endif // ENABLE_GCODE_VIEWER_AS_STATE
load_shells ( print , initialized );
2020-06-08 12:27:32 +02:00
#if ENABLE_GCODE_VIEWER_AS_STATE
2020-06-08 13:17:07 +02:00
if ( wxGetApp (). mainframe -> get_mode () == MainFrame :: EMode :: GCodeViewer ) {
// adjust printbed size
const double margin = 10.0 ;
Vec2d min ( m_bounding_box . min ( 0 ) - margin , m_bounding_box . min ( 1 ) - margin );
Vec2d max ( m_bounding_box . max ( 0 ) + margin , m_bounding_box . max ( 1 ) + margin );
Pointfs bed_shape = {
{ min ( 0 ), min ( 1 ) },
{ max ( 0 ), min ( 1 ) },
{ max ( 0 ), max ( 1 ) },
{ min ( 0 ), max ( 1 ) } };
wxGetApp (). plater () -> set_bed_shape ( bed_shape , "" , "" );
}
2020-06-08 12:27:32 +02:00
#endif // ENABLE_GCODE_VIEWER_AS_STATE
2020-04-14 16:40:08 +02:00
}
2020-04-22 16:29:07 +02:00
void GCodeViewer :: refresh ( const GCodeProcessor :: Result & gcode_result , const std :: vector < std :: string >& str_tool_colors )
2020-04-20 16:04:59 +02:00
{
2020-04-27 14:10:18 +02:00
#if ENABLE_GCODE_VIEWER_STATISTICS
2020-04-27 12:43:51 +02:00
auto start_time = std :: chrono :: high_resolution_clock :: now ();
2020-04-27 14:10:18 +02:00
#endif // ENABLE_GCODE_VIEWER_STATISTICS
2020-04-27 12:43:51 +02:00
2020-04-20 16:04:59 +02:00
if ( m_vertices . vertices_count == 0 )
return ;
2020-04-25 11:16:28 +02:00
// update tool colors
2020-04-22 16:29:07 +02:00
m_tool_colors = decode_colors ( str_tool_colors );
2020-04-27 11:44:29 +02:00
// update ranges for coloring / legend
2020-04-20 16:04:59 +02:00
m_extrusions . reset_ranges ();
for ( size_t i = 0 ; i < m_vertices . vertices_count ; ++ i )
{
// skip first vertex
if ( i == 0 )
continue ;
const GCodeProcessor :: MoveVertex & curr = gcode_result . moves [ i ];
switch ( curr . type )
{
case GCodeProcessor :: EMoveType :: Extrude :
2020-04-24 08:46:31 +02:00
{
m_extrusions . ranges . height . update_from ( curr . height );
m_extrusions . ranges . width . update_from ( curr . width );
m_extrusions . ranges . fan_speed . update_from ( curr . fan_speed );
m_extrusions . ranges . volumetric_rate . update_from ( curr . volumetric_rate ());
[[fallthrough]] ;
}
2020-04-20 16:04:59 +02:00
case GCodeProcessor :: EMoveType :: Travel :
{
2020-04-25 11:16:28 +02:00
if ( m_buffers [ buffer_id ( curr . type )]. visible )
2020-04-20 16:04:59 +02:00
m_extrusions . ranges . feedrate . update_from ( curr . feedrate );
2020-04-25 11:16:28 +02:00
2020-04-20 16:04:59 +02:00
break ;
}
2020-04-21 15:55:26 +02:00
default : { break ; }
2020-04-20 16:04:59 +02:00
}
}
2020-04-27 12:43:51 +02:00
2020-04-28 15:08:36 +02:00
// update buffers' render paths
2020-05-18 13:24:07 +02:00
refresh_render_paths ( false , false );
2020-04-28 15:08:36 +02:00
2020-04-27 14:10:18 +02:00
#if ENABLE_GCODE_VIEWER_STATISTICS
m_statistics . refresh_time = std :: chrono :: duration_cast < std :: chrono :: milliseconds > ( std :: chrono :: high_resolution_clock :: now () - start_time ). count ();
#endif // ENABLE_GCODE_VIEWER_STATISTICS
2020-04-20 16:04:59 +02:00
}
2020-04-14 16:40:08 +02:00
void GCodeViewer :: reset ()
{
2020-04-15 16:29:11 +02:00
m_vertices . reset ();
2020-04-23 10:24:03 +02:00
for ( IBuffer & buffer : m_buffers ) {
2020-04-14 16:40:08 +02:00
buffer . reset ();
}
2020-04-17 13:28:25 +02:00
m_bounding_box = BoundingBoxf3 ();
2020-05-05 12:09:11 +02:00
m_tool_colors = std :: vector < Color > ();
2020-04-22 16:29:07 +02:00
m_extruder_ids = std :: vector < unsigned char > ();
2020-04-17 10:43:29 +02:00
m_extrusions . reset_role_visibility_flags ();
2020-04-20 10:52:16 +02:00
m_extrusions . reset_ranges ();
2020-04-15 14:31:39 +02:00
m_shells . volumes . clear ();
2020-04-14 16:40:08 +02:00
m_layers_zs = std :: vector < double > ();
2020-04-27 11:44:29 +02:00
m_layers_z_range = { 0.0 , 0.0 };
2020-04-18 10:41:37 +02:00
m_roles = std :: vector < ExtrusionRole > ();
2020-04-27 14:10:18 +02:00
#if ENABLE_GCODE_VIEWER_STATISTICS
m_statistics . reset_all ();
#endif // ENABLE_GCODE_VIEWER_STATISTICS
2020-04-14 10:02:08 +02:00
}
void GCodeViewer :: render () const
{
2020-04-27 14:10:18 +02:00
#if ENABLE_GCODE_VIEWER_STATISTICS
m_statistics . reset_opengl ();
#endif // ENABLE_GCODE_VIEWER_STATISTICS
2020-05-11 13:09:26 +02:00
if ( m_roles . empty ())
return ;
2020-04-14 10:02:08 +02:00
glsafe ( :: glEnable ( GL_DEPTH_TEST ));
2020-04-15 14:31:39 +02:00
render_toolpaths ();
2020-06-09 08:12:51 +02:00
m_sequential_view . marker . set_world_position ( m_sequential_view . current_position );
2020-05-11 13:09:26 +02:00
m_sequential_view . marker . render ();
2020-04-15 14:31:39 +02:00
render_shells ();
2020-04-27 14:10:18 +02:00
render_legend ();
#if ENABLE_GCODE_VIEWER_STATISTICS
render_statistics ();
#endif // ENABLE_GCODE_VIEWER_STATISTICS
2020-05-26 08:16:08 +02:00
#if ENABLE_GCODE_VIEWER_SHADERS_EDITOR
render_shaders_editor ();
#endif // ENABLE_GCODE_VIEWER_SHADERS_EDITOR
2020-04-14 10:02:08 +02:00
}
2020-04-23 10:24:03 +02:00
bool GCodeViewer :: is_toolpath_move_type_visible ( GCodeProcessor :: EMoveType type ) const
2020-04-14 16:40:08 +02:00
{
size_t id = static_cast < size_t > ( buffer_id ( type ));
return ( id < m_buffers . size ()) ? m_buffers [ id ]. visible : false ;
}
2020-04-17 10:43:29 +02:00
void GCodeViewer :: set_toolpath_move_type_visible ( GCodeProcessor :: EMoveType type , bool visible )
2020-04-14 16:40:08 +02:00
{
size_t id = static_cast < size_t > ( buffer_id ( type ));
if ( id < m_buffers . size ())
m_buffers [ id ]. visible = visible ;
}
2020-04-28 08:50:52 +02:00
unsigned int GCodeViewer :: get_options_visibility_flags () const
{
auto set_flag = []( unsigned int flags , unsigned int flag , bool active ) {
return active ? ( flags | ( 1 << flag )) : flags ;
};
unsigned int flags = 0 ;
2020-05-18 13:24:07 +02:00
flags = set_flag ( flags , static_cast < unsigned int > ( Preview :: OptionType :: Travel ), is_toolpath_move_type_visible ( GCodeProcessor :: EMoveType :: Travel ));
flags = set_flag ( flags , static_cast < unsigned int > ( Preview :: OptionType :: Retractions ), is_toolpath_move_type_visible ( GCodeProcessor :: EMoveType :: Retract ));
flags = set_flag ( flags , static_cast < unsigned int > ( Preview :: OptionType :: Unretractions ), is_toolpath_move_type_visible ( GCodeProcessor :: EMoveType :: Unretract ));
flags = set_flag ( flags , static_cast < unsigned int > ( Preview :: OptionType :: ToolChanges ), is_toolpath_move_type_visible ( GCodeProcessor :: EMoveType :: Tool_change ));
flags = set_flag ( flags , static_cast < unsigned int > ( Preview :: OptionType :: ColorChanges ), is_toolpath_move_type_visible ( GCodeProcessor :: EMoveType :: Color_change ));
flags = set_flag ( flags , static_cast < unsigned int > ( Preview :: OptionType :: PausePrints ), is_toolpath_move_type_visible ( GCodeProcessor :: EMoveType :: Pause_Print ));
flags = set_flag ( flags , static_cast < unsigned int > ( Preview :: OptionType :: CustomGCodes ), is_toolpath_move_type_visible ( GCodeProcessor :: EMoveType :: Custom_GCode ));
flags = set_flag ( flags , static_cast < unsigned int > ( Preview :: OptionType :: Shells ), m_shells . visible );
flags = set_flag ( flags , static_cast < unsigned int > ( Preview :: OptionType :: ToolMarker ), m_sequential_view . marker . is_visible ());
flags = set_flag ( flags , static_cast < unsigned int > ( Preview :: OptionType :: Legend ), is_legend_enabled ());
2020-04-28 08:50:52 +02:00
return flags ;
}
2020-04-24 16:12:38 +02:00
void GCodeViewer :: set_options_visibility_from_flags ( unsigned int flags )
{
auto is_flag_set = [ flags ]( unsigned int flag ) {
2020-04-28 08:50:52 +02:00
return ( flags & ( 1 << flag )) != 0 ;
2020-04-24 16:12:38 +02:00
};
2020-05-18 13:24:07 +02:00
set_toolpath_move_type_visible ( GCodeProcessor :: EMoveType :: Travel , is_flag_set ( static_cast < unsigned int > ( Preview :: OptionType :: Travel )));
set_toolpath_move_type_visible ( GCodeProcessor :: EMoveType :: Retract , is_flag_set ( static_cast < unsigned int > ( Preview :: OptionType :: Retractions )));
set_toolpath_move_type_visible ( GCodeProcessor :: EMoveType :: Unretract , is_flag_set ( static_cast < unsigned int > ( Preview :: OptionType :: Unretractions )));
set_toolpath_move_type_visible ( GCodeProcessor :: EMoveType :: Tool_change , is_flag_set ( static_cast < unsigned int > ( Preview :: OptionType :: ToolChanges )));
set_toolpath_move_type_visible ( GCodeProcessor :: EMoveType :: Color_change , is_flag_set ( static_cast < unsigned int > ( Preview :: OptionType :: ColorChanges )));
set_toolpath_move_type_visible ( GCodeProcessor :: EMoveType :: Pause_Print , is_flag_set ( static_cast < unsigned int > ( Preview :: OptionType :: PausePrints )));
set_toolpath_move_type_visible ( GCodeProcessor :: EMoveType :: Custom_GCode , is_flag_set ( static_cast < unsigned int > ( Preview :: OptionType :: CustomGCodes )));
m_shells . visible = is_flag_set ( static_cast < unsigned int > ( Preview :: OptionType :: Shells ));
m_sequential_view . marker . set_visible ( is_flag_set ( static_cast < unsigned int > ( Preview :: OptionType :: ToolMarker )));
enable_legend ( is_flag_set ( static_cast < unsigned int > ( Preview :: OptionType :: Legend )));
2020-04-24 16:12:38 +02:00
}
2020-05-15 09:22:51 +02:00
void GCodeViewer :: set_layers_z_range ( const std :: array < double , 2 >& layers_z_range )
{
2020-05-18 13:24:07 +02:00
bool keep_sequential_current_first = layers_z_range [ 0 ] >= m_layers_z_range [ 0 ];
bool keep_sequential_current_last = layers_z_range [ 1 ] <= m_layers_z_range [ 1 ];
2020-05-15 09:22:51 +02:00
m_layers_z_range = layers_z_range ;
2020-05-18 13:24:07 +02:00
refresh_render_paths ( keep_sequential_current_first , keep_sequential_current_last );
2020-05-15 12:25:38 +02:00
wxGetApp (). plater () -> update_preview_moves_slider ();
2020-05-15 09:22:51 +02:00
}
2020-05-20 14:11:22 +02:00
void GCodeViewer :: init_shaders ()
{
unsigned char begin_id = buffer_id ( GCodeProcessor :: EMoveType :: Retract );
unsigned char end_id = buffer_id ( GCodeProcessor :: EMoveType :: Count );
2020-05-27 16:31:02 +02:00
bool is_glsl_120 = wxGetApp (). is_glsl_version_greater_or_equal_to ( 1 , 20 );
2020-05-20 14:11:22 +02:00
for ( unsigned char i = begin_id ; i < end_id ; ++ i )
{
switch ( buffer_type ( i ))
{
2020-05-27 16:31:02 +02:00
case GCodeProcessor :: EMoveType :: Tool_change : { m_buffers [ i ]. shader = is_glsl_120 ? "options_120_solid" : "options_110" ; break ; }
case GCodeProcessor :: EMoveType :: Color_change : { m_buffers [ i ]. shader = is_glsl_120 ? "options_120_solid" : "options_110" ; break ; }
case GCodeProcessor :: EMoveType :: Pause_Print : { m_buffers [ i ]. shader = is_glsl_120 ? "options_120_solid" : "options_110" ; break ; }
case GCodeProcessor :: EMoveType :: Custom_GCode : { m_buffers [ i ]. shader = is_glsl_120 ? "options_120_solid" : "options_110" ; break ; }
case GCodeProcessor :: EMoveType :: Retract : { m_buffers [ i ]. shader = is_glsl_120 ? "options_120_solid" : "options_110" ; break ; }
case GCodeProcessor :: EMoveType :: Unretract : { m_buffers [ i ]. shader = is_glsl_120 ? "options_120_solid" : "options_110" ; break ; }
2020-05-20 14:11:22 +02:00
case GCodeProcessor :: EMoveType :: Extrude : { m_buffers [ i ]. shader = "extrusions" ; break ; }
case GCodeProcessor :: EMoveType :: Travel : { m_buffers [ i ]. shader = "travels" ; break ; }
default : { break ; }
}
}
}
2020-04-14 10:02:08 +02:00
2020-04-15 14:31:39 +02:00
void GCodeViewer :: load_toolpaths ( const GCodeProcessor :: Result & gcode_result )
{
2020-04-27 14:10:18 +02:00
#if ENABLE_GCODE_VIEWER_STATISTICS
2020-04-15 14:31:39 +02:00
auto start_time = std :: chrono :: high_resolution_clock :: now ();
2020-04-28 15:08:36 +02:00
m_statistics . results_size = SLIC3R_STDVEC_MEMSIZE ( gcode_result . moves , GCodeProcessor :: MoveVertex );
2020-04-27 14:10:18 +02:00
#endif // ENABLE_GCODE_VIEWER_STATISTICS
2020-04-15 14:31:39 +02:00
2020-04-15 16:29:11 +02:00
// vertex data
m_vertices . vertices_count = gcode_result . moves . size ();
if ( m_vertices . vertices_count == 0 )
return ;
2020-04-17 13:28:25 +02:00
// vertex data / bounding box -> extract from result
2020-06-22 09:10:41 +02:00
std :: vector < float > vertices_data ( m_vertices . vertices_count * 3 );
for ( size_t i = 0 ; i < m_vertices . vertices_count ; ++ i ) {
const GCodeProcessor :: MoveVertex & move = gcode_result . moves [ i ];
2020-06-08 09:12:20 +02:00
#if ENABLE_GCODE_VIEWER_AS_STATE
2020-06-22 09:10:41 +02:00
if ( wxGetApp (). mainframe -> get_mode () == MainFrame :: EMode :: GCodeViewer )
m_bounding_box . merge ( move . position . cast < double > ());
else {
#endif // ENABLE_GCODE_VIEWER_AS_STATE
if ( move . type == GCodeProcessor :: EMoveType :: Extrude && move . width != 0.0f && move . height != 0.0f )
2020-06-08 12:27:32 +02:00
m_bounding_box . merge ( move . position . cast < double > ());
2020-06-08 09:12:20 +02:00
#if ENABLE_GCODE_VIEWER_AS_STATE
}
2020-06-22 09:10:41 +02:00
#endif // ENABLE_GCODE_VIEWER_AS_STATE
:: memcpy ( static_cast < void *> ( & vertices_data [ i * 3 ]), static_cast < const void *> ( move . position . data ()), 3 * sizeof ( float ));
}
2020-04-15 16:29:11 +02:00
2020-05-12 11:33:50 +02:00
m_bounding_box . merge ( m_bounding_box . max + m_sequential_view . marker . get_bounding_box (). max [ 2 ] * Vec3d :: UnitZ ());
2020-04-27 14:10:18 +02:00
#if ENABLE_GCODE_VIEWER_STATISTICS
2020-04-28 15:08:36 +02:00
m_statistics . vertices_size = SLIC3R_STDVEC_MEMSIZE ( vertices_data , float );
m_statistics . vertices_gpu_size = vertices_data . size () * sizeof ( float );
2020-04-27 14:10:18 +02:00
#endif // ENABLE_GCODE_VIEWER_STATISTICS
2020-04-15 16:29:11 +02:00
// vertex data -> send to gpu
glsafe ( :: glGenBuffers ( 1 , & m_vertices . vbo_id ));
glsafe ( :: glBindBuffer ( GL_ARRAY_BUFFER , m_vertices . vbo_id ));
glsafe ( :: glBufferData ( GL_ARRAY_BUFFER , vertices_data . size () * sizeof ( float ), vertices_data . data (), GL_STATIC_DRAW ));
glsafe ( :: glBindBuffer ( GL_ARRAY_BUFFER , 0 ));
2020-05-06 11:18:37 +02:00
// vertex data -> no more needed, free ram
2020-04-15 16:29:11 +02:00
vertices_data = std :: vector < float > ();
// indices data -> extract from result
2020-05-06 11:18:37 +02:00
std :: vector < std :: vector < unsigned int >> indices ( m_buffers . size ());
2020-04-15 16:29:11 +02:00
for ( size_t i = 0 ; i < m_vertices . vertices_count ; ++ i )
2020-04-15 14:31:39 +02:00
{
// skip first vertex
if ( i == 0 )
continue ;
const GCodeProcessor :: MoveVertex & prev = gcode_result . moves [ i - 1 ];
const GCodeProcessor :: MoveVertex & curr = gcode_result . moves [ i ];
2020-05-06 11:18:37 +02:00
unsigned char id = buffer_id ( curr . type );
IBuffer & buffer = m_buffers [ id ];
std :: vector < unsigned int >& buffer_indices = indices [ id ];
2020-04-15 14:31:39 +02:00
switch ( curr . type )
{
case GCodeProcessor :: EMoveType :: Tool_change :
2020-04-22 16:29:07 +02:00
case GCodeProcessor :: EMoveType :: Color_change :
case GCodeProcessor :: EMoveType :: Pause_Print :
case GCodeProcessor :: EMoveType :: Custom_GCode :
2020-04-15 14:31:39 +02:00
case GCodeProcessor :: EMoveType :: Retract :
case GCodeProcessor :: EMoveType :: Unretract :
{
2020-05-06 11:18:37 +02:00
buffer . add_path ( curr , static_cast < unsigned int > ( buffer_indices . size ()), static_cast < unsigned int > ( i ));
buffer_indices . push_back ( static_cast < unsigned int > ( i ));
2020-04-15 14:31:39 +02:00
break ;
}
case GCodeProcessor :: EMoveType :: Extrude :
case GCodeProcessor :: EMoveType :: Travel :
{
2020-04-23 10:24:03 +02:00
if ( prev . type != curr . type || ! buffer . paths . back (). matches ( curr )) {
2020-05-06 11:18:37 +02:00
buffer . add_path ( curr , static_cast < unsigned int > ( buffer_indices . size ()), static_cast < unsigned int > ( i ));
2020-05-05 12:09:11 +02:00
Path & last_path = buffer . paths . back ();
last_path . first . position = prev . position ;
last_path . first . s_id = static_cast < unsigned int > ( i - 1 );
2020-05-06 11:18:37 +02:00
buffer_indices . push_back ( static_cast < unsigned int > ( i - 1 ));
2020-04-16 15:09:04 +02:00
}
2020-05-06 11:18:37 +02:00
buffer . paths . back (). last = { static_cast < unsigned int > ( buffer_indices . size ()), static_cast < unsigned int > ( i ), curr . position };
buffer_indices . push_back ( static_cast < unsigned int > ( i ));
2020-04-15 14:31:39 +02:00
break ;
}
default :
{
2020-04-28 12:24:03 +02:00
break ;
2020-04-15 14:31:39 +02:00
}
}
}
2020-05-04 09:37:06 +02:00
#if ENABLE_GCODE_VIEWER_STATISTICS
for ( IBuffer & buffer : m_buffers )
{
m_statistics . paths_size += SLIC3R_STDVEC_MEMSIZE ( buffer . paths , Path );
}
#endif // ENABLE_GCODE_VIEWER_STATISTICS
2020-04-15 16:29:11 +02:00
// indices data -> send data to gpu
2020-05-06 11:18:37 +02:00
for ( size_t i = 0 ; i < m_buffers . size (); ++ i )
2020-04-15 16:29:11 +02:00
{
2020-05-06 11:18:37 +02:00
IBuffer & buffer = m_buffers [ i ];
std :: vector < unsigned int >& buffer_indices = indices [ i ];
buffer . indices_count = buffer_indices . size ();
2020-04-27 14:10:18 +02:00
#if ENABLE_GCODE_VIEWER_STATISTICS
2020-05-06 11:18:37 +02:00
m_statistics . indices_size += SLIC3R_STDVEC_MEMSIZE ( buffer_indices , unsigned int );
m_statistics . indices_gpu_size += buffer . indices_count * sizeof ( unsigned int );
2020-04-27 14:10:18 +02:00
#endif // ENABLE_GCODE_VIEWER_STATISTICS
2020-05-06 11:18:37 +02:00
if ( buffer . indices_count > 0 ) {
2020-04-15 16:29:11 +02:00
glsafe ( :: glGenBuffers ( 1 , & buffer . ibo_id ));
glsafe ( :: glBindBuffer ( GL_ELEMENT_ARRAY_BUFFER , buffer . ibo_id ));
2020-05-06 11:18:37 +02:00
glsafe ( :: glBufferData ( GL_ELEMENT_ARRAY_BUFFER , buffer . indices_count * sizeof ( unsigned int ), buffer_indices . data (), GL_STATIC_DRAW ));
2020-04-15 16:29:11 +02:00
glsafe ( :: glBindBuffer ( GL_ELEMENT_ARRAY_BUFFER , 0 ));
}
}
2020-04-22 16:29:07 +02:00
// layers zs / roles / extruder ids / cp color ids -> extract from result
2020-05-04 09:37:06 +02:00
for ( size_t i = 0 ; i < m_vertices . vertices_count ; ++ i )
{
const GCodeProcessor :: MoveVertex & move = gcode_result . moves [ i ];
2020-04-15 16:29:11 +02:00
if ( move . type == GCodeProcessor :: EMoveType :: Extrude )
2020-04-27 11:44:29 +02:00
m_layers_zs . emplace_back ( static_cast < double > ( move . position [ 2 ]));
2020-04-18 10:41:37 +02:00
2020-04-22 16:29:07 +02:00
m_extruder_ids . emplace_back ( move . extruder_id );
2020-05-04 09:37:06 +02:00
if ( i > 0 )
m_roles . emplace_back ( move . extrusion_role );
2020-04-15 16:29:11 +02:00
}
// layers zs -> replace intervals of layers with similar top positions with their average value.
2020-04-18 10:41:37 +02:00
std :: sort ( m_layers_zs . begin (), m_layers_zs . end ());
2020-04-15 14:31:39 +02:00
int n = int ( m_layers_zs . size ());
int k = 0 ;
for ( int i = 0 ; i < n ;) {
int j = i + 1 ;
double zmax = m_layers_zs [ i ] + EPSILON ;
for (; j < n && m_layers_zs [ j ] <= zmax ; ++ j );
m_layers_zs [ k ++ ] = ( j > i + 1 ) ? ( 0.5 * ( m_layers_zs [ i ] + m_layers_zs [ j - 1 ])) : m_layers_zs [ i ];
i = j ;
}
if ( k < n )
m_layers_zs . erase ( m_layers_zs . begin () + k , m_layers_zs . end ());
2020-04-27 11:44:29 +02:00
// set layers z range
m_layers_z_range = { m_layers_zs . front (), m_layers_zs . back () };
2020-04-18 10:41:37 +02:00
// roles -> remove duplicates
std :: sort ( m_roles . begin (), m_roles . end ());
m_roles . erase ( std :: unique ( m_roles . begin (), m_roles . end ()), m_roles . end ());
2020-04-22 16:29:07 +02:00
// extruder ids -> remove duplicates
std :: sort ( m_extruder_ids . begin (), m_extruder_ids . end ());
m_extruder_ids . erase ( std :: unique ( m_extruder_ids . begin (), m_extruder_ids . end ()), m_extruder_ids . end ());
2020-04-27 14:10:18 +02:00
#if ENABLE_GCODE_VIEWER_STATISTICS
m_statistics . load_time = std :: chrono :: duration_cast < std :: chrono :: milliseconds > ( std :: chrono :: high_resolution_clock :: now () - start_time ). count ();
#endif // ENABLE_GCODE_VIEWER_STATISTICS
2020-04-15 14:31:39 +02:00
}
void GCodeViewer :: load_shells ( const Print & print , bool initialized )
{
if ( print . objects (). empty ())
// no shells, return
return ;
// adds objects' volumes
int object_id = 0 ;
for ( const PrintObject * obj : print . objects ())
{
const ModelObject * model_obj = obj -> model_object ();
std :: vector < int > instance_ids ( model_obj -> instances . size ());
2020-04-23 10:24:03 +02:00
for ( int i = 0 ; i < ( int ) model_obj -> instances . size (); ++ i ) {
2020-04-15 14:31:39 +02:00
instance_ids [ i ] = i ;
}
m_shells . volumes . load_object ( model_obj , object_id , instance_ids , "object" , initialized );
++ object_id ;
}
if ( wxGetApp (). preset_bundle -> printers . get_edited_preset (). printer_technology () == ptFFF ) {
// adds wipe tower's volume
double max_z = print . objects ()[ 0 ] -> model_object () -> get_model () -> bounding_box (). max ( 2 );
const PrintConfig & config = print . config ();
size_t extruders_count = config . nozzle_diameter . size ();
if (( extruders_count > 1 ) && config . wipe_tower && ! config . complete_objects ) {
const DynamicPrintConfig & print_config = wxGetApp (). preset_bundle -> prints . get_edited_preset (). config ;
double layer_height = print_config . opt_float ( "layer_height" );
double first_layer_height = print_config . get_abs_value ( "first_layer_height" , layer_height );
double nozzle_diameter = print . config (). nozzle_diameter . values [ 0 ];
float depth = print . wipe_tower_data ( extruders_count , first_layer_height , nozzle_diameter ). depth ;
float brim_width = print . wipe_tower_data ( extruders_count , first_layer_height , nozzle_diameter ). brim_width ;
m_shells . volumes . load_wipe_tower_preview ( 1000 , config . wipe_tower_x , config . wipe_tower_y , config . wipe_tower_width , depth , max_z , config . wipe_tower_rotation_angle ,
! print . is_step_done ( psWipeTower ), brim_width , initialized );
}
}
2020-06-22 09:10:41 +02:00
// remove modifiers
while ( true ) {
GLVolumePtrs :: iterator it = std :: find_if ( m_shells . volumes . volumes . begin (), m_shells . volumes . volumes . end (), []( GLVolume * volume ) { return volume -> is_modifier ; });
if ( it != m_shells . volumes . volumes . end ())
{
delete ( * it );
m_shells . volumes . volumes . erase ( it );
}
else
break ;
}
2020-04-15 14:31:39 +02:00
for ( GLVolume * volume : m_shells . volumes . volumes )
{
volume -> zoom_to_volumes = false ;
volume -> color [ 3 ] = 0.25f ;
volume -> force_native_color = true ;
volume -> set_render_color ();
}
}
2020-05-18 13:24:07 +02:00
void GCodeViewer :: refresh_render_paths ( bool keep_sequential_current_first , bool keep_sequential_current_last ) const
2020-04-15 14:31:39 +02:00
{
2020-05-05 13:57:51 +02:00
#if ENABLE_GCODE_VIEWER_STATISTICS
auto start_time = std :: chrono :: high_resolution_clock :: now ();
#endif // ENABLE_GCODE_VIEWER_STATISTICS
2020-04-16 15:59:36 +02:00
auto extrusion_color = [ this ]( const Path & path ) {
2020-05-05 12:09:11 +02:00
Color color ;
2020-04-16 15:59:36 +02:00
switch ( m_view_type )
{
2020-04-21 12:51:58 +02:00
case EViewType :: FeatureType : { color = Extrusion_Role_Colors [ static_cast < unsigned int > ( path . role )]; break ; }
case EViewType :: Height : { color = m_extrusions . ranges . height . get_color_at ( path . height ); break ; }
case EViewType :: Width : { color = m_extrusions . ranges . width . get_color_at ( path . width ); break ; }
case EViewType :: Feedrate : { color = m_extrusions . ranges . feedrate . get_color_at ( path . feedrate ); break ; }
case EViewType :: FanSpeed : { color = m_extrusions . ranges . fan_speed . get_color_at ( path . fan_speed ); break ; }
case EViewType :: VolumetricRate : { color = m_extrusions . ranges . volumetric_rate . get_color_at ( path . volumetric_rate ); break ; }
2020-04-21 15:55:26 +02:00
case EViewType :: Tool : { color = m_tool_colors [ path . extruder_id ]; break ; }
2020-04-22 16:29:07 +02:00
case EViewType :: ColorPrint : { color = m_tool_colors [ path . cp_color_id ]; break ; }
2020-04-20 16:04:59 +02:00
default : { color = { 1.0f , 1.0f , 1.0f }; break ; }
2020-04-16 15:59:36 +02:00
}
return color ;
};
2020-04-24 08:46:31 +02:00
auto travel_color = [ this ]( const Path & path ) {
return ( path . delta_extruder < 0.0f ) ? Travel_Colors [ 2 ] /* Retract */ :
(( path . delta_extruder > 0.0f ) ? Travel_Colors [ 1 ] /* Extrude */ :
Travel_Colors [ 0 ] /* Move */ );
};
2020-05-05 12:09:11 +02:00
#if ENABLE_GCODE_VIEWER_STATISTICS
m_statistics . render_paths_size = 0 ;
#endif // ENABLE_GCODE_VIEWER_STATISTICS
2020-05-18 13:24:07 +02:00
m_sequential_view . endpoints . first = m_vertices . vertices_count ;
m_sequential_view . endpoints . last = 0 ;
if ( ! keep_sequential_current_first )
m_sequential_view . current . first = 0 ;
if ( ! keep_sequential_current_last )
m_sequential_view . current . last = m_vertices . vertices_count ;
2020-05-05 12:09:11 +02:00
2020-05-05 13:57:51 +02:00
// first pass: collect visible paths and update sequential view data
std :: vector < std :: pair < IBuffer * , size_t >> paths ;
2020-05-05 12:09:11 +02:00
for ( IBuffer & buffer : m_buffers ) {
2020-05-05 13:57:51 +02:00
// reset render paths
buffer . render_paths = std :: vector < RenderPath > ();
2020-05-05 12:09:11 +02:00
if ( ! buffer . visible )
continue ;
for ( size_t i = 0 ; i < buffer . paths . size (); ++ i ) {
const Path & path = buffer . paths [ i ];
2020-05-05 13:57:51 +02:00
if ( path . type == GCodeProcessor :: EMoveType :: Travel ) {
if ( ! is_travel_in_z_range ( i ))
continue ;
}
else if ( ! is_in_z_range ( path ))
2020-05-05 12:09:11 +02:00
continue ;
2020-05-05 13:57:51 +02:00
if ( path . type == GCodeProcessor :: EMoveType :: Extrude && ! is_visible ( path ))
continue ;
// store valid path
paths . push_back ({ & buffer , i });
2020-05-05 12:09:11 +02:00
2020-05-18 13:24:07 +02:00
m_sequential_view . endpoints . first = std :: min ( m_sequential_view . endpoints . first , path . first . s_id );
m_sequential_view . endpoints . last = std :: max ( m_sequential_view . endpoints . last , path . last . s_id );
2020-05-05 12:09:11 +02:00
}
}
2020-05-05 13:57:51 +02:00
// update current sequential position
2020-05-18 13:24:07 +02:00
m_sequential_view . current . first = keep_sequential_current_first ? std :: clamp ( m_sequential_view . current . first , m_sequential_view . endpoints . first , m_sequential_view . endpoints . last ) : m_sequential_view . endpoints . first ;
m_sequential_view . current . last = keep_sequential_current_last ? std :: clamp ( m_sequential_view . current . last , m_sequential_view . endpoints . first , m_sequential_view . endpoints . last ) : m_sequential_view . endpoints . last ;
2020-05-06 11:18:37 +02:00
glsafe ( :: glBindBuffer ( GL_ARRAY_BUFFER , m_vertices . vbo_id ));
size_t v_size = VBuffer :: vertex_size_bytes ();
2020-05-18 13:24:07 +02:00
glsafe ( :: glGetBufferSubData ( GL_ARRAY_BUFFER , static_cast < GLintptr > ( m_sequential_view . current . last * v_size ), static_cast < GLsizeiptr > ( v_size ), static_cast < void *> ( m_sequential_view . current_position . data ())));
2020-05-06 11:18:37 +02:00
glsafe ( :: glBindBuffer ( GL_ARRAY_BUFFER , 0 ));
2020-04-28 15:08:36 +02:00
2020-05-05 13:57:51 +02:00
// second pass: filter paths by sequential data
for ( auto && [ buffer , id ] : paths ) {
const Path & path = buffer -> paths [ id ];
2020-05-18 13:24:07 +02:00
if (( m_sequential_view . current . last <= path . first . s_id ) || ( path . last . s_id <= m_sequential_view . current . first ))
2020-05-05 12:09:11 +02:00
continue ;
2020-05-05 13:57:51 +02:00
Color color ;
switch ( path . type )
{
case GCodeProcessor :: EMoveType :: Extrude : { color = extrusion_color ( path ); break ; }
case GCodeProcessor :: EMoveType :: Travel : { color = ( m_view_type == EViewType :: Feedrate || m_view_type == EViewType :: Tool || m_view_type == EViewType :: ColorPrint ) ? extrusion_color ( path ) : travel_color ( path ); break ; }
default : { color = { 0.0f , 0.0f , 0.0f }; break ; }
2020-04-28 15:08:36 +02:00
}
2020-05-05 13:57:51 +02:00
auto it = std :: find_if ( buffer -> render_paths . begin (), buffer -> render_paths . end (), [ color ]( const RenderPath & path ) { return path . color == color ; });
if ( it == buffer -> render_paths . end ()) {
it = buffer -> render_paths . insert ( buffer -> render_paths . end (), RenderPath ());
it -> color = color ;
}
2020-05-18 13:24:07 +02:00
it -> sizes . push_back ( std :: min ( m_sequential_view . current . last , path . last . s_id ) - std :: max ( m_sequential_view . current . first , path . first . s_id ) + 1 );
unsigned int delta_1st = 0 ;
if (( path . first . s_id < m_sequential_view . current . first ) && ( m_sequential_view . current . first <= path . last . s_id ))
delta_1st = m_sequential_view . current . first - path . first . s_id ;
it -> offsets . push_back ( static_cast < size_t > (( path . first . i_id + delta_1st ) * sizeof ( unsigned int )));
2020-04-28 15:08:36 +02:00
}
2020-05-05 12:09:11 +02:00
#if ENABLE_GCODE_VIEWER_STATISTICS
for ( const IBuffer & buffer : m_buffers ) {
m_statistics . render_paths_size += SLIC3R_STDVEC_MEMSIZE ( buffer . render_paths , RenderPath );
for ( const RenderPath & path : buffer . render_paths ) {
m_statistics . render_paths_size += SLIC3R_STDVEC_MEMSIZE ( path . sizes , unsigned int );
m_statistics . render_paths_size += SLIC3R_STDVEC_MEMSIZE ( path . offsets , size_t );
}
}
2020-05-05 13:57:51 +02:00
m_statistics . refresh_paths_time = std :: chrono :: duration_cast < std :: chrono :: milliseconds > ( std :: chrono :: high_resolution_clock :: now () - start_time ). count ();
2020-05-05 12:09:11 +02:00
#endif // ENABLE_GCODE_VIEWER_STATISTICS
2020-04-28 15:08:36 +02:00
}
void GCodeViewer :: render_toolpaths () const
{
2020-05-26 08:16:08 +02:00
#if ENABLE_GCODE_VIEWER_SHADERS_EDITOR
2020-05-29 12:29:04 +02:00
float point_size = m_shaders_editor . point_size ;
2020-05-26 08:16:08 +02:00
#else
2020-05-29 12:29:04 +02:00
float point_size = 1.0f ;
2020-05-26 08:16:08 +02:00
#endif // ENABLE_GCODE_VIEWER_SHADERS_EDITOR
2020-05-27 16:19:40 +02:00
const Camera & camera = wxGetApp (). plater () -> get_camera ();
double zoom = camera . get_zoom ();
const std :: array < int , 4 >& viewport = camera . get_viewport ();
2020-05-29 12:29:04 +02:00
float near_plane_height = camera . get_type () == Camera :: Perspective ? static_cast < float > ( viewport [ 3 ]) / ( 2.0f * static_cast < float > ( 2.0 * std :: tan ( 0.5 * Geometry :: deg2rad ( camera . get_fov ())))) :
static_cast < float > ( viewport [ 3 ]) * 0.0005 ;
2020-05-22 13:21:43 +02:00
2020-05-27 16:19:40 +02:00
Transform3d inv_proj = camera . get_projection_matrix (). inverse ();
2020-06-01 08:55:44 +02:00
auto render_options = [ this , zoom , inv_proj , viewport , point_size , near_plane_height ]( const IBuffer & buffer , EOptionsColors colors_id , GLShaderProgram & shader ) {
2020-05-25 10:48:53 +02:00
shader . set_uniform ( "uniform_color" , Options_Colors [ static_cast < unsigned int > ( colors_id )]);
2020-05-29 12:29:04 +02:00
shader . set_uniform ( "zoom" , zoom );
2020-05-26 08:16:08 +02:00
#if ENABLE_GCODE_VIEWER_SHADERS_EDITOR
shader . set_uniform ( "percent_outline_radius" , 0.01f * static_cast < float > ( m_shaders_editor . percent_outline ));
shader . set_uniform ( "percent_center_radius" , 0.01f * static_cast < float > ( m_shaders_editor . percent_center ));
#else
shader . set_uniform ( "percent_outline_radius" , 0.15f );
shader . set_uniform ( "percent_center_radius" , 0.15f );
#endif // ENABLE_GCODE_VIEWER_SHADERS_EDITOR
2020-06-01 08:55:44 +02:00
shader . set_uniform ( "viewport" , viewport );
2020-05-27 16:19:40 +02:00
shader . set_uniform ( "inv_proj_matrix" , inv_proj );
2020-05-29 12:29:04 +02:00
shader . set_uniform ( "point_size" , point_size );
shader . set_uniform ( "near_plane_height" , near_plane_height );
2020-05-26 08:16:08 +02:00
glsafe ( :: glEnable ( GL_VERTEX_PROGRAM_POINT_SIZE ));
2020-05-29 12:29:04 +02:00
glsafe ( :: glEnable ( GL_POINT_SPRITE ));
2020-05-26 08:16:08 +02:00
2020-05-25 10:48:53 +02:00
for ( const RenderPath & path : buffer . render_paths ) {
glsafe ( :: glMultiDrawElements ( GL_POINTS , ( const GLsizei * ) path . sizes . data (), GL_UNSIGNED_INT , ( const void * const * ) path . offsets . data (), ( GLsizei ) path . sizes . size ()));
#if ENABLE_GCODE_VIEWER_STATISTICS
++ m_statistics . gl_multi_points_calls_count ;
#endif // ENABLE_GCODE_VIEWER_STATISTICS
}
2020-05-29 12:29:04 +02:00
glsafe ( :: glDisable ( GL_POINT_SPRITE ));
2020-05-26 08:16:08 +02:00
glsafe ( :: glDisable ( GL_VERTEX_PROGRAM_POINT_SIZE ));
2020-05-25 10:48:53 +02:00
};
2020-04-15 14:31:39 +02:00
glsafe ( :: glCullFace ( GL_BACK ));
2020-04-22 16:29:07 +02:00
glsafe ( :: glLineWidth ( 3.0f ));
2020-04-15 14:31:39 +02:00
unsigned char begin_id = buffer_id ( GCodeProcessor :: EMoveType :: Retract );
unsigned char end_id = buffer_id ( GCodeProcessor :: EMoveType :: Count );
2020-04-15 16:29:11 +02:00
glsafe ( :: glBindBuffer ( GL_ARRAY_BUFFER , m_vertices . vbo_id ));
glsafe ( :: glVertexPointer ( 3 , GL_FLOAT , VBuffer :: vertex_size_bytes (), ( const void * ) 0 ));
glsafe ( :: glEnableClientState ( GL_VERTEX_ARRAY ));
2020-04-23 10:24:03 +02:00
for ( unsigned char i = begin_id ; i < end_id ; ++ i ) {
2020-04-15 16:29:11 +02:00
const IBuffer & buffer = m_buffers [ i ];
if ( buffer . ibo_id == 0 )
2020-04-15 14:31:39 +02:00
continue ;
2020-04-15 16:29:11 +02:00
2020-04-15 14:31:39 +02:00
if ( ! buffer . visible )
continue ;
2020-05-20 14:11:22 +02:00
GLShaderProgram * shader = wxGetApp (). get_shader ( buffer . shader . c_str ());
if ( shader != nullptr ) {
2020-05-22 16:08:02 +02:00
shader -> start_using ();
2020-05-20 14:11:22 +02:00
2020-04-15 16:29:11 +02:00
GCodeProcessor :: EMoveType type = buffer_type ( i );
2020-04-15 14:31:39 +02:00
2020-04-15 16:29:11 +02:00
glsafe ( :: glBindBuffer ( GL_ELEMENT_ARRAY_BUFFER , buffer . ibo_id ));
2020-04-15 14:31:39 +02:00
switch ( type )
{
case GCodeProcessor :: EMoveType :: Tool_change :
{
2020-05-25 10:48:53 +02:00
render_options ( buffer , EOptionsColors :: ToolChanges , * shader );
2020-04-15 14:31:39 +02:00
break ;
}
2020-04-22 16:29:07 +02:00
case GCodeProcessor :: EMoveType :: Color_change :
{
2020-05-25 10:48:53 +02:00
render_options ( buffer , EOptionsColors :: ColorChanges , * shader );
2020-04-22 16:29:07 +02:00
break ;
}
case GCodeProcessor :: EMoveType :: Pause_Print :
{
2020-05-25 10:48:53 +02:00
render_options ( buffer , EOptionsColors :: PausePrints , * shader );
2020-04-22 16:29:07 +02:00
break ;
}
case GCodeProcessor :: EMoveType :: Custom_GCode :
{
2020-05-25 10:48:53 +02:00
render_options ( buffer , EOptionsColors :: CustomGCodes , * shader );
2020-04-22 16:29:07 +02:00
break ;
}
2020-04-15 14:31:39 +02:00
case GCodeProcessor :: EMoveType :: Retract :
{
2020-05-25 10:48:53 +02:00
render_options ( buffer , EOptionsColors :: Retractions , * shader );
2020-04-15 14:31:39 +02:00
break ;
}
case GCodeProcessor :: EMoveType :: Unretract :
{
2020-05-25 10:48:53 +02:00
render_options ( buffer , EOptionsColors :: Unretractions , * shader );
2020-04-15 14:31:39 +02:00
break ;
}
case GCodeProcessor :: EMoveType :: Extrude :
{
2020-04-28 15:08:36 +02:00
for ( const RenderPath & path : buffer . render_paths )
{
2020-05-20 14:11:22 +02:00
shader -> set_uniform ( "uniform_color" , path . color );
2020-04-28 15:08:36 +02:00
glsafe ( :: glMultiDrawElements ( GL_LINE_STRIP , ( const GLsizei * ) path . sizes . data (), GL_UNSIGNED_INT , ( const void * const * ) path . offsets . data (), ( GLsizei ) path . sizes . size ()));
#if ENABLE_GCODE_VIEWER_STATISTICS
++ m_statistics . gl_multi_line_strip_calls_count ;
#endif // ENABLE_GCODE_VIEWER_STATISTICS
}
2020-04-15 14:31:39 +02:00
break ;
}
case GCodeProcessor :: EMoveType :: Travel :
{
2020-04-28 15:08:36 +02:00
for ( const RenderPath & path : buffer . render_paths )
{
2020-05-20 14:11:22 +02:00
shader -> set_uniform ( "uniform_color" , path . color );
2020-04-28 15:08:36 +02:00
glsafe ( :: glMultiDrawElements ( GL_LINE_STRIP , ( const GLsizei * ) path . sizes . data (), GL_UNSIGNED_INT , ( const void * const * ) path . offsets . data (), ( GLsizei ) path . sizes . size ()));
#if ENABLE_GCODE_VIEWER_STATISTICS
++ m_statistics . gl_multi_line_strip_calls_count ;
#endif // ENABLE_GCODE_VIEWER_STATISTICS
}
2020-04-15 14:31:39 +02:00
break ;
}
}
2020-04-15 16:29:11 +02:00
glsafe ( :: glBindBuffer ( GL_ELEMENT_ARRAY_BUFFER , 0 ));
2020-05-20 14:11:22 +02:00
shader -> stop_using ();
2020-04-15 14:31:39 +02:00
}
}
2020-04-15 16:29:11 +02:00
glsafe ( :: glDisableClientState ( GL_VERTEX_ARRAY ));
glsafe ( :: glBindBuffer ( GL_ARRAY_BUFFER , 0 ));
2020-04-15 14:31:39 +02:00
}
void GCodeViewer :: render_shells () const
{
2020-05-20 14:11:22 +02:00
if ( ! m_shells . visible || m_shells . volumes . empty ())
return ;
2020-05-27 16:19:40 +02:00
GLShaderProgram * shader = wxGetApp (). get_shader ( "gouraud_light" );
2020-05-20 14:11:22 +02:00
if ( shader == nullptr )
return ;
// glsafe(::glDepthMask(GL_FALSE));
shader -> start_using ();
m_shells . volumes . render ( GLVolumeCollection :: Transparent , true , wxGetApp (). plater () -> get_camera (). get_view_matrix ());
shader -> stop_using ();
// glsafe(::glDepthMask(GL_TRUE));
2020-04-15 14:31:39 +02:00
}
2020-04-27 14:10:18 +02:00
void GCodeViewer :: render_legend () const
2020-04-18 10:41:37 +02:00
{
static const ImVec4 ORANGE ( 1.0f , 0.49f , 0.22f , 1.0f );
static const ImU32 ICON_BORDER_COLOR = ImGui :: GetColorU32 ( ImVec4 ( 0.0f , 0.0f , 0.0f , 1.0f ));
2020-05-11 13:09:26 +02:00
if ( ! m_legend_enabled )
2020-04-18 10:41:37 +02:00
return ;
ImGuiWrapper & imgui = * wxGetApp (). imgui ();
2020-05-28 07:52:11 +02:00
#define USE_ICON_HEXAGON 1
2020-05-05 12:09:11 +02:00
imgui . set_next_window_pos ( 0.0f , 0.0f , ImGuiCond_Always );
2020-04-18 10:41:37 +02:00
ImGui :: PushStyleVar ( ImGuiStyleVar_WindowRounding , 0.0f );
2020-05-05 12:09:11 +02:00
ImGui :: SetNextWindowBgAlpha ( 0.6f );
2020-04-23 14:02:47 +02:00
imgui . begin ( std :: string ( "Legend" ), ImGuiWindowFlags_AlwaysAutoResize | ImGuiWindowFlags_NoDecoration | ImGuiWindowFlags_NoMove );
2020-04-18 10:41:37 +02:00
ImDrawList * draw_list = ImGui :: GetWindowDrawList ();
2020-05-22 16:37:53 +02:00
enum class EItemType : unsigned char
{
Rect ,
Circle ,
2020-05-28 07:52:11 +02:00
Hexagon ,
2020-05-22 16:37:53 +02:00
Line
};
2020-05-26 08:16:08 +02:00
#if ENABLE_GCODE_VIEWER_SHADERS_EDITOR
auto add_item = [ this , draw_list , & imgui ]( EItemType type , const Color & color , const std :: string & label , std :: function < void () > callback = nullptr ) {
#else
2020-05-22 16:37:53 +02:00
auto add_item = [ draw_list , & imgui ]( EItemType type , const Color & color , const std :: string & label , std :: function < void () > callback = nullptr ) {
2020-05-26 08:16:08 +02:00
#endif // ENABLE_GCODE_VIEWER_SHADERS_EDITOR
2020-04-27 12:43:51 +02:00
float icon_size = ImGui :: GetTextLineHeight ();
ImVec2 pos = ImGui :: GetCursorPos ();
2020-05-22 16:37:53 +02:00
switch ( type )
{
default :
case EItemType :: Rect :
{
draw_list -> AddRect ({ pos . x , pos . y }, { pos . x + icon_size , pos . y + icon_size }, ICON_BORDER_COLOR , 0.0f , 0 );
draw_list -> AddRectFilled ({ pos . x + 1.0f , pos . y + 1.0f }, { pos . x + icon_size - 1.0f , pos . y + icon_size - 1.0f },
ImGui :: GetColorU32 ({ color [ 0 ], color [ 1 ], color [ 2 ], 1.0f }));
break ;
}
case EItemType :: Circle :
{
2020-05-26 08:16:08 +02:00
#if ENABLE_GCODE_VIEWER_SHADERS_EDITOR
2020-05-28 07:52:11 +02:00
ImVec2 center ( 0.5f * ( pos . x + pos . x + icon_size ), 0.5f * ( pos . y + pos . y + icon_size ));
2020-05-27 16:19:40 +02:00
if ( m_shaders_editor . shader_version == 1 ) {
2020-05-29 12:29:04 +02:00
draw_list -> AddCircleFilled ( center , 0.5f * icon_size ,
2020-05-26 08:16:08 +02:00
ImGui :: GetColorU32 ({ 0.5f * color [ 0 ], 0.5f * color [ 1 ], 0.5f * color [ 2 ], 1.0f }), 16 );
2020-05-29 12:29:04 +02:00
float radius = 0.5f * icon_size * ( 1.0f - 0.01f * static_cast < float > ( m_shaders_editor . percent_outline ));
2020-05-28 07:52:11 +02:00
draw_list -> AddCircleFilled ( center , radius , ImGui :: GetColorU32 ({ color [ 0 ], color [ 1 ], color [ 2 ], 1.0f }), 16 );
2020-05-27 16:19:40 +02:00
if ( m_shaders_editor . percent_center > 0 ) {
2020-05-29 12:29:04 +02:00
radius = 0.5f * icon_size * 0.01f * static_cast < float > ( m_shaders_editor . percent_center );
2020-05-28 07:52:11 +02:00
draw_list -> AddCircleFilled ( center , radius , ImGui :: GetColorU32 ({ 0.5f * color [ 0 ], 0.5f * color [ 1 ], 0.5f * color [ 2 ], 1.0f }), 16 );
2020-05-27 16:19:40 +02:00
}
2020-05-29 12:29:04 +02:00
}
else
draw_list -> AddCircleFilled ( center , 0.5f * icon_size , ImGui :: GetColorU32 ({ color [ 0 ], color [ 1 ], color [ 2 ], 1.0f }), 16 );
// ImVec2 center(0.5f * (pos.x + pos.x + icon_size), 0.5f * (pos.y + pos.y + icon_size));
// draw_list->AddCircle(center, 0.5f * icon_size, ICON_BORDER_COLOR, 16);
// if (m_shaders_editor.shader_version == 1) {
// draw_list->AddCircleFilled(center, (0.5f * icon_size) - 2.0f,
// ImGui::GetColorU32({ 0.5f * color[0], 0.5f * color[1], 0.5f * color[2], 1.0f }), 16);
// float radius = ((0.5f * icon_size) - 2.0f) * (1.0f - 0.01f * static_cast<float>(m_shaders_editor.percent_outline));
// draw_list->AddCircleFilled(center, radius, ImGui::GetColorU32({ color[0], color[1], color[2], 1.0f }), 16);
// if (m_shaders_editor.percent_center > 0) {
// radius = ((0.5f * icon_size) - 2.0f) * 0.01f * static_cast<float>(m_shaders_editor.percent_center);
// draw_list->AddCircleFilled(center, radius, ImGui::GetColorU32({ 0.5f * color[0], 0.5f * color[1], 0.5f * color[2], 1.0f }), 16);
// }
// } else
// draw_list->AddCircleFilled(center, (0.5f * icon_size) - 2.0f, ImGui::GetColorU32({ color[0], color[1], color[2], 1.0f }), 16);
2020-05-26 08:16:08 +02:00
#else
2020-05-29 12:29:04 +02:00
draw_list -> AddCircleFilled ({ 0.5f * ( pos . x + pos . x + icon_size ), 0.5f * ( pos . y + pos . y + icon_size ) }, 0.5f * icon_size ,
2020-05-22 16:37:53 +02:00
ImGui :: GetColorU32 ({ color [ 0 ], color [ 1 ], color [ 2 ], 1.0f }), 16 );
2020-05-29 12:29:04 +02:00
// draw_list->AddCircle({ 0.5f * (pos.x + pos.x + icon_size), 0.5f * (pos.y + pos.y + icon_size) }, 0.5f * icon_size, ICON_BORDER_COLOR, 16);
// draw_list->AddCircleFilled({ 0.5f * (pos.x + pos.x + icon_size), 0.5f * (pos.y + pos.y + icon_size) }, (0.5f * icon_size) - 2.0f,
// ImGui::GetColorU32({ color[0], color[1], color[2], 1.0f }), 16);
2020-05-26 08:16:08 +02:00
#endif // ENABLE_GCODE_VIEWER_SHADERS_EDITOR
2020-05-22 16:37:53 +02:00
break ;
}
2020-05-28 07:52:11 +02:00
case EItemType :: Hexagon :
{
ImVec2 center ( 0.5f * ( pos . x + pos . x + icon_size ), 0.5f * ( pos . y + pos . y + icon_size ));
2020-05-29 12:29:04 +02:00
draw_list -> AddNgonFilled ( center , 0.5f * icon_size , ImGui :: GetColorU32 ({ color [ 0 ], color [ 1 ], color [ 2 ], 1.0f }), 6 );
// draw_list->AddNgon(center, 0.5f * icon_size, ICON_BORDER_COLOR, 6);
// draw_list->AddNgonFilled(center, (0.5f * icon_size) - 2.0f,
// ImGui::GetColorU32({ color[0], color[1], color[2], 1.0f }), 6);
2020-05-28 07:52:11 +02:00
break ;
}
2020-05-22 16:37:53 +02:00
case EItemType :: Line :
{
draw_list -> AddLine ({ pos . x + 1 , pos . y + icon_size - 1 }, { pos . x + icon_size - 1 , pos . y + 1 }, ImGui :: GetColorU32 ({ color [ 0 ], color [ 1 ], color [ 2 ], 1.0f }), 3.0f );
break ;
}
}
2020-04-27 12:43:51 +02:00
2020-04-23 14:02:47 +02:00
// draw text
2020-04-27 12:43:51 +02:00
ImGui :: Dummy ({ icon_size , icon_size });
ImGui :: SameLine ();
2020-04-28 08:50:52 +02:00
if ( callback != nullptr )
{
if ( ImGui :: MenuItem ( label . c_str ()))
callback ();
}
else
imgui . text ( label );
2020-04-22 16:29:07 +02:00
};
auto add_range = [ this , draw_list , & imgui , add_item ]( const Extrusions :: Range & range , unsigned int decimals ) {
auto add_range_item = [ this , draw_list , & imgui , add_item ]( int i , float value , unsigned int decimals ) {
2020-04-20 13:24:25 +02:00
char buf [ 1024 ];
2020-04-20 16:04:59 +02:00
:: sprintf ( buf , "%.*f" , decimals , value );
2020-05-28 07:52:11 +02:00
#if USE_ICON_HEXAGON
add_item ( EItemType :: Hexagon , Range_Colors [ i ], buf );
#else
2020-05-22 16:37:53 +02:00
add_item ( EItemType :: Rect , Range_Colors [ i ], buf );
2020-05-28 07:52:11 +02:00
#endif // USE_ICON_HEXAGON
2020-04-20 13:24:25 +02:00
};
float step_size = range . step_size ();
if ( step_size == 0.0f )
2020-04-22 16:29:07 +02:00
// single item use case
add_range_item ( 0 , range . min , decimals );
2020-04-20 13:24:25 +02:00
else
{
2020-04-23 10:24:03 +02:00
for ( int i = static_cast < int > ( Range_Colors . size ()) - 1 ; i >= 0 ; -- i ) {
2020-04-22 16:29:07 +02:00
add_range_item ( i , range . min + static_cast < float > ( i ) * step_size , decimals );
2020-04-20 13:24:25 +02:00
}
}
};
2020-04-25 11:16:28 +02:00
// extrusion paths -> title
2020-04-18 10:41:37 +02:00
ImGui :: PushStyleColor ( ImGuiCol_Text , ORANGE );
switch ( m_view_type )
{
2020-05-21 13:19:07 +02:00
case EViewType :: FeatureType : { imgui . text ( _u8L ( "Feature type" )); break ; }
case EViewType :: Height : { imgui . text ( _u8L ( "Height (mm)" )); break ; }
case EViewType :: Width : { imgui . text ( _u8L ( "Width (mm)" )); break ; }
case EViewType :: Feedrate : { imgui . text ( _u8L ( "Speed (mm/s)" )); break ; }
case EViewType :: FanSpeed : { imgui . text ( _u8L ( "Fan Speed (%%)" )); break ; }
2020-05-13 13:55:00 +02:00
case EViewType :: VolumetricRate : { imgui . text ( _u8L ( "Volumetric flow rate (mm³/s)" )); break ; }
2020-05-21 13:19:07 +02:00
case EViewType :: Tool : { imgui . text ( _u8L ( "Tool" )); break ; }
case EViewType :: ColorPrint : { imgui . text ( _u8L ( "Color Print" )); break ; }
2020-04-22 16:29:07 +02:00
default : { break ; }
2020-04-18 10:41:37 +02:00
}
ImGui :: PopStyleColor ();
ImGui :: Separator ();
2020-04-25 11:16:28 +02:00
// extrusion paths -> items
2020-04-18 10:41:37 +02:00
switch ( m_view_type )
{
case EViewType :: FeatureType :
{
2020-04-23 10:24:03 +02:00
for ( ExtrusionRole role : m_roles ) {
2020-04-27 12:43:51 +02:00
bool visible = is_visible ( role );
2020-04-25 12:24:56 +02:00
if ( ! visible )
ImGui :: PushStyleVar ( ImGuiStyleVar_Alpha , 0.3333f );
2020-05-28 07:52:11 +02:00
#if USE_ICON_HEXAGON
add_item ( EItemType :: Hexagon , Extrusion_Role_Colors [ static_cast < unsigned int > ( role )], _u8L ( ExtrusionEntity :: role_to_string ( role )), [ this , role ]() {
#else
2020-05-22 16:37:53 +02:00
add_item ( EItemType :: Rect , Extrusion_Role_Colors [ static_cast < unsigned int > ( role )], _u8L ( ExtrusionEntity :: role_to_string ( role )), [ this , role ]() {
2020-05-28 07:52:11 +02:00
#endif // USE_ICON_HEXAGON
2020-04-28 08:50:52 +02:00
if ( role < erCount )
{
m_extrusions . role_visibility_flags = is_visible ( role ) ? m_extrusions . role_visibility_flags & ~ ( 1 << role ) : m_extrusions . role_visibility_flags | ( 1 << role );
2020-04-28 15:08:36 +02:00
// update buffers' render paths
2020-05-18 13:24:07 +02:00
refresh_render_paths ( false , false );
2020-04-28 08:50:52 +02:00
wxGetApp (). plater () -> get_current_canvas3D () -> set_as_dirty ();
wxGetApp (). plater () -> update_preview_bottom_toolbar ();
}
});
2020-04-25 12:24:56 +02:00
if ( ! visible )
ImGui :: PopStyleVar ();
2020-04-18 10:41:37 +02:00
}
break ;
}
2020-04-21 11:38:42 +02:00
case EViewType :: Height : { add_range ( m_extrusions . ranges . height , 3 ); break ; }
case EViewType :: Width : { add_range ( m_extrusions . ranges . width , 3 ); break ; }
case EViewType :: Feedrate : { add_range ( m_extrusions . ranges . feedrate , 1 ); break ; }
case EViewType :: FanSpeed : { add_range ( m_extrusions . ranges . fan_speed , 0 ); break ; }
case EViewType :: VolumetricRate : { add_range ( m_extrusions . ranges . volumetric_rate , 3 ); break ; }
2020-04-21 15:55:26 +02:00
case EViewType :: Tool :
{
size_t tools_count = m_tool_colors . size ();
2020-04-23 10:24:03 +02:00
for ( size_t i = 0 ; i < tools_count ; ++ i ) {
// shows only extruders actually used
2020-04-22 16:29:07 +02:00
auto it = std :: find ( m_extruder_ids . begin (), m_extruder_ids . end (), static_cast < unsigned char > ( i ));
if ( it == m_extruder_ids . end ())
continue ;
2020-05-28 07:52:11 +02:00
#if USE_ICON_HEXAGON
add_item ( EItemType :: Hexagon , m_tool_colors [ i ], ( boost :: format ( _u8L ( "Extruder %d" )) % ( i + 1 )). str ());
#else
2020-05-22 16:37:53 +02:00
add_item ( EItemType :: Rect , m_tool_colors [ i ], ( boost :: format ( _u8L ( "Extruder %d" )) % ( i + 1 )). str ());
2020-05-28 07:52:11 +02:00
#endif // USE_ICON_HEXAGON
2020-04-21 15:55:26 +02:00
}
break ;
}
2020-04-22 16:29:07 +02:00
case EViewType :: ColorPrint :
{
const std :: vector < CustomGCode :: Item >& custom_gcode_per_print_z = wxGetApp (). plater () -> model (). custom_gcode_per_print_z . gcodes ;
const int extruders_count = wxGetApp (). extruders_edited_cnt ();
2020-04-23 10:24:03 +02:00
if ( extruders_count == 1 ) { // single extruder use case
2020-04-22 16:29:07 +02:00
if ( custom_gcode_per_print_z . empty ())
// no data to show
2020-05-28 07:52:11 +02:00
#if USE_ICON_HEXAGON
add_item ( EItemType :: Hexagon , m_tool_colors . front (), _u8L ( "Default print color" ));
#else
2020-05-22 16:37:53 +02:00
add_item ( EItemType :: Rect , m_tool_colors . front (), _u8L ( "Default print color" ));
2020-05-28 07:52:11 +02:00
#endif // USE_ICON_HEXAGON
2020-04-23 10:24:03 +02:00
else {
2020-04-22 16:29:07 +02:00
std :: vector < std :: pair < double , double >> cp_values ;
cp_values . reserve ( custom_gcode_per_print_z . size ());
2020-04-23 10:24:03 +02:00
for ( auto custom_code : custom_gcode_per_print_z ) {
2020-06-12 10:35:18 +02:00
if ( custom_code . type != ColorChange )
2020-04-22 16:29:07 +02:00
continue ;
auto lower_b = std :: lower_bound ( m_layers_zs . begin (), m_layers_zs . end (), custom_code . print_z - Slic3r :: DoubleSlider :: epsilon ());
if ( lower_b == m_layers_zs . end ())
continue ;
double current_z = * lower_b ;
double previous_z = lower_b == m_layers_zs . begin () ? 0.0 : * ( -- lower_b );
// to avoid duplicate values, check adding values
2020-04-23 10:24:03 +02:00
if ( cp_values . empty () || ! ( cp_values . back (). first == previous_z && cp_values . back (). second == current_z ))
2020-04-22 16:29:07 +02:00
cp_values . emplace_back ( std :: make_pair ( previous_z , current_z ));
}
const int items_cnt = static_cast < int > ( cp_values . size ());
2020-04-23 10:24:03 +02:00
if ( items_cnt == 0 ) { // There is no one color change, but there are some pause print or custom Gcode
2020-05-28 07:52:11 +02:00
#if USE_ICON_HEXAGON
add_item ( EItemType :: Hexagon , m_tool_colors . front (), _u8L ( "Default print color" ));
#else
2020-05-22 16:37:53 +02:00
add_item ( EItemType :: Rect , m_tool_colors . front (), _u8L ( "Default print color" ));
2020-05-28 07:52:11 +02:00
#endif // USE_ICON_HEXAGON
2020-04-22 16:29:07 +02:00
}
2020-04-23 10:24:03 +02:00
else {
for ( int i = items_cnt ; i >= 0 ; -- i ) {
// create label for color change item
std :: string id_str = " (" + std :: to_string ( i + 1 ) + ")" ;
2020-04-22 16:29:07 +02:00
if ( i == 0 ) {
2020-05-28 07:52:11 +02:00
#if USE_ICON_HEXAGON
add_item ( EItemType :: Hexagon , m_tool_colors [ i ], ( boost :: format ( _u8L ( "up to %.2f mm" )) % cp_values . front (). first ). str () + id_str );
#else
2020-05-22 16:37:53 +02:00
add_item ( EItemType :: Rect , m_tool_colors [ i ], ( boost :: format ( _u8L ( "up to %.2f mm" )) % cp_values . front (). first ). str () + id_str );
2020-05-28 07:52:11 +02:00
#endif // USE_ICON_HEXAGON
2020-04-22 16:29:07 +02:00
break ;
}
else if ( i == items_cnt ) {
2020-05-28 07:52:11 +02:00
#if USE_ICON_HEXAGON
add_item ( EItemType :: Hexagon , m_tool_colors [ i ], ( boost :: format ( _u8L ( "above %.2f mm" )) % cp_values [ i - 1 ]. second ). str () + id_str );
#else
2020-05-22 16:37:53 +02:00
add_item ( EItemType :: Rect , m_tool_colors [ i ], ( boost :: format ( _u8L ( "above %.2f mm" )) % cp_values [ i - 1 ]. second ). str () + id_str );
2020-05-28 07:52:11 +02:00
#endif // USE_ICON_HEXAGON
2020-04-22 16:29:07 +02:00
continue ;
}
2020-05-28 07:52:11 +02:00
#if USE_ICON_HEXAGON
add_item ( EItemType :: Hexagon , m_tool_colors [ i ], ( boost :: format ( _u8L ( "%.2f - %.2f mm" )) % cp_values [ i - 1 ]. second % cp_values [ i ]. first ). str () + id_str );
#else
2020-05-22 16:37:53 +02:00
add_item ( EItemType :: Rect , m_tool_colors [ i ], ( boost :: format ( _u8L ( "%.2f - %.2f mm" )) % cp_values [ i - 1 ]. second % cp_values [ i ]. first ). str () + id_str );
2020-05-28 07:52:11 +02:00
#endif // USE_ICON_HEXAGON
2020-04-22 16:29:07 +02:00
}
}
}
}
2020-04-23 10:24:03 +02:00
else // multi extruder use case
2020-04-22 16:29:07 +02:00
{
2020-04-23 10:24:03 +02:00
// extruders
for ( unsigned int i = 0 ; i < ( unsigned int ) extruders_count ; ++ i ) {
2020-05-28 07:52:11 +02:00
#if USE_ICON_HEXAGON
add_item ( EItemType :: Hexagon , m_tool_colors [ i ], ( boost :: format ( _u8L ( "Extruder %d" )) % ( i + 1 )). str ());
#else
2020-05-22 16:37:53 +02:00
add_item ( EItemType :: Rect , m_tool_colors [ i ], ( boost :: format ( _u8L ( "Extruder %d" )) % ( i + 1 )). str ());
2020-05-28 07:52:11 +02:00
#endif // USE_ICON_HEXAGON
2020-04-23 10:24:03 +02:00
}
// color changes
int color_change_idx = 1 + static_cast < int > ( m_tool_colors . size ()) - extruders_count ;
size_t last_color_id = m_tool_colors . size () - 1 ;
for ( int i = static_cast < int > ( custom_gcode_per_print_z . size ()) - 1 ; i >= 0 ; -- i ) {
2020-06-12 10:35:18 +02:00
if ( custom_gcode_per_print_z [ i ]. type == ColorChange ) {
2020-04-23 10:24:03 +02:00
// create label for color change item
std :: string id_str = " (" + std :: to_string ( color_change_idx -- ) + ")" ;
2020-05-28 07:52:11 +02:00
#if USE_ICON_HEXAGON
add_item ( EItemType :: Hexagon , m_tool_colors [ last_color_id -- ],
#else
2020-05-22 16:37:53 +02:00
add_item ( EItemType :: Rect , m_tool_colors [ last_color_id -- ],
2020-05-28 07:52:11 +02:00
#endif // USE_ICON_HEXAGON
2020-05-13 13:55:00 +02:00
( boost :: format ( _u8L ( "Color change for Extruder %d at %.2f mm" )) % custom_gcode_per_print_z [ i ]. extruder % custom_gcode_per_print_z [ i ]. print_z ). str () + id_str );
2020-04-23 10:24:03 +02:00
}
}
2020-04-22 16:29:07 +02:00
}
break ;
}
default : { break ; }
2020-04-18 10:41:37 +02:00
}
2020-04-25 11:16:28 +02:00
// travel paths
if ( m_buffers [ buffer_id ( GCodeProcessor :: EMoveType :: Travel )]. visible )
{
switch ( m_view_type )
{
case EViewType :: Feedrate :
case EViewType :: Tool :
case EViewType :: ColorPrint :
{
break ;
}
default :
{
// title
ImGui :: Spacing ();
ImGui :: Spacing ();
ImGui :: PushStyleColor ( ImGuiCol_Text , ORANGE );
2020-05-13 13:55:00 +02:00
imgui . text ( _u8L ( "Travel" ));
2020-04-25 11:16:28 +02:00
ImGui :: PopStyleColor ();
ImGui :: Separator ();
// items
2020-05-22 16:37:53 +02:00
add_item ( EItemType :: Line , Travel_Colors [ 0 ], _u8L ( "Movement" ));
add_item ( EItemType :: Line , Travel_Colors [ 1 ], _u8L ( "Extrusion" ));
add_item ( EItemType :: Line , Travel_Colors [ 2 ], _u8L ( "Retraction" ));
2020-04-25 11:16:28 +02:00
break ;
}
}
}
2020-05-22 11:52:07 +02:00
auto any_option_visible = [ this ]() {
return m_buffers [ buffer_id ( GCodeProcessor :: EMoveType :: Color_change )]. visible ||
m_buffers [ buffer_id ( GCodeProcessor :: EMoveType :: Custom_GCode )]. visible ||
m_buffers [ buffer_id ( GCodeProcessor :: EMoveType :: Pause_Print )]. visible ||
m_buffers [ buffer_id ( GCodeProcessor :: EMoveType :: Retract )]. visible ||
m_buffers [ buffer_id ( GCodeProcessor :: EMoveType :: Tool_change )]. visible ||
m_buffers [ buffer_id ( GCodeProcessor :: EMoveType :: Unretract )]. visible ;
};
auto add_option = [ this , add_item ]( GCodeProcessor :: EMoveType move_type , EOptionsColors color , const std :: string & text ) {
const IBuffer & buffer = m_buffers [ buffer_id ( move_type )];
if ( buffer . visible && buffer . indices_count > 0 )
2020-05-27 16:19:40 +02:00
#if ENABLE_GCODE_VIEWER_SHADERS_EDITOR
add_item (( m_shaders_editor . shader_version == 0 ) ? EItemType :: Rect : EItemType :: Circle , Options_Colors [ static_cast < unsigned int > ( color )], text );
#else
add_item (( buffer . shader == "options_110" ) ? EItemType :: Rect : EItemType :: Circle , Options_Colors [ static_cast < unsigned int > ( color )], text );
#endif // ENABLE_GCODE_VIEWER_SHADERS_EDITOR
2020-05-22 11:52:07 +02:00
};
// options
if ( any_option_visible ())
{
// title
ImGui :: Spacing ();
ImGui :: Spacing ();
ImGui :: PushStyleColor ( ImGuiCol_Text , ORANGE );
imgui . text ( _u8L ( "Options" ));
ImGui :: PopStyleColor ();
ImGui :: Separator ();
// items
add_option ( GCodeProcessor :: EMoveType :: Retract , EOptionsColors :: Retractions , _u8L ( "Retractions" ));
add_option ( GCodeProcessor :: EMoveType :: Unretract , EOptionsColors :: Unretractions , _u8L ( "Unretractions" ));
add_option ( GCodeProcessor :: EMoveType :: Tool_change , EOptionsColors :: ToolChanges , _u8L ( "Tool changes" ));
add_option ( GCodeProcessor :: EMoveType :: Color_change , EOptionsColors :: ColorChanges , _u8L ( "Color changes" ));
add_option ( GCodeProcessor :: EMoveType :: Pause_Print , EOptionsColors :: PausePrints , _u8L ( "Pause prints" ));
add_option ( GCodeProcessor :: EMoveType :: Custom_GCode , EOptionsColors :: CustomGCodes , _u8L ( "Custom GCodes" ));
}
2020-04-18 10:41:37 +02:00
imgui . end ();
ImGui :: PopStyleVar ();
}
2020-04-27 14:10:18 +02:00
#if ENABLE_GCODE_VIEWER_STATISTICS
void GCodeViewer :: render_statistics () const
{
static const ImVec4 ORANGE ( 1.0f , 0.49f , 0.22f , 1.0f );
static const float offset = 250.0f ;
ImGuiWrapper & imgui = * wxGetApp (). imgui ();
2020-05-05 12:09:11 +02:00
imgui . set_next_window_pos ( 0.5f * wxGetApp (). plater () -> get_current_canvas3D () -> get_canvas_size (). get_width (), 0.0f , ImGuiCond_Once , 0.5f , 0.0f );
2020-04-27 14:10:18 +02:00
imgui . begin ( std :: string ( "Statistics" ), ImGuiWindowFlags_AlwaysAutoResize | ImGuiWindowFlags_NoResize | ImGuiWindowFlags_NoCollapse );
ImGui :: BringWindowToDisplayFront ( ImGui :: GetCurrentWindow ());
ImGui :: PushStyleColor ( ImGuiCol_Text , ORANGE );
imgui . text ( std :: string ( "Load time:" ));
ImGui :: PopStyleColor ();
ImGui :: SameLine ( offset );
imgui . text ( std :: to_string ( m_statistics . load_time ) + "ms" );
ImGui :: PushStyleColor ( ImGuiCol_Text , ORANGE );
imgui . text ( std :: string ( "Resfresh time:" ));
ImGui :: PopStyleColor ();
ImGui :: SameLine ( offset );
imgui . text ( std :: to_string ( m_statistics . refresh_time ) + "ms" );
2020-05-05 13:57:51 +02:00
ImGui :: PushStyleColor ( ImGuiCol_Text , ORANGE );
imgui . text ( std :: string ( "Resfresh paths time:" ));
ImGui :: PopStyleColor ();
ImGui :: SameLine ( offset );
imgui . text ( std :: to_string ( m_statistics . refresh_paths_time ) + "ms" );
2020-04-27 14:10:18 +02:00
ImGui :: Separator ();
2020-04-28 15:08:36 +02:00
ImGui :: PushStyleColor ( ImGuiCol_Text , ORANGE );
imgui . text ( std :: string ( "Multi GL_POINTS calls:" ));
ImGui :: PopStyleColor ();
ImGui :: SameLine ( offset );
imgui . text ( std :: to_string ( m_statistics . gl_multi_points_calls_count ));
ImGui :: PushStyleColor ( ImGuiCol_Text , ORANGE );
imgui . text ( std :: string ( "Multi GL_LINE_STRIP calls:" ));
ImGui :: PopStyleColor ();
ImGui :: SameLine ( offset );
imgui . text ( std :: to_string ( m_statistics . gl_multi_line_strip_calls_count ));
2020-04-27 14:10:18 +02:00
ImGui :: Separator ();
2020-04-28 10:29:25 +02:00
ImGui :: PushStyleColor ( ImGuiCol_Text , ORANGE );
2020-04-28 15:49:01 +02:00
imgui . text ( std :: string ( "GCodeProcessor results:" ));
2020-04-28 10:29:25 +02:00
ImGui :: PopStyleColor ();
ImGui :: SameLine ( offset );
imgui . text ( std :: to_string ( m_statistics . results_size ) + " bytes" );
2020-05-04 09:37:06 +02:00
ImGui :: Separator ();
2020-04-27 14:10:18 +02:00
ImGui :: PushStyleColor ( ImGuiCol_Text , ORANGE );
2020-04-28 15:08:36 +02:00
imgui . text ( std :: string ( "Vertices CPU:" ));
2020-04-27 14:10:18 +02:00
ImGui :: PopStyleColor ();
ImGui :: SameLine ( offset );
imgui . text ( std :: to_string ( m_statistics . vertices_size ) + " bytes" );
2020-04-28 15:08:36 +02:00
ImGui :: PushStyleColor ( ImGuiCol_Text , ORANGE );
imgui . text ( std :: string ( "Indices CPU:" ));
2020-04-27 14:10:18 +02:00
ImGui :: PopStyleColor ();
ImGui :: SameLine ( offset );
imgui . text ( std :: to_string ( m_statistics . indices_size ) + " bytes" );
2020-05-04 09:37:06 +02:00
ImGui :: PushStyleColor ( ImGuiCol_Text , ORANGE );
imgui . text ( std :: string ( "Paths CPU:" ));
ImGui :: PopStyleColor ();
ImGui :: SameLine ( offset );
imgui . text ( std :: to_string ( m_statistics . paths_size ) + " bytes" );
ImGui :: PushStyleColor ( ImGuiCol_Text , ORANGE );
2020-05-05 12:09:11 +02:00
imgui . text ( std :: string ( "Render paths CPU:" ));
2020-05-04 09:37:06 +02:00
ImGui :: PopStyleColor ();
ImGui :: SameLine ( offset );
2020-05-05 12:09:11 +02:00
imgui . text ( std :: to_string ( m_statistics . render_paths_size ) + " bytes" );
2020-05-04 09:37:06 +02:00
ImGui :: Separator ();
ImGui :: PushStyleColor ( ImGuiCol_Text , ORANGE );
imgui . text ( std :: string ( "Vertices GPU:" ));
ImGui :: PopStyleColor ();
ImGui :: SameLine ( offset );
imgui . text ( std :: to_string ( m_statistics . vertices_gpu_size ) + " bytes" );
2020-04-28 15:08:36 +02:00
ImGui :: PushStyleColor ( ImGuiCol_Text , ORANGE );
imgui . text ( std :: string ( "Indices GPU:" ));
ImGui :: PopStyleColor ();
ImGui :: SameLine ( offset );
imgui . text ( std :: to_string ( m_statistics . indices_gpu_size ) + " bytes" );
2020-04-27 14:10:18 +02:00
imgui . end ();
}
#endif // ENABLE_GCODE_VIEWER_STATISTICS
2020-05-26 08:16:08 +02:00
#if ENABLE_GCODE_VIEWER_SHADERS_EDITOR
void GCodeViewer :: render_shaders_editor () const
{
auto set_shader = [ this ]( const std :: string & shader ) {
unsigned char begin_id = buffer_id ( GCodeProcessor :: EMoveType :: Retract );
unsigned char end_id = buffer_id ( GCodeProcessor :: EMoveType :: Custom_GCode );
for ( unsigned char i = begin_id ; i <= end_id ; ++ i ) {
m_buffers [ i ]. shader = shader ;
}
};
static const ImVec4 ORANGE ( 1.0f , 0.49f , 0.22f , 1.0f );
ImGuiWrapper & imgui = * wxGetApp (). imgui ();
Size cnv_size = wxGetApp (). plater () -> get_current_canvas3D () -> get_canvas_size ();
imgui . set_next_window_pos ( static_cast < float > ( cnv_size . get_width ()), 0.5f * static_cast < float > ( cnv_size . get_height ()), ImGuiCond_Once , 1.0f , 0.5f );
imgui . begin ( std :: string ( "Shaders editor (DEV only)" ), ImGuiWindowFlags_AlwaysAutoResize | ImGuiWindowFlags_NoResize );
2020-05-27 16:19:40 +02:00
ImGui :: RadioButton ( "glsl version 1.10 (low end PCs)" , & m_shaders_editor . shader_version , 0 );
ImGui :: RadioButton ( "glsl version 1.20 flat (billboards)" , & m_shaders_editor . shader_version , 1 );
ImGui :: RadioButton ( "glsl version 1.20 solid (spheres default)" , & m_shaders_editor . shader_version , 2 );
switch ( m_shaders_editor . shader_version )
2020-05-26 08:16:08 +02:00
{
case 0 : { set_shader ( "options_110" ); break ; }
2020-05-27 16:19:40 +02:00
case 1 : { set_shader ( "options_120_flat" ); break ; }
case 2 : { set_shader ( "options_120_solid" ); break ; }
2020-05-26 08:16:08 +02:00
}
if ( ImGui :: CollapsingHeader ( "Options" , ImGuiTreeNodeFlags_DefaultOpen ))
{
2020-06-01 08:55:44 +02:00
ImGui :: SliderFloat ( "point size" , & m_shaders_editor . point_size , 0.5f , 3.0f , "%.1f" );
2020-05-27 16:19:40 +02:00
if ( m_shaders_editor . shader_version == 1 )
2020-05-26 08:16:08 +02:00
{
ImGui :: SliderInt ( "percent outline" , & m_shaders_editor . percent_outline , 0 , 50 );
ImGui :: SliderInt ( "percent center" , & m_shaders_editor . percent_center , 0 , 50 );
}
}
imgui . end ();
}
#endif // ENABLE_GCODE_VIEWER_SHADERS_EDITOR
2020-05-04 09:37:06 +02:00
bool GCodeViewer :: is_travel_in_z_range ( size_t id ) const
{
const IBuffer & buffer = m_buffers [ buffer_id ( GCodeProcessor :: EMoveType :: Travel )];
if ( id >= buffer . paths . size ())
return false ;
Path path = buffer . paths [ id ];
int first = static_cast < int > ( id );
unsigned int last = static_cast < unsigned int > ( id );
// check adjacent paths
while ( first > 0 && path . first . position . isApprox ( buffer . paths [ first - 1 ]. last . position )) {
-- first ;
path . first = buffer . paths [ first ]. first ;
}
while ( last < static_cast < unsigned int > ( buffer . paths . size () - 1 ) && path . last . position . isApprox ( buffer . paths [ last + 1 ]. first . position )) {
++ last ;
path . last = buffer . paths [ last ]. last ;
}
return is_in_z_range ( path );
}
2020-04-14 10:02:08 +02:00
} // namespace GUI
} // namespace Slic3r
#endif // ENABLE_GCODE_VIEWER